学徒浅析Android开发:第二讲——ListView和GridView的应用

时间:2022-03-23 22:42:03

                本讲的核心是向大家介绍如何通过自定义适配器来应用到ListView和GridView上,并介绍ListView和GridView的常用方法。

               作为最常使用的两种控件,ListView  和GridView广泛出现在各种APP中,最常见的就是电话薄和九宫格,Android自身也提供了相应的适配器比如SimpleAdapter,但往往我们在开发过程中对于列表项有更高的要求,此时SimpleAdapter便不能胜任了,同时SimpleAdapter的书写过于繁琐,对比一下就知道:

               // 使用simpleAdapter封装数据,将图片显示出来,此时的适配器没有监听功能
               // 参数一是当前上下文Context对象
               // 参数二是图片数据列表,要显示数据都在其中
               // 参数三是界面的XML文件,注意,不是整体界面,而是要显示在GridView中的单个Item的界面XML
               // 参数四是动态数组中与map中图片对应的项,也就是map中存储进去的相对应于图片value的key
              // 参数五是单个Item界面XML中的图片ID
             SimpleAdapter simpleAdapter = new SimpleAdapter(this, imagelist, R.layout.items, new String[] { "image", "text" }, new int[] {R.id.image, R.id.title });
             gridview.setAdapter(simpleAdapter);

               // 使用自定义的DownAdapter封装数据,此时的适配器有监听功能
               // 参数一是当前上下文Context对象
               // 参数二是列表项数据列表,一个列表项要显示的数据都在其中
               // 参数三是当前要使用该适配器的视图

             DownAdapter downadapter = new DownAdapter(this,list,girdview);

              gridview.setAdapter(downadapter);
            怎么样,差距是不是很明显,没有人喜欢这么长的输入方式,除非你是女的。

            好了,不说废话了,下面就是我们今天用到的代码,具体的解释都写在里面了,有疑问的可以留言。

            首先我们西安家里两个包,分别分装ListView和GirdView的项目格式。这个格式随你而变。

        学徒浅析Android开发:第二讲——ListView和GridView的应用

相应的我们重建一下第一讲中的view_first.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:orientation="vertical" >
<!-- @author Arthur Lee -->
<!-- 垂直分布两个,以AB标记 -->
<!-- A -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4"
android:gravity="center_vertical|center_horizontal">
<TextView
android:id="@+id/view_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一页面"
android:textSize="20sp" />
</LinearLayout>
<!-- A -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<!-- 水平分布两个,一12标记 -->
<!-- 1 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4">
<!-- 提示栏 -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="上栏是ListView,下栏是GridView"
android:textSize="20sp"/>
</LinearLayout>
<!-- 2 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1">
<!-- 垂直分布两个,以ab标记 -->
<!-- a -->
<LinearLayout
android:id="@+id/firist_upview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<!-- ListView展示区 -->
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/first_up"></ListView>
</LinearLayout>
<!-- b -->
<LinearLayout
android:id="@+id/firist_downview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<!-- GridView展示区 -->
<GridView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/first_down"
android:horizontalSpacing="5dp"
android:verticalSpacing="5dp"
android:stretchMode="columnWidth"
android:columnWidth="90dp"
android:numColumns="4" ></GridView>
</LinearLayout>
</LinearLayout>

</LinearLayout>


</LinearLayout>

package com.teach.up;
/**
* @author Arthur Lee
* @time 04/12/2014
* */
//Up是一个角色类,也可以把它写成一个内部类,用它来封装列表项的数据,既方便有美观。
public class Up {
//自定义的参数
private String strName;
private String strNum;

public Up(String strName, String strNum) {
super();
this.strName = strName;
this.strNum = strNum;
}
//我们需要为这个角色类设置get和set方法,以便于获取和传递数据
public String getStrName() {
return strName;
}
public void setStrName(String strName) {
this.strName = strName;
}
public String getStrNum() {
return strNum;
}
public void setStrNum(String strNum) {
this.strNum = strNum;
}
}

package com.teach.up;
/**
* @author Arthur Lee
* @time 04/12/2014
* */
import java.util.ArrayList;
import java.util.List;

public class UpSerivce {
/**
* 在这个服务类里,我只定义了一个getString方法来获得列表项数据,大家可以在这里对数据进行封装处理。
* 尽你所能,我在这里就偷懒了,大家不要学我啊,
* by the way,这个服务类可有可无,我这样单独建一个类主要是为了方便大家学习。只要有getString这个方法就行
* @param 这里的参数可以是任何形式,对于客户端的开发来说,最常用的就是JSON格式。这个我会在第七讲中详细介绍JSON格式
* @return 直接返回我们封装好的数据队列
*/
public static List<Up> getString(int count){
List<Up> up = new ArrayList<Up>();
for(int i=0;i<count;i++)
up.add(new Up("观众"+i+"号","按键"+i+"号"));
return up;
}

}

package com.teach.up;
/**
* @author Arthur Lee
* @time 04/12/2014
* */
import java.util.List;

