ListItem 应在按下时更改背景颜色、文本和图像的颜色
Posted
技术标签:
【中文标题】ListItem 应在按下时更改背景颜色、文本和图像的颜色【英文标题】:ListItem should change bg color, color of text and images on it while pressed 【发布时间】:2012-11-17 12:48:59 【问题描述】:我有一个 ListView,其中每个项目都有一个自定义 LinearLayout,其中包含一个 bg 图像、一个 textView 和 2 个 imageView。 现在我需要在用户触摸项目时,所有这些都切换到“按下”状态:
LiearLayout 的背景图片必须替换为另一张 TextView 应该改变 textColor 项目中的两个 ImageView 都应切换到替代图像通常这样的事情会使用内部带有选择器的 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_
android:layout_
android:orientation="horizontal"
android:background="@color/white"
android:gravity="center_vertical"
android:padding="5dp" >
<ImageView
android:id="@+id/img_menu_item_icon"
android:layout_
android:layout_
android:src="@drawable/info" />
<TextView
android:id="@+id/txt_menu_item_text"
android:layout_
android:layout_
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_
android:layout_
android:src="@drawable/arrow" />
</LinearLayout>
【问题讨论】:
【参考方案1】:经过大量试验,终于成功了:
列表项布局内的每个子视图都必须有android:duplicateParentState="true"
。
然后他们都可以只使用选择器可绘制对象。在代码中不需要额外的工作。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
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_
android:layout_
android:src="@drawable/selector_info"
android:duplicateParentState="true" />
<TextView
android:id="@+id/txt_menu_item_text"
android:layout_
android:layout_
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_
android:layout_
android:src="@drawable/selector_arrow"
android:duplicateParentState="true" />
</LinearLayout>
【讨论】:
我看到您将 TextView 的背景从颜色更改为可绘制...那么 selector_color_my_button_text 的内容是什么? 你节省了我的时间。谢谢!【参考方案2】:您应该创建自定义可绘制选择器,并将它们设置为列表视图元素的背景。
步骤#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"/>
最后,要在列表中使用它,当您为适配器设置布局时,请将其设置为我们刚刚创建的选择器,而不是您的标准布局。
可能有点难以解释,但您想使用“可绘制选择器”来完成您想要的。
【讨论】:
谢谢,但这仅适用于背景,不会更改附加到列表视图的视图。还是我理解错了? 您可以在不同的布局中指定您想要的任何视图。您可以通过提供替代布局来控制您想要的任何内容。实际上,您对我的理解不正确,因为您可以通过在备用布局中提供适当的值来控制 UI 的任何元素。我相信这就是你的答案。【参考方案3】:我建议为列表视图添加 ViewHolder 模式。这将优化您的列表视图绘图和创建 UI。
另外,我们可以使用 setTag 来保存行的实例。你可以处理触摸事件。
【讨论】:
使用 ViewHolder 是个好主意,但这并不能解决他提出的问题。 确实,刚刚试了下,问题依旧:OnTouchListener无法访问列表项内的TextView,因为View对象和ViewHolder对象都不能保存。相反,您只能在 getView() 方法中接收它们 好的,然后通过创建一个接口来使用观察者设计模式,该接口应该由每个 UI 行实现。 & 从 Listview 的 OnTouchListener 调用该方法。以上是关于ListItem 应在按下时更改背景颜色、文本和图像的颜色的主要内容,如果未能解决你的问题,请参考以下文章