您当前的位置: 首页 >  android
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Android自定义侧滑菜单选项

沙漠一只雕得儿得儿 发布时间:2020-04-25 16:05:31 ,浏览量:0

看下整体实现效果,侧边滑出一个菜单选项。

完整代码详见

首先,我们需要实现从右边滑出菜单选项的背景色,利用二阶贝塞尔曲线即可实现:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

public class MenuBgView extends View {

    Paint paint;
    Path path;

    public MenuBgView(Context context) {
        this(context, null);
    }

    public MenuBgView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MenuBgView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }


    private void init() {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.BLUE);
        path = new Path();
    }

    public void setTouchY(float y, float percent) {
        path.reset();

        float width = getWidth() * percent;

        float offsetY = getHeight() / 9;
        float beginX = 0;
        float beginY = -offsetY;

        float endX = 0;
        float endY = getHeight() + offsetY;

        float controllX = width * 3 / 2;
        float controllY = y;

        path.lineTo(beginX, beginY);
        path.quadTo(controllX, controllY, endX, endY);

        path.close();
        invalidate();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(path, paint);
    }

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

在MainActivity中使用:

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.MotionEvent;

public class MainActivity extends AppCompatActivity {

    MenuBgView menuBgView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);

        menuBgView = new MenuBgView(this);
        setContentView(menuBgView);

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {

        menuBgView.setTouchY(event.getY(),0.8f);

        return super.onTouchEvent(event);

    }
}

完成后效果如图,这个就是我们菜单栏的背景view。

下面完成菜单view里面的文字内容的view,这里叫MenuContentLayout:

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

public class MenuContentLayout extends LinearLayout {

    private float maxTranslationX;

    public MenuContentLayout(Context context) {
        this(context, null);
    }

    public MenuContentLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MenuContentLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        setOrientation(VERTICAL);
        if (attrs != null) {
            TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.SideBar);
            maxTranslationX = array.getDimension(R.styleable.SideBar_maxTranslationX, 0);
            array.recycle();
        }
    }

    public void setTouchY(float y, float slideOffset) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            apply(child, y, slideOffset);
        }
    }

    private void apply(View child, float y, float slideOffset) {

        float translationX = 0;

        int centerY = child.getTop() + child.getHeight() / 2;
        float distance = Math.abs(y - centerY);
        float scale = distance / getHeight() * 3;
        translationX = maxTranslationX - scale * maxTranslationX;
        child.setTranslationX(translationX);

    }

}

上面这个view也很简单,就是遍历整个MenuContentLayout里面的子view,拿出来一个一个动态的设置他们的位置,这里主要是如何根据手指的上下移动,来确定和哪个内容子view最近,从而将该子view重新设置它的横轴位置,达到动态的左右移动。

下面这个MenuPutLayout就是将上面两个自定义view进行整合的layout,负责传递onTouchEvent事件,以及设置两个子view:

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.widget.RelativeLayout;

public class MenuPutLayout extends RelativeLayout {

    MenuContentLayout contentLayout;
    MenuBgView bgView;

    public MenuPutLayout(MenuContentLayout contentLayout) {
        this(contentLayout.getContext());
        init(contentLayout);
    }

    public MenuPutLayout(Context context) {
        this(context, null);
    }

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

    public MenuPutLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init(MenuContentLayout contentLayout) {
        this.contentLayout = contentLayout;
        //把content的   宽高转移到外面RelatiLayout
        setLayoutParams(contentLayout.getLayoutParams());

        //背景先添加进去
        bgView = new MenuBgView(getContext());
        bgView.setColor(contentLayout.getBackground());
        addView(bgView, 0, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

        //把contentView  的背景颜色取出来    设置给 bgView   把contentView弄成透明
        contentLayout.setBackgroundColor(Color.TRANSPARENT);
        addView(contentLayout, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    }

    /**
     * 传递偏移Y
     * @param y
     * @param slideOffset
     */
    public void setTouchY(float y, float slideOffset) {
        bgView.setTouchY(y,slideOffset);
        contentLayout.setTouchY(y, slideOffset);
    }
}

最后就是MenuDrawerLayout,这里利用DrawerLayout的滑动回调的参数,往MenuPutLayout中传递参数:

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;

public class MenuDrawerLayout extends DrawerLayout implements DrawerLayout.DrawerListener {

    private MenuContentLayout menuContentLayout;
    private View contentView;
    private MenuPutLayout menuPutLayout;
    private float y;
    private float slideOffset;

    public MenuDrawerLayout(@NonNull Context context) {
        super(context);
    }

    public MenuDrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MenuDrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init();
    }

    private void init() {
        for (int i = 0; i < getChildCount(); i++) {
            View view = getChildAt(i);
            if (view instanceof MenuContentLayout) {
                menuContentLayout = (MenuContentLayout) view;
            } else {
                contentView = view;
            }
        }
        removeView(menuContentLayout);
        menuPutLayout = new MenuPutLayout(menuContentLayout);
        addView(menuPutLayout);
        addDrawerListener(this);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        y = ev.getY();
        //没有打开之前 不拦截     打开之后拦不拦截  大于1  后  内容区域不再进行偏移
//        if (slideOffset < 0.8) {
//            return super.dispatchTouchEvent(ev);
//        } else {
//            //等于  1
//            menuPutLayout.setTouchY(y, slideOffset);
//        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
        this.slideOffset = slideOffset;
        menuPutLayout.setTouchY(y, slideOffset);
        //针对内容区域进行破偏移
        float contentViewOffset = drawerView.getWidth() * slideOffset / 2;
        contentView.setTranslationX(contentViewOffset);
    }

    @Override
    public void onDrawerOpened(@NonNull View drawerView) {
        setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN, GravityCompat.END);
    }

    @Override
    public void onDrawerClosed(@NonNull View drawerView) {

    }

    @Override
    public void onDrawerStateChanged(int newState) {

    }
}

整个项目的完整代码详见:https://github.com/buder-cp/CustomView/tree/master/buder_DN_view/buderdn18

关注
打赏
1657159701
查看更多评论
立即登录/注册

微信扫码登录

0.0389s