You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义按钮ClickListener咨询:PressedButton类的实现与点击处理问题

Fixing Pressed State & Implementing Click Listener for Your Custom Android Button

Hey there! Let's get your PressedButton working correctly. Your current code has a solid foundation, but we need to fix the pressed state management and properly integrate the click listener to make it behave like a standard Android button (with custom state support).

1. Fix the Core Pressed State Logic

First, your setPressed method is incomplete, and you're not properly integrating Android's view state system. Android uses onCreateDrawableState to combine custom states with the default view states, so we need to override that method. Here's how to fix it:

Update the setPressed Method

Your current setPressed doesn't trigger a state refresh. Let's complete it and ensure the view updates its appearance:

@Override
public void setPressed(boolean isPressed) {
    // Update our custom flag
    mIsPressed = isPressed;
    // Reset the unpressed flag (since a button can't be both pressed and unpressed)
    mIsUnpressed = !isPressed;
    // Tell the view to refresh its drawable state
    refreshDrawableState();
    // Don't forget to call the super method to maintain default button behavior
    super.setPressed(isPressed);
}

Override onCreateDrawableState to Merge Custom States

This method lets us combine our custom state_pressed/state_unpressed with Android's default button states (like focused, enabled):

@Override
protected int[] onCreateDrawableState(int extraSpace) {
    // Get the default state array from the super class
    int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
    
    // Add our custom pressed state if applicable
    if (mIsPressed) {
        mergeDrawableStates(drawableState, STATE_PRESSED);
    }
    // Add our custom unpressed state if applicable
    if (mIsUnpressed) {
        mergeDrawableStates(drawableState, STATE_UNPRESSED);
    }
    
    return drawableState;
}

2. Properly Implement OnClickListener

Good news: you don't need to re-invent the click listener wheel! The parent Button class already handles OnClickListener out of the box. But if you want to add custom logic when the button is clicked (alongside external listeners), you can override performClick():

Option 1: Use Default Click Listener (Simple)

Just let external code set the listener like a normal button:

// In your Activity/Fragment
PressedButton myButton = findViewById(R.id.my_pressed_button);
myButton.setOnClickListener(v -> {
    // Your click logic here
    Toast.makeText(this, "Custom button clicked!", Toast.LENGTH_SHORT).show();
});

Option 2: Add Custom Internal Click Logic

If you want to run some code every time the button is clicked (before external listeners), override performClick():

@Override
public boolean performClick() {
    // Add your custom pre-click logic here (e.g., log the click, update a variable)
    Log.d("PressedButton", "Button was clicked!");
    
    // Call the super method to trigger the external OnClickListener
    return super.performClick();
}

3. Full Working PressedButton Code

Here's the complete class with all fixes:

public class PressedButton extends Button {
    private static final int[] STATE_PRESSED = {R.attr.state_pressed};
    private static final int[] STATE_UNPRESSED = {R.attr.state_unpressed};
    
    private boolean mIsPressed = false;
    private boolean mIsUnpressed = true; // Start in unpressed state

    public PressedButton(Context context) {
        super(context);
        init();
    }

    public PressedButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PressedButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // Optional: Set default behavior, like enabling clickable
        setClickable(true);
    }

    @Override
    public void setPressed(boolean isPressed) {
        mIsPressed = isPressed;
        mIsUnpressed = !isPressed;
        refreshDrawableState();
        super.setPressed(isPressed);
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
        
        if (mIsPressed) {
            mergeDrawableStates(drawableState, STATE_PRESSED);
        }
        if (mIsUnpressed) {
            mergeDrawableStates(drawableState, STATE_UNPRESSED);
        }
        
        return drawableState;
    }

    @Override
    public boolean performClick() {
        // Optional custom internal logic
        Log.d("PressedButton", "Custom button clicked internally");
        return super.performClick();
    }
}

4. Bonus: Handle Touch Events for Precise State Control

For even better control over when the pressed state activates (e.g., if the user presses the button and drags away), override onTouchEvent:

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            setPressed(true);
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            setPressed(false);
            break;
    }
    // Let the super class handle the rest (like triggering performClick on ACTION_UP)
    return super.onTouchEvent(event);
}

This ensures the pressed state only stays active while the user's finger is on the button, which matches standard Android button behavior.

内容的提问来源于stack exchange,提问作者Francisco Peters

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:31:31