一、ListView的使用
ListView以列表的形式展示数据内容,并且能够根据列表的高度自适应屏幕显示。
属性名称 |
功能描述 |
android:listSelector |
当条目被点击后,改变条目的背景颜色 |
android:divider |
设置分割线的颜色 |
android:dividerHeight |
设置分割线的高度 |
android:scrollbars |
是否显示滚动条 |
android:fadingEdge |
去掉上边和下边的黑色阴影 |
常用数据适配器(Adapter):数据适配器是数据与视图之间的桥梁,它类似于一个转换器,将复杂的数据转换成用户可以接受的方式进行呈现。
常用的数据适配器 BaseAdapter、SimpleAdapter 、ArrayAdapter
①BaseAdapter顾名思义是基本的适配器。他实际上是一个抽象类,通常在自定义适配器时会继承BaseAdapter。
BaseAdapter中的方法
方法名称
|
功能描述
|
public int getCount()
|
获取Item条目的总数
|
public Object getItem(int position)
|
根据position(位置)获取某个Item的对象
|
public long getItemId(int position)
|
根据position(位置)获取某个Item的id
|
public View getView(int position, View convertView, ViewGroup parent)
|
获取相应position对应的Item视图,position是当前Item的位置,convertView用于复用旧视图,parent用于加载XML布局。
|
②SimpleAdapter继承自BaseAdapter,实现了BaseAdapter的四个抽象方法并进行封装。因此在使用SimpleAdapter进行数据适配时,只需要在构造方法中传入相应的参数即可。SimpleAdapter的构造方法的具体信息如下:
③ArrayAdapter也是BaseAdapter的子类,用法与SimpleAdapter类似,开发者只需要在构造方法里面传入相应参数即可。ArrayAdapter通常用于适配TextView控件。的构造方法如下:
public ArrayAdapter(Context context,int resource); //context上下文对象 resource Item布局的资源ID
public ArrayAdapter(Context context,int resource, int textViewResourceId); //textViewResourceId Item布局中相应TextView的id
public ArrayAdapter(Context context,int resource,T[] objects); //objects 需要适配的数组类型的数据
public ArrayAdapter(Context context,int resource,int textViewResourceId,T[] objects);
public ArrayAdapter(Context context,int resource,List<T> objects);
public ArrayAdapter(Context context,int resource,int textViewResourceId, List<T> objects) //需要适配的List类型的数据
ListView案例:
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"
tools:context=".MainActivity"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="45dp"
android:text="购物商城"
android:textColor="#FFFFFF"
android:background="#FF8F03"
android:gravity="center"
/>
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:layout_width="120dp"
android:layout_height="90dp"
android:layout_centerVertical="true"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/iv"
android:layout_centerVertical="true">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="桌子"
android:textSize="20sp"
android:textColor="#000000"/>
<TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="价格"
android:textSize="20sp"
android:layout_marginTop="10dp"
android:layout_below="@+id/title"
android:textColor="#FF8F03"/>
<TextView
android:id="@+id/price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1000"
android:textSize="20sp"
android:layout_below="@+id/title"
android:layout_toRightOf="@id/tv_price"
android:textColor="#FF8F03"
android:layout_marginTop="10dp"/>
</RelativeLayout>
</RelativeLayout>
MainActivity.java
package com.example.listviewdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.w3c.dom.Text;
public class MainActivity extends AppCompatActivity {
private String[] titles = {"桌子","苹果","蛋糕","线衣","猕猴桃"};
private String[] prices = {"1800元","10元/kg","300元","350元","10元/kg"};
private int[] icons = {R.drawable.table,R.drawable.apple,R.drawable.cakes,R.drawable.wireclothes,R.drawable.scarf};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = findViewById(R.id.lv);
MyBaseAdapter adapter = new MyBaseAdapter();
listView.setAdapter(adapter);
}
class MyBaseAdapter extends BaseAdapter{
@Override
public int getCount() { //获取item总数
return titles.length;
}
@Override
public Object getItem(int i) { //返回items的数据对象
return titles[i];
}
@Override
public long getItemId(int i) { //返回items的id
return i;
}
@Override
public View getView(int i, View convertview, ViewGroup viewGroup) { //返回items的view视图
//方案一
// //将xml转换成view对象
// View view = View.inflate(MainActivity.this,R.layout.list_item,null);
// //初始化view对象的控件
// TextView title = view.findViewById(R.id.title);
// TextView price = view.findViewById(R.id.price);
// ImageView imageView = view.findViewById(R.id.iv);
// title.setText(titles[i]);
// price.setText(prices[i]);
// imageView.setImageResource(icons[i]);
// return view;
ViewHolder holder;
if(convertview == null){
convertview = View.inflate(MainActivity.this,R.layout.list_item,null);
holder = new ViewHolder();
holder.title = convertview.findViewById(R.id.title);
holder.price = convertview.findViewById(R.id.price);
holder.iv = convertview.findViewById(R.id.iv);
convertview.setTag(holder);
}else{
holder = (ViewHolder)convertview.getTag();
}
holder.title.setText(titles[i]);
holder.price.setText(prices[i]);
holder.iv.setImageResource(icons[i]);
return convertview;
}
}
class ViewHolder{
TextView title;
TextView price;
ImageView iv;
}
}
运行结果:
二、RecyclerVi ew的使用
RecyclerView:是Android5.0之后提供的用于在有限的窗口范围内显示大量数据的控件。
与ListView相比,RecyclerView的优势为:
-
展示效果:RecyclerView控件可以通过LayoutManager类实现横向或竖向的列表效果、瀑布流效果和GridView效果,而ListView控件只能实现竖直的列表效果。
-
适配器:RecyclerView控件使用的是RecyclerView.Adapter适配器,该适配器将BaseAdapter中的getView()方法拆分为onCreateViewHolder()方法和onBindViewHolder()方法,强制使用ViewHolder类,使代码编写规范化,避免了初学者写的代码性能不佳。
与ListView相比,RecyclerView的优势为:
-
复用效果:RecyclerView控件复用Item对象的工作由该控件自己实现,而ListView控件复用Item对象的工作需要开发者通过convertView的setTag()方法和getTag()方法进行操作。
-
动画效果:RecyclerView控件可以通过setItemAnimator()方法为Item添加动画效果,而ListView控件不可以通过该方法为Item添加动画效果。
示例:
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"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycleview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
</RelativeLayout>
recycler_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="wrap_content"
android:padding="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv"
android:layout_width="120dp"
android:layout_height="90dp"
android:src="@drawable/siberiankusky"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#FF8F03"
android:text="哈士奇"/>
<TextView
android:id="@+id/introduce"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_marginTop="10dp"
android:layout_below="@+id/name"
android:textColor="#FF716C"
android:minLines="2"
android:ellipsize="end"
android:text="西伯利亚雪橇犬,常见别名哈士奇,昵称为二哈"/>
</RelativeLayout>
</LinearLayout>
MainActicty.java
package com.example.recyclerview;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.w3c.dom.Text;
public class MainActivity extends AppCompatActivity {
private RecyclerView recycleview;
private HomeAdapter homeAdapter;
private String[] names = { "小猫", "哈士奇", "小黄鸭","小鹿","老虎"};
private int[] icons= { R.drawable.cat,R.drawable.siberiankusky,
R.drawable.yellowduck,R.drawable.fawn, R.drawable.tiger};
private String[] introduces = {
"猫,属于猫科动物,分家猫、野猫,是全世界家庭中较为广泛的宠物。",
"西伯利亚雪橇犬,常见别名哈士奇,昵称为二哈。",
"鸭的体型相对较小,颈短,一些属的嘴要大些。腿位于身体后方,因而步态蹒跚。",
"鹿科是哺乳纲偶蹄目下的一科动物。体型大小不等,为有角的反刍类。",
"虎,大型猫科动物;毛色浅黄或棕黄色,满有黑色横纹;头圆、耳短,耳背面黑色,中央有一白斑甚显著;四肢健壮有力;尾粗长,具黑色环纹,尾端黑色。"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recycleview = findViewById(R.id.recycleview); //初始化recycleview
recycleview.setLayoutManager(new LinearLayoutManager(this/*,LinearLayoutManager.HORIZONTAL,true*/));//设置recleview 的布局方式为线性布局默认为垂直方向
homeAdapter = new HomeAdapter();
recycleview.setAdapter(homeAdapter); //设置适配器
}
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>{ //自定义适配器
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.recylcer_item,parent,false); //将xml转换成view控件
MyViewHolder myViewHolder = new MyViewHolder(view); //放置在Holder中
return myViewHolder;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { //给适配器绑定Holder
holder.name.setText(names[position]);
holder.introduce.setText(introduces[position]);
holder.iv.setImageResource(icons[position]);
}
@Override
public int getItemCount() {
return names.length;
} //返回items的长度
class MyViewHolder extends RecyclerView.ViewHolder{ //自定义holder
TextView name;
TextView introduce;
ImageView iv;
public MyViewHolder(@NonNull View itemView) { //设置holder的变量
super(itemView);
name =(TextView) itemView.findViewById(R.id.name);
introduce =(TextView) itemView.findViewById(R.id.introduce);
iv =(ImageView) itemView.findViewById(R.id.iv);
}
}
}
}
运行结果:
三、自定义View
当使用系统控件不满足需求时,需要自定义控件。最简单的自定义View就是创建一个类继承自View类或者其子类,并重写该类的构造方法。
public class Customview extends View{
public Customview(Context context) { //在Java代码中创建对象时,使用该构造函数
super(context);
}
public Customview(Context context, AttributeSet attrs) { //在XML布局中引入自定义控件时,使用该构造函数
super(context, attrs);
}
}
由于系统自带的控件不能满足需求中的某种样式或功能,因此我们需要在自定义View中通过重写指定的方法来添加额外的样式和功能。
自定义View常用的3个方法如下:
-
onMeasure()方法:测量尺寸。
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
widthMeasureSpec获取父容器指定该控件的宽度,heightMeasureSpec获取父容器指定该控件的高度
-
onDraw()方法:绘制图像。
canvas表示画布,他与Paint类(画笔)配合使用。
-
onLayout()方法:指定布局中子控件的位置。
onLayout(boolean changed,int left,int top,int right,int bottom)
changed表示自定义View的大小和位置是否发生变化。left、top、right、bottom分别表示子控件与父容器左边、顶部、右边、底部的距离。
测量模式
-
EXACTLY:当自定义控件的宽高的值设置为具体值时使用,如100dp,此时控件的宽高值是精确的尺寸。
-
AT_MOST:当自定义控件的宽高值为wrap_content时使用,此时控件的宽高值是控件中的数据内容可获得的最大空间值。
-
UNSPECIFIED:当父容器没有指定自定义控件的宽高值时使用。
注意:参数widthMeasureSpec和heightMeasureSpec是父容器指定该控件的宽高,该控件还需要通过setMeasuredDimension(int,int)方法设置具体的宽高。
示例:
cirecleview.java
package com.example.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
public class circleview extends View {
public circleview(Context context) {
super(context);
}
public circleview(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//半径
int r = getMeasuredHeight()/2;
//圆心位置
int centerX = getLeft() + r;
int centerY = getTop() + r;
Paint paint = new Paint();
paint.setColor(Color.RED);
//绘制
canvas.drawCircle(centerX,centerY,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"
tools:context=".MainActivity">
<com.example.myapplication.circleview
android:layout_width="100dp"
android:layout_height="100dp"
tools:ignore="MissingConstraints" />
</RelativeLayout>
运行结果: