zoukankan      html  css  js  c++  java
  • Android-自定义侧滑菜单

    效果图:

    需要继承ViewGroup,因为包含了子控件,菜单子控件 与 主页面子控件

    Activity Xml布局相关:

    <!-- 自定义侧滑菜单 SlideMenu -->
    
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <view.custom.heimacustomview.my_slide_menu.MySlideMenu
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <include layout="@layout/slide_menu" />
    
            <include layout="@layout/slide_main" />
    
        </view.custom.heimacustomview.my_slide_menu.MySlideMenu>
    
    </LinearLayout>

    菜单界面子控件布局相关:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:background="#ffff80"
        android:orientation="vertical">
    
        <!-- 这里的View不能写 wrap_content 不然在测量后,一直是TextView的宽度 -->
        <TextView
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:textSize="30sp"
            android:text="侧滑菜单"
            android:gravity="center_horizontal"
            />
        
    </LinearLayout>

    主页界面子控件布局相关:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#80ffff">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="我是首页"
            android:textSize="30sp"
            android:layout_centerInParent="true"
            android:layout_centerHorizontal="true"/>
    
    </RelativeLayout>

    自定义侧滑菜单类相关:

    package view.custom.heimacustomview.my_slide_menu;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.GestureDetector;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Scroller;
    
    public class MySlideMenu extends ViewGroup {
    
        private static final String TAG = MySlideMenu.class.getSimpleName();
    
        private Scroller mScroller;
    
        /**
         * 以往我是在onTouchEvent方法中处理,这次我采用手势识别器
         * 注意:手势识别器只处理事件相关,不能拦截时间,相当于只过滤处理水,并不能阻止水
         */
        private GestureDetector mGestureDetector;
    
        float mDistanceX;
        float countX = 0f;
    
        /**
         * 构造方法,由布局xml指引来初始化,并传入属性集合
         * @param context
         * @param attrs
         */
        public MySlideMenu(final Context context, AttributeSet attrs) {
            super(context, attrs);
    
            mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){
    
                /**
                 * 滑动过程中的方法
                 * @param e1 可以理解为 手指按下记录用到的MotionEvent
                 * @param e2 可以理解为 手机滑到某个点记录用到的MotionEvent
                 * @param distanceX 计算好的X轴距离值
                 * @param distanceY 计算好的Y轴距离值
                 * @return
                 */
                @Override
                public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                    // return super.onScroll(e1, e2, distanceX, distanceY);
                    /* if (getScrollX() < 0) {
                        distanceX = 0;
                    }*/
    
                    Log.d(TAG, "onScroll() distanceX:" + distanceX + " getScrollX:" + getScrollX());
                    mDistanceX = distanceX;
                    countX += distanceX;
    
                    if (countX > 0) {
                        countX = 0;
                    } else if (countX < -slideMenuView.getMeasuredWidth()) {
                        countX = -slideMenuView.getMeasuredWidth();
                    }
    
                    scrollTo((int) countX, getScrollY());
    
                    return true;
                }
    
                /*@Override
                public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                    // return super.onFling(e1, e2, velocityX, velocityY);
                    Log.d(TAG, "onFling() velocityX:" + velocityX + " velocityY:" + velocityY);
    
                    if (countX > -slideMenuView.getMeasuredWidth() / 2) {
                        countX = 0;
                    } else if (countX < -slideMenuView.getMeasuredWidth() / 2) {
                        countX = -slideMenuView.getMeasuredWidth();
                    }
    
                    int dx =  (int) countX - getScrollX();
    
                    // scrollTo((int) countX, getScrollY());
                    mScroller.startScroll(getScrollX(), 0, dx, 0, Math.abs(1000));
                    invalidate();
                    return true;
                }*/
    
            });
    
            // 实现弹性滑动,不要滑动那么生硬
            mScroller = new Scroller(context);
        }
    
        /**
         * 定义两个子控件
         */
        private View slideMenuView;
        private View slideMainView;
    
        /**
         * 当布局xml加载完成后,就会调用此方法,然后此方法再去获取子控件View
         */
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
    
            // 获取子控件View
            slideMenuView = getChildAt(0);
            slideMainView = getChildAt(1);
        }
    
        /**
         * 测量方法
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            // 测量菜单子控件的高和宽,宽是布局文件设置的宽度,高度获取当前MySlideMenu的高度(与屏幕保存一致高度)
            int slideMenuViewWidth = slideMenuView.getLayoutParams().width;
            Log.d(TAG, "获取布局中的宽度 slideMenuViewWidth:" + slideMenuViewWidth);
            if (null != slideMenuView) {
                slideMenuView.measure(slideMenuViewWidth, heightMeasureSpec);
            }
    
            // 测量主页子控件的高和宽,宽度高度获取当前MySlideMenu的宽度高度(与屏幕保存一致高度)
            if (null != slideMainView) {
                slideMainView.measure(widthMeasureSpec, heightMeasureSpec);
            }
        }
    
        /**
         * 给子控件位置排版,固定好位置
         * @param changed 当发生改变的时候
         * @param l 父控件距离左手边左边线距离
         * @param t 父控件距离顶边顶边线距离
         * @param r 父控件距离左手边右边线距离
         * @param b 父控件距离顶部边底部线距离
         */
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
    
            slideMenuView = getChildAt(0);
    
            Log.d(TAG, "slideMenuView.getMeasuredWidth():" + slideMenuView.getMeasuredWidth());
            Log.d(TAG, "slideMainView.getMeasuredWidth():" + slideMainView.getMeasuredWidth());
    
            // 给菜单子控件固定好位置
            slideMenuView.layout(-slideMenuView.getMeasuredWidth(), 0, 0, slideMenuView.getMeasuredHeight());
    
            // 给主页子控件固定好位置 r和父控件保持一直,b和父控件保持一致
            slideMainView.layout(0, 0, r, b);
        }
    
        private float downX;
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            super.onTouchEvent(event);
            mGestureDetector.onTouchEvent(event);
    
            if (event.getAction() == MotionEvent.ACTION_UP) {
                if (countX > -slideMenuView.getMeasuredWidth() / 2) {
                    countX = 0;
                } else if (countX < -slideMenuView.getMeasuredWidth() / 2) {
                    countX = -slideMenuView.getMeasuredWidth();
                }
    
                int dx =  (int) countX - getScrollX();
    
                // scrollTo((int) countX, getScrollY()); // 这种方式体验过于生硬
    
                mScroller.startScroll(getScrollX(), 0, dx, 0, Math.abs(1000));
                invalidate();
            } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
                downX = event.getX();
            }
            return true;
        }
    
        @Override
        public void computeScroll() {
            super.computeScroll();
            if (mScroller.computeScrollOffset()) {
                int currX = mScroller.getCurrX();
                scrollTo(currX, mScroller.getCurrY());
                postInvalidate();
            }
        }
    }
  • 相关阅读:
    HashMap死循环造成CPU100%
    ArrayList升级为线程安全的List
    并发容器-ConncurrentHashMap
    并发容器-概览
    不可变性final
    CAS
    原子类-Adder累加器
    hue-使用mysql作为元数据库
    yhd日志分析(二)
    yhd日志分析(一)
  • 原文地址:https://www.cnblogs.com/android-deli/p/9710036.html
Copyright © 2011-2022 走看看