Добавить кнопку в дескриптор SlidingDrawer? - PullRequest
9 голосов
/ 14 апреля 2011

Я работал над этим некоторое время. Идея началась просто, я хотел кнопку на ручке SlidingDrawer, чтобы позволить пользователю просматривать настройки, специфичные для содержимого ящика. Поэтому я сделал макет с кнопкой в ​​стороне и установил ее в качестве ручки. Ящик хорошо рисовал, но не позволял нажимать кнопку (на ручке). Всякий раз, когда я пытаюсь щелкнуть вещь, щелчок интерпретируется как щелчок ручки и переключает состояние ящика.

Кто-нибудь знает, что происходит?

Спасибо ~ Aedon

Ответы [ 4 ]

13 голосов
/ 08 декабря 2011

Я опубликую свою реализацию, чтобы избавить других от проблем.

В основном вам нужно расширить класс 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 просто используйте <my.package.name.ClickableSlidingDrawer> вместо <SlidingDrawer>

13 голосов
/ 22 марта 2012

Я опробовал реализацию d4n3, но так как мой дескриптор содержит кнопку, вложенную в несколько ViewGroup s, мне пришлось изменить ее, чтобы она работала.

Мои реализации также предполагают, что вы используете ViewGroup для дескриптора, но дочерние представления не должны быть кликабельными. Кроме того, вы должны установить tag на " click_intercepted " представлений, которые вы хотите, чтобы в дескрипторе было кликабельно. Только дочерние представления с этим конкретным набором тегов будут учитываться для кликов в дескрипторе. Таким образом, вы можете расположить свой дескриптор так, как вы хотите, и при этом действовать соответствующим образом при нажатии на определенные View s (например, 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;
    }
}
5 голосов
/ 15 апреля 2011

Вы можете подавить действие, которое интерпретирует щелчок на кнопке дескриптора как «открытый» с атрибутом в элементе SlidingDrawer в XML макета.Вот так:

<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" Затем просто реализуйте обработчик щелчка для кнопки, как вы это обычно делаете.Это остановит его от открытия / закрытия ящика, но вам может потребоваться перехватить события для кнопки, чтобы заставить ее делать то, что ВЫ хотите, чтобы она делала.

0 голосов
/ 20 июля 2013

Сначала создайте макет и поместите в него содержимое 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);

Надеюсь, это поможет вам.

...