Android 常见界面控件(ListView、RecyclerView、自定义View篇)

目录

    • 3.3 ListView的使用
      • 3.3.1 ListView控件的简单使用
      • 3.3.2 常用数据适配器
      • 3.3.3 案例——Android生物商城
    • 3.4 RecyclerView的使用
    • 3.5 自定义View
      • 3.5.1 自定义View常用的3个方法
      • 3.5.2 用自定义View在界面中显示圆形
  • 在这里插入图片描述

3.3 ListView的使用

例如微信淘宝等应用程序,这些程序通常会在一个页面中展示多个条目,并且每一个条目布局风格一致,这种数据的展示方式是通过ListView控件实现的

3.3.1 ListView控件的简单使用

ListView以列表的形式展示数据内容,并且能根据列表高度自适应屏幕显示,ListView控件的常用属性:

3.3.2 常用数据适配器

在为ListView控件添加数据时会用到数据适配器。数据适配器是数据与视图之间的桥梁,它类似于一个转换器,将复杂的数据转换成用户可以接受的方式进行呈现。在Android系统中提供了多种适配器(Adapter)对ListView控件进行数据适配

  1. BaseAdapter

BaseAdapter是基础的适配器,其实际上是一个抽象类,通常在自定义适配器时会继承BaseAdapter,该类有四个抽象方法,根据这些抽象方法来对ListView控件进行数据适配

  1. SimpleAdapter

SimpleAdapter继承自BaseAdapter,实现了BaseAdapter的四个抽象方法对其进行封装,因此在使用SimpleAdapter进行数据适配时,只需要在构造方法中传入相应的参数即可

public SimpleAdapter(Context context,List<? extends Map ?>

data, int resource,String[] from,int[] to)

  • context:上下文对象
  • data:数据集合,data中的每一项对应ListView控件中的条目的数据
  • resource:Item布局的资源id
  • from:Map集合中的key值
  • to:Item布局中对应的控件
  1. ArrayAdapter

ArrayAdapter也是BaseAdapter的子类,使用时只需要在构造方法中传入相应的参数即可,ArrayAdapter常用于适配TextView控件,例如Android Studio的Help,ArrayAdapter有多个构造方法

  • context:上下文对象
  • resource:Item布局的资源id
  • textViewResourceID:Item布局中相应TextView的id
  • T[] objects:需要适配的数组类型的数据
  • List object:需要适配的List类型的数据

在创建数据适配器后,可以通过ListView对象的setAdapter()方法添加适配器

例如:要将继承 BaseAdapter的MyBaseAdapter实例添加到ListView

ListView mListView = (ListView)findViewById(R.id.lv);
MyBaseAdapter mAdapter = new MyBaseAdapter();
mListView.setAdapter(mAdapter);

3.3.3 案例——Android生物商城

  1. 创建listview应用程序

  2. 导入图片资源

  3. 放置界面控件(编写activity_main.xml文件)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="368dp"android:layout_height="45dp"android:text="生物图鉴"android:textSize="18sp"android:textColor="#FFFFFF"android:background="#FF8F03"android:gravity="center" /><ListViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/lv"/>
</LinearLayout>
  1. 创建Item界面(编写list_item.xml文件)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="16dp"><ImageViewandroid:id="@+id/iv"android:layout_width="120dp"android:layout_height="90dp"android:layout_centerVertical="true"/><RelativeLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_toRightOf="@+id/iv"android:layout_centerVertical="true"><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="豹猫"android:textSize="20sp"android:textColor="#000000"/><TextViewandroid:id="@+id/tv_price"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="价格"android:textSize="20sp"android:textColor="#FF8F03"android:layout_below="@+id/title"android:layout_marginTop="10dp"/><TextViewandroid:id="@+id/price"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="1000"android:textSize="20sp"android:textColor="#FF8F03"android:layout_below="@+id/tv_price"android:layout_marginTop="10dp"/></RelativeLayout>
</RelativeLayout>
  1. 编写界面交互代码(MainActivity中的MyBaseAdapter)