import com.teach.demo.R;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class UpAdapter extends BaseAdapter{

private Context context;
private LayoutInflater inflater;
private List<Up> first;
private ListView list;
//设定列表项所需控件,要和自己设计 的列表项控件一致。
//在这里我偷懒一下,就放三个。
static class ListItem{
TextView tView;
ImageView iView;
Button bt_click;
Button bt_delect;

}
/**设置构造函数,对pUAdapter的内容进行绑定
* @param context 决定当前Actvity类
* @param first 所需加载啊的列表项数据
* @param list 当前适配器匹配的视图类型,这里换成GridView类型的话,显示的列表项就会是九宫格风格
*/
public UpAdapter(Context context,List<Up> first,ListView list){
this.context = context;
//指定当前LayoutInflater服务的Activity,一遍后面初始化相应的视图。
this.inflater = LayoutInflater.from(context);
this.list = list;
this.first = first;
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return first.size();
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return first.get(position);
}

@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}

/**
* @param position 指定列表项的当前所处位置
* @param view 指定视图,即当前列表项
* @param parents 指定视图所属的父类,即当前列表项所属的列表
*
* 此处是Adapter的关键所在,任何视图在配置Adapter时,
* 都是通过调用Adapter的getView方法,将视图中所需的每个小项组装成定义后的样子。
*/
@Override
public View getView(final int position, View view, ViewGroup parents) {
// TODO Auto-generated method stub
ListItem item = null;
//如果当前为空,则对视图进行初始化
if(view == null){
//指定当前视图所对应xml文件。并初始化其中的控件,这个view就是一个小的列表项
view = inflater.inflate(R.layout.view_first_upitem, null);
item = new ListItem();
item.iView = (ImageView)view.findViewById(R.id.first_photo);
item.bt_click = (Button)view.findViewById(R.id.first_click);
item.bt_delect = (Button)view.findViewById(R.id.first_delect);
item.tView = (TextView)view.findViewById(R.id.first_name);
//当且视图控件指向item,即完成绑定
view.setTag(item);
}else{
//若当前视图不为空,那么直接从当前view中绑定控件,以便执行相应操作。
item = (ListItem)view.getTag();
}
/**我可可以在这里执行响应的页面操作,比如赋值,删除,点击事件等
* 下面我会一一举个小例子
*/
/**
* 赋值
* 这里的数据可以是从本地数据库中,服务端,网络,或者是程序自动生成的
*
*/
Up up = first.get(position);
item.tView.setText(up.getStrName());
item.iView.setImageResource(R.drawable.ic_launcher);
item.bt_delect.setText("删除");
item.bt_click.setText(up.getStrNum());
/**
* 添加监听
* 在开发过程中,一般为了方便起见,都是将监听操作写在Adapter里面,主要是方便,你也可以在外部通过OnItemClickListener对视图注册监听
* */
item.bt_click.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
//我在这让输出一个提示,打击可以在这里进行任何操作。
Toast.makeText(context, "你选择了"+position, Toast.LENGTH_LONG).show();
}
});
/**
* 删除
* 对于LsitView和GridView操作,删除操作常用的事,而BaseAdapter也提供给我们两种删除的反馈机制
* 分别是notifyDataSetInvalidated()和notifyDataSetChanged()
* 这两个方法可以直接使用,也可以对他们进行重写,在这里我就不重写了
* 他们的区别是出发后的机制不同
* notifyDataSetChanged():重绘当前可见区域,它是通过调用getView来刷新
* notifyDataSetInvalidated():重绘控件,他是通过在内部调用onChanged事件
* */
item.bt_delect.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
first.remove(position);
notifyDataSetChanged();
}
});
return view;
}
//想重写的话,在这里添加内容即可
@Override
public void notifyDataSetChanged() {
// TODO Auto-generated method stub
super.notifyDataSetChanged();
}

}
 
 
package com.teach.down;import java.util.ArrayList;import java.util.List;public class Down {private String strName;public Down(String strName) {super();this.strName = strName;}public String getStrName() {return strName;}public void setStrName(String strName) {this.strName = strName;}public static List<Down> getString (int count){List<Down> down = new ArrayList<Down>();for(int i=0;i<count;i++)down.add(new Down("男"+i+"号"));return down;}}

package com.teach.down;
/**
* @author Arthur Lee
* @time 04/12/2014
* */
import java.util.List;

import com.teach.demo.R;
import com.teach.up.Up;

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;

public class DownAdapter extends BaseAdapter{

private Context context;
private LayoutInflater inflater;
private List<Down> first;
private GridView grid;
private static int selectItem;
//设定列表项所需控件,要和自己设计 的列表项控件一致。
//在这里我偷懒一下,就放三个。
static class GridItem{
TextView tView;
ImageView iView;

}
/**设置构造函数,对pUAdapter的内容进行绑定
* @param context 决定当前Actvity类
* @param first 所需加载啊的列表项数据
* @param list 当前适配器匹配的视图类型,这里换成GridView类型的话,显示的列表项就会是九宫格风格
*/
public DownAdapter(Context context,List<Down> first,GridView grid){
this.context = context;
//指定当前LayoutInflater服务的Activity,一遍后面初始化相应的视图。
this.inflater = LayoutInflater.from(context);
this.grid = grid;
this.first = first;
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return first.size();
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return first.get(position);
}

@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}

