一、ListView的使用
说明:1、LIstView与滚动视图(ScrollView)类似,可以将多个组件加入到ListView之中以达到组件的滚动显示效果,
可以通过divider设置分割线颜色和高度
布局文件中:android:dividerHeight="20dp"
android:paddingTop="10dp"(设置listview和顶部的距离)
ListView组件本身也有对应的ListView类支持,可以通过操作ListView类以完成对此组组件的操作,
ListView类的继承结构如下所示:
java.lang.Object
? android.view.View
? android.view.ViewGroup
? android.widget.AdapterView<T extends android.widget.Adapter>
? android.widget.AbsListView
? android.widget.ListView
2、ListView的使用需要3个元素
*ListView控件的支持
*需要Adapter,用于将数据显示到ListView的每一个item布局中
*数据源。多条数据的集合
ArrayAdapter:
系统线性布局适配器,只显示一行字,绑定的数据类型,可以是基本数据类型,也可以是自定义的对象类型。
ArrayAdapter(Context context, int textViewResourceId, List<T> objects)
context:Context对象,为this;
textViewResourceId:每一行布局文件的id;
objects:数据源;
代码: private void intiArrayList(){
//数据构建
str_list=new ArrayList<String>();
str_list.add("Android");
str_list.add("IOS");
str_list.add("WindowsPhone");
ArrayAdapter adapter=new ArrayAdapter(this,android.R.layout.simple_list_item_1,str_list);
//将适配器设置给listview
lv.setAdapter(adapter);
}
SimpleAdapter:
具有良好的扩展性,可以自定义item布局,实现没有逻辑的图文混排的效果
步骤:a/在acvitity布局文件中定义ListView布局,并给布局添加ID
b/在layout文件中新建自定义的布局文件
c/构建数据源,新建simpleadapter,给listview设置adapter
代码:private void intiSimpleAdapter(){
List<HashMap<String,Object>> list=new ArrayList();
for (int i = 0; i <names.length ; i++) {
HashMap<String,Object> map=new HashMap<>();
map.put("name",names[i]);
map.put("img",ids[i]);
list.add(map);
}
//上下文对象 数据源 资源文件的id
//String[] from
//int[] to
String[] from=new String[]{"name","img"};
int[] to =new int[]{R.id.name,R.id.iv_img};
SimpleAdapter adapter=new SimpleAdapter(this,list,R.layout.activity_item_list,from,to);
lv.setAdapter(adapter);
自定义Adapter:
可以有自己的逻辑,实现带按钮的item布局
步骤:a/在acvitity布局文件中定义ListView布局,并给布局添加ID
b/在layout文件中新建自定义的布局文件
c/构建数据源,新建自定义adapter继承与BaseAdapter(创建有参的构造函数,重写里边的四个方法),给listview设置adapter
代码:
public class MyAdapter extends BaseAdapter {
private List<CarCompany> list;//数据源
private Context context;//上下文对象
private LayoutInflater inflater;//布局加载器
//有参的构造函数,为数据源,上下文对象复制,同时实例化布局加载器
public MyAdapter(List<CarCompany> list,Context context) {
this.list=list;
this.context=context;
inflater=LayoutInflater.from(context);
}
//有多少条数据,需要创建多少个item布局
@Override
public int getCount() {
return list.size();
}
//返回position对应位置的数据
@Override
public Object getItem(int position) {
return list.get(position);
}
//返回position对应位置item的id
@Override
public long getItemId(int position) {
return position;
}
/**
* 具体定义加载item布局,并将数据显示到item布局上的方法。
* @param position
* @param convertView
* @param parent
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//加载item布局 将xml布局加载到内存中,形成一个view
View view=inflater.inflate(R.layout.activity_item_list,null);
//实例化item布局上的控件
ImageView iv= (ImageView) view.findViewById(R.id.iv_img);
TextView tv= (TextView) view.findViewById(R.id.name);
//往控件上显示数据
//获取position对应位置的数据
CarCompany company= (CarCompany) getItem(position);
iv.setImageResource(company.getImg());
tv.setText(company.getCompany());
return view;
}
在activity中实例化adapter,设置给listview
private void intiCustomAdapter(){
List<CarCompany> list=new ArrayList<CarCompany>();
for (int i = 0; i < names.length; i++) {
CarCompany company=new CarCompany();
company.setImg(ids[i]);
company.setCompany(names[i]);
list.add(company);
}//数据源构建好之后实例化自定义的适配器,将数据源list作为参数传入适配器中,然后将adapter加载到ListView的布局中
MyAdapter myadapter=new MyAdapter(list,this);
lv.setAdapter(myadapter);
}
ListView的优化:
1、复用convertview,减少item的数量:节省内存,运行更流畅
2、使用ViewHolder类,减少findviewbyid的次数,好处就是运行更流畅
代码:在自定义Adapter从写BaseAdapter的getview()方法时:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder=null;
//加载item布局 将xml布局加载到内存中,形成一个view
if(convertView==null){ //被复用后的convertview类依然包含tag
holder=new ViewHolder();
convertView=inflater.inflate(R.layout.activity_phone_list,null);
holder.iv= (ImageView) convertView.findViewById(R.id.img_phone);
holder.tv_phonename= (TextView) convertView.findViewById(R.id.phone_name);
holder.tv_phoneprice= (TextView) convertView.findViewById(R.id.phone_price);
holder.tv_phonecounter= (TextView) convertView.findViewById(R.id.phone_counter);
convertView.setTag(holder);
}else {//convertview不为空,不为空则说明convertview包含tag
holder= (ViewHolder) convertView.getTag();
}
// View view=inflater.inflate(R.layout.activity_phone_list,null);
//实例化item布局上的控件
// ImageView iv= (ImageView) view.findViewById(R.id.img_phone);
// TextView tv_phonename= (TextView) view.findViewById(R.id.phone_name);
// TextView tv_phoneprice= (TextView) view.findViewById(R.id.phone_price);
// TextView tv_phonecounter= (TextView) view.findViewById(R.id.phone_counter);
//往控件上显示数据
//获取position对应位置的数据
PhoneEntity phonety= (PhoneEntity) getItem(position);
holder.iv.setImageResource(phonety.getImg());
holder.tv_phonename.setText(phonety.getName());
holder.tv_phoneprice.setText(phonety.getPrice());
holder.tv_phonecounter.setText(phonety.getCountNum());
return convertView;
}
class ViewHolder{
//ViewHolder内部类:相当于一个View视图的缓存容量池,里边记录了自定义adapter布局中所有控件的属性,不用每次重新加载自定义布局
public ImageView iv;
public TextView tv_phonename;
public TextView tv_phoneprice;
public TextView tv_phonecounter;
}
******************************************************************************************************************************************************************************
二、GridView的使用(展示相同图片大小的网格布局):
说明:1、GridView组件是以网格的形式显示所有的组件(大小相同),
例如:在制作相册的时候,所有的图片都会以相同大小显示在不同的格子之中,就可以依靠此组件完成,
让图文混排组件整体居中的方法就是在整个自定义item布局中设置
android:gravity="center"
此组件的继承结构如下所示:
java.lang.Object
? android.view.View
? android.view.ViewGroup
? android.widget.AdapterView<T extends android.widget.Adapter>
? android.widget.AbsListView
? android.widget.GridView
2、GridView常用方法说明:
public GridView(Context context) 创建GridView对象
public void setStretchMode(int stretchMode) android:stretchMode 缩放模式
public void setVerticalSpacing(int verticalSpacing) android:verticalSpacing 设置垂直间距
public void setHorizontalSpacing(int horizontalSpacing) android:horizontalSpacing 设置水平间距
public void setNumColumns(int numColumns) android:numColumns 设置每列显示的数据量,如果设置为auto_fit则表示自动设置
public void setSelection(int position) 设置默认选中项
public void setGravity(int gravity) android:gravity 设置对齐模式,由Gravity类指定
public void setAdapter(ListAdapter adapter) 设置显示图片集
3、代码:
a/自定义布局样式layout:item_gridview.xml,给样例中每个控件添加id
<LinearLayout 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_img"
android:src="@drawable/benz"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="10dp"/>
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="奔驰"
android:textSize="30sp"
android:layout_marginLeft="10dp"/>
b/acvitity_gridview.xml设置GridView属性,给布局文件添加id
<!--显示3列(auto_fit自己适应屏幕),垂直距离为30dp-->
<GridView
android:id="@+id/gv"
android:numColumns="3"
android:verticalSpacing="30dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
c/在Acvitity的Java代码中实例化GridView布局,并给布局构建数据源
public class GridBarActivity extends AppCompatActivity {
private GridView gv;
private String[] names = new String[]{"长安", "沃尔沃", "大众", "宾利", "奔驰"};
private int[] ids = new int[]{R.drawable.changan, R.drawable.vol, R.drawable.das, R.drawable.bl, R.drawable.benz};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grid_bar);
gv= (GridView) findViewById(R.id.gv);
//adapter SimpleAdapter 自定义也可
intiGrid();
}
private void intiGrid(){
//构建数据源
final List<Map<String,Object>> list =new ArrayList<>();
for (int i = 0; i <names.length ; i++) {
Map<String,Object> map=new HashMap<>();
map.put("name",names[i]);
map.put("img",ids[i]);
list.add(map);
}
String[] from=new String[]{"name","img"};
int[] to=new int[]{R.id.tv_name, R.id.iv_img};
SimpleAdapter adapter=new SimpleAdapter(this,list,R.layout.item_gridview,from,to);
gv.setAdapter(adapter);
//添加点击事件
gv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(GridBarActivity.this,"点击"+list.get(position).get("name").toString(),Toast.LENGTH_SHORT).show();
}
});
gv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(GridBarActivity.this,"长按"+list.get(position).get("name").toString(),Toast.LENGTH_SHORT).show();
return true;//不再返回上一次监听
}
});
**重点内容**
GridView中每个item的点击事件(将点击的item的属性设置在另一个控件上显示):(点击事件要在GridView的adapter加载后设置才会有效果,并且监听事件的返回值要设置成void,不能return view)
gv_pig.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
iv_move.setImageResource(ids[position]);
tv_move.setText(kind[position]);
return true;
}
});
******************************************************************************************************************************************************************************
三、RecycleView的使用:
说明: 1、RecyclerView:5.0之后的控件,扩展优化,吸收了ViewHolder,我们操作Recyvlerview的adapter的时候我们只操作ViewHolder
以前listview:使用viewholder减少实例化的次数,本质上是一种实例化的方式。我们就负责创建holder.负责给holder上的控件设置数据。
2、ViewHolder./RecyclerView的adapter与BaseAdapter不同
3、RecyclerView的adapter:只负责创建holder,给holder设置展示的数据
4、通过设置LayoutManager可设置展示方式
rv.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));//瀑布流
rv.setLayoutManager(new LinearLayoutManager(this));//像ListView一样展示
rv.setLayoutManager(new GridLayoutManager(this, 3));//gridview
步骤: 1、添加兼容包,依赖包 File-->project stru-->选中module,Dependes--->加号-->选择recyvlerview的包,添加。
2、自定义item布局
3、创建实体类
4、搭建数据集:List<实体类>
5、Adapter:ViewHolder:实例化控件
自定义Adapter步骤:
a、先创建一个ViewHolder的内部类MyHolder继承于ViewHolder,在内部类中实例化控件属性
b、让主类RecyclePhoneAdapter继承于RecycleView下的adapter并且给Adapter加上内部类的泛型
主要为了重写3个方法时候不用再强转返回值类型(不设置泛型返回值为父类)
c、新建自定义adapter完成后要在对应主Java代码中( RecyclePhoneAdapter adapter=new RecyclePhoneAdapter(this,list);)使用
并且设置展示样式( //设置布局管理器
rv_phone.setLayoutManager(new LinearLayoutManager(this));//像ListView一样展示
rv_phone.setAdapter(adapter);)
ps; //使用系统自带默认分割线
rv_phone.addItemDecoration(new DividerItemDecoration(this,LinearLayoutManager.VERTICAL));
自定义Adapter代码样例:
/**自定义adapter的作用,创建ViewHolder,给holder设置数据展示
* 继承RecycleView.Adapter<当前类的泛型.MyHolder>,重写里边三个方法
* Created by Administrator on 2017/2/20.
* 步骤:1、先创建一个ViewHolder的内部类MyHolder继承于ViewHolder,在内部类中实例化控件属性
* 2、让主类RecyclePhoneAdapter继承于RecycleView下的adapter并且给Adapter加上内部类的泛型
* 主要为了重写3个方法时候不用再强转返回值类型(不设置泛型返回值为父类)
* 3、新建自定义adapter完成后要在对应主Java代码中( RecyclePhoneAdapter adapter=new RecyclePhoneAdapter(this,list);)使用
* 并且设置展示样式( //设置布局管理器
rv_phone.setLayoutManager(new LinearLayoutManager(this));//像ListView一样展示
rv_phone.setAdapter(adapter);)
ps; //使用系统自带默认分割线
rv_phone.addItemDecoration(new DividerItemDecoration(this,LinearLayoutManager.VERTICAL));
*/
public class RecyclePhoneAdapter extends RecyclerView.Adapter<RecyclePhoneAdapter.MyHolder> implements View.OnClickListener{
private Context pContext;
private List<PhoneEntity> list;
private LayoutInflater inflater;
private OnItemClick ItemClickListener=null;
//给自定义接口一个实例,并提供下边set方法
public void setItemClickListener(OnItemClick itemClickListener) {
ItemClickListener = itemClickListener;
}
//有参的构造函数,并实例化布局加载器
public RecyclePhoneAdapter(Context pContext, List<PhoneEntity> list) {
this.pContext = pContext;
this.list = list;
inflater=LayoutInflater.from(pContext);
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//第二个参数是容器 第三个参数:true使用父布局的布局参数,false使用自己的布局参数
View view=inflater.inflate(R.layout.activity_phone_list,parent,false);//使用自定义布局格式
MyHolder holder=new MyHolder(view);//将自定义的布局传给MyHolder内置处理
holder.itemView.setOnClickListener(this);//为当前item设置点击事件
return new MyHolder(view);
}
@Override
public void onBindViewHolder(MyHolder holder, int position) {
//获取对应位置的数据, 不能再此重新实例化
PhoneEntity phone=list.get(position);
holder.phone_name.setText(phone.getName());
holder.img_phone.setImageResource(phone.getImg());
holder.phone_price.setText(phone.getPrice());
holder.phone_counter.setText(phone.getCountNum());
holder.itemView.setTag(position);//将item位置设置成标签,
}
@Override
public int getItemCount() {
return list.size();
}
//继承自定义接口,重写自定义接口中的方法,给item添加点击事件
@Override
public void onClick(View v) {
//调用自定义接口中的方法,给当前item添加点击事件
if(ItemClickListener!=null){
ItemClickListener.onitemclick(Integer.parseInt(v.getTag().toString()));
}
}
//创建内部类继承于RecycleView.ViewHolder实例化自定义布局中的属性
class MyHolder extends RecyclerView.ViewHolder{
private ImageView img_phone;
private TextView phone_name;
private TextView phone_price;
private TextView phone_counter;
public MyHolder(View itemView) {
super(itemView);
img_phone= (ImageView) itemView.findViewById(R.id.img_phone);
phone_name= (TextView) itemView.findViewById(R.id.phone_name);
phone_price= (TextView) itemView.findViewById(R.id.phone_price);
phone_counter= (TextView) itemView.findViewById(R.id.phone_counter);
}
}
//有方法 我们需要知道点击的是第几个item.
// 自定义接口,同时传入position参数设置item布局点击的是哪一个item
public interface OnItemClick{
void onitemclick(int position);
}
自定义Adapter中自定义接口的使用步骤:
1.在adapter中新建一个接口,接口在adapter中有一个实例,并且提供set方法
2.在createViewHolder的时候给itemview设置点击事件this(Adapter实现了View.OnClickListener 接口).
3.在onBindViewHolder的时候给itemview设置tag,目的是让itemview带着自己的位置,被复用后会设置新的。
4.重写Adapter的OnClickListener方法。
if (ItemclickListener != null) {
ItemclickListener.onitemclick(Integer.parseInt(view.getTag().toString()));
}
5.在Activity中去使用。给adapter.setItemclickListener(匿名内部类的方式)。
也可以Activity实现OnItemClick接口,重写onitemclick方法。
代码:
public class RecyclePhoneAdapter extends RecyclerView.Adapter<RecyclePhoneAdapter.MyHolder> implements View.OnClickListener{
private Context pContext;
private List<PhoneEntity> list;
private LayoutInflater inflater;
private OnItemClick ItemClickListener=null;
//给自定义接口一个实例,并提供下边set方法
public void setItemClickListener(OnItemClick itemClickListener) {
ItemClickListener = itemClickListener;
}
//有参的构造函数,并实例化布局加载器
public RecyclePhoneAdapter(Context pContext, List<PhoneEntity> list) {
this.pContext = pContext;
this.list = list;
inflater=LayoutInflater.from(pContext);
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//第二个参数是容器 第三个参数:true使用父布局的布局参数,false使用自己的布局参数
View view=inflater.inflate(R.layout.activity_phone_list,parent,false);//使用自定义布局格式
MyHolder holder=new MyHolder(view);//将自定义的布局传给MyHolder内置处理
holder.itemView.setOnClickListener(this);//为当前item设置点击事件
return new MyHolder(view);
}
@Override
public void onBindViewHolder(MyHolder holder, int position) {
//获取对应位置的数据, 不能再此重新实例化
PhoneEntity phone=list.get(position);
holder.phone_name.setText(phone.getName());
holder.img_phone.setImageResource(phone.getImg());
holder.phone_price.setText(phone.getPrice());
holder.phone_counter.setText(phone.getCountNum());
holder.itemView.setTag(position);//将item位置设置成标签,
}
@Override
public int getItemCount() {
return list.size();
}
//继承自定义接口,重写自定义接口中的方法,给item添加点击事件
@Override
public void onClick(View v) {
//调用自定义接口中的方法,给当前item添加点击事件
if(ItemClickListener!=null){
ItemClickListener.onitemclick(Integer.parseInt(v.getTag().toString()));
}
}
//创建内部类继承于RecycleView.ViewHolder实例化自定义布局中的属性
class MyHolder extends RecyclerView.ViewHolder{
private ImageView img_phone;
private TextView phone_name;
private TextView phone_price;
private TextView phone_counter;
public MyHolder(View itemView) {
super(itemView);
img_phone= (ImageView) itemView.findViewById(R.id.img_phone);
phone_name= (TextView) itemView.findViewById(R.id.phone_name);
phone_price= (TextView) itemView.findViewById(R.id.phone_price);
phone_counter= (TextView) itemView.findViewById(R.id.phone_counter);
}
}
// 自定义接口,通过触发不同位置item的方式,调用接口中的方法,实现点击事件的监听效果
public interface OnItemClick{
void onitemclick(int position);
}