自定义左右侧滑菜单

平面图

一、首先新建一个类,继承RelativeLayout,重写其构造方法。

public class MyMenu extends RelativeLayout {
    public MyMenu(Context context) {
        this(context, null);
    }
    public MyMenu(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public MyMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
}

二、把实现效果分成三个部分,即中间部分跟左右两个部分,以中间部分为主体,创建三个FrameLayout,并添加到布局。

    private Context context;
    private FrameLayout leftMenu;
    private FrameLayout bodyMenu;
    private FrameLayout rightMenu;
    private FrameLayout bodyMask;
    private Scroller mScroller; 

    /**
     *      初始化
     * @param context
     */
    private void init(Context context) {
        this.context = context;
        mScroller = new Scroller(context, new DecelerateInterpolator());
        leftMenu = new FrameLayout(context);
        bodyMenu = new FrameLayout(context);
        rightMenu = new FrameLayout(context);
        bodyMask = new FrameLayout(context);
        leftMenu.setBackgroundColor(Color.YELLOW);
        bodyMenu.setBackgroundColor(Color.RED);
        rightMenu.setBackgroundColor(Color.GREEN);
        bodyMask.setBackgroundColor(0x88000000);
        leftMenu.setId(R.id.LETF_ID);
        bodyMenu.setId(R.id.BODY_ID);
        rightMenu.setId(R.id.RIGTH_ID);
        addView(leftMenu);
        addView(bodyMenu);
        addView(rightMenu);
        addView(bodyMask);
        bodyMask.setAlpha(0);
    }

其中setId() 用于添加页面,需要在values中创建一个ids.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="LETF_ID" format="integer" type="id">0xaabbcc</item>
    <item name="BODY_ID" format="integer" type="id">0xaabbcc</item>
    <item name="RIGTH_ID" format="integer" type="id">0xaabbcc</item>
</resources>

三、重写onMeasure() 方法,获取屏幕的宽高,并计算FrameLayout的大小。

