2

我有一个 ListView,其中每个项目都有一个带有 bg 图像、一个 textView 和 2 个 imageViews 的自定义 LinearLayout。现在我需要在用户触摸项目时,所有这些都切换到“按下”状态:

  • LiearLayout 的背景图像必须替换为另一个
  • TextView 应该改变 textColor
  • 项目中的两个 ImageViews 都应该切换到替代图像

通常这样的事情将使用内部带有选择器的xml资源来完成,例如LinearLayout将使用带有内部选择器的drawable作为背景,TextView将使用带有选择器和颜色的drawable作为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>
4

3 回答 3

4

经过大量的试验终于成功了:列表项布局中的每个子视图都必须有android:duplicateParentState="true". 然后他们都可以只使用选择器可绘制对象。代码内部不需要额外的努力。

<?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>
于 2012-11-29T15:00:15.570 回答
-1

您应该创建自定义可绘制选择器,并将它们设置为列表视图元素的背景。

第 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"/>

最后,要在列表中使用它,当您为适配器设置布局时,请将其设置为我们刚刚创建的选择器,而不是您的标准布局。

也许有点难以解释,但您想使用“可绘制选择器”来完成您想要的。

于 2012-11-29T12:45:46.397 回答
-1

我建议为列表视图添加 ViewHolder 模式。这将优化您的列表视图绘图和创建 UI。

此外,我们可以使用 setTag 来保存行的实例。在那里你可以处理触摸事件。

于 2012-11-29T12:48:46.930 回答