我有一个ListView,其中每个项目都有一个带有bg图像的自定义LinearLayout,一个textView和2个imageViews。 现在我需要在用户触摸项目时,所有这些都切换到“按下”状态:
通常这样的东西可以使用带有选择器的xml资源来完成,例如LinearLayout将使用带有选择器的drawable用于背景,TextView带有选择器的drawable和textColor的颜色,而ImageViews使用带有src内部图像的选择器。
问题是,按下状态仅由LinearLayout检测,而不是由子视图(?)检测,因此只有背景图像会发生变化。
我已尝试使用OnTouchListener实现此功能,但随后出现了无法安全访问列表项中的Views的问题。
我尝试缓存我在列表项的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>
答案 0 :(得分:4)
经过大量的实验,最终确实有效:
列表项布局中的每个子视图都必须具有android:duplicateParentState="true"
。
然后他们都可以使用选择器drawables。代码内部不需要额外的努力。
<?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>
答案 1 :(得分:-1)
您应该创建自定义可绘制选择器,并将它们设置为listview元素的背景。
步骤#1,创建另一个布局(此示例名称为:layout_selected),具有适合您按下状态的背景颜色(如您提供的布局文件,但线性设置的背景属性为另一种颜色)。
然后,您将定义一个可绘制的选择器,该选择器将放置在您的drawable文件夹中),定义应在哪个实例中使用哪个背景。这看起来像这样:
<!-- 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"/>
最后,要在列表中使用它,在设置适配器的布局时,将其设置为我们刚创建的选择器,而不是标准布局。
也许有点难以解释,但你想使用'Drawable Selectors'来完成你想要的。
答案 2 :(得分:-1)
我建议为listview添加ViewHolder模式。这将优化您的listview绘图和&amp;创建UI。
另外,我们可以使用setTag来保存行的实例。在那你可以处理触摸事件。