    /**
     *   计算布局大小
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        bodyMenu.measure(widthMeasureSpec, heightMeasureSpec);
        bodyMask.measure(widthMeasureSpec,heightMeasureSpec);
        // 获取屏幕的最大宽度
        int realWidth = MeasureSpec.getSize(widthMeasureSpec);
        // 屏幕百分之八十的宽度
        int tempWidthMeasure = MeasureSpec.makeMeasureSpec((int) (realWidth * 0.8f), MeasureSpec.EXACTLY);
        leftMenu.measure(tempWidthMeasure, heightMeasureSpec);
        rightMenu.measure(tempWidthMeasure, heightMeasureSpec);
    }

四、重写onLayout() 方法,计算FrameLayout 的初始位置。

    /**
     *   计算启始位置
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        bodyMenu.layout(l, t, r, b);
        bodyMask.layout(l, t, r, b);
        leftMenu.layout(-leftMenu.getMeasuredWidth(), t, r, b);
        rightMenu.layout(l + bodyMenu.getMeasuredWidth(), t, l + bodyMenu.getMeasuredWidth() + r + rightMenu.getMeasuredWidth(), b);
    }

五、添加滑动监听事件。

   /**
     *    事件监听处理
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!isTestCompete) {
            getEventType(ev);
            return true;
        }
        // 左右滑动
        if (isleftrightEvent) {
            switch (ev.getActionMasked()) {
                case MotionEvent.ACTION_MOVE:
                    int curScrollX = getScrollX();      // 获取滚动距离
                    int dis_x = (int) (ev.getX() - point.x);        // 获取手指滑动距离
                    int expectX = -dis_x + curScrollX;
                    int finalX = 0;
                    if (expectX < 0) {
                        finalX = Math.max(expectX, -leftMenu.getMeasuredWidth());   // 向左
                    } else {
                        finalX = Math.min(expectX, rightMenu.getMeasuredWidth());   //向右
                    }
                    scrollTo(finalX, 0);        //移动
                    point.x = (int) ev.getX();
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    curScrollX = getScrollX();
                    if (Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1) {
                        if (curScrollX < 0) {
                            mScroller.startScroll(curScrollX,0,-leftMenu.getMeasuredWidth()-curScrollX,0,200);
                        }else{
                            mScroller.startScroll(curScrollX,0,leftMenu.getMeasuredWidth()-curScrollX,0,200);
                        }
                    }else{
                        mScroller.startScroll(curScrollX,0,-curScrollX,0,200);
                    }
                    invalidate();
                    isleftrightEvent = false;
                    isTestCompete = false;
                    break;
            }
        } else {
            switch (ev.getActionMasked()) {
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    isleftrightEvent = false;
                    isTestCompete = false;
                    break;
            }
        }
        return super.dispatchTouchEvent(ev);
    }
    private Point point = new Point();
    private static final int TEST_DIS = 20;
    private boolean isleftrightEvent;
    private void getEventType(MotionEvent ev) {
        switch (ev.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                point.x = (int) ev.getX();
                point.y = (int) ev.getY();
                super.dispatchTouchEvent(ev);
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = Math.abs((int) (ev.getX() - point.x));
                int dy = Math.abs((int) (ev.getY() - point.y));
                if (dx > TEST_DIS && dx > dy) {
                    //左右滑动
                    isleftrightEvent = true;
                    isTestCompete = true;
                    point.x = (int) ev.getX();
                    point.y = (int) ev.getY();
                } else if (dy > TEST_DIS && dy > dx) {
                    //上下滑动
                    isleftrightEvent = false;
                    isTestCompete = true;
                    point.x = (int) ev.getX();
                    point.y = (int) ev.getY();
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                super.dispatchTouchEvent(ev);
                isTestCompete = false;
                isleftrightEvent = false;
                break;
            default:
                break;
        }
    }

六、添加左右滑动动画

    private Scroller mScroller;
    private void init(Context context) {
    // 在init()方法中添加Scroller的初始化
        mScroller = new Scroller(context, new DecelerateInterpolator());
    }

    // 在事件监听dispatchTouchEvent()方法中添加滑动位置
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
        curScrollX = getScrollX();
           if (Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1) {
              if (curScrollX < 0) {
                   mScroller.startScroll(curScrollX,0,-leftMenu.getMeasuredWidth()-curScrollX,0,200);
              }else{
                   mScroller.startScroll(curScrollX,0,leftMenu.getMeasuredWidth()-curScrollX,0,200);
              }
           }else{
              mScroller.startScroll(curScrollX,0,-curScrollX,0,200);
           }
          // 刷新
           invalidate();
           isleftrightEvent = false;
           isTestCompete = false;
           break;
  // 最后别忘了添加滑动方法,不然不会执行滑动效果
    @Override
    public void computeScroll() {
        super.computeScroll();
        if(!mScroller.computeScrollOffset()){
            return;
        }
        int tempX = mScroller.getCurrX();
        scrollTo(tempX,0);
    }

七、进行滑动阴影模板计算。

    /**
     *  滑动
     */
    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
        int curX = Math.abs(getScrollX());
        float scale = curX/(float)leftMenu.getMeasuredWidth();
        bodyMask.setAlpha(scale);
        System.out.println("透明度:"+scale);
    }

这样就完成一个简单的自定义左右侧滑菜单,在mainActivtiy中可以这样调用。

package com.niowoo.laok.iliaotian;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
    private MyMenu myMenu;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myMenu = new MyMenu(this);
        setContentView(myMenu);
        // 使用app包下的Framgnet添加布局
        getFragmentManager().beginTransaction().replace(R.id.LETF_ID,new TestFragment()).commit();
    }
}

Fragment的代码,记住是app包下的Fragment。

package com.niowoo.laok.iliaotian;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
    private MyMenu myMenu;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myMenu = new MyMenu(this);
        setContentView(myMenu);
        // 使用app包下的Framgnet添加布局
        getFragmentManager().beginTransaction().replace(R.id.LETF_ID,new TestFragment()).commit();
    }
}

Fragment的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/button"
        android:layout_gravity="center_horizontal" />
</LinearLayout>
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值