20170831工作日记
1.关于LayoutInflater的原理解析
LayoutInflater它主要是用于加载布局的。由于加载布局的任务通常都是在Activity中调用setContentView()方法来完成的,但是其实setContentView()方法的内部也是使用LayoutInflater
来加载布局的。
首先需要获取到LayoutInflater的实例,有两种方法可以获取到,第一种写法如下:
LayoutInflater layoutInflater = LayoutInflater.from(context);
还有另外一种写法也可以完成同样的效果:
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
其实第一种就是第二种的简单写法,只是Android给我们做了一下封装而已。得到了LayoutInflater的实例之后就可以调用它的inflate()方法来加载布局了,如下所示:
layoutInflater.inflate(resourceId, root);
inflate()方法一般接收两个参数,第一个参数就是要加载的布局id,第二个参数是指给该布局的外部再嵌套一层父布局,如果不需要就直接传null。这样就成功成功创建了一个布局的实例,之后再将它添加到指定的位置就可以显示出来了。
1 public class MainActivity extends Activity { 2 3 private LinearLayout mainLayout; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 mainLayout = (LinearLayout) findViewById(R.id.main_layout); 10 LayoutInflater layoutInflater = LayoutInflater.from(this); 11 View buttonLayout = layoutInflater.inflate(R.layout.button_layout, null); 12 mainLayout.addView(buttonLayout); 13 } 14 15 }
这里先是获取到了LayoutInflater的实例,然后调用它的inflate()方法来加载button_layout这个布局,最后调用LinearLayout的addView()方法将它添加到LinearLayout中。
借助LayoutInflater成功将button_layout这个布局添加到LinearLayout中了。LayoutInflater技术广泛应用于需要动态添加View的时候,比如在ScrollView和ListView中,经常都可以看到LayoutInflater的身影。
具体源码解析,参看郭霖博客 http://blog.csdn.net/guolin_blog/article/details/12921889/
1 /** 2 * Created by nubia on 2017/8/30. 3 */ 4 5 public class AnimalAdapter extends BaseAdapter { 6 7 private LinkedList<Animal> mData; 8 private Context mContext; 9 10 public AnimalAdapter(LinkedList<Animal> mData, Context mContext) { 11 this.mData = mData; 12 this.mContext = mContext; 13 } 14 15 @Override 16 public int getCount() { 17 return mData.size(); 18 } 19 20 @Override 21 public Object getItem(int i) { 22 return null; 23 } 24 25 @Override 26 public long getItemId(int i) { 27 return i; 28 } 29 30 @Override 31 public View getView(int position, View convertView, ViewGroup parent) { 32 convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list_animal,parent,false); 33 ImageView img_icon = convertView.findViewById(R.id.img_icon); 34 TextView txt_aName = convertView.findViewById(R.id.txt_aName); 35 TextView txt_aSpeak = convertView.findViewById(R.id.txt_aSpeak); 36 37 img_icon.setBackgroundResource(mData.get(position).getaIcon()); 38 txt_aName.setText(mData.get(position).getaName()); 39 txt_aSpeak.setText(mData.get(position).getaSpeak()); 40 return convertView; 41 } 42 }
分析:构造函数为啥要传参mContext以及mData。 1.传入mContext是因为在getView()中需要加入到父布局中的上下文环境。2.传入mData是因为在每一个view中需要填充入将要显示的数据。
下面是MainActivity文件:
1 public class MainActivity extends AppCompatActivity { 2 3 /** 4 * 注意下context用法 5 */ 6 private List<Animal> mData = null; 7 private Context mContext; 8 private AnimalAdapter mAdapter = null; 9 private ListView list_animal; 10 11 @Override 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.activity_main); 15 16 mContext = MainActivity.this; 17 list_animal = (ListView) findViewById(R.id.list_animal); 18 mData = new LinkedList<>(); 19 mData.add(new Animal("狗说", "你是狗么?", R.mipmap.aaa)); 20 mData.add(new Animal("牛说", "你是牛么?", R.mipmap.bbb)); 21 mData.add(new Animal("鸭说", "你是鸭么?", R.mipmap.ccc)); 22 mData.add(new Animal("鱼说", "你是鱼么?", R.mipmap.ddd)); 23 mData.add(new Animal("马说", "你是马么?", R.mipmap.eee)); 24 /** 25 * 将需要的数据和上下文传递到Adapter中进行填充 26 */ 27 mAdapter = new AnimalAdapter((LinkedList<Animal>) mData, mContext); 28 list_animal.setAdapter(mAdapter); 29 } 30 }
分析:在主文件中构造出来了mAdapter的对象,并将上下文以及数据传入到适配器中去。
综上,ListView的使用方式总结:
1.mListView.setAadapter(mAdapter); 其中mListView通过(ListView) findViewById(R.id.xxx)寻找到,
2.mAdapter通过自定义的适配器打造,核心是重写getView()方法。首先加载自己的view布局,然后设置自己的view布局文件,其中的数据可以是从其他地方传进来的也可以是自己的数据。最终该方法返回一个view。
2. ListView由于item项中包含某些可以抢焦点的控件导致无法获取焦点问题的解决方案
如果你自定义ListView的项中包含能获得焦点的子控件(RadioGroup、Button、CheckBox、 DatePicker、ImageButton、ScrollView、SeekBar、EditText、ToggleButton、 RatingBar等)的话,默认焦点会被交给这些子控件,而ListView的项能被选中的基础是它能获取焦点,所以项中的这些子控件的焦点必须为 false,这样ListView的项才能获取onItemLongClick事件与onItemClick事件。
解决方案:
1. 在xml中设置Button的android:focusable="false", 这样Button就不会去抢夺焦点了.
2. 在getView()中设置Button不去获取焦点, btn.setFocusable(false).
3. 设置item的根布局的配置android:descendantFocusability="blocksDescendant"
三种方式都可以解决ListView条目失去焦点的问题.
3. ListView 的动态加载
(1)需要在getView()中加上add()方法
1 public void add(Data data) { 2 if (mData == null) { 3 mData = new LinkedList<>(); 4 } 5 mData.add(data); 6 notifyDataSetChanged(); 7 }
向特定位置添加元素:
1 //往特定位置,添加一个元素 2 public void add(int position, Data data) { 3 if (mData == null) { 4 mData = new LinkedList<>(); 5 } 6 mData.add(position, data); 7 notifyDataSetChanged(); 8 }
删除元素,代码如下:
1 public void remove(Data data) { 2 if (mData != null) { 3 mData.remove(data); 4 } 5 notifyDataSetChanged(); 6 } 7 8 public void remove(int position) { 9 if (mData != null) { 10 mData.remove(position); 11 } 12 notifyDataSetChanged(); 13 }
整个MyAdapter的类代码如下:
1 /** 2 * Created by nubia on 2017/8/31. 3 */ 4 5 public class MyAdapter extends BaseAdapter { 6 7 private Context mContext; 8 private LinkedList<Data> mData; 9 10 public MyAdapter() { 11 } 12 13 public MyAdapter(LinkedList<Data> mData, Context mContext) { 14 this.mData = mData; 15 this.mContext = mContext; 16 } 17 18 @Override 19 public int getCount() { 20 return mData.size(); 21 } 22 23 @Override 24 public Object getItem(int i) { 25 return null; 26 } 27 28 @Override 29 public long getItemId(int i) { 30 return i; 31 } 32 33 @Override 34 public View getView(int position, View convertView, ViewGroup parent) { 35 ViewHolder holder = null; 36 if (convertView == null) { 37 convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false); 38 holder = new ViewHolder(); 39 holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon); 40 holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content); 41 convertView.setTag(holder); 42 } else { 43 holder = (ViewHolder) convertView.getTag(); 44 } 45 holder.img_icon.setImageResource(mData.get(position).getImgId()); 46 holder.txt_content.setText(mData.get(position).getContent()); 47 return convertView; 48 } 49 50 private class ViewHolder { 51 ImageView img_icon; 52 TextView txt_content; 53 } 54 55 //添加一个元素 56 public void add(Data data) { 57 if (mData == null) { 58 mData = new LinkedList<>(); 59 } 60 mData.add(data); 61 notifyDataSetChanged(); 62 } 63 64 //往特定位置,添加一个元素 65 public void add(int position, Data data) { 66 if (mData == null) { 67 mData = new LinkedList<>(); 68 } 69 mData.add(position, data); 70 notifyDataSetChanged(); 71 } 72 73 public void remove(Data data) { 74 if (mData != null) { 75 mData.remove(data); 76 } 77 notifyDataSetChanged(); 78 } 79 80 public void remove(int position) { 81 if (mData != null) { 82 mData.remove(position); 83 } 84 notifyDataSetChanged(); 85 } 86 87 public void clear() { 88 if (mData != null) { 89 mData.clear(); 90 } 91 notifyDataSetChanged(); 92 } 93 94 }
(2)在显示页面上:
1 public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 2 3 private ListView list_one; 4 5 private Button btn_add; 6 private Button btn_remove2; 7 8 private MyAdapter mAdapter = null; 9 private List<Data> mData = null; 10 private Context mContext = null; 11 12 private int flag = 1; 13 @Override 14 protected void onCreate(Bundle savedInstanceState) { 15 super.onCreate(savedInstanceState); 16 setContentView(R.layout.activity_main); 17 18 mContext = MainActivity.this; 19 mData = new LinkedList<>(); 20 mAdapter = new MyAdapter((LinkedList<Data>)mData,mContext); 21 bindViews(); 22 23 } 24 25 private void bindViews() { 26 list_one = (ListView) findViewById(R.id.list_one); 27 28 btn_add = (Button) findViewById(R.id.btn_add); 29 btn_remove2 = (Button) findViewById(R.id.btn_remove2); 30 31 list_one.setAdapter(mAdapter); 32 33 btn_add.setOnClickListener(this); 34 btn_remove2.setOnClickListener(this); 35 } 36 37 @Override 38 public void onClick(View v) { 39 switch (v.getId()){ 40 case R.id.btn_add: 41 mAdapter.add(new Data(R.mipmap.ic_icon_qitao,"给猪哥跪了~~~ x " + flag)); 42 flag++; 43 break; 44 case R.id.btn_remove2: 45 mAdapter.remove(2);//删除第三行的数据,由数字决定删除哪一列 46 break; 47 } 48 } 49 }
静态代码中的listview元素是固定的,无法动态增加和减少,在动态listview中要实现添加和删除,需要在MyAdapter中添加增加/删除 view的方法。