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

Android学习笔记(十八):ListView和RatingBar

2012-12-04 00:02 330 查看
我们对ListView做了进一步的探讨,然而给出的例子list中的元素可以有多个widget,并可灵活设置他们的值,但是这些widget之间缺乏互动,而且getView()的调用,需要重刷给list的entry,我们希望能够在entry中触发变化。



本次,我们继续根据《Beginging Android 2》的学习,结合RatingBar,将程序稍微复杂一点。RatingBar看用于媒体库的平级,我们用RatingBar取代了之前例子的图标,当RatingBar设置为三星时,该entry后面的文本改为大写,如果低于三星将恢复原来的小写显示。

例子:自定义数据结构和内部widget的触发处理

1)Android XML文件:用RatingBar替代之前例子的ImageView

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout ……>

<RatingBar android:id="@+id/c85_rating"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:numStars = "3" <!-- 设置三星平级方式-->

android:stepSize = "0.5" <!--step为0.5,也就是允许2.5的星级评比 -->

android:rating = "2"/> <!-- 缺省为2星-->

<TextView android:id="@+id/c85_label"

android:paddingLeft="2px"

android:paddingRight="2px"

android:paddingTop="10px"

android:textSize="24sp"

android:layout_width="fill_parent"

android:layout_height="wrap_content" />

</LinearLayout>

2)设置自定制数据结构来存储信息,并提供查询信息的方法

在之前的例子中,我们使用了ArrayList<String>来存放每个单元的数据信息,在这个例子中,作为更通用的方式,每个单元信息为我们自定的类RowModel。

class RowModel{

String label; //存储entry的当前文本显示内容,通过调用toString()给出,如果三星将提供大写显示。

float rating = 2.0f; //存储entry的星级数据,对应RatingBar的星级显示



RowModel(String label){

this.label = label;

}

public String toString(){

if(rating >= 3.0){

return label.toUpperCase();

}

return label;

}

}

在我们的主类中,根据自定义的数据结构设置我们的数据信息list,并导入list adapter中,同时我们增加一个方法,根据position(index)来从数据信息中获取该单元的数据。

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

ArrayList<RowModel> list = new ArrayList<RowModel>(); //步骤1:list作为数据的存储

for(String s: items){ //步骤2:将String[] items的信息导入list中,这种写法比较特别,我一般会老老实实for(int i =0; i <items.length; i++)的方式来写。

list.add(new RowModel(s));

}

setListAdapter(new RatingAdapter(list)); //步骤3:设置自定制的listadapter(具体在后面处理),并将信息数据list导入其中

}

//根据List的位置,获得具体的list元素,一般add,del,find的处理中,相当于find

private RowModel getModel(int position){

return ((RatingAdapter)getListAdapter()).getItem(position);

}

3)List单元的View和widget信息捆绑,实现快速定位widget

根据之前的学习,为了使程序运行得更有效率,我们会使用setTag的方式,将list单元的UI的View和存储单元UI中widget信息的类捆绑,以便可以快速定位widget。

步骤1:设置存储List单元View中widget的相关类。

其实,我们可以将这些widget信息和2)中的数据信息放在一起,在这个例子中程序会更借鉴,但是这样的处理很不好,我们尽可能把要将UI相关的信息和数据信息放在一起,否则UI修改或者进行尺寸适配时出现麻烦。

private class ViewWrapper{

View base;

RatingBar rate = null;

TextView label = null;



ViewWrapper(View base){

this.base = base;

}



RatingBar getRatingBar(){

if(rate == null)

rate =(RatingBar) base.findViewById(R.id.c85_rating);

return rate;

}



TextView getLabel(){

if(label == null)

label = (TextView)base.findViewById(R.id.c85_label);

return label;

}

}

步骤2:List单元View的呈现(getView),并且提供其中widget触发的处理



一个List单元的View对应两个内容,一个是存储的数据,可以通过getModel来获得,另一个是对应的单元UI的widget队形的存储,通过getTag()和setTag(),这个在上一次学习中已经学习了,我们还需要增加View中widget的触发,在这个例子中,当RatingBar的星级出现变化是,可能需要重写刷新后面文章的显示。我们具体看代码:

private class RatingAdapter extends ArrayAdapter<RowModel>{

//步骤2.1:设置构造函数,将数据信息放入ArrayAdapter中,这样可以通过getItem() 获取数据信息,同时也设置layout格式

RatingAdapter(ArrayList<RowModel> list){

super(Chapter8Test5.this,R.layout.entry,list);

}

//步骤2.2: 编写ListView中每个单元的呈现

public View getView(int position, View convertView, ViewGroup parent) {

View row = convertView;

ViewWrapper wrapper;

RatingBar ratebar = null;

//步骤2.3:如果没有创建View,根据layout创建之,并将widget的存储类的对象与之捆绑为tag

if(row == null){

LayoutInflater inflater=getLayoutInflater();

row = inflater.inflate(R.layout.entry, parent,false);

wrapper = new ViewWrapper(row);

row.setTag(wrapper);

//步骤2.4:在生成View的时候,添加将widget的触发处理

ratebar = wrapper.getRatingBar();

ratebar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {

public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {

//步骤2.4.1:存储变化的数据

Integer index = (Integer)ratingBar.getTag();

RowModel model = getModel(index);

model.rating = rating;

//步骤2.4.2:设置变化

LinearLayout parent = (LinearLayout)ratingBar.getParent();

TextView label = (TextView)parent.findViewById(R.id.c85_label);

label.setText(model.toString());

}

});

}else{ //步骤2.4:利用已有的View,获得相应的widget

wrapper = (ViewWrapper) row.getTag();

ratebar = wrapper.getRatingBar();

}

//步骤2.5:设置显示的内容,同时设置ratingbar捆绑tag为list的位置,因为setTag()是View的方法,因此我们不能降至加在ViewWrapper,所以需要加载ViewWrapper中的widget中,这里选择了ratebar进行捆绑。

RowModel model= getModel(position);

wrapper.getLabel().setText(model.toString());

ratebar.setTag(new Integer(position));

ratebar.setRating(model.rating);

return row;

}

}

我们在这里例子中进行了一个实验,考察什么时候convertView可以为null,一屏可以显示0-8个row,这些list的元素都是null,需要通过程序来创建,然而当我混动屏幕的时候,我想象中,后面的元素第一次也应该为0,但是出乎我的意外,只有position=14的出现row=null。对于通过scroll屏幕的情况,下一屏Android可能根据第一屏对UI的处理情况进行了处理。因此Android对UI的智能处理情况我们不太能把握,因此任何与数据有关,不是纯粹的UI问题的初始赋值的问题,不要只放置在if(row==null)中进行初始处理,否则会引起不可预测的意外。例如我们将步骤2.5中的ratebar.setTag(new
Integer(position))此句放在if(row==null)会得到不正常的结果,因为不是所有的list元素中的该widget都在初始的情况下成功进行了捆绑,所以我们将它放置在外面或者通知方式在if和else的判断中,保证所有情况都覆盖。

ListAdapter:CursorAdapter

一般来讲,我们可以使用ArrayAdapter来适用很多情况,还有其他的Adapter,使用方式类似,但是CursorAdapter有些不一样,通过newView()和bindView(),如果没有创建,使用newView(),然后调用bindView(),如果已经创建,使用bindView()。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: