自定义ViewGroup,实现Android的侧滑菜单

之前写过一片文章是关于使用Android的DrawerLayout来实现侧滑菜单的——Android侧滑菜单DrawerLayout使用

本文直接使用自定义的ViewGroup来实现Android侧滑菜单。

用到的技术: 1、Android自定义控件; 2、Android 的事件拦截onInterceptTouchEvent和触摸事件onTouchEvent处理。 3、Scroller的使用。

效果图:

不多说,马上上代码,自定义的MyViewGroup:

public class MyViewGroup extends ViewGroup {

    private int mMostRecentX; // 最新的x轴偏移量

    private final int MENU_SCREEN = 0; // 菜单界面
    private final int MAIN_SCREEN = 1; // 主界面
    private int currentScreen = MAIN_SCREEN; // 当前屏幕, 默认为: 主界面

    private Scroller mScroller; // 模拟数据对象

    public MyViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);

        mScroller = new Scroller(context);
    }

    /**
     * 此方法是SlideMenu控件测量宽和高时回调.
     * widthMeasureSpec 宽度测量规格: 整个屏幕的宽
     * heightMeasureSpec 高度测量规格: 整个屏幕的高
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 测量菜单的宽和高
        View menuView = getChildAt(0);
        menuView.measure(menuView.getLayoutParams().width, heightMeasureSpec);

        // 测量主界面的宽和高
        View mainView = getChildAt(1);
        // 主界面的宽度是整个屏幕的宽.
        mainView.measure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 布置SlideMenu中包含的子控件的位置.
     * left = 0;
     * top = 0;
     * right = 整个屏幕的宽度;
     * bottom = 整个屏幕的高度;
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // 布置菜单界面的位置: left=-菜单的宽度, top=0, right=0, bottom=整个屏幕的高度
        View menuView = getChildAt(0);
        menuView.layout(-menuView.getMeasuredWidth(), 0, 0, b);

        // 布置主界面的位置: left=0, top=0, right=整个屏幕的宽度, bottom=整个屏幕的高度;
        View mainView = getChildAt(1);
        mainView.layout(l, t, r, b);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mMostRecentX = (int) event.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) event.getX();

                // 1. 计算差值: mMostRecentX - moveX = 48 - 42 = 6;
                int diff = mMostRecentX - moveX;

                // 2. 限定左右边界
                int currentX = getScrollX() + diff;
                if(currentX < -getChildAt(0).getMeasuredWidth()) {
                    // 超出了左边界, 已经移动超过-240
                    scrollTo(-getChildAt(0).getMeasuredWidth(), 0);
                } else if(currentX > 0) {
                    scrollTo(0, 0);
                } else {
                    // 3. 根据差值, 使用scrollBy方法移动屏幕. scrollBy(6, 0);
                    scrollBy(diff, 0);
                }

                // 4. 需要把mMostRecentX重新赋值, 赋值为moveX.    mMostRecentX = 48;
                mMostRecentX = moveX;
                break;
            case MotionEvent.ACTION_UP:
                // 取出当前x轴的偏移量
                int scrollX = getScrollX();

                if(scrollX > (-getChildAt(0).getMeasuredWidth() / 2)) {
                    // 当前应该切换到主界面
                    currentScreen = MAIN_SCREEN;
                } else {
                    // 当前应该切换到菜单界面
                    currentScreen = MENU_SCREEN;
                }
                switchScreen();
                break;
            default:
                break;
        }
        return true; // 完全自己处理事件
    }

    /**
     * 根据currentScreen来切换屏幕显示的界面
     */
    private void switchScreen() {
        int startX = getScrollX();

        int dx = 0;

        if(currentScreen == MAIN_SCREEN) {
            // 切换到主界面
//			scrollTo(0, 0);
            // 算法: 目地的值 - startX
            dx = 0 - startX;
        } else if(currentScreen == MENU_SCREEN) {
//			scrollTo(-getChildAt(0).getMeasuredWidth(), 0);
            dx = -getChildAt(0).getMeasuredWidth() - startX;
        }

        // 开始模拟数据了, 只模拟数据
        mScroller.startScroll(startX, 0, dx, 0, Math.abs(dx) * 2);

        // 重绘刷新.
        invalidate(); // invalidate -> drawChild -> child.draw -> computeScroll
    }

    @Override
    public void computeScroll() {
        // 更新scrollX或者scrollY的值.

        if(mScroller.computeScrollOffset()) {
            // 当前正在模拟数据, 取出x轴模拟的值, 设置给scrollTo方法.
            int currX = mScroller.getCurrX();
//			System.out.println("currX: " + currX);

            scrollTo(currX, 0);

            invalidate(); // 递归
        }
    }

    /**
     * 是否显示菜单
     * @return
     */
    public boolean isShowMenu() {
        return currentScreen == MENU_SCREEN;
    }

    /**
     * 隐藏菜单
     */
    public void hideMenu() {
        currentScreen = MAIN_SCREEN;
        switchScreen();
    }

    /**
     * 显示菜单
     */
    public void showMenu() {
        currentScreen = MENU_SCREEN;
        switchScreen();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mMostRecentX = (int) ev.getX();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) ev.getX();

                // 如果移动的偏移量的距离超过了10
                int diff = moveX - mMostRecentX;

                if(Math.abs(diff) > 10) {
//				System.out.println("横着滑动了");
                    return true;
                }
                break;
            default:
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }
}
复制代码

希望读者可以认真的看下注释,注释已经标注得很明白了。

使用的时候,在xml中使用,需要布局侧滑菜单栏和主界面

activity_custom_view_group:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="com.example.linwj.myapplication.CustomViewGroupActivity">
    <com.example.linwj.myapplication.com.example.linwj.myapplication.view.MyViewGroup
        android:id="@+id/slidemenu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <include layout="@layout/slidemenu_menu"/>

        <include layout="@layout/slidemenu_main"/>

    </com.example.linwj.myapplication.com.example.linwj.myapplication.view.MyViewGroup>
</RelativeLayout>

复制代码

slidemenu_menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="240dip"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="240dip"
        android:layout_height="match_parent"
        android:background="@mipmap/menu_bg"
        android:orientation="vertical" >

        <TextView
            style="@style/menu_tab_style"
            android:background="#33663300"
            android:drawableLeft="@mipmap/tab_news"
            android:text="新闻" />

        <TextView
            style="@style/menu_tab_style"
            android:drawableLeft="@mipmap/tab_read"
            android:text="订阅" />

        <TextView
            style="@style/menu_tab_style"
            android:drawableLeft="@mipmap/tab_local"
            android:text="本地" />

        <TextView
            style="@style/menu_tab_style"
            android:drawableLeft="@mipmap/tab_ties"
            android:text="跟帖" />

        <TextView
            style="@style/menu_tab_style"
            android:drawableLeft="@mipmap/tab_pics"
            android:text="图片" />

        <TextView
            style="@style/menu_tab_style"
            android:drawableLeft="@mipmap/tab_ugc"
            android:text="话题" />
    </LinearLayout>

</ScrollView>
复制代码

slidemenu_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="com.example.linwj.myapplication.CustomViewGroupActivity">
    <com.example.linwj.myapplication.com.example.linwj.myapplication.view.MyViewGroup
        android:id="@+id/slidemenu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <include layout="@layout/slidemenu_menu"/>

        <include layout="@layout/slidemenu_main"/>

    </com.example.linwj.myapplication.com.example.linwj.myapplication.view.MyViewGroup>
</RelativeLayout>

复制代码

Activity:

public class CustomViewGroupActivity extends AppCompatActivity implements View.OnClickListener {

    private MyViewGroup myViewGroup;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_custom_view_group);
        findViewById(R.id.ib_slidemenu_main_back).setOnClickListener(this);

        myViewGroup = (MyViewGroup) findViewById(R.id.slidemenu);
    }

    @Override
    public void onClick(View v) {

        // 切换当前屏幕显示的状态

        if(myViewGroup.isShowMenu()) {
            // 显示菜单, 切换到主界面
            myViewGroup.hideMenu();
        } else {
            // 显示主界面, 切换到菜单
            myViewGroup.showMenu();
        }

    }

    public void clickTab(View v) {
        TextView tv = (TextView) v;
        Toast.makeText(this, tv.getText(), Toast.LENGTH_SHORT).show();
    }
}
复制代码

这就是自定义ViewGroup实现Android的侧滑菜单以及使用,希望大家喜欢!!!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值