public class MainActivity extends AppCompatActivity {private ListView mListView;//生物与价格数据集合private String[] titles = {"豹猫","毪菇","马","狼"};private String[] prices = {"1000","4000","6577","5000"};//图片数据集合private int[] icons = {R.mipmap.cat,R.mipmap.cow,R.mipmap.horse,R.mipmap.wolf};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化ListView控件mListView = (ListView)findViewById(R.id.lv);//创建一个数据适配器实例MyBaseAdapter ma = new MyBaseAdapter();mListView.setAdapter(ma);}//编写一个实现了BaseAdapter抽象类的数据适配器类class MyBaseAdapter extends BaseAdapter{@Overridepublic int getCount() {//获取Item的总数return titles.length;}@Overridepublic Object getItem(int position) {//返回Item的数据对象return titles[position];}@Overridepublic long getItemId(int position) {//返回item的idreturn position;}//得到item的视图@Overridepublic View getView(int position, View convertView, ViewGroup parent) {//加载activity_item.xml布局文件View view = View.inflate(MainActivity.this,R.layout.activity_item,null);TextView title = (TextView) view.findViewById(R.id.title);TextView price = (TextView) view.findViewById(R.id.price);ImageView iv = (ImageView) view.findViewById(R.id.iv);title.setText(titles[position]);price.setText(prices[position]);iv.setBackgroundResource(icons[position]);return view;}}
}

启动测试

  1. 优化ListView加载数据逻辑

运行上述程序后,当ListView控件 上加载的Item过多并快速滑动该控件时,界面会出现卡顿的现象,出现这个现象的原因如下:

(1)当滑动屏幕时,不断地创建Item对象。ListView控件在当前屏幕上显示多少个Item,就会在适配器MyBaseAdapter中的getView0方法中创建多少Item对象。当滑动ListView控件时, 滑出屏幕的Item对象会被销毁,新加载到屏幕上的Item会创建新的对象,因此快速滑动ListView控件时会不断地对Item对象进行销毁和创建

(2)不断执行findViewByld0方法初始化控件。每创建-一个Item对象都需要加载一次Item布局,加载布局时会不断地执行findViewByld0方法初始化控件。这些操作比较耗费设备(模拟器、手机等设备)的内存并且浪费时间,如果每个Item都需要加载网络图片,加载网络图片是个比较耗时的操作,就会造成程序内存溢出的异常

由于以上两点原因,我们需要对ListView控件进行优化,优化的目的就是使ListView控件在快速滑动时不再重复创建Item对象,减少内存的消耗和屏幕渲染的处理

优化步骤

  1. 创建ViewHolder类。 在MainActivity中创建一 个ViewHolder类, 将需要加载的控件变量放在改类中
class ViewHolder{TextView title;ImageView iv;
}
  1. 在MyBaseAdapter的getView(int position, View convertView, ViewGroup parent)方法中,第2个参数convertView代表的就是之前滑出屏幕的Item对象。如果第一次加载getView0方法时,会创建Item对象,当滑动ListView控件时, 滑出屏幕的Item对象会以缓存的形式存在,而convertView代表的就是缓存的Item对象,我们可以通过复用convertView对象从而减少Item对象的创建,在getView()方法中进行优化的代码
@Override
public View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder = null;if(convertView == null){//将activity_item.xml布局文件找出来并转换为View对象convertView = View.inflate(MainActivity.this,R.layout.activity_item,null);//找到activity_item.xml中的TextViewholder = new ViewHolder();holder.title = (TextView) convertView.findViewById(R.id.title);holder.price = (TextView) convertView.findViewById(R.id.price);holder.iv = (ImageView) convertView.findViewById(R.id.iv);convertView.setTag(holder);}else{holder = (ViewHolder) convertView.getTag();}holder.title.setText(titles[position]);holder.price.setText(prices[position]);holder.iv.setBackgroundResource(icons[position]);return convertView;
}

代码解析

第2行代码用于判断convertView对象是否为null,若为null,则会创建ViewHolder类中的对象holder,并将获取的界面控件赋值给ViewHolder类中的属性,最后通过setTag()方法将对象holder添加到convertView对象中,否则不会创建ViewHolder类的对象,会通过getTag()方法获取缓存在convertView对象中的ViewHolder类的对象

3.4 RecyclerView的使用

在Android5.0之后,谷歌提供了用于在有限的窗口范围内显示大量数据的控件RecyclerView,与ListView控件相似,RecyclerView控件同样 是以列表的形式展示数据,并且数据都是通过适配器加载的。但是,RecyclerView的功能更加强大

(1)展示效果: RecyclerView控件 可以通过LayoutManager类实现横向或竖向的列表效果、瀑布流效果和GridView效果,而ListView控件 只能实现竖直的列表效果

