2012-11-29 103 views
2

我有一個ListView,其中每個項目都有一個自定義LinearLayout與bg圖像,textView和2 imageViews。 現在我需要在用戶觸摸的項目,所有的切換到「按下」狀態:ListItem應該改變bg顏色,文本和圖像的顏色,同時按下

  • 的LiearLayout的背景圖片必須用另一個
  • TextView的應該改變文字顏色更換
  • 在該項目的兩個ImageViews應該切換到替代圖像

通常這樣的東西將使用XML資源與選擇器內進行,例如LinearLayout將使用一個帶選擇器內部的可繪製的背景,TextView帶有選擇器的可繪製和用於textColor的顏色,ImageViews使用帶有用於src的圖像的選擇器。

問題是按下的狀態只能被LinearLayout檢測到,而不是被子視圖(?)檢測到,因此只有背景圖像發生變化。

我已經嘗試過使用OnTouchListener實現此功能,但隨後出現問題,無法安全地訪問列表項中的視圖。

我試着緩存視圖,我在列表項的getView()中返回,然後更改圖像和文本顏色。這通常起作用,但例如如果其中一個列表項打開另一個活動,則該視圖以某種方式丟失,並且突出顯示的狀態將無限期地保留。我已經嘗試過調試,如果通過調試器直接運行,它會正常工作。另外,重複使用cachedView似乎並沒有帶來好處,並且完全混淆了事情,所以我只是每次爲列表項添加一個新視圖(這必須是低效的)。

以防萬一,這裏是我使用自定義列表適配器自定義列表項項目代碼:

public class MyListItem extends AbstractListItem 
{ 
    private int iconResource, iconHighlightedResource; 
    private int textResource; 
    private View.OnClickListener onClickListener; 
    private LinearLayout currentView; 

    private ImageView imgIcon; 
    private TextView txtText; 
    private ImageView imgArrow; 
    private boolean bIsHighlighted; 

    public MyListItem(int iconResource, int iconHighlightedResource, int textResource, View.OnClickListener onClickListener) 
    { 
     this.iconResource = iconResource; 
     this.iconHighlightedResource = iconHighlightedResource; 
     this.textResource = textResource; 
     this.onClickListener = onClickListener; 
    } 

    public View getView(View cachedView) 
    { 
     this.currentView = buildView(); 
     populateView(); 
     update(); 
     return this.currentView; 
    } 

    private LinearLayout buildView() 
    { 
     LayoutInflater inflater = (LayoutInflater)App.get().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     return (LinearLayout)inflater.inflate(R.layout.my_menu_item, null); 
    } 
    private void populateView() 
    { 
     this.imgIcon = (ImageView)this.currentView.findViewById(R.id.img_menu_item_icon); 
     this.txtText = (TextView)this.currentView.findViewById(R.id.txt_menu_item_text); 
     this.txtText.setText(this.textResource); 
     this.txtText.setTypeface(App.fontCommon); 
     this.imgArrow = (ImageView)this.currentView.findViewById(R.id.img_menu_item_arrow); 
     this.currentView.setOnClickListener(this.onClickListener); 
     this.currentView.setOnTouchListener(this.highlighter); 
    } 

    private View.OnTouchListener highlighter = new View.OnTouchListener() 
    { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) 
     { 
      int nAction = event.getAction(); 
      int nActionCode = nAction & MotionEvent.ACTION_MASK; 
      switch (nActionCode) 
      { 
       case MotionEvent.ACTION_DOWN: 
        bIsHighlighted = true; 
        update(); 
        break; 
       case MotionEvent.ACTION_UP: 
       case MotionEvent.ACTION_CANCEL: 
        bIsHighlighted = false; 
        update(); 
        break; 
      } 
      return false; 
     } 
    }; 

    private void update() 
    { 
     if (this.bIsHighlighted) 
     { 
      updateForHighlightedState(); 
     } 
     else 
     { 
      updateForNormalState(); 
     } 
    } 

    private void updateForHighlightedState() 
    { 
     Resources r = App.get().getResources(); 
     this.currentView.setBackgroundResource(R.drawable.button_beveled_m_call_to_action_taking_input); 
     this.imgIcon.setImageResource(this.iconHighlightedResource); 
     this.txtText.setTextColor(r.getColor(R.color.white)); 
     this.imgArrow.setImageResource(R.drawable.arrow_highlighted); 
    } 
    private void updateForNormalState() 
    { 
     Resources r = App.get().getResources(); 
     this.currentView.setBackgroundColor(r.getColor(R.color.white)); 
     this.imgIcon.setImageResource(this.iconResource); 
     this.txtText.setTextColor(r.getColor(R.color.text_dark)); 
     this.imgArrow.setImageResource(R.drawable.arrow); 
    } 
} 

