我的activity_main上的LinearLayout中有多个按钮,并且想要检测哪个Button最接近用户手指。当用户在一个手势中移动手指时,最近的按钮应该突出显示,当他移开手指时,最近的按钮应该执行其onClick功能。
它应该像android或iphone计算器上的默认键盘。它选择最靠近手指的按钮。当您将手指拖过它时,会将选择更改为最近的键,只有当您松开手指时才会执行onClick功能。
引用Get button coordinates and detect if finger is over them - 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>
Java
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);
}
答案 0 :(得分:0)
创建一个新类来扩展LinearLayout并覆盖onInterceptTouchEvent。将外部LinearLayout设置为新类。
警告:如果您只点按一个按钮(一次在父级,一次在孩子上),这会产生两次调用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;
}
<强> ExtendedLinearLayout 强>
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;
}
}