SeniorUI25_自定义DrawerLayout设置背景和item动画效果

SeniorUI_高级UI汇总目录

一 自定义DrawerLayout设置背景和item动画效果

1 效果图

在这里插入图片描述

2 原理

  1. 自定义MyDrawSlideBar继承LinearLayout作为侧拉栏
  2. 自定义MyDrawerLayout从而获取对应的侧拉栏SlideBar,偷梁换柱:移除SlideBar添加一个自定义的RelativeLayout,再将一个要显示的背景View和SlideBar添加到RelativeLayout中去
  3. 背景View通过MyDrawerLayout获取移动要素,绘制背景(贝塞尔曲线),当设置背景为图片时,使用paint的Shader实现
  4. MyDrawSlideBar获取移动要素,计算出每个child的平移距离,实现动画效果

3 主要代码

MyDrawerLayout

public class MyDrawerLayout extends DrawerLayout  implements DrawerLayout.DrawerListener {
    //背景 自定义控件
    private MyDrawBgRealativeLayout myDrawBgRealativeLayout;

    //含有 布局内容的 Linealayout自定义控件
    private MyDrawSlideBar myDrawSlideBar;
    private  float y;

    private float slideOffset;
    //内容区域
    private  View contenView;
    public MyDrawerLayout(Context context) {
        super(context);
    }

    public MyDrawerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        initChild();

    }

    private void initChild() {
        for(int i=0;i<getChildCount();i++) {
            View view = getChildAt(i);
            if (view instanceof MyDrawSlideBar) {
                myDrawSlideBar= (MyDrawSlideBar) view;
                break;
            }else {
                contenView=view;
            }
        }
        //移除子控件   因为不符合我们的需求
        removeView(myDrawSlideBar);
        myDrawBgRealativeLayout = new MyDrawBgRealativeLayout(myDrawSlideBar);
        addView(myDrawBgRealativeLayout);
        addDrawerListener(this);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        if (ev.getAction() == MotionEvent.ACTION_UP) {
            closeDrawers();
            myDrawBgRealativeLayout.onMotionEventUp();
            return super.dispatchTouchEvent(ev);
        }
        y=ev.getY();

        if (slideOffset < 1) {
            super.dispatchTouchEvent(ev);
        }else if(ev.getAction() == MotionEvent.ACTION_MOVE) {
            //当大于1时   内容区域不做偏移  只是把背景贝塞尔曲线进行变化  拦截后  DrawerLayout.DrawerListener 不再起作用  因为内容不做偏移
            myDrawBgRealativeLayout.setTouch(y,slideOffset);
        }
        return true;
    }

    @Override
    public void onDrawerSlide(View drawerView, float slideOffset) {
        this.slideOffset = slideOffset;
        myDrawBgRealativeLayout.setTouch(y,slideOffset);
        float contentViewoffset=drawerView.getWidth()*slideOffset/2;
        contenView.setTranslationX(contentViewoffset);
    }

    @Override
    public void onDrawerOpened(View drawerView) {

    }

    @Override
    public void onDrawerClosed(View drawerView) {

    }

    @Override
    public void onDrawerStateChanged(int newState) {

    }

}

MyDrawBgRealativeLayout

public class MyDrawBgRealativeLayout extends RelativeLayout {

    private MyDrawSlideBar myDrawSlideBar;
    private MyDrawBgView myDrawBgView;


    public MyDrawBgRealativeLayout(MyDrawSlideBar myDrawSlideBar) {
        super(myDrawSlideBar.getContext() );
        init(myDrawSlideBar);
    }