這裏是佈局文件(XML):

<?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="wrap_content" 
    android:orientation="horizontal" 
    android:background="@color/white" 
    android:gravity="center_vertical" 
    android:padding="5dp" > 

    <ImageView 
     android:id="@+id/img_menu_item_icon" 
     android:layout_width="48dp" 
     android:layout_height="48dp" 
     android:src="@drawable/info" /> 

    <TextView 
     android:id="@+id/txt_menu_item_text" 
     android:layout_width="0dp" 
     android:layout_height="wrap_content" 
     android:layout_weight="1" 
     android:textSize="24dp" 
     android:text="Menu item" 
     android:textColor="@color/text_dark" 
     android:layout_marginLeft="5dp" /> 

    <ImageView 
     android:id="@+id/img_menu_item_arrow" 
     android:layout_width="48dp" 
     android:layout_height="48dp" 
     android:src="@drawable/arrow" /> 

</LinearLayout> 

回答

3

經過大量實驗終於有效: 列表項佈局中的每個子視圖必須有android:duplicateParentState="true"。 然後他們都可以使用選擇器drawable。代碼內不需要額外的努力。

<?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="wrap_content" 
    android:orientation="horizontal" 
    android:background="@drawable/my_item_bg" 
    android:gravity="center_vertical" 
    android:padding="5dp" > 

    <ImageView 
     android:id="@+id/img_menu_item_icon" 
     android:layout_width="48dp" 
     android:layout_height="48dp" 
     android:src="@drawable/selector_info" 
     android:duplicateParentState="true" /> 

    <TextView 
     android:id="@+id/txt_menu_item_text" 
     android:layout_width="0dp" 
     android:layout_height="wrap_content" 
     android:layout_weight="1" 
     android:textSize="24dp" 
     android:text="Menu item" 
     android:textColor="@drawable/selector_color_my_button_text" 
     android:layout_marginLeft="5dp" 
     android:duplicateParentState="true" /> 

    <ImageView 
     android:layout_width="48dp" 
     android:layout_height="48dp" 
     android:src="@drawable/selector_arrow" 
     android:duplicateParentState="true" /> 

</LinearLayout> 
+0

我看到你將TextView的背景從一個顏色改變爲一個drawable ...那麼selector_color_my_button_text的內容是什麼? –

-1

您應該創建自定義可繪製選擇器,並將它們設置爲您的listview元素的背景。

第1步,爲您的按下狀態創建另一個佈局(命名爲layout_selected)(與您提供的佈局文件類似,但線性背景屬性爲另一種顏色) 。

然後,您將定義一個可繪製的選擇器,它將放置在您的可繪製文件夾中),定義在哪個實例中應使用哪個背景。這將是這個樣子:

<!-- pressed --> 
<item android:drawable="@drawable/layout_selected" android:state_pressed="true"/> 
<!-- focused --> 
<item android:drawable="@drawable/layout_normal" android:state_focused="true"/> 
<!-- default --> 
<item android:drawable="@drawable/layout_normal"/> 

最後,在你的列表,這樣,當你爲你的適配器設置佈局,將其設置爲我們剛剛創建的選擇,而不是你的標準佈局。

也許有點難以解釋,但你想用'可繪製選擇器'來完成你想要的。

+0

謝謝,但這隻適用於背景,不會更改附加到列表視圖的視圖。還是我錯誤地理解了你? – iseeall

+0

您可以在不同的佈局中指定您想要的任何視圖。您可以通過提供替代佈局來控制任何你想要的。事實上,您的理解不正確,因爲您可以通過在備用版式中提供適當的值來控制UI的任何元素。我相信這是你的答案。 – Booger

-1

我建議爲listview添加ViewHolder模式。這將優化您的列表視圖繪圖&創建用戶界面。

此外,我們可以使用setTag來保存行的實例。在那你可以處理觸摸事件。

+0

使用ViewHolder的好主意,但這並不能解決他所問的問題。 – Booger

+0

事實上,剛剛嘗試過,問題仍然存在:OnTouchListener無法訪問列表項中的TextView,因爲View對象或ViewHolder對象都無法保存。相反,你只能在getView()方法內接收它們,方法 – iseeall

+0

好的,然後通過創建一個接口來使用觀察者設計模式,該接口應該由每個UI行實現。從ListView的OnTouchListener中調用該方法。 –