(2)适配器: RecyclerView 控件使用的是RecyclerView.Adapter适配器,该适配器将BaseAdapter中的getView()方法拆分为onCreateViewHolder()方法和onBindViewHolder0方法,强制使用ViewHolder类,使代码编写规范化,避免了初学者写的代码性能不佳

(3)复用效果: RecyclerView控件复用Item对象的工作由该控件自己实现,而ListView控件复用Item对象的工作需要开发者通过convertView的setTag()方法和getTag()方法进行操作

(4)动画效果: RecyclerView控件可以通过setltemAnimator()方法为Item添加动画效果,而ListView控件不可以通过该方法为Item添加动画效果

典例

RecyclerView是com.android. support:recyclerview-v7库中的控件,因此需要将该库添加到程序中。首先选中程序名称,右击选择[Open Module Settings]选项,在Project Structure窗口中的左侧选择[app],接着选中[Dependencies]选项卡,单击右上角的绿色加号

activity_main.xml文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v7.app.AlertController.RecycleListViewandroid:id="@+id/id_recyclerview"android:layout_width="match_parent"android:layout_height="match_parent"></android.support.v7.app.AlertController.RecycleListView>
</RelativeLayout>

activity_item.xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="16dp"android:gravity="center"android:orientation="horizontal"><ImageViewandroid:id="@+id/iv"android:layout_width="120dp"android:layout_height="90dp"android:src="@drawable/cat"/><RelativeLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginTop="5dp"><TextViewandroid:id="@+id/name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="豹猫"android:textSize="20sp"android:textColor="#000000"/><TextViewandroid:id="@+id/introduce"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="16sp"android:textColor="#FF716C6D"android:layout_below="@+id/name"android:layout_marginTop="10dp"android:maxLines="2"android:ellipsize="end"android:text="没有被驯服的豹猫会杀鸡,它会渐渐靠近一只鸡,然后迅速扑过去杀掉它,也是十分的凶残啊!小豹猫一点也不示弱,照样会杀鸡哦!"/></RelativeLayout>
</LinearLayout>

MainActivity.java文件

public class MainActivity extends AppCompatActivity {private RecyclerView mRecyclerView;private HomeAdapter mAdapter;private String[] names = {"豹猫","马","毪菇","兔子"};private int[] icons = {R.drawable.cat,R.drawable.cow,R.drawable.horse,R.drawable.wolf};private String[] introduces = {"...","...","...","..."};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mRecyclerView = (RecyclerView)findViewById(R.id.id_recyclerview);mRecyclerView.setLayoutManager(new LinearLayoutManager(this));mAdapter = new HomeAdapter();mRecyclerView.setAdapter(mAdapter);}class HomeAdapter extends  RecyclerView.Adapter<HomeAdapter.MyViewHolder>{@Overridepublic HomeAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {MyViewHolder holder = new MyViewHolder(LayoutInflater.from(MainActivity.this).inflate(R.layout.activity_item,parent,false));return holder;}@Overridepublic void onBindViewHolder(MyViewHolder holder, int position) {holder.name.setText(names[position]);holder.iv.setImageResource(icons[position]);holder.introduce.setText(introduces[position]);}@Overridepublic int getItemCount() {return names.length;}class MyViewHolder extends RecyclerView.ViewHolder {TextView name;ImageView iv;TextView introduce;public MyViewHolder(View itemView) {super(itemView);name = (TextView) itemView.findViewById(R.id.name);iv = (ImageView) itemView.findViewById(R.id.iv);introduce = (TextView) itemView.findViewById(R.id.introduce);}}}
}

代码解析

先在第11行代码获取RecyclerView控件,接着通过setLayoutManager()方法设置RecyclerView控件的显示方式为线性垂直的效果,然后通过setAdapter()方法将适配器HomeAdapter的对象设置在RecyclerView上

在第17行创建一个HomeAdapter类继承自RecyclerView.Adapter类,并在其中重写方法,onCreateViewHolder()方法用于加载Item界面的布局文件,并将MyViewHolder类的对象返回,onBindViewHolder()方法用于将获取的数据设置在对应控件上,getItemCount()方法用于获取列表条目的总数

第33行创建了一个MyViewHolder类继承自RecyclerView.ViewHolder类,在该类中获取Item界面上的控件

关键语句:

