Android學習筆記(十八):ListView和RatingBar

來源:互聯網
上載者:User

在學習筆記(十七)中,我們對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()。

相關連結:我的Andriod開發相關文章

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.