我是靠谱客的博主 简单酒窝,这篇文章主要介绍自定义控件和ListView,RecyclerView引入布局创建自定义控件ListViewRecyclerView实例练习(聊天界面),现在分享给大家,希望可以做个参考。

自定义控件和ListView,RecyclerView

  • 引入布局
  • 创建自定义控件
  • ListView
    • ListView的简单用法
    • 定制ListView的界面
    • 提升ListView的运行效率
    • ListView的点击事件
  • RecyclerView
    • RecyclerView的基本用法
    • 实现横向滚动和瀑布流布局
    • RecyclerView的点击事件
  • 实例练习(聊天界面)

引入布局

Android:background可以为布局或者控件指定一个背景;
Android:layout_margin可以指定控件在上下左右方向上偏移的距离,也可以使用android:layout_marginLeft等属性来单独指定控件在某个方向上偏移的距离。
成功定义一个布局之后,在主布局文件里面用将其引入;

在这里插入图片描述
隐藏系统自带标题栏的方式:调用gerSupportActionBar()来获得ActionBar实例,然后调用ActionBar的hide()将标题栏隐藏起来。

在这里插入图片描述

创建自定义控件

1.新建类继承LinearLayout,成为自定义控件;
2.重写LinearLayout里面带有两个参数的构造函数,在布局里面引入自定义控件就会调用这个构造函数,通过LayoutInflater的from()方法可以构建出一个LayoutInflater对象,然后调用inflate()方法可以动态加载一个布局文件,inflater()方法接收两个参数,(第一个参数是要加载布局文件的id,第二个参数是给加载好的布局再添加一个父布局);
在这里插入图片描述

3.在布局文件里面添加自定义控件;
在这里插入图片描述

ListView

ListView的简单用法

1.在.xml里面加入ListView布局;
2.在类里面定义数据。然后将数据传递给ListView,这里借助适配器完成:
将ArrayAdapter泛型指定成String;
在ArrayAdapter的构造函数中依次传入当前上下文,ListView子项布局的id,要适配的数据;
调用ListView的setAdapter()方法,将构建好的适配器对象传递进去;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MainActivity extends AppCompatActivity { private String[] data = { "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango", "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ArrayAdapter<String> adapter = new ArrayAdapter<String>( MainActivity.this, android.R.layout.simple_list_item_1, data); ListView listView = (ListView) findViewById(R.id.list_view); listView.setAdapter(adapter);} }

定制ListView的界面

1.定义一个实体类,作为ListView适配器的适配类型;
2.为ListView的子项指定一个自定义布局;
3.创建一个自定义的适配器,继承ArrayAdapter,泛型指定为刚刚自定义的实体类;在新建的适配器里重写了父类的一组构造函数,将上下文,ListView子项布局的id,数据都传递进去;重写getView()方法,首先通过getItem()得到当前的实例,然后通过LayoutInflater来为这个子项加载我们传入的布局;
LayoutInflater的inflate()接收三个参数,第三个参数是false是表示只让我们在父布局中声明layout属性生效,不会为这个View添加父布局,因为一旦View有了父布局之后,他就不能再添加到ListView中了。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class FruitAdapter extends ArrayAdapter<Fruit> { private int resourceId; public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) { super(context, textViewResourceId, objects); resourceId = textViewResourceId; }@Override public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); // 获取当前项的Fruit实例 View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false); ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image); TextView fruitName = (TextView) view.findViewById(R.id.fruit_name); fruitImage.setImageResource(fruit.getImageId()); fruitName.setText(fruit.getName()); return view; } }

提升ListView的运行效率

在getView方法里面,每次都将布局重新加载了一遍,当ListView快速滚动的时候,这就会成为性能的瓶颈。
在getView()方法里面还有一个convertView参数,这个参数是用于将之前加载好的布局进行缓存,以便之后可以进行重用。
我们可以在getView()方法里面进行判断,如果convertView为null,那么就使用LayoutInflater去加载布局,如果不是null则直接对convertView进行复用;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class FruitAdapter extends ArrayAdapter<Fruit> { ... @Override public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); View view; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false); } else { view = convertView; }ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image); TextView fruitName = (TextView) view.findViewById(R.id.fruit_name); fruitImage.setImageResource(fruit.getImageId()); fruitName.setText(fruit.getName()); return view; } }

在此优化基础上,虽然现在不会再重复去加载布局了,但是在每次getView()方法里面还是会去调用View的findViewById来获取一次控件的实例,这时我们可以借助ViewHolder来对这部分性能进行优化;
新增一个内部类ViewHolder,用于对控件的实例进行缓存,当convertView为null的时候,创建一个ViewHolder对象,将控件的实例都存在ViewHolder里面,然后调用View的setTag()方法,将ViewHolder对象存储在View中,当convertView不为null的时候,则调用View的getTag()方法,将ViewHolder重新取出来(这样控件存在ViewHolder里面就不用每次通过findViewById去获取控件实例了)。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class FruitAdapter extends ArrayAdapter<Fruit> { ... @Override public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); View view; ViewHolder viewHolder; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false); viewHolder = new ViewHolder(); viewHolder.fruitImage = (ImageView) view.findViewById (R.id.fruit_image); viewHolder.fruitName = (TextView) view.findViewById (R.id.fruit_name); view.setTag(viewHolder); // 将ViewHolder存储在View中 } else { view = convertView; viewHolder = (ViewHolder) view.getTag(); // 重新获取ViewHolder } viewHolder.fruitImage.setImageResource(fruit.getImageId()); viewHolder.fruitName.setText(fruit.getName()); return view; } class ViewHolder { ImageView fruitImage; TextView fruitName; }}