MyViewHolder holder = new MyViewHolder(LayoutInflater.from(MainActivity.this).inflate(R.layout.activity_item,parent,false));

启动测试

3.5 自定义View

通常开发Android应用的界面时,使用的控件都不直接使用View,而是使用View的子类。例如,如果要显示一段文字,可以使用View的 子类TextView,如果要显示-一个按钮,可以使用View的子类Button。虽然Android系统中提供了很多继承自View类的控件,但是在实际开发中,还会出现不满足需求的情况,因此我们可以通过自定义View的方式进行实现

最简单的自定义View就是创建一个类继承View类或其子类,并重写该类的构造方法

public class CustomView extends View{public CustomView(Context context){super(context);}public CustomView(Context context,AttributeSet attrs){super(context,attrs);}
}

定义好自定义类CustomView后,若想创建一个该类的对象,则需要使用到该类的第一个构造方法,若想要在布局文件中引入该自定义的CustomView控件,则需要使用到该类的第二个构造方法

3.5.1 自定义View常用的3个方法

由于系统自带的控件不能满足需求中的某种样式或功能,因此我们需要在自定义View中通过重写指定的方法来添加额外的样式和功能,自定义View常用的3个方法的具体介绍如下:

(1) onMeasure()方法:该方法用于测量尺寸,在该方法中可以设置控件本身或其子控件的宽高

onMeasure (int widthMeasureSpec, int heightMeasureSpec)

onMeasure()方法中的第1个参数widthMeasureSpec表示获取父容器指定该控件的宽度,第2个参数heightMeasureSpec表示获取父容器指定该控件的高度
widthMeasureSpec和heightMeasureSpec参数不仅包含父容器指定的属性值,还包括父容器指定的测量模式

测量模式分为三种:

●EXACTLY: 当自定义控件的宽高的值设置为具体值时使用,如100dp、 match _parent等,此时控件的宽高值是精确的尺寸
●AT_MOST: 当自定义控件的宽高值为wrap_content时使用,此时控件的宽高值是控件中的数据内容可获得的最大空间值
●UNSPECIFIED: 当父容器没有指定自定义控件的宽高值时使用

需要注意的是,虽然参数widthMeasureSpec和heightMeasureSpec是父容器指定该控件的宽高,但是该控件还需要通过setMeasuredDimension(int,int)方法设置具体的宽高

(2) onDraw()方法:该方法用于绘制图像

onDraw (Canvas canvas)

onDraw0方法中的参数canvas表示画布。Canvas类经常与Paint类(画笔)配合使用,使用Paint类可以在Canvas类中绘制图像

(3) onLayout()方法:onLayout()方 法用于指定布局中子控件的位置,该方法通常在自定义ViewGroup中重写

onLayout (boolean changed, int left, int top, int right, int bottom)

