【问题标题】:Add button to a SlidingDrawer handle?将按钮添加到 SlidingDrawer 句柄?
【发布时间】:2011-04-14 16:50:48
【问题描述】:

我已经为此工作了一段时间。这个想法一开始很简单,我想要一个 SlidingDrawer 手柄上的按钮,以允许用户查看特定于抽屉内容的设置。所以我做了一个布局,旁边有一个按钮,并将其设置为手柄。抽屉画得很好,但不允许按下按钮(在把手上)。当我尝试点击该东西时,点击被解释为手柄点击,并切换抽屉的状态。

有人知道怎么回事吗?

谢谢~艾顿

【问题讨论】:

    标签: android onclick slidingdrawer


    【解决方案1】:

    我将发布我的实现,以免其他人麻烦。

    您基本上必须扩展 SlidingDrawer 类并处理 onInterceptTouch 事件,以便当它们位于句柄布局内的项目顶部时通过。

    这假设您使用 ViewGroup(例如任何布局)作为句柄,并且其中的所有视图都是可点击的。

    import android.content.Context;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.SlidingDrawer;
    
    public class ClickableSlidingDrawer extends SlidingDrawer {
    
        private ViewGroup mHandleLayout;
        private final Rect mHitRect = new Rect();
    
        public ClickableSlidingDrawer(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public ClickableSlidingDrawer(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
    
    
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
    
            View handle = getHandle();
    
            if (handle instanceof ViewGroup) {
                mHandleLayout = (ViewGroup) handle;
            }
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent event) {
            if (mHandleLayout != null) {
                int childCount = mHandleLayout.getChildCount();
                int handleClickX = (int)(event.getX() - mHandleLayout.getX());
                int handleClickY = (int)(event.getY() - mHandleLayout.getY());
    
                Rect hitRect = mHitRect;
    
                for (int i=0;i<childCount;i++) {
                    View childView = mHandleLayout.getChildAt(i);
                    childView.getHitRect(hitRect);
    
                    if (hitRect.contains(handleClickX, handleClickY)) {
                        return false;
                    }
                }
            }
    
            return super.onInterceptTouchEvent(event);
        }
    }
    

    然后,在您的布局 .xml 中,只需使用 &lt;my.package.name.ClickableSlidingDrawer&gt; 而不是 &lt;SlidingDrawer&gt;

    【讨论】:

    • 另外,如果你总是调用 super.onInterceptTouchEvent,它不会阻塞按钮上的拖动事件。
    【解决方案2】:

    我尝试了 d4n3 的实现,但由于我的句柄包含一个嵌套在多个 ViewGroups 中的按钮,我不得不对其进行修改以使其工作。

    我的实现还假设您使用ViewGroup 作为句柄,但子视图不必是可点击的。此外,您必须将要在句柄中单击的视图的 tag 设置为“click_intercepted”。只有具有此特定标签集的子视图才会考虑在句柄内进行点击。这样,您可以根据需要对句柄进行布局,并且仍然可以在单击句柄中特定的Views(例如Button)时采取适当的行动。此外,通过此实现,您仍然可以拖动和单击句柄来切换其状态。

    import android.content.Context;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.SlidingDrawer;
    
    public class ClickableSlidingDrawer extends SlidingDrawer
    {
        private static final String TAG_CLICK_INTERCEPTED = "click_intercepted";
    
        private ViewGroup mHandleLayout;
        private final Rect mHitRect = new Rect();
    
        public ClickableSlidingDrawer(Context context, AttributeSet attrs)
        {
            super(context, attrs);
        }
    
        public ClickableSlidingDrawer(Context context, AttributeSet attrs, int defStyle)
        {
            super(context, attrs, defStyle);
        }
    
        @Override
        protected void onFinishInflate()
        {
            super.onFinishInflate();
    
            View handle = getHandle();
    
            if (handle instanceof ViewGroup)
            {
                mHandleLayout = (ViewGroup) handle;
            }
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent event)
        {
            if (mHandleLayout != null)
            {
                int clickX = (int) (event.getX() - mHandleLayout.getLeft());
                int clickY = (int) (event.getY() - mHandleLayout.getTop());
    
                if (isAnyClickableChildHit(mHandleLayout, clickX, clickY))
                {
                    return false;
                }
            }
            return super.onInterceptTouchEvent(event);
        }
    
        private boolean isAnyClickableChildHit(ViewGroup viewGroup, int clickX, int clickY)
        {
            for (int i = 0; i < viewGroup.getChildCount(); i++)
            {
                View childView = viewGroup.getChildAt(i);
    
                if (TAG_CLICK_INTERCEPTED.equals(childView.getTag()))
                {
                    childView.getHitRect(mHitRect);
    
                    if (mHitRect.contains(clickX, clickY))
                    {
                        return true;
                    }
                }
    
                if (childView instanceof ViewGroup && isAnyClickableChildHit((ViewGroup) childView, clickX, clickY))
                {
                    return true;
                }
            }
            return false;
        }
    }
    

    【讨论】:

    • 稍作改动,这完全符合我的要求……只是一个问题……当我点击“手柄”空间拖动滑块时,所有孩子都进入“按下”状态.你知道解决这个问题的方法吗?我唯一的猜测是对孩子使用 dupilicataParentState="false" 但这似乎不是解决方案。有什么想法吗?
    • 我给你们两个都投了赞成票,但你的实现是最好的。
    • 对我来说,int clickX = (int) (mHandleLayout.getRight() - event.getX());似乎有效,而不是上面的那个。
    【解决方案3】:

    您可以使用布局 XML 中的 SlidingDrawer 元素中的属性抑制将手柄按钮上的单击解释为“打开”的操作。像这样:

    <SlidingDrawer android:layout_width="fill_parent"android:id="@+id/SlidingDrawer" android:handle="@+id/slideHandleButton"
                        android:content="@+id/txtHolder" android:layout_height="fill_parent"
                        android:orientation="horizontal" android:allowSingleTap="false">
    

    只需创建android:allowSingleTap="false" 然后像往常一样为按钮实现一个点击处理程序。这将阻止它打开/关闭抽屉,但您可能需要拦截按钮的事件以使其执行您希望它执行的操作。

    【讨论】:

    • 感谢您的意见,我会试一试。
    • 谢谢您,先生,经过一番修改,它完美无缺。我想你刚刚给我上了一课,我真的应该早点学习。 :)
    • @AedonEtLIRA 你能给我一个示例代码吗?我正在尝试同样的事情,但它不会工作。我通过实现我的句柄内的按钮的onClickListener 来拦截 onClickEvent。但是该事件不会被触发。你能告诉我为什么吗?
    • @Aki - 您是否检查以确保点击在按钮的范围内?您必须获得按钮的命中矩形,然后检查拦截的触摸是否在边界内。如果是这样:手动关闭按钮onClick(View) 方法。希望有帮助,如果不是我还在这里:)
    • @AedonEtLIRA 我在Button 本身上实现了onClickListener。那行不通吗?而且,为什么我需要确保点击是在按钮的范围内,它的按钮的 onClickListener 正在被触发,这不意味着点击是在按钮的范围内吗?
    【解决方案4】:

    首先制作一个布局并将您的 Handle 内容放入其中(假设您放入了 handle_content.xml)。

    第二次用这个替换你当前的句柄handle:

    <include android:id="@id/handle" 
    android:layout="@layout/handle_content.xml"/>
    

    现在按如下操作(我之所以这样说是因为如果您按照上述操作,则以下工作正常)

    这是我的实现:

    package com.examples.my.views;
    
    import android.content.Context;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.SlidingDrawer;
    
    import com.examples.my.MainFragmentActivity;
    
    public class MYSlidingDrawer extends SlidingDrawer {
    
        private View button;
        private int height;
        private MainFragmentActivity activity;
    
        public MYSlidingDrawer (Context context, AttributeSet attrs) {
            super(context, attrs);
            DisplayMetrics metrics = this.getResources().getDisplayMetrics();
            height = metrics.heightPixels;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // TODO Auto-generated method stub
            int left = button.getLeft();
            int top = button.getTop();
            int right = button.getRight();
            int bottom = button.getBottom();
            Rect rect = new Rect(left, top, right, bottom);
            int x = (int) event.getX();
            int y = (int) event.getY();
            if (isOpened()) {
                if (rect.contains(x, y)) {
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        if (activity != null)
                            {
                             //HERE DO YOUR WORK
                             // Like activity.tooglePlay();
                            }
    
                    }
                    return true;
                }
            } else {
                y -= height;
                if (rect.contains(x, Math.abs(y))) {
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        if (activity != null)
                             {
                              //HERE DO YOUR WORK
                              // Like activity.tooglePlay();
                              }
                    }
                    return true;
                }
            }
            return super.onTouchEvent(event);
        }
    
        public void setButton(View button) {
            this.button = button;
        }
    
        public void setActivity(MainFragmentActivity activity) {
            this.activity = activity;
        }
    
    }
    

    现在定义它,其中包含 MYSlidingDrawer:

            MYSlidingDrawer drawer = (MYSlidingDrawer) findViewById(R.id.drawer);
            drawer.setActivity(this);
            Button btn = (Button) findViewById(R.id.play_btn);//button inside your handle
            drawer.setButton(btn);
    

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-19
      • 1970-01-01
      • 2017-04-14
      • 1970-01-01
      • 2011-08-28
      • 2018-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多