2012-11-29 57 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中调用该方法。 –