Android 带recycleview的左滑动布局

Android 带recycleview的左滑动布局,android,android-recyclerview,Android,Android Recyclerview,我正试图使这个布局,正确的部分(黄色)必须始终是可访问的。我尝试使用抽屉布局,但没有找到移除scim的方法。scim块位于右侧部分 我本来打算使用de-SlidingPanelLayout,但它已被弃用。所以我创建了自己的布局 public class LeftSlidingLayout extends FrameLayout { private static final int LEFT = 0; private static final int RIGHT = 1;

我正试图使这个布局,正确的部分(黄色)必须始终是可访问的。我尝试使用抽屉布局,但没有找到移除scim的方法。scim块位于右侧部分

我本来打算使用de-SlidingPanelLayout,但它已被弃用。所以我创建了自己的布局

    public class LeftSlidingLayout extends FrameLayout
{
    private static final int LEFT = 0;
    private static final int RIGHT = 1;

    private static final int DEFAULT_ALWAYS_SWIPEABLE_WIDTH = 35;
    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;
    private static final int MAX_ANIMATION_DURATION = 500;
    public static final int EXCLUSION_ZONE_HEIGHT = 100;

    private int _alwaysSwipeableWidth;
    private int _xDelta;
    private int _xDown;
    private Rect _bottomExlusionSwipeableZone;

    public LeftSlidingLayout(final Context context)
    {
        this(context, null);
    }

    public LeftSlidingLayout(final Context context, final AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public LeftSlidingLayout(final Context context, final AttributeSet attrs, final int defStyleAttr)
    {
        this(context, attrs, defStyleAttr, 0);
    }

    public LeftSlidingLayout(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes)
    {
        super(context, attrs, defStyleAttr, defStyleRes);
        final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.LeftSlidingLayout);
        setAlwaysSwipeableWidth(attributes.getDimensionPixelOffset(R.styleable.LeftSlidingLayout_always_swipeable_width, DEFAULT_ALWAYS_SWIPEABLE_WIDTH));
        attributes.recycle();
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
    {
        final int adjustedWidth = widthMeasureSpec + getAlwaysSwipeableWidth();
        super.onMeasure(adjustedWidth, heightMeasureSpec);
    }

    private Rect getBottomExlusionSwipeableZone()
    {
        return new Rect(getWidth() - getAlwaysSwipeableWidth(),
                        getHeight() - EXCLUSION_ZONE_HEIGHT,
                        getWidth(),
                        getHeight());
    }

    public void setAlwaysSwipeableWidth(final int alwaysSwipeableWidth)
    {
        _alwaysSwipeableWidth = alwaysSwipeableWidth;
        setPadding(getPaddingLeft(),
                   getPaddingTop(),
                   getPaddingRight() + _alwaysSwipeableWidth,
                   getPaddingBottom());
    }

    public int getAlwaysSwipeableWidth()
    {
        return _alwaysSwipeableWidth;
    }

    @Override
    public boolean onTouchEvent(final MotionEvent event)
    {
        if(isNotSwipeable(event))
            return false;

        final int X = (int) event.getRawX();
        final long duration = event.getEventTime() - event.getDownTime();
        switch(event.getAction() & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:
                final ViewGroup.MarginLayoutParams lParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
                _xDelta = X - lParams.leftMargin;
                _xDown = X;
                break;
            case MotionEvent.ACTION_UP:
                animateAdjustment(_xDown - X, duration);
                break;
            case MotionEvent.ACTION_MOVE:
                slideLeft(formatWithingBound(X - _xDelta, -getWidth() + getAlwaysSwipeableWidth(), 0));
                break;
            default:
                //Do nothing
        }
        ((View) getParent()).invalidate();

        return true;
    }

    private boolean isNotSwipeable(final MotionEvent event)
    {
        return !isOpen() && getBottomExlusionSwipeableZone().contains((int) event.getX(), (int) event.getY());
    }

    private void animateAdjustment(final int swipedPixelDistance, final float durationInMs)
    {
        final float velocityInMsX = swipedPixelDistance / durationInMs;

        if(velocityInMsX == 0 || swipedPixelDistance == 0)
            return;

        final int direction;
        if(Math.abs(swipedPixelDistance) > SWIPE_THRESHOLD && Math.abs(velocityInMsX) > SWIPE_VELOCITY_THRESHOLD)
        {
            direction = swipedPixelDistance < 0 ? LEFT : RIGHT;
        }
        else
        {
            direction = swipedPixelDistance < 0 ? RIGHT : LEFT;
        }

        animateCurrentView(direction == LEFT ? -getWidth() + getAlwaysSwipeableWidth() : 0, velocityInMsX);
    }

    private void animateCurrentView(final int endMargin, final float speed)
    {
        final ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();

        final int startMargin = layoutParams.leftMargin;
        final Animation animation = new Animation()
        {

            @Override
            protected void applyTransformation(final float interpolatedTime, final Transformation transformation)
            {
                slideLeft(startMargin + (int) ((endMargin - startMargin) * interpolatedTime));
            }
        };
        final long duration = calculateDuration(startMargin, endMargin, speed);
        animation.setDuration(Math.min(duration, MAX_ANIMATION_DURATION));
        startAnimation(animation);
    }

    private void slideLeft(final int leftMargin)
    {
        final ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
        layoutParams.leftMargin = leftMargin;
        setLayoutParams(layoutParams);
    }

    private long calculateDuration(final int startMargin, final int endMargin, final float speed)
    {
        return Math.abs((long) ((endMargin - startMargin) / speed));
    }

    private int formatWithingBound(final int valueToFormat, final int minBound, final int maxBound)
    {
        return Math.max(Math.min(valueToFormat, maxBound), minBound);
    }

    public void open()
    {
        animateCurrentView(0, 1);
    }

    public void closes()
    {
        animateCurrentView(-getWidth() + getAlwaysSwipeableWidth(), 1);
    }

    public boolean isOpen()
    {
        final ViewGroup.MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams();
        return layoutParams.leftMargin == 0;
    }

    public interface SlidingListener
    {
        void onLeftMarginChanged(final int leftMargin);
    }
}
公共类LeftSlidingLayout扩展了FrameLayout
{
私有静态final int LEFT=0;
私有静态final int RIGHT=1;
私有静态最终整数默认值总是可开关宽度=35;
专用静态最终整数滑动\u阈值=100;
专用静态最终整数滑动速度阈值=100;
私有静态最终int MAX_ANIMATION_DURATION=500;
公共静态最终内部隔离区高度=100;
私有int_始终可擦除宽度;
私人国际电信公司;
私人内部网络;
私有矩形底部ExlusionsWipeTableZone;
公共左滑块布局(最终上下文)
{
这个(上下文,空);
}
公共LeftSlidingLayout(最终上下文,最终属性集属性)
{
这(上下文,属性,0);
}
公共LeftSlidingLayout(最终上下文上下文、最终属性集属性、最终int defStyleAttr)
{
这(context,attrs,defStyleAttr,0);
}
公共LeftSlidingLayout(最终上下文上下文、最终属性集属性、最终整型defStyleAttr、最终整型defStyleRes)
{
super(context、attrs、defStyleAttr、defStyleRes);
最终类型Darray attributes=context.actainStyledAttributes(attrs,R.styleable.LeftSlidingLayout);
setAlwaysSwipeableWidth(attributes.getDimensionPixelOffset(R.styleable.LeftSlidingLayout_always_swipeable_width,默认值_always_swipeable_width));
attributes.recycle();
}
@凌驾
测量时的保护空隙(最终内部宽度测量等级、最终内部高度测量等级)
{
最终整数调整宽度=宽度测量等级+getAlwaysSwipeableWidth();
超级测量(调整宽度、高度测量值);
}
private Rect GetBottomExlusionsWipeTableZone()的
{
返回新的Rect(getWidth()-getAlwaysSwipeableWidth(),
getHeight()-排除区高度,
getWidth(),
getHeight());
}
公共无效设置alwaysSwipeableWidth(最终整数alwaysSwipeableWidth)
{
_alwaysSwipeableWidth=alwaysSwipeableWidth;
setPadding(getPaddingLeft(),
getPaddingTop(),
getPaddingRight(),
getPaddingBottom());
}
public int getAlwaysSwipeableWidth()
{
返回_alwaysSwipeableWidth;
}
@凌驾
公共布尔onTouchEvent(最终运动事件)
{
如果(不可切换(事件))
返回false;
final int X=(int)event.getRawX();
最终长持续时间=event.getEventTime()-event.getDownTime();
开关(event.getAction()&MotionEvent.ACTION\u掩码)
{
case MotionEvent.ACTION\u DOWN:
final ViewGroup.MarginLayoutParams lParams=(ViewGroup.MarginLayoutParams)getLayoutParams();
_xDelta=X-lParams.leftMargin;
_xDown=X;
打破
case MotionEvent.ACTION\u UP:
动画调整(xDown-X,持续时间);
打破
case MotionEvent.ACTION\u移动:
slideLeft(formatWithingBound(X-xDelta,-getWidth()+getAlwaysSwipeableWidth(),0));
打破
违约:
//无所事事
}
((视图)getParent()).invalidate();
返回true;
}
私有布尔值不可切换(最终MotionEvent事件)
{
return!isOpen()和&getbottomexlusionswipablezone()。包含((int)event.getX(),(int)event.getY());
}
私有void动画调整(最终整数旋转像素距离、最终浮点持续时间)
{
最终浮点速度InMsx=swipedPixelDistance/durationInMs;
if(VelocityInIMSx==0 | | swipedPixelDistance==0)
返回;
最终整数方向;
if(Math.abs(swipedPixelDistance)>滑动阈值和&Math.abs(velocityInMsX)>滑动速度阈值)
{
方向=旋转像素距离<0?左:右;
}
其他的
{
方向=旋转像素距离<0?右:左;
}
animateCurrentView(方向==左?-getWidth()+GetAlwaysWipeableWidth():0,速度inMsx);
}
私有void animateCurrentView(最终的int-endMargin,最终的浮点速度)
{
final ViewGroup.MarginLayoutParams layoutParams=(ViewGroup.MarginLayoutParams)getLayoutParams();
final int startMargin=布局参数leftMargin;
最终动画=新动画()
{
@凌驾
受保护的无效应用转换(最终浮点插值时间,最终转换)
{
slidelft(startMargin+(int)((endMargin-startMargin)*插值时间);
}
};
最终长持续时间=计算(起始边缘、结束边缘、速度);
setDuration(Math.min(duration,MAX_animation_duration));
startAnimation(动画);
}
私有void slideLeft(最终整型左边距)
{
final ViewGroup.MarginLayoutParams layoutParams=(ViewGroup.MarginLayoutParams)getLayoutParams();
layoutParams.leftMargin=leftMargin;
setLayoutParams(layoutParams);
}
专用长计算(最终整数起始边距、最终整数结束边距、最终浮点速度)
{
返回数学值abs((长)((endMargin-startMargin)/速度);
}
私有int-formatWithingBound(最终int-valueToFormat、最终int-minBound、最终int-maxBound)
{
返回Math.max(Math.min(valueToFormat,maxBound),minBound);
}
公开作废
{
动画片
@Override
public void computeScroll()
{
    super.computeScroll();
    if(!_hasScrim)
    {
        try
        {
            overrideScrimOpacity();
        }
        catch(final ReflectionException ignore)
        {}
    }
}

protected void overrideScrimOpacity() throws ReflectionException
{
    try
    {
        FieldUtils.writeField(this, "mScrimOpacity", 0, true);
    }
    catch(final IllegalAccessException | IllegalArgumentException e)
    {
        throw new ReflectionException();
    }
}