自定义左右侧滑菜单

来源:互联网 发布:hr人力资源软件免费 编辑:程序博客网 时间:2024/05/02 00:04

平面图

一、首先新建一个类,继承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>
1 0