安卓:移开手指时选择最近的按钮



我的activity_main上的线性布局中有多个按钮,并且想要检测哪个按钮最接近用户的手指。当用户以单个手势移动手指时,最近的按钮应突出显示,当他移开手指时,最近的按钮应执行其onClick功能。

它应该像安卓或iPhone计算器上的默认键盘一样。它选择最靠近手指的按钮。当您在手指上拖动时,它会将选择更改为最接近的键,并且只有当您松开手指时,它才会执行onClick功能。

引用获取按钮坐标并检测手指是否在它们上方 - Android我到了选择工作的地步,但只有当我点击任何不是按钮的地方并且当不在按钮上时选择最近的按钮不起作用时。

(API 21 的编程,以防万一重要(

activity_main.xml

<TextView/>
<ButtonLayout>
    <LinearLayout1>
        <Button1/>
        <Space/>
        <Button2/>
        <Space/>
        <Button3/>
        <Space/>
        <Button4/>
    </LinearLayout1>
    <LinearLayout2>
        <Button5/>
        <Space/>
        <Button6/>
        <Space/>
        <Button7/>
        <Space/>
        <Button8/>
    </LinearLayout2>
</OuterLinearLayout>

爪哇岛

private View.OnTouchListener buttonLayoutTouchListener= new View.OnTouchListener(){
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        //OuterLayout
        for (int i = 0; i < buttonLayout.getChildCount(); i++) {
            View inner = buttonLayout.getChildAt(i);
            //Inner
            if(inner instanceof LinearLayout) {
                for (int j = 0;j<((LinearLayout) inner).getChildCount();j++) {
                    View current = ((LinearLayout) inner).getChildAt(j);
                    if (current instanceof Button) {
                        Button b = (Button) current;
                        Rect rect = new Rect();
                        b.getGlobalVisibleRect(rect);
                        //factors for textview
                        rect.top-=300;
                        rect.bottom-=300;
                        if (!isPointWithin(x, y, rect.left, rect.right, rect.top,
                                rect.bottom)) {
                            b.getBackground().setState(defaultStates);
                        }
                        if (isPointWithin(x, y, rect.left, rect.right, rect.top,
                                rect.bottom)) {
                            if (b != mLastButton) {
                                mLastButton = b;
                                b.getBackground().setState(STATE_PRESSED);
                                //highlight button finger currently over
                           Log.d("button",mLastButton.getText().toString());
                            }
                        }
                    }
                }
            }
        }
        return true;
    }
};
static boolean isPointWithin(int x, int y, int x1, int x2, int y1, int y2) {
    return (x <= x2 && x >= x1 && y <= y2 && y >= y1);
}

创建一个新类来扩展 LinearLayout 并覆盖 onInterceptTouchEvent。将外部线性布局设置为新类。

警告:如果您只点击一个按钮,这会产生调用 onClick 两次的副作用(一次在父级上,一次在子项上(。这是我超级肮脏的解决方法。请考虑找到真正的解决方法并发布回复。

双击解决方法

//call if(doubleClick()) in buttons' onClicklistener
public mLastClickTime=0;
public boolean doubleClick() {
    //29 is arbitrary
    if (SystemClock.elapsedRealtime() - mLastClickTime < 29) {
        return true;
    }
    mLastClickTime = SystemClock.elapsedRealtime();
    return false;
}

扩展线性布局

import android.content.Context;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
public class ButtonLayout extends LinearLayout {
    public int layoutTop;
    public ButtonLayout(Context context) {
        super(context);
    }
    public ButtonLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    public ButtonLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    public ButtonLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        Rect rect = new Rect();
        this.getGlobalVisibleRect(rect);
        layoutTop =rect.top;
        super.onSizeChanged(w, h, oldw, oldh);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Button keep=null;
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        int count = 0;
        //number of buttons
        int buttonMax =0;
        int distance = Integer.MAX_VALUE;
        //Outer LinearLayout
        outerLoop:
        for (int i = 0; i < this.getChildCount(); i++) {
            View inner = this.getChildAt(i);
            if (inner instanceof LinearLayout) {
                //Inner LinearLayout
                for (int j = 0; j < ((LinearLayout) inner).getChildCount(); j++) {
                    View current = ((LinearLayout) inner).getChildAt(j);
                    if (current instanceof Button) {
                        buttonMax++;
                        Button b = (Button) current;
                        Rect rect = new Rect();
                        b.getGlobalVisibleRect(rect);
                        rect.top -= layoutTop;
                        rect.bottom -= layoutTop;
                        //finger in button
                        if (isPointWithin(x, y, rect.left, rect.right, rect.top,
                                rect.bottom)) {
                            b.setPressed(true);
                            keep=b;
                            break outerLoop;
                        }else{
                            b.setPressed(false);
                            count++;
                            int buttonDistance = distance(x, y, rect.left, rect.right, rect.top, rect.bottom);
                            if(buttonDistance<distance){
                                keep=b;
                                distance=buttonDistance;
                            }
                        }
                    }
                }
            }
        }
        //if non are selected let button be selected
        if(count==buttonMax){
            keep.setPressed(true);
        }
        //on release
        if(ev.getAction()==MotionEvent.ACTION_UP){
            keep.callOnClick();
            return false;
        }
        return super.onInterceptTouchEvent(ev);
    }
    static boolean isPointWithin(int x, int y, int x1, int x2, int y1, int y2) {
        return (x <= x2 && x >= x1 && y <= y2 && y >= y1);
    }
    static int distance(int x, int y,int x1, int x2, int y1, int y2){
        x1 = Math.abs(x1-x);
        x2 = Math.abs(x2-x);
        y1 = Math.abs(y1-y);
        y2 = Math.abs(y2-y);
        x = (x1>x2?x2:x1);
        y = (y1>y2?y2:y1);
        return x+y;
    }
}

最新更新