    private void init(MyDrawSlideBar myDrawSlideBar) {
        //转移宽高属性
        setLayoutParams(myDrawSlideBar.getLayoutParams());
        int parentLayoutGravity = ((DrawerLayout.LayoutParams) getLayoutParams()).gravity;

        this.myDrawSlideBar=myDrawSlideBar;

        //子控件 是否居中
        myDrawBgView = new MyDrawBgView(getContext());
        addView( myDrawBgView, 0, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        //添加滑动内容区域
        myDrawBgView.setColor(myDrawSlideBar.getBackground());
        myDrawSlideBar.setBackgroundColor(Color.TRANSPARENT);
        addView(myDrawSlideBar, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    }


    public void setTouch(float y, float offset) {
        //背景做贝塞尔曲线
        myDrawBgView.setTouchY(y,offset);
        myDrawSlideBar.setTouchY(y,offset);
    }

    public void onMotionEventUp() {
        myDrawSlideBar.onMotionEventUp();
    }
}

MyDrawBgRealativeLayout

public class MyDrawBgRealativeLayout extends RelativeLayout {

    private MyDrawSlideBar myDrawSlideBar;
    private MyDrawBgView myDrawBgView;


    public MyDrawBgRealativeLayout(MyDrawSlideBar myDrawSlideBar) {
        super(myDrawSlideBar.getContext() );
        init(myDrawSlideBar);
    }

    private void init(MyDrawSlideBar myDrawSlideBar) {
        //转移宽高属性
        setLayoutParams(myDrawSlideBar.getLayoutParams());
        int parentLayoutGravity = ((DrawerLayout.LayoutParams) getLayoutParams()).gravity;

        this.myDrawSlideBar=myDrawSlideBar;

        //子控件 是否居中
        myDrawBgView = new MyDrawBgView(getContext());
        addView( myDrawBgView, 0, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        //添加滑动内容区域
        myDrawBgView.setColor(myDrawSlideBar.getBackground());
        myDrawSlideBar.setBackgroundColor(Color.TRANSPARENT);
        addView(myDrawSlideBar, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    }


    public void setTouch(float y, float offset) {
        //背景做贝塞尔曲线
        myDrawBgView.setTouchY(y,offset);
        myDrawSlideBar.setTouchY(y,offset);
    }

    public void onMotionEventUp() {
        myDrawSlideBar.onMotionEventUp();
    }
}

MyDrawBgView

public class MyDrawBgView extends View {

    private Paint paint;
    private Path path;
    private BitmapDrawable drawable;
    public MyDrawBgView(Context context) {
        this(context,null);
    }

    public MyDrawBgView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setAntiAlias(true);
        path = new Path();
    }


    public void setTouchY(float y, float percent) {
        path.reset();
        float width=getWidth()*percent;
        float height=getHeight();
        float firstPointX=width/2;
        float offsetY=height/8;
        path.lineTo(firstPointX,-offsetY);
        path.quadTo(width * 3 / 2, y, firstPointX, height + offsetY);
        path.lineTo(0, height);
        path.close();
        path.offset(getWidth() - width, 0);
        invalidate();
    }


    @Override
    protected void onDraw(Canvas canvas) {
         //完成图片的绘制
        if (drawable != null) {
            Bitmap bitmap=drawable.getBitmap();
            Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            paint.setShader(shader);
        }
        paint.setStyle(Paint.Style.FILL);
        canvas.drawPath(path,paint);
    }

    public void setColor(Drawable color) {
        if (color instanceof ColorDrawable) {
            ColorDrawable colorDrawable= (ColorDrawable) color;
            paint.setColor(colorDrawable.getColor());
        } else if (color instanceof BitmapDrawable) {
            this.drawable= (BitmapDrawable) color;
        }
    }

}

4 Demo

DrawerLayoutActivity

二 设置响应触摸区域

1 效果图

在这里插入图片描述## 2 需求
当使用DrawerLayout实现侧拉栏效果时,经常发现手势的识别如左滑,响应效果不理想,特别是华为手机系统带左滑退出当前页面时;需要扩大滑动的识别区域

3 实现

  public static void setDrawerLeftEdgeSize(Activity activity, DrawerLayout drawerLayout, float displayWidthPercentage) {
        if (activity == null || drawerLayout == null) return;
        try {
            Field leftDraggerField = drawerLayout.getClass().getDeclaredField("mLeftDragger");
            leftDraggerField.setAccessible(true);
            ViewDragHelper leftDragger = (ViewDragHelper) leftDraggerField.get(drawerLayout);
            Field edgeSizeField = leftDragger.getClass().getDeclaredField("mEdgeSize");
            edgeSizeField.setAccessible(true);
            int edgeSize = edgeSizeField.getInt(leftDragger);
            DisplayMetrics dm = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
            edgeSizeField.setInt(leftDragger, Math.max(edgeSize, (int) (dm.widthPixels * displayWidthPercentage)));
        } catch (Exception e) {
        }
    }

4 Demo

DrawerLayoutActivity

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值