ListView的点击事件

使用setOnItemClickListener()为ListView注册一个监听器,当用户点击了ListView里面任意一个子项,就回调onItemClick()方法,然后通过position参数判断用户点击的是哪一个子项,然后获取对应的实例,用Toast显示出来。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MainActivity extends AppCompatActivity { private List<Fruit> fruitList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initFruits(); FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout. fruit_item, fruitList); ListView listView = (ListView) findViewById(R.id.list_view); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Fruit fruit = fruitList.get(position); Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show(); } }); } ... }

RecyclerView

RecyclerView的基本用法

1.在build.gradle里添加相应的依赖库;
在这里插入图片描述

2.在布局文件里加入RecyclerView,因为它不是内置在系统SDK里面的,所以需要把完整的包路径写出来;
在这里插入图片描述

3.为RecyclerView准备一个适配器,新建一个类,让这个适配器继承RecyclerView.Adapter,将其泛型指定为类名.ViewHolder,ViewHolder时我们在类里定义的一个内部类,这个内部类继承RecyclerView.ViewHolder,ViewHolder的构造函数里面传入一个View参数(这个参数通常是RecyclerView子项的最外层布局);
4.由于这个类时继承RecyclerView.Adapter的,那么就要重写onCreateViewHolder(),onBindViewHolder(),getItemCount()这三个方法。
在这里插入图片描述

onCreateViewHolder()是用于创建ViewHolder实例的,在这里面可以将自定义布局传进去,然后创建一个ViewHolder实例,把加载出来的布局传入到构造函数里面,最后将ViewHolder实例返回;
onBindViewHolder()是用于对RecyclerView子项的数据进行赋值的,会在每个子项被滚动到屏幕内的时候执行,通过position参数得到当前项的实例,然后再将数据设置到ViewHolder的对应数据里面;
getItemCount()用于告诉RecyclerView一共有多少个子项,直接返回数据源的长度就可以了;

5.在MainActivity函数里面,使用了一个initFruits()方法,用于初始化所有数据,然后再OnCreate()方法里面先获取到了RecyclerView的实例,然后创建了一个LinearLayoutManager对象,并且将它设置到RecyclerView中。(LayoutManager用于指定RecyclerView的布局方式,这里LinearLayoutManager是线性布局的意思,可以实现和ListView类似的效果),然后创建了适配器的实例,将数据传入到适配器的构造函数里面,最后调用RecyclerView的setAdapter()方法来完成适配器的设置,这样RecyclerViewg和数据之间的关联就建立完成了。
在这里插入图片描述

实现横向滚动和瀑布流布局

把前面自定义的元素布局改成垂直排列;在MainActivity里面加入一行代码:调用LinearLayout的setOrientation()方法来设置布局的排列方向(默认是纵向排列的),传入LinearLayout.HORIZONTAL表示让布局横向排列;
ListView的布局排列是由自身去管理的,RecyclerView将这个工作交给了LayoutManager,LayoutManager里面定制了一套可扩展的布局排列接口。除了LinearLayoutManager还有GridLayoutManager(网格布局)和StaggeredGridLayoutManager(瀑布流布局)
在onCreate()方法里面,创建一个StaaggerdeGiridLayoutManager的实例,StaaggeredGrildLayoutManager的构造函数接收两个参数,第一个参数用于指定布局的列数,第二个参数用于指定布局的排列方向,传入StaggeredGridLayoutManager.VERTICAL表示让布局纵向排列;然后再把创建好的实例设置到RecyclerView中就好了。(因为瀑布流的布局需要各个子项的高度1不一致才可以看到效果,所以可以使用gerRandomLengthName()这个方法,使用random对象来创造一个1到20之间的随机数)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

RecyclerView的点击事件

RecyclerView没有提供类似于setOnItemClickListener()这样的组测监听的方法,所以需要自己给子项具体的View注册点击事件;
先修改ViewHolder,在ViewHolder里面添加变量来保存子项最外层布局的实例,然后再onCreateViewHolder()方法里面注册事件就好了
在这里插入图片描述
在这里插入图片描述

实例练习(聊天界面)

https://github.com/yyyyy-yu/UI

最后

以上就是简单酒窝最近收集整理的关于自定义控件和ListView,RecyclerView引入布局创建自定义控件ListViewRecyclerView实例练习(聊天界面)的全部内容,更多相关自定义控件和ListView内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(78)

评论列表共有 0 条评论

立即
投稿
返回
顶部