/**
* @param position 指定列表项的当前所处位置
* @param view 指定视图,即当前列表项
* @param parents 指定视图所属的父类,即当前列表项所属的列表
*
* 此处是Adapter的关键所在,任何视图在配置Adapter时,
* 都是通过调用Adapter的getView方法,将视图中所需的每个小项组装成定义后的样子。
*/
@Override
public View getView(int position, View view, ViewGroup parents) {
// TODO Auto-generated method stub
GridItem gitem = null;
//如果当前为空,则对视图进行初始化
if(view == null){
//指定当前视图所对应xml文件。并初始化其中的控件,这个view就是一个小的列表项
view = inflater.inflate(R.layout.view_first_downitem, null);
gitem = new GridItem();
gitem.iView = (ImageView)view.findViewById(R.id.first_downiv);
gitem.tView = (TextView)view.findViewById(R.id.first_downtv);
//当且视图控件指向item,即完成绑定
view.setTag(gitem);
}else{
//若当前视图不为空,那么直接从当前view中绑定控件,以便执行相应操作。
gitem = (GridItem)view.getTag();
}

gitem.iView.setImageResource(R.drawable.ic_launcher);
gitem.tView.setText(first.get(position).getStrName().toString());
//点击高亮效果
if(position == selectItem){
view.setBackgroundColor(Color.CYAN);
}else{
view.setBackgroundColor(Color.WHITE);
}

return view;
}
//获取当前点击的项目位置
public static void getSelectItem(int select){
selectItem = select;
}
}


同时我们要建立两个列表项的xml文件,在这个xml文件中你所构造的布局,就是应用到ListView或GridView的项目格式,他们的每一项都将按照这个布局显示出来

学徒浅析Android开发:第二讲——ListView和GridView的应用
这是view_first_downitem.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" >
<!-- @author Arthur Lee -->
<TextView
android:id="@+id/first_downtv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/first_downiv"
android:layout_below="@+id/first_downiv"
android:text="TextView" />

<ImageView
android:id="@+id/first_downiv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_launcher" />

</RelativeLayout>
这是view_first_upitem.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:orientation="vertical" >
<!-- @author Arthur Lee -->
<ImageView
android:id="@+id/first_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="66dp"
android:layout_marginTop="89dp"
android:src="@drawable/ic_launcher" />

<TextView
android:id="@+id/first_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/first_photo"
android:layout_marginLeft="14dp"
android:layout_marginTop="14dp"
android:layout_toRightOf="@+id/first_photo"
android:text="TextView" />

<Button
android:id="@+id/first_click"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/first_photo"
android:layout_marginLeft="27dp"
android:layout_toRightOf="@+id/first_name"
android:text="Button" />

<Button
android:id="@+id/first_delect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/first_click"
android:layout_alignBottom="@+id/first_click"
android:layout_toRightOf="@+id/first_click"
android:text="Button" />

</RelativeLayout>

下面我们就要对第一讲里的FirstFragment进行重写

package com.teach.demo;
/**
* @author Arthur Lee
* @time 04/08/2014
* */
import java.util.ArrayList;
import java.util.List;

import com.teach.down.Down;
import com.teach.down.DownAdapter;
import com.teach.up.Up;
import com.teach.up.UpAdapter;
import com.teach.up.UpSerivce;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.ListView;

public class FirstFragment extends Fragment{
//缓存视图
private View view,upview,downview;
private Context context;
/*
*ListView相关控件 */
private List<Up> up;
private ListView listview;
private UpAdapter Uadapter;
/*
* GridView相关控件*/
private List<Down> down;
private GridView gridview;
private DownAdapter Dadapter;


@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
//如果当前视图为空,初始化视图
if(view == null){
//指定当前视图在viewpager中显示的是view_first。xml,通过LayoutInflater来指定.
view = inflater.inflate(R.layout.view_first, container,false);
}
//指定当前视图的父类,以便调用父类的移除功能。
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
parent.removeView(view);
}

upview = (View)view.findViewById(R.id.firist_upview);
listview = (ListView)upview.findViewById(R.id.first_up);
up = new ArrayList<Up>();
up = UpSerivce.getString(5);
Uadapter = new UpAdapter(getActivity(),up,listview);
//此时的listview已经具有了监听功能
listview.setAdapter(Uadapter);


downview = (View)view.findViewById(R.id.firist_downview);
gridview = (GridView)downview.findViewById(R.id.first_down);
down = new ArrayList<Down>();
down = Down.getString(5);
Dadapter = new DownAdapter(getActivity(),down,gridview);
gridview.setAdapter(Dadapter);
//在这里我使用了和ListView不同的监听注册方法
gridview.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int position, long arg3) {
// TODO Auto-generated method stub
Dadapter.getSelectItem(position);
//通知适配器控件发生变化。无需重绘视图。
Dadapter.notifyDataSetInvalidated();
}
});

return view;
}
}


运行模拟器,效果图如下:



学徒浅析Android开发:第二讲——ListView和GridView的应用


还是那句话:我不是一名好的程序员,因为我只会默默奉献