onLayout(方法中有5个参数,其中,第1个参数changed表示自定义View的大小和位置是否发生变化,剩余的4个参数left、top、 right、 bottom分别表示子控件与父容器左边、顶部、右边、底部的距离

3.5.2 用自定义View在界面中显示圆形

CustomView.java

public class CustomView extends View {public CustomView(Context context) {super(context);}public CustomView(Context context,AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int r = getMeasuredWidth()/2;int cX = getLeft()+r;int cY = getTop()+r;Paint paint = new Paint();paint.setColor(Color.RED);//绘制canvas.drawCircle(cX,cY,r,paint);}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginLeft="16dp"android:layout_marginTop="16dp"><com.itcast.CustomView.CustomViewandroid:layout_width="100dp"android:layout_height="100dp"/>
</RelativeLayout>

启动测试

如果文章对您有所帮助,记得一键三连支持一下哦~

Android 常见界面控件(ListView、RecyclerView、自定义View篇)相关推荐

  1. Android常见界面控件(基础入门)

    Android本意指"机器人",Google公司将Android的标识设计为一个绿色机器人, 表示Android系统符合环保概念,是一个轻薄短小,功能强大的移动系统,是第一个真正为 ...

  2. android listview 滑动条显示_第七十六回:Android中UI控件之RecyclerView基础

    各位看官们,大家好,上一回中咱们说的是Android中UI控件之ListView优化的例子,这一回咱们说的例子是UI控件之RecyclerView.闲话休提,言归正转.让我们一起Talk Androi ...

  3. CH3-Android常见界面控件

    目标 掌握简单控件的使用,能够独立搭建一个注册界面 掌握ListView控件与RecyclerView控件的使用,能独立搭建列表界面 掌握自定义控件的定义方式,能够自定义一个简单的控件 ​ 几乎每一个 ...

  4. listview控件在php的使用方法,Android_Android编程之控件ListView使用方法,本文实例讲述了Android编程之控 - phpStudy...

    Android编程之控件ListView使用方法 本文实例讲述了Android编程之控件ListView使用方法.分享给大家供大家参考.具体分析如下: 控件ListView是一个重要的控件,可以被用作 ...

  5. android studio 画控件,Android Studio 基础控件使用

    TextView android:gravity="center" //文字对其方式 top bottom left right center android:textColor= ...

  6. android播放视频控件,视频播放控件VideoView的基本使用

    在Android的界面控件中有一个视频播放控件,可以直接在手机上面开辟一个视频播放的UI,播放视频,下面ATAAW.COM大概介绍下视频控件VideoView的使用,由于视频播放是属于Android多 ...

  7. Android 数据库(SQLite)【简介、创建、使用(增删改查、事务、实战演练)、数据显示控件(ListView、Adapter、实战演练-绿豆通讯录)】

    目   录 (壹)SQLite数据库简介 (贰)数据库的创建 (叁)数据库的使用 3.1.SQlite的基本操作 3.1.1.添加数据 3.1.2.修改数据 3.1.3.查询数据 3.1.4.删除数据 ...

  8. android选项菜单源代码,Android应用程序----UI界面控件(菜单menu)

    菜单是应用程序中非常重要的组成部分,能够在不占用界面空间的前提下,为应用程序提供了统一的功能和设置界面,并为程序开发人员提供了易于使用的编程接口 Android系统支持三种菜单 选项菜单(Option ...

  9. android绿豆通讯录xml,Android 数据库(SQLite)【简介、创建、使用(增删改查、事务、实战演练)、数据显示控件(ListView、Adapter、实战演练)】...

    目   录 (壹)SQLite数据库简介 (贰)数据库的创建 (叁)数据库的使用 3.1.SQlite的基本操作 3.1.1.添加数据 3.1.2.修改数据 3.1.3.查询数据 3.1.4.删除数据 ...

最新文章

  1. 微软MVP社区活动(西宁站)
  2. golang查找重复行
  3. VScode设置中文
  4. Vue中使用Openlayers加载Geoserver发布的TileWMS时单击获取shp文件的坐标信息
  5. asp.net MVC中的tip
  6. 手把手教你使用spring cloud+dotnet core搭建微服务架构:服务治理(-)
  7. 仓库货位卡标识牌_仓库应如何规划?
  8. 想网站稳定运营?不可不知 DDoS的攻击原理与防御方法
  9. 例题 9-2 巴比伦塔(The Tower of Babylon, UVa 437)
  10. USYD悉尼大学INFO1110 详细作业解析Week3 all quizzes
  11. 关于部分Win10降成WIN7的安装步骤
  12. amd linux显卡驱动,AMD Radeon系列显卡催化剂驱动14.4 正式版For Linux AMD Radeon系列显卡催化剂驱动14.4 正式版 显卡驱动 超威半导体...
  13. 【Windows】Windows如何使用注册表修改软件默认安装路径?
  14. 另一个小程序 返回的支付结果如何得到_微信小程序商城的开发商家需要注意什么?...
  15. ASP.NET MVC 分部页 PartialViewResult
  16. 手游客户端开发招聘要求
  17. PAT 1051 复数乘法
  18. Redis Cluster 添加/删除 完整折腾步骤
  19. html如何设置多级列表,如何在Word文档中设置多级列表
  20. 多态是什么 父类如何调用子类的方法(美团面试)

热门文章

  1. centos 内网ip访问mysql数据库
  2. Spring优雅停机
  3. 【数据结构Note4】-串、数组和广义表(kmp算法详解)
  4. 虚拟机连接数据库报错2059
  5. gz文件解压 linux,linux下.tar.gz和.gz文件解压详解
  6. ESP32设备驱动-Si1145红外接近-紫外 (UV) 指数和环境光传感器驱动
  7. 分布式文件存储——FastDFS
  8. 【机器学习】样本方差和标准差
  9. 【数据结构】栈的介绍
  10. Spring配置文件beans.xml头部配置解释