您的位置:首页 > 移动开发 > Android开发

ListView数据项隔行换色控制实现详解 推荐

2012-03-19 14:24 399 查看
看到有朋友在群里问过ListView项达到一定数量时加不同色选项的功能,有时间就学习了下ListView隔行换色的效果,大体效果实现出来了,吼吼,写博客里面,跟大家学习交流,一样的,先贴效果,再上代码,效果图如下:

一:五行换色效果





二:快速拖动块显示效果





三:循环从0开始时的效果图三 这个地方贴此图原因大家看主控制代码中的注释





四:循环从0开始时的效果图四





五:单击按钮后触发事件(小工具做的,有点失真,真机上正常的,大家放心)





六:工程结构图如下





七:主控制类代码如下:

package com.xiaoma.listviewbackground;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

/**
* @Title: ListViewBackgroundDemoActivity.java
* @Package com.xiaoma.listviewbackground
* @Description: 小马学习隔行换色,一定仔细看注释
* @author XiaoMa
*/
public class ListViewBackgroundDemoActivity extends Activity
implements OnItemSelectedListener{

private ListView lv = null;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

lv = (ListView)findViewById(R.id.listview);

/**
* 设置快速滚动块可用,这个大家注意下,就是设置之后,ListView
* 里面的数据条数必须大于一定数量(小马试了下,这个数量是大于一屏)
* 才会显示这个小拖块,不然无效
*/
lv.setFastScrollEnabled(true);
lv.setOnItemSelectedListener(this);
lv.setAdapter(new ListDemoAdapter(getApplicationContext()));
}

/**
* @Title: ListViewBackgroundDemoActivity.java
* @Package com.xiaoma.listviewbackground
* @Description:适配器实现
* @author XiaoMa
*/
private class ListDemoAdapter extends BaseAdapter{

private static final int ITEM = 0;
private static final int SEPARATOR = 1;
private static final int TYPE_MAX_COUNT = SEPARATOR + 1;
private LayoutInflater inflater = null ;
private List<String> listItem = new ArrayList<String>();

/*
* 用这个set来保存分隔线的位置,这个地方必须注意,小马写两个不同类型的Set来跟大家复习下
* 这两个小东东的不同之处,效果太神奇了,这个Set你该用哪个会直接影响到换色效果的,不同之
* 处是:
*
* TreeSet:基于 TreeMap 的 NavigableSet 实现。使用元素的自然顺序对元素进行排序
*               或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法
*
* Set:一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2)
*     的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学
*     上的 set 抽象
*/
@SuppressWarnings("rawtypes")
//private Set set = new HashSet();
private TreeSet set = new TreeSet();
private Map map = new HashMap();

public ListDemoAdapter(Context context ){
this.inflater = LayoutInflater.from(context);

/**
* 大家稍微注意下这个循环,i从1开始?为什么?  小马在这犯的错
* 每5条数据加一条换色Item是用 i%6 == 0来控制的,如果这
* 个i值从0开始的话,会出现上面贴图中错误的换色,看图三,图四,
* 原因是取余的时候小马犯了低级错误,小错,记下:两数取余,前者
* 大于后者时,取余会按正常取余来取,如果前者小于后者时,取余
* 后的值始终是前者,如果这个地方的i从0开始取的话,正好是满
* 足取余后的值等于0这个情况,就出现上面两图中的错误隔色图了,
* 当前者大于等于后者时,这个隔色就又正常了,一定注意下,记在这,
* 提醒大家也提醒自己,吼吼,听不明白的可以看下小马在工程中加的
* 一个测试类(测试取余规律的类PercentTest.java)
*/
//填充ListView
for(int i=1;i<=50;i++){
this.listItem.add("添加的第"+i+"条数据");
if(i%6 == 0){
addSeparatorItem();
}
Log.i("KKK", "添加的第"+i+"条数据");
}
}

/**
* 添加换色项方法实现
* @param item
*/
@SuppressWarnings("unchecked")
public void addSeparatorItem() {
set.add(listItem.size()-1);
notifyDataSetChanged();
}

/**
* 此处是根据特定值(在getView方法中加入)
* 来判断应该绘制选项还是换色选项的分支值
* 由position返回view type id
*/
@Override
public int getItemViewType(int position) {
return set.contains(position) ? SEPARATOR : ITEM;
}

/**
* 返回你有多少个不同的布局
*/
@Override
public int getViewTypeCount() {
return TYPE_MAX_COUNT;
}

@Override
public int getCount() {
return listItem.size();
}

@Override
public Object getItem(int position) {
return listItem.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

/**
* 这个地方也需要注意下,小马这个方法里面写的有点多了,其实官方是不支持在
* getView()方法中写太多的逻辑因为你手拖下屏幕,这个方法是逛调用
* 的,所以太多逻辑不适合放在这个地方,大家可自行调整下,但有些还是必
* 须的,写在这无防...吼吼
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int type = getItemViewType(position);
XiaoMa xiaoMa = null;
final int location = position;
if(convertView == null){
switch (type) {
//如果需要绘制选项时分支
case ITEM:
xiaoMa = new XiaoMa();
convertView = inflater.inflate(R.layout.listview_items, null);
xiaoMa.iv = (ImageView)convertView.findViewById(R.id.ItemImage);
xiaoMa.tv = (TextView)convertView.findViewById(R.id.ItemTitle);
xiaoMa.text = (TextView)convertView.findViewById(R.id.itemtext);
xiaoMa.btn = (Button)convertView.findViewById(R.id.view_btn);
break;
//如果需要绘制换色选项时分支
case SEPARATOR:
xiaoMa = new XiaoMa();
convertView = inflater.inflate(R.layout.listview_items, null);
xiaoMa.iv = (ImageView)convertView.findViewById(R.id.ItemImage);
xiaoMa.tv = (TextView)convertView.findViewById(R.id.ItemTitle);
xiaoMa.text = (TextView)convertView.findViewById(R.id.itemtext);
xiaoMa.btn = (Button)convertView.findViewById(R.id.view_btn);
convertView = inflater.inflate(R.layout.separator, null);
/*
* 这个地方的drawable2用法跟在ListView换色选项布局中的
* android:background="@drawable/gradient_box"
* 效果是一样的,小马写在这,熟悉下两种方式,大家根据自己需要改
*/
Drawable drawable2 = getResources().getDrawable(R.drawable.gradient_box);
xiaoMa.sep = (TextView)convertView.findViewById(R.id.sep);
xiaoMa.sep.setBackgroundDrawable(drawable2);
break;
}
/*
* 此处小马犯错了,如果下面这句不加的话,
* 加载时正常,拖动列表时就会报空指针了,
* 小点注意下
*/
convertView.setTag(xiaoMa);
}else{
xiaoMa = (XiaoMa)convertView.getTag();
}
xiaoMa.iv.setBackgroundResource(R.drawable.xiaolvzi);
xiaoMa.tv.setText("这是第"+(position+1)+"个标题");
xiaoMa.text.setText("这是第"+(position+1)+"个概述");
/**
* 按钮事件监听实现
*/
xiaoMa.btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//单击Item按钮后,弹出提示
ShowDialog(location);
}
});

