有时候我的UI中有一个按钮,它很小,很难点击。到目前为止我的解决方案是在photoshop中的按钮周围添加透明边框。只是增加按钮上的填充不起作用,因为这也会拉伸图像。因为每次想要更改可点击表面时打开photoshop都有点大惊小怪,有没有办法以编程方式执行此操作?我尝试在按钮后面放置一个framelayout并使其可点击,但是按钮不会改变触摸的外观。当然我还可以在framelayout上添加一个ontouchlistener来改变按钮的外观,但是如果我有几个按钮那么就会有一些代码。
干杯,
答案 0 :(得分:34)
我个人而言,我会使用TouchDelegate。这使您可以处理触摸目标,视觉视图可以作为两个不同的东西。非常方便...
http://developer.android.com/reference/android/view/TouchDelegate.html
答案 1 :(得分:28)
我刚刚找到了解决这个问题的简洁方法。
在Button中,将duplicateParentState设置为true,当您在按钮外部但在LinearLayout内部单击时,该按钮会突出显示。
<LinearLayout
android:layout_height="fill_parent"
android:onClick="searchButtonClicked"
android:layout_centerVertical="true"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:paddingRight="10dp"
android:paddingLeft="30dp">
<Button
android:id="@+id/search_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/toggle_button_selector"
android:textColor="#fff"
android:text="Search"
android:focusable="true"
android:textStyle="bold"
android:onClick="searchButtonClicked"
android:layout_gravity="center_vertical"
android:duplicateParentState="true"/>
</LinearLayout>
答案 2 :(得分:12)
这是一个非常晚的“我也是”,但在谈到这个以及寻找解决方案的其他问题之后,我发现了一个简单,优雅的解决方案。
另一位question抱怨他们图片的透明背景无法点击。如果这是一个问题,这似乎也解决了这个问题。
这是按钮:
<ImageButton
android:id="@+id/arrowUp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/arrow_up"
android:background="@drawable/clear_button_background" />
相关的行是最后两行。 "@drawable/arrow_up"
是* .png文件中的几个按钮状态,在可绘制的* .xml文件中定义,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true"
android:drawable="@drawable/tri_up_blue" /> <!-- pressed -->
<item android:state_selected="true"
android:drawable="@drawable/tri_up_blue" /> <!-- selected -->
<item android:state_focused="true"
android:drawable="@drawable/tri_up_blue" /> <!-- focused -->
<item android:drawable="@drawable/tri_up_green" /> <!-- default -->
</selector>
只是你的基本按钮。没什么特别的。而"@drawable/clear_button_background"
就是这样:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/transparent"/>
<size android:width="20dp" android:height="30dp" />
</shape>
此处的高度和宽度是可点击区域,根据需要调整大小。与荒谬细致的TouchDelegate不同,您可以在单个视图中根据需要重复使用此按钮。没有额外的听众。它不会向您的层次结构中添加任何视图或组,并且您不会整天使用填充和边距。
简单。优雅。
答案 3 :(得分:2)
我认为您的解决方案是目前最好的解决方案,如果您不想深入了解某些Android内容并自行拦截所有的motionEvent和TouchEvents,那么您还需要触发按下的视图按钮自己等。
只需创建一个带有可伸展透明边框的nine patch image即可。通过这种方式,您可以更改图像的大小而无需更改图像本身,并且您的按钮将增大或缩小而不会显示实际显示的背景。
答案 4 :(得分:1)
另一个想法是制作新的透明图像并在其上放置图标,使触摸区域更加美观,设计看起来更完美。 Check out the image
谢谢。
答案 5 :(得分:0)
只需在布局中提供填充以代替边距
<ImageView
android:id="@+id/back_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="25dip"
android:src="@drawable/back_btn" />
答案 6 :(得分:0)
我不推荐这样做,很少有人会觉得有用。
对我来说,这是最好的解决方案,因为TouchDelegate并非在所有View层次结构方案中都适用。
解决方案基于覆盖隐藏的
View class
public boolean pointInView(float localX, float localY, float slop)
代码如下:
public boolean pointInView(float localX, float localY, float slop) {
boolean res = ae_pointInView(localX, localY, slop, slop);
if(!res) {
if(viewIsClickableButToSmall(this)) {
//our view is clickable itself
float newSlopX = Math.max(slop, slop + minTouchableViewWidth - this.getWidth());
float newSlopY = Math.max(slop, slop + minTouchableViewHeight - this.getHeight());
if(ae_pointInView(localX, localY, newSlopX, newSlopY)) {
return true;
}
}
//the point is outside our view, now check for views with increased tap area that may extent beyond it
int childCount = getChildCount();
for(int i = 0; i < childCount;i++) {
View child = getChildAt(i);
if(child instanceof MyViewGroup) {
//this is our container that may also contain views with increased tap area
float[] newPoint = ae_transformPointToViewLocal(localX, localY, child);
if(((MyViewGroup) child).pointInView(newPoint[0], newPoint[1], slop)) {
return true;
}
}
else {
if(viewIsClickableButToSmall(child)) {
float[] newPoint = ae_transformPointToViewLocal(localX, localY, child);
float newSlopX = Math.max(slop, slop + minTouchableViewWidth - this.getWidth());
float newSlopY = Math.max(slop, slop + minTouchableViewHeight - this.getHeight());
if(ae_pointInView(newPoint[0], newPoint[1], newSlopX, newSlopY)) {
return true;
}
}
}
}
return false;
}
else
return true;
}
private int minTouchableViewHeight, minTouchableViewWidth;
private boolean viewIsClickableButToSmall(View view)
{
minTouchableViewHeight = GlobalHelper.dipToDevicePixels(40);
minTouchableViewWidth = GlobalHelper.dipToDevicePixels(40);
return (view.getHeight() < minTouchableViewHeight || view.getWidth() < minTouchableViewWidth) && view.hasOnClickListeners();
}
public boolean ae_pointInView(float localX, float localY, float slopX, float slopY) {
boolean res = localX >= -slopX && localY >= -slopY && localX < ((getRight() - getLeft()) + slopX) &&
localY < ((getBottom() - getTop()) + slopY);
return res;
}
private float[] tempPoint;
public float[] ae_transformPointToViewLocal(float x, float y, View child) {
if(tempPoint == null) {
tempPoint = new float[2];
}
tempPoint[0] = x + getScrollX() - child.getLeft();
tempPoint[1] = y + getScrollY() - child.getTop();
return tempPoint;
}
答案 7 :(得分:-1)
也许你可以通过查看传递给MotionEvent的onTouchEvent的X和Y坐标来做到这一点?