我有一个 Gallery,其 Adapter 创建了多个 LinearLayout 实例。然而,那些线性布局实例有按钮,当有人点击按钮时,他们不能拖动画廊。
我的想法是拥有一个用户可以滚动浏览的菜单。这种事情通常会用 ScrollView 完成,但因为我希望 ScrollView “捕捉”到当前按钮页面,所以 Gallery 效果更好。
这个问题与这个问题类似:Android gallery of LinearLayouts
但是,虽然我已经解决了拖动问题时“按钮显示为已单击”的问题,但我似乎无法通过将按钮作为拖动区域的一部分来使其像 ScrollView 那样工作。
有什么提示吗?
不确定代码是否相关,但在这里。
包含图库的布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Gallery
android:id="@+id/gallery"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:fadingEdge="none"
android:spacing="0dp"/>
</FrameLayout>
填充图库的测试 Activity :
import com.zehfernando.display.widgets.ZGallery;
public class ScrollTestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scrolltest);
Gallery gallery = (Gallery) findViewById(R.id.gallery);
gallery.setAdapter(new LayoutAdapter(this));
}
public class LayoutAdapter extends BaseAdapter {
private Context mContext;
public LayoutAdapter(Context c) {
mContext = c;
}
public int getCount() {
return 3;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater vi = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = vi.inflate(R.layout.scrolllayout, null);
v.setMinimumWidth(getWindowManager().getDefaultDisplay().getWidth());
return v;
}
}
}
画廊内部框架的布局:
<?xml version="1.0" encoding="utf-8"?>
<com.zehfernando.display.widgets.ScrollableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/buttonRegister"
android:layout_width="200dp"
android:layout_height="72dp"
android:text="REGISTER"/>
<Button
android:id="@+id/buttonUnregister"
android:layout_width="match_parent"
android:layout_height="72dp"
android:text="UNREGISTER" />
</com.zehfernando.display.widgets.ScrollableLinearLayout>
“ScrollableLinearLayout”只是我扩展 LinearLayout 以覆盖 onPressed 的类。
最佳答案
好的,我想我明白了,所以把它放在这里以防将来有人遇到这个问题。
我不太清楚触摸事件是如何在显示列表中传播的,所以这比我承认的要多得多,但基本上:可以拦截父级上的触摸事件而不让它传播给 child ,基本上使按钮变得无用(允许用户单击并拖动它,而是将事件发送到 parent 的 onTouchEvent
)。这是通过 onInterceptTouchEvent
方法完成的。
因此,我没有使用 Gallery
,而是对其进行了扩展(暂时将其称为 ZGallery
)。这足以使包含的按钮无用:
@Override
public boolean onInterceptTouchEvent(MotionEvent __e) {
return true;
}
但当然,我想确保按钮有效(它们是可点击的),同时还允许拖动。
可能有更聪明的方法来做到这一点,但我所做的是在我的新图库(如上)上拦截触摸事件,但允许它通过(返回 false
) 直到用户将“光标”移动了给定的阈值 - 然后我将其解释为拖动 Intent ,开始正确拦截触摸事件。这会导致触摸事件发送到我自己的画廊,按预期工作。
您可以对其进行修改,使其也仅适用于垂直或水平拖动。
所以无论如何,这是一个简化版本的 Gallery
类,允许在其中拖动任何元素:
public class ZGallery extends Gallery {
// Constants
protected static final float DRAG_THRESHOLD = 10; // If dragging for more than this amount of pixels, means it's a scroll
// Properties
protected boolean isPressed;
protected float startPressX;
protected float startPressY;
protected boolean isDragging;
// ================================================================================================================
// CONSTRUCTOR ----------------------------------------------------------------------------------------------------
public ZGallery(Context context) {
this(context, null);
}
public ZGallery(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.galleryStyle);
}
public ZGallery(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
// ================================================================================================================
// EVENT INTERFACE ------------------------------------------------------------------------------------------------
@Override
public boolean onInterceptTouchEvent(MotionEvent __e) {
// Intercepts all touch screen motion events. This allows you to watch events as they are dispatched to your children, and take ownership of the current gesture at any point.
// Return true to steal motion events from the children and have them dispatched to this ViewGroup through onTouchEvent().
// The current target will receive an ACTION_CANCEL event, and no further messages will be delivered here.
//return super.onInterceptTouchEvent(__e); // super always returns false
// If this function returns TRUE, NO children get dragging events. This only happens
// the first interception (mouse down); if true is returned, nothing is intercepted anymore, and
// events are passed to onTouchEvent directly.
// If FALSE is returned, this may be called again, but only if there's a children receiving the
// events instead of this.
// In sum, once onTouchEvent is called here, onInterceptTouchEvent is not called anymore.
// Interprets drag data
return evaluateTouchEvent(__e);
}
@Override
public boolean onTouchEvent(MotionEvent __e) {
// Interprets drag data
evaluateTouchEvent(__e);
// Properly lets superclass interpret touch events (for dragging, fling, etc)
return super.onTouchEvent(__e);
}
protected boolean evaluateTouchEvent(MotionEvent __e) {
// Interprets motion to see if the user is dragging the View
// This will run in parallel with the children events
float dragDeltaX;
float dragDeltaY;
switch (__e.getAction()) {
case MotionEvent.ACTION_DOWN:
// Pressing...
isPressed = true;
startPressX = __e.getX();
startPressY = __e.getY();
break;
case MotionEvent.ACTION_MOVE:
// Moving...
if (isPressed && !isDragging) {
dragDeltaX = __e.getX() - startPressX;
dragDeltaY = __e.getY() - startPressY;
if (Math.abs(dragDeltaX) > DRAG_THRESHOLD || Math.abs(dragDeltaY) > DRAG_THRESHOLD) {
// Moved too far, means it's dragging!
// Inject click from correct position so superclass code knows where to drag from
MotionEvent me = MotionEvent.obtain(__e);
me.setAction(MotionEvent.ACTION_DOWN);
me.setLocation(__e.getX() - dragDeltaX, __e.getY() - dragDeltaY);
super.onTouchEvent(me);
isDragging = true;
}
}
break;
case MotionEvent.ACTION_UP:
// Releasing...
if (isPressed) {
isPressed = false;
// Let go while pressed
if (isDragging) {
// Was dragging, so just go back
isDragging = false;
} else {
// Was not dragging, this will trigger a click
}
}
break;
}
// If not dragging, event should be passed on
// If dragging, the event should be intercepted and interpreted by this gallery's onTouchEvent instead
return isDragging;
}
}
看起来效果不错。希望它会对其他人有所帮助!
关于android - 使用按钮滚动图库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8127828/