buder

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的方法。

 

posted on 2017-08-31 10:37  buder  阅读(141)  评论(0编辑  收藏  举报

导航