Issues with Button press states in each ListView r

2019-07-29 06:30发布

I'm having problems with button presses in ListView rows. The background attribute for each Button refers to a XML selector file; in order to select a different image on button presses. I'm able to get press events from OnClickListener, but the state selector breaks and does not register presses with android:state_pressed="true" and android:state_focused="false".

If I remove android:descendantFocusability="blocksDescendants" from the parent/root Layout XML for the button; then the press state will work, but will fire no matter where you touch on the ListView row, which is annoying.

My problem: cannot manage the press/default states of rows separate from the buttons inside. They interfere with each other.

Code:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/mainListLayout"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content" 
   android:descendantFocusability="blocksDescendants">
..........

Row item button further down:

<Button
        android:id="@+id/deleteButton"
        android:background="@drawable/del_button_selector"
        .....
        .....
        />
..........

And the drawable/del_button_selector:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/deleteico" android:state_focused="true" android:state_pressed="false"/>
    <item android:drawable="@drawable/deletepressed" android:state_focused="true" android:state_pressed="true"/>
    <item android:drawable="@drawable/deleteico" android:state_focused="false" android:state_pressed="true" />

Changing the drawable background in the last selector line there does not work. It will show the pressed image but it does not matter where you click on the row, away from the button.

I can change the background on button click events but I need to switch back to default background upon button release, which is hard to capture(?). If I can capture press/release events in listeners then that would be great for buttons only.

Any help appreciated! Thanks!

2条回答
干净又极端
2楼-- · 2019-07-29 07:06

The easy solution is to set android:clickable="true" to the parent view.

This way it will intercept the touch event and the child views will not be highlighted.

In your concrete case:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/mainListLayout"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" 
      android:clickable="true">
查看更多
爷的心禁止访问
3楼-- · 2019-07-29 07:08

Did you find an answer?

I've had this problem also. I think there is a bug in the android framework (and/or we are facing - as usual - a poor framework design). However there is a xml field called android:duplicateParentState it is useless in this case (to tell the truth I used it in another project to duplicate the state of the parent setting it to true).

So my solution was this (I know it is ugly and should be an easier way to do this):

  • define 2 different drawables: one for the pressed and one for the unpressed state
  • parent of the button defines android:descendantFocusability="blocksDescendants"
  • set an onTouchListener on the button

This latter looks like this:

    button.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                v.setBackgroundDrawable(mButtonDownDrawable); // this call is deprecated since Jelly Bean, use setBackground() instead
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_OUTSIDE: // just in case. this is never called
            case MotionEvent.ACTION_CANCEL:
                v.setBackgroundDrawable(mButtonUpDrawable);
                break;
            case MotionEvent.ACTION_MOVE:
                final Rect rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
                if(!rect.contains((int)event.getX(), (int)event.getY())){
                    // User moved outside bounds
                    v.setBackgroundDrawable(mButtonUpDrawable);
                }
                break;
            }
            return false;
        }
    });
查看更多
登录 后发表回答