return convertView;
}

}

/**
* 弹出提示实现,这个地方扩展一下,细心的话大家会发现小马违反了方法命名规范,其实不是的,
* 安卓Activity有临时弹出对话框方法的,跟下面这个方法只有一个字母之差(小马故意
* 首字母大写的),安卓自带弹出方法在这个方法下面的注释中
* @param posi
*/
private void ShowDialog(int posi){
Toast.makeText(getApplicationContext(), "单击了第"+(posi+1)
+"个按钮", Toast.LENGTH_SHORT).show();
/*
* 下面这两个方法大家熟悉吧?调用系统提供的临时弹出对话框,必须实现下面的
* onCreateDialog(int id)方法
*/
showDialog(1);//弹出时可以做如:从服务器取数据等操作

/**
* 这个地方小马就简单的睡眠5秒种来模拟从服务器下载数据完成后关闭对话框
*/
new Thread(new Runnable() {
@Override
public void run() {
try {
Log.i("KKK", "已进入睡眠");
Thread.sleep(3000);
dismissDialog(1);//隐藏 表示数据下载完毕等的...
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}

@Override
protected Dialog onCreateDialog(int id) {
/*
* 下面这个构造器中的this不能用getApplicationContext()来代替,
* 但可用类名.this来代替,没有为什么, 必须这样写!!!这个地方小马晕了
* 不少时间,如果直接get....代码没错,但还是会报错,很邪门的哦 ...
*/
ProgressDialog dialog = new ProgressDialog(this);
//小测试,中文就临时写这了,大家要注意把内容都写到string.xml中去,好习惯从小开始养,嘿嘿
dialog.setCancelable(false);//设置用户不能用返回键取消对话框
dialog.setIcon(getResources().getDrawable(R.drawable.xiaolvzi));
dialog.setTitle("那些年,我们一起追的女孩");
dialog.setMessage("小马果 呆丫头 O_O");
dialog.show();
return dialog;
}

/**
* @Title: ListViewBackgroundDemoActivity.java
* @Package com.xiaoma.listviewbackground
* @Description: 为提高加载效率而写的类,可以看下ListView优化
* @author XiaoMa
*/
public final class XiaoMa{
public  ImageView iv ;
public TextView tv ;
public Button btn ;
public TextView text;
public TextView sep;
}

@Override
public void onItemSelected(AdapterView<?> parent, View view, int position,
long id) {
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
}

八:临时测试类代码如下(小儿科的东西,但还是注意下):

package com.xiaoma.listviewbackground;

/**
* @Title: PercentTest.java
* @Package com.xiaoma.listviewbackground
* @Description: 测试取余规律,必须在JAVA工程下Run,别直接在这跑
* @author XiaoMa
*/
public class PercentTest {
public static void main(String[] args) {
int a = 15;
int b = 9;
System.out.println("9%15 = "+9%15);
System.out.println("15%9 = "+15%9);
}
}

九:看代码大家一定注意仔细看下小马注释部分,主布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<!--  Back Up <ListView
android:id="@+id/listview"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:smoothScrollbar="true"
android:drawSelectorOnTop="false"
android:listSelector="#00000000"
/>
-->

<ListView
android:id="@+id/listview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:smoothScrollbar="true"
android:choiceMode="none"
android:focusable="false" android:scrollingCache="false"
android:clickable="false" android:dividerHeight="0.5dip"
/>

<!--   <ListView android:id="@+id/list_coupon"
android:layout_height="wrap_content"
android:drawSelectorOnTop="false" android:choiceMode="none"
android:focusable="false" android:scrollingCache="false"
android:fadingEdge="none" android:focusableInTouchMode="false"
android:clickable="false" android:dividerHeight="0.5dip"
android:divider="@drawable/separator" />
-->
</LinearLayout>

最后,还是跟往常一样,如果代码没详细看的,可以下载下此小DEMO源码,共同学习交流下,这个里面还是有很多地方可以改进的,只是写个思路,这里面问题还是蛮多的,如果觉得代码不清楚,有问题了还请大家多指点指点,小马在此先谢过啦,谢谢...加油!

附件:http://down.51cto.com/data/2360085
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息