ListView条目长按状态选择器

4

在默认的ListView上,如果您长按某个项目,背景会在注册LongClick期间从深蓝色渐变为浅蓝色(在Galaxy Tab上是橙色到浅橙色,其他设备上也可能是这样)。我假设这是通过选择器来完成的,但到目前为止,我只看到了如何使用选择器来处理状态:selected、state:focused和state:pressed。

这个页面似乎没有显示任何关于LongClick状态的内容,因此我的假设可能是不正确的?

有人可以告诉我默认的ListView如何获得这种效果以及我如何将其应用于其他视图吗?


实现这个的简单方法:https://dev59.com/t2w15IYBdhLWcg3wmM19 - Sabre
3个回答

4

事实证明,这比我想象的要困难一些,但现在我已经将其几乎正确地运行。

这是我最终使用的OnTouchListener:

listOnTouchListener = new OnTouchListener() {
         public boolean onTouch(View v, MotionEvent me){
             if (me.getAction() == MotionEvent.ACTION_DOWN){
                 //This means a finger has come down on top of our view
                 //We are going to start the animation now.
                 Log.i(myTag, "Action Down");
                 Context mContext = getApplicationContext();
                 Resources res = mContext.getResources();
                 TransitionDrawable transition = (TransitionDrawable) res.getDrawable(R.drawable.listtransition);
                 v.setBackgroundDrawable(transition);
                 //LongClick took approx. 510-530 milliseconds to register after OnTouch. So I set the duration at 500 millis.
                 transition.startTransition(500);
             }else if (me.getAction() == MotionEvent.ACTION_UP){
                 //This means we didn't hold long enough to get a LongClick
                 //Set the background back to the normal one.
                 v.setBackgroundResource(R.drawable.bubblelight);

             }else if (me.getAction() == MotionEvent.ACTION_MOVE){
                 //Do Nothing
             }else if (me.getAction() == MotionEvent.ACTION_CANCEL){
                 Log.i(myTag, "Action Cancel");
                 //This means we are scrolling on the list, not trying to longpress
                 //So set the background back to the normal one.
                 v.setBackgroundResource(R.drawable.bubblelight);
             }
             return false;

         }
     };

我在其中使用了OnLongClickListener,然后将背景恢复为正常状态。
以下是Transition XML:
<transition xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@drawable/bubblelight1" />
  <item android:drawable="@drawable/bubbledark" />
</transition>

你可能会问什么是bubblelight1?稍后再说。

这里是我在适配器中使用的getView()方法,用于返回在列表中显示的视图:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        v = convertView;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.row, null);
        }
        Status s = items.get(position);
        if (s != null) {
            v.setOnTouchListener(listOnTouchListener);
            v.setOnLongClickListener(listOnLongClickListener);
            tweetTxt = (TextView) v.findViewById(R.id.tweetTxt);
            timeTxt = (TextView) v.findViewById(R.id.timeTxt);
            if (tweetTxt != null) {
                tweetTxt.setText(s.getText());
                tweetTxt.setOnTouchListener(gestureListener);
            }
            if(timeTxt != null){
                timeTxt.setText(getTimeFromNow(s.getCreatedAt().getTime()));
                //timeTxt.setText(s.getCreatedAt().toLocaleString());
            }
        }
        LinkifyWithTwitter.addLinks(tweetTxt, Linkify.ALL);
        return v;
    }

v.setOnTouchListener(listOnTouchListener); 和 v.setOnLongClickListener(listOnLongClickListener); 这两行代码设置了视图与我上面展示的监听器。

现在说一下bubblelight1。bubblelight和bubbledark是我第一次尝试时使用的九宫格图片。每当转换开始时,背景不是从bubblelight过渡到bubbledark,而是bubblelight变得更大,bubbledark出现在bubblelight内部。所以我有一个大的浅色气泡,一个小的深色气泡,然后是里面的文本。为了解决这个问题,我复制了bubblelight并将九宫格的底部和右侧边缘完全填充。我只需要对第一张图片进行这样的处理,而不是第二张。如果我用同样的方法处理第二张图片,那么我的文本就会跳出气泡,有些文本会显示在气泡的顶部和侧面。我不完全确定为什么会发生这种情况,或者为什么这个修复方法起作用。但是现在它可以完成工作了。


1
你应该使用ViewConfiguration.getLongPressTimeout()而不是固定的 500 毫秒。 - Michael Butscher

1

http://developer.android.com/guide/topics/ui/menus.html#context-menu

当用户在ListView中的项目上执行长按操作并且该列表已注册以提供上下文菜单时,列表项通过动画化其背景颜色来向用户发出信号,表明上下文菜单可用 - 在打开上下文菜单之前,它从橙色过渡到白色。(联系人应用程序演示了此功能。)
因此,它使用了动画效果。我相信它使用View的默认On...()方法来显示它。您可能需要考虑为其提供clickable="true"或longClickable="true"属性。

所以我将设置一个OnTouchListener,它启动动画来过渡视图的背景。有没有人知道触摸需要多长时间才能被注册为LongClick?这样我就可以同步动画持续的时间,而不需要手动试错。 - FoamyGuy
经过再次考虑,我认为我可以在OnTouch中检查系统时间,然后在OnLongClick中再次检查并进行减法运算以获取持续时间。如果有人恰好知道系统默认用于listview项目的动画名称,那对我仍然非常有帮助。 - FoamyGuy

0
除了您的OnTouchListener之外,您还可以使用一个Runnable来将背景恢复为其原始状态,这样您就不需要在OnLongClick处理程序中明确地执行它。
Handler myHandler = new Handler();
...
transition.startTransition(ViewConfiguration.getLongPressTimeout());
ResetBG r = new ResetBG(transition);
myHandler.postDelayed(r, ViewConfiguration.getLongPressTimeout());

ResetBG 是什么:

class ResetBG implements Runnable {
    protected TransitionDrawable myTran;

    public Runnable(TransitionDrawable tran) {
        myTran = tran;
    }

    public void run() {
        myTran.resetTransition();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接