【问题标题】:Scrolling a Gallery with buttons使用按钮滚动图库
【发布时间】:2011-11-14 20:42:26
【问题描述】:

我有一个画廊,它的适配器创建了几个 LinearLayout 实例。然而,那些线性布局实例有按钮,当有人点击按钮时,他们无法拖动图库。

我的想法是有一个用户可以滚动浏览的菜单。通常使用 ScrollView 可以完成的事情,但因为我希望滚动视图“捕捉”到当前按钮页面,所以画廊效果更好。

这个问题和这个问题类似: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>

填充图库的测试活动:

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。

【问题讨论】:

    标签: android button android-layout gallery android-linearlayout


    【解决方案1】:

    好的,我想我明白了,所以这里是为了以防将来有人遇到这种情况。

    我不太清楚触摸事件是如何在显示列表中传播的,所以这比我想承认的要多得多的试验和错误,但基本上:可以拦截父级上的触摸事件而不让它传播给孩子,基本上使按钮变得无用(允许用户单击并拖动它,而是将事件发送到父母的onTouchEvent)。这是通过onInterceptTouchEvent 方法完成的。

    所以我没有使用Gallery,而是对其进行了扩展(现在称之为ZGallery)。这足以使包含的按钮无用:

    @Override
    public boolean onInterceptTouchEvent(MotionEvent __e) {
        return true;
    }
    

    当然,我想确保按钮可以正常工作(它们是可点击的),同时还允许拖动。

    可能有一个更聪明的方法来做到这一点,但我所做的是拦截我的新画廊上的触摸事件(如上),但允许它通过(返回false)直到用户将“光标”移动给定阈值 - 然后我将其解释为拖动意图,开始正确拦截触摸事件。这会导致触摸事件被发送到我自己的画廊,按预期工作。

    您可以对其进行修改,使其也仅适用于垂直或水平拖动。

    无论如何,这是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 新手...如何在 Main Activity 中实现此代码?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 1970-01-01
    • 2020-07-30
    相关资源
    最近更新 更多