一个简易的ListView还是很好写的,不过这个demo我还是花了一些功夫,有些判断确实让我想了一番。当然了,这样更更好地演示listview的用法。
一、分析结构
主Activity,一个自定义的集合类,还有一个自定义的Listview适配器。布局就是主布局和listview项布局。
二、建立集合类
从一开始的截图可以看出,我们需要三个参数,英雄图片,名字,还有描述。于是如下,主要是写构造方法,以及提供get方法调用(提供给适配器的)
public class ListViewItem {
private int image;
private String name;
private String description;
public ListViewItem(int image, String name, String description) {
this.image = image;
this.name = name;
this.description = description;
}
public int getImage() {
return image;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
}
这个就不多解释了,没什么难度。
二、写好适配器的构造方法
这里我们可以参考之前学的自定义Spinner那一节的方法
构造方法如下:
public ListViewItemAdapter(Context context, int resourceId,
List<ListViewItem> items) {
super(context, resourceId, items);
this.mContext = context;
this.resourceId = resourceId;
}
三、回到主Activity
private void init() {
listView = (ListView) findViewById(R.id.listView);
items = new ArrayList<ListViewItem>();
addItems();
adapter = new ListViewItemAdapter(MainActivity.this,
R.layout.listview_layout, items);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
adapter.setCurrentIndex(position);
adapter.notifyDataSetChanged();
}
});
}
以上是初始化的,我为listview绑了一个列表项点击监听器,里面的代码先不解释,之后说。
上面的addItems方法如下,就是用来内部添加元素的
private void addItems() {
items.add(new ListViewItem(pics[0], "斧王", getResources().getString(
R.string.strHero)));
items.add(new ListViewItem(pics[1], "祈求者", getResources().getString(
R.string.intHero)));
items.add(new ListViewItem(pics[2], "小精灵", getResources().getString(
R.string.intHero)));
items.add(new ListViewItem(pics[3], "主宰", getResources().getString(
R.string.dexHero)));
items.add(new ListViewItem(pics[4], "变体精灵", getResources().getString(
R.string.dexHero)));
items.add(new ListViewItem(pics[5], "瘟疫法师", getResources().getString(
R.string.intHero)));
items.add(new ListViewItem(pics[6], "痛苦女王", getResources().getString(
R.string.intHero)));
items.add(new ListViewItem(pics[7], "影魔", getResources().getString(
R.string.dexHero)));
items.add(new ListViewItem(pics[8], "沉默术士", getResources().getString(
R.string.intHero)));
items.add(new ListViewItem(pics[9], "天怒法师", getResources().getString(
R.string.intHero)));
items.add(new ListViewItem(pics[10], "斯拉克", getResources().getString(
R.string.dexHero)));
items.add(new ListViewItem(pics[11], "风暴之灵", getResources().getString(
R.string.intHero)));
items.add(new ListViewItem(pics[12], "圣堂刺客", getResources().getString(
R.string.dexHero)));
items.add(new ListViewItem(pics[13], "巨魔战将", getResources().getString(
R.string.dexHero)));
items.add(new ListViewItem(pics[14], "寒冬飞龙", getResources().getString(
R.string.intHero)));
}
相关的知识点,前几次都说了。即list<集合类>以及getResource的用法。
四、重新回到适配器,先看xml文件
对了,忘了上主Activity的xml文件,没什么难度,直接上代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.dota.example.fishychenoflistview.MainActivity" >
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/linearLayout_bottm" />
<LinearLayout
android:id="@+id/linearLayout_bottm"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:background="@drawable/background"
android:orientation="vertical"
android:padding="16dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是可爱的底部栏"
android:textSize="18sp"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
</RelativeLayout>
下面是listview的布局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:background="@drawable/background_selector">
<RelativeLayout
android:id="@+id/relativeLayout_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:paddingTop="8dp" >
<LinearLayout
android:id="@+id/item_selected"
android:layout_width="8dp"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/item_image"
android:layout_alignBottom="@+id/item_image"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:background="@android:color/holo_blue_light"
android:orientation="vertical"
android:visibility="invisible" />
<ImageView
android:id="@+id/item_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/item_selected"/>
<TextView
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="8dp"
android:layout_toRightOf="@+id/item_image"
android:textSize="22sp" />
<ImageView
android:id="@+id/item_icon"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/time_setting_right_unselected" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/relativeLayout_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/relativeLayout_top"
android:background="@android:color/black" >
<TextView
android:id="@+id/item_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@android:color/white"
android:textSize="16sp"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
还是这样看的最清楚!
主布局嵌了两层,第二层是用来显示描述的,默认view.gone。第一层,分别是一个选中显示的小蓝条,默认隐藏(之前在MainActivity里写的算法就是用来显示选中的显示蓝条)。剩下的几个分别是头像,名字,小三角图像。
五、分析适配器的getView方法
先上代码
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
item = getItem(position);
View view;
if (convertView == null) {
view = LayoutInflater.from(mContext).inflate(resourceId, parent,
false);
holder = new ViewHolder();
holder.select = (LinearLayout) view
.findViewById(R.id.item_selected);
holder.image = (ImageView) view.findViewById(R.id.item_image);
holder.icon = (ImageView) view.findViewById(R.id.item_icon);
holder.icon.setTag(false);
holder.name = (TextView) view.findViewById(R.id.item_name);
holder.description = (TextView) view
.findViewById(R.id.item_description);
view.setTag(holder);
} else {
view = convertView;
holder = (ViewHolder) view.getTag();
}
holder.description.setText(item.getDescription());
holder.description.setVisibility(View.GONE);
holder.image.setBackgroundResource(item.getImage());
if ((lastIconIndex == position) && iconFlag) {
iconFlag = false;
holder.icon
.setImageResource(R.drawable.time_setting_right_unselected_2);
Animation animation = new RotateAnimation(0, -90,
holder.icon.getWidth() / 2, holder.icon.getHeight() / 2);
animation.setDuration(200);
animation.setFillAfter(true);
holder.icon.startAnimation(animation);
}
if ((iconIndex == position) && iconFlag2) {
iconFlag2 = false;
if (lastIconIndex != iconIndex) {
holder.icon
.setImageResource(R.drawable.time_setting_right_unselected);
Animation animation = new RotateAnimation(0, 90,
holder.icon.getWidth() / 2, holder.icon.getHeight() / 2);
animation.setDuration(200);
animation.setFillAfter(true);
holder.icon.startAnimation(animation);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
notifyDataSetChanged();
}
});
}
} else {
if ((iconIndex == position) && (iconFlag2 == false)) {
holder.description.setVisibility(View.VISIBLE);
}
}
holder.icon.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
lastIconIndex = iconIndex;
iconIndex = position;
iconFlag = true;
iconFlag2 = true;
notifyDataSetChanged();
}
});
holder.name.setText(item.getName());
holder.select.setVisibility(View.INVISIBLE);
if (currentIndex == position) {
holder.select.setVisibility(View.VISIBLE);
}
return view;
}
}
其实并不复杂,根据position来遍历整个列表项。而整个列表项集合就是我们之前提供的list。
关于ViewHolder的使用,之前也说过了,是为了让有缓存过得快速加载,再利用,防止卡。
viewholder类,以及声明
class ViewHolder {
LinearLayout select;
ImageView image, icon;
TextView name, description;
}
private Context mContext;
private int resourceId;
private ListViewItem item;
private ViewHolder holder;
private int currentIndex = -1;
private int iconIndex = -1;
private int lastIconIndex = -1;
private boolean iconFlag = false;
private boolean iconFlag2 = false;
先得到列表项对象
item = getItem(position);
对应的,通过之前自定义集合类的封装好的方法得到参数
holder.description.setText(item.getDescription());
holder.description.setVisibility(View.GONE);
holder.image.setBackgroundResource(item.getImage());
其实呢,这样listview的基本使用就完成了。切记!!listview在主布局中,长、高要用match_parent,用了wrap_content的话,会造成多次刷新的问题。之后会造成判定时不必要的麻烦。
不过,我另外加了一些效果。类似于酷狗音乐的音乐表单。就是动画效果做的有点简陋,下拉的隐藏布局做的不太美观,毕竟时间有限(都大三了为什么还有那么多课和作业T^T)。
完整的getView方法上面有,就不重复上了。简单提一下,通过设置一个int 参数,然后在你要判定的事件里,给int参数赋值,并调用notifyDataSetChanged方法。(相当于刷新)大致思路就是这样。
然后提及一下RotateAnimation
Animation animation = new RotateAnimation(0, 90,
holder.icon.getWidth() / 2, holder.icon.getHeight() / 2);
animation.setDuration(200);
animation.setFillAfter(true);
holder.icon.startAnimation(animation);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation animation) {
notifyDataSetChanged();
}
});
用法如下,构造方法是4参数的,代表旋转前角度、旋转后角度、旋转中心X,旋转中心Y。
setDuration设置时长,setFillAfter设置是否显示动画后的模样(默认是false)。设置好了,用startAnimation方法就可以开始动画了,并绑一个监听器。有一个注意点!!动画的话,和线程一样,是异步的!也就是说,你动画在放的时候,其他的代码块照样正常运行。这点要注意!
完整的代码:百度云链接
http://pan.baidu.com/s/1dDztv4d