`
ycyxb104
  • 浏览: 26666 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Android自定义侧滑菜单

 
阅读更多

 现在android中有很多产品实现了侧边栏菜单的滑动,比如说百度贴吧、腾讯QQ、Facebook、知乎等,这样做的好处:

一是可以装下更多的内容,二是给用户更好的视觉感受。

 

 下面举一个知乎的例子:

 

一、实现的思路:

首先定义三个FrameLayout:leftMenu、middleMenu、rightMenu

middleMenu为主面板,大小设置为屏幕的大小;

leftMenu、rightMenu为左右侧边栏,大小设置为屏幕的一定比例,我设置的是80%,位置分别设置在middleMenu的左右两边,一开始打开的时候并不能看见。

 

实现的滑动的方法是dispatchTouchEvent() :

通过ACTION_DOWN和ACTION_MOVE不断获取滑动中的x、y坐标来进行判断是上下滑动还是左右滑动,通过Scroller来实现滑动的动画效果。

 

二、代码: 

import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.Scroller;
public class MainUI extends RelativeLayout {
    private Context context;
    private FrameLayout leftMenu;//设置左面板
    private FrameLayout middleMenu;//设置主面板
    private FrameLayout rightMenu;//设置右面板
    private Scroller mScroller;
    private FrameLayout middleMask;

    public static final int LEFT_ID = 0xaabbcc;
    public static final int MIDDLE_ID = 0xaaccbb;
    public static final int RIGHT_ID = 0xccbbaa;

    public MainUI(Context context) {
        super(context);
        initView(context);
    }

    public MainUI(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    private void initView(Context context) {//初始化
        this.context = context;
        mScroller = new Scroller(context, new DecelerateInterpolator());
        leftMenu = new FrameLayout(context);
        middleMenu = new FrameLayout(context);
        rightMenu = new FrameLayout(context);
        middleMask = new FrameLayout(context);
        leftMenu.setBackgroundColor(Color.RED);
        middleMenu.setBackgroundColor(Color.GREEN);
        rightMenu.setBackgroundColor(Color.RED);
        leftMenu.setId(LEFT_ID);
        middleMenu.setId(MIDDLE_ID );
        rightMenu.setId(RIGHT_ID );
        middleMask.setBackgroundColor(0x88000000);
        addView(leftMenu);
        addView(middleMenu);
        addView(rightMenu);
        addView(middleMask);
        middleMask.setAlpha(0);//设置透明度
    }
    public float onMiddleMask(){
        System.out.println("透明度:"+middleMask.getAlpha());
        return middleMask.getAlpha();
    }
    public void scrollTo(int x,int y){//滑动方法
        super.scrollTo(x,y);
        onMiddleMask();
        int curX = Math.abs(getScrollX());
        float scale = curX/(float)leftMenu.getMeasuredWidth();
        middleMask.setAlpha(scale);
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//设置面板大小
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        middleMenu.measure(widthMeasureSpec, heightMeasureSpec);
        middleMask.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);
    }

    protected void onLayout(boolean changed, int l, int t, int r, int b) {//设置面板位置
        super.onLayout(changed, l, t, r, b);
        middleMenu.layout(l, t, r, b);
        middleMask.layout(l, t, r, b);
        leftMenu.layout(l - leftMenu.getMeasuredWidth(), t, l, b);
        rightMenu.layout(l + middleMenu.getMeasuredWidth(), t,
                r + rightMenu.getMeasuredWidth(), b);
    }

    private boolean isTestCompete;
    private boolean isleftrightEvent;

    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);
                        } else {//向右
                            mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth() - curScrollX, 0);
                        }
                    } else {
                        mScroller.startScroll(curScrollX, 0, -curScrollX, 0);//距离不到返回原点

                    }
                    invalidate();//View重绘
                    isleftrightEvent = false;
                    isTestCompete = false;
                    break;
            }
        } else {//上下滑动也要初始化
            switch (ev.getActionMasked()) {
                case MotionEvent.ACTION_UP:
                    isleftrightEvent = false;
                    isTestCompete = false;
                    break;
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    private Point point = new Point();
    private static  final int TEST_DIS = 20;
    public void computeScroll() {//回调方法
        super.computeScroll();
        if (!mScroller.computeScrollOffset()) {
            return;
        }
        int tempX = mScroller.getCurrX();//总滑动值
        scrollTo(tempX, 0);
    }

    private void getEventType(MotionEvent e) {//判断事件类型
        switch (e.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                point.x=(int) e.getX();
                point.y=(int) e.getY();
                super.dispatchTouchEvent(e);
                break;
            case MotionEvent.ACTION_MOVE:
                int dX = Math.abs((int) e.getX()-point.x);
                int dY = Math.abs((int) e.getY()-point.y);
                if(dX > TEST_DIS && dX > dY){//左右滑动
                    isleftrightEvent = true;
                    isTestCompete = true;
                    point.x = (int)e.getX();
                    point.y = (int)e.getY();
                }else if(dY > TEST_DIS && dY>dX){//上下滑动
                    isleftrightEvent = false;
                    isTestCompete = true;
                    point.x = (int)e.getX();
                    point.y = (int)e.getY();
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                super.dispatchTouchEvent(e);
                isleftrightEvent = false;
                isTestCompete = false;
                break;
        }
    }
}

 

 

源码已上传。



 

  • 大小: 46.9 KB
0
0
分享到:
评论

相关推荐

    Android仿网易自定义侧滑菜单

    本项目是针对网易新闻客户端的侧滑菜单效果进行的仿制,旨在帮助开发者学习如何在Android中实现自定义的侧滑菜单功能。 首先,我们来了解一下侧滑菜单的基本结构。一个典型的侧滑菜单通常由两部分组成:主内容视图...

    Android双向侧滑菜单 自定义控件

    在Android应用开发中,侧滑菜单(DrawerLayout)是一种常见的设计模式,用于提供导航和功能选项。本实例代码着重讲解如何实现一个支持双向侧滑的自定义控件,即不仅可从左侧滑出,也能从右侧滑出。下面将详细阐述...

    Android自制侧滑菜单

    总结起来,实现Android自定义侧滑菜单涉及的关键步骤包括使用`DrawerLayout`作为基础容器,创建菜单视图,处理滑动手势,控制菜单的开关,以及实现菜单项的交互。通过这些步骤,我们可以创建出符合用户习惯的侧滑...

    Android自定义侧滑框架

    总的来说,自定义ViewGroup和实现侧滑功能是Android开发中的重要技能,通过"Android自定义侧滑框架"项目,你可以锻炼到布局设计、手势检测和动画应用等多个方面的技术。对于初学者来说,这是一个很好的实践项目,有...

    Android高级应用源码-android自定义控件-侧滑菜单.zip

    这个“Android高级应用源码-android自定义控件-侧滑菜单.zip”压缩包中,很可能包含了一个实现这种侧滑效果的自定义控件的源代码。 侧滑菜单通常由两部分组成:主要内容视图和侧滑视图。主要内容视图显示在屏幕中央...

    ViewDragHelper自定义侧滑菜单(解决与ScrollView的滑动事件冲突)

    标题提到的"ViewDragHelper自定义侧滑菜单"就是一个典型的例子,它允许开发者创建类似Google Material Design中的抽屉式菜单,通常用于隐藏主界面之外的附加内容,如导航菜单。ViewDragHelper是Android SDK提供的一...

    Android 酷炫侧滑菜单Demo例子

    在Android应用开发中,侧滑菜单(也称为抽屉式导航菜单)是一种常见的设计模式,它允许用户通过从屏幕边缘向内滑动来显示或隐藏菜单。这种设计为用户提供了一种方便的方式来浏览应用的主要功能,而不会遮挡主内容...

    Android自定义实现侧滑菜单效果

    总的来说,自定义侧滑菜单涉及到了Android视图系统的深度理解,包括自定义视图、事件分发、状态监听以及布局管理。通过以上步骤,我们可以创建一个功能完善的侧滑菜单,提供给用户更加直观和便捷的操作体验。在实际...

    安卓SlidingMenu各种菜单侧滑菜单相关-android自定义控件-侧滑菜单.zip

    这个"安卓SlidingMenu各种菜单侧滑菜单相关-android自定义控件-侧滑菜单.zip"文件包含了一些关于如何在Android应用中实现这一功能的资源和代码示例。以下是一些关键知识点: 1. **SlidingMenu库**:SlidingMenu是一...

    android 侧滑菜单-实例代码

    在Android应用开发中,侧滑菜单(Slide Menu)是一种常见的设计模式,用于提供导航和功能选项,用户只需从屏幕边缘向内滑动即可显示或隐藏菜单。这种菜单通常被用在许多应用程序中,如Google应用、Facebook应用等,...

    Android Studio官方版DrawerLayout侧滑菜单

    在Android开发中, DrawerLayout 是一个非常重要的布局组件,它被广泛用于实现应用程序的侧滑菜单功能。这个组件是Google官方Android SDK的一部分,是Android Studio中的一个标准库,因此被称为"Android Studio官方...

    android自定义控件-侧滑菜单

    5. **集成到项目中**:将自定义侧滑菜单作为一个单独的组件,可以通过继承`View`或`ViewGroup`来实现,然后在需要的地方通过XML布局文件或代码动态添加到Activity或Fragment中。 6. **兼容性考虑**:确保自定义控件...

    Android自定义控件侧滑菜单

    总的来说,实现一个自定义的Android侧滑菜单涉及到手势检测、动画实现、布局管理和组件交互等多个方面。尽管有现成的库可以使用,但自定义控件能让我们更好地控制用户体验,实现更加个性化的设计。通过不断实践和...

    自定义android侧滑菜单

    1. `CustomSideslipMenu.java`:这是自定义侧滑菜单的核心类,实现了上述两种效果的逻辑。 2. `activity_main.xml`:主布局文件,包含了内容视图和菜单视图。 3. `menu_left.xml`:定义了侧滑菜单的布局和内容。 4. ...

    Android酷炫侧滑菜单

    在Android应用开发中,侧滑菜单(也称为抽屉式导航菜单)是常见的设计模式,它为用户提供了一种直观的方式来浏览应用的主要功能或导航选项。本篇将详细讲解如何实现一个具有折叠动画效果的酷炫侧滑菜单。 首先,...

    android:侧滑菜单效果

    在Android应用开发中,侧滑菜单(也称为抽屉式导航)是一种常见的设计模式,它允许用户通过从屏幕边缘向内滑动来显示隐藏的菜单选项。这种效果在许多流行的应用如易信中都可以看到。在本文中,我们将深入探讨如何...

    Android自定义ViewGroup(侧滑菜单)详解及简单实例

    总之,自定义ViewGroup在Android开发中扮演着重要角色,尤其对于实现特定交互效果如侧滑菜单来说,自定义ViewGroup能帮助开发者更好地控制布局和动画,提升应用的可定制性和用户体验。通过理解并实践这些关键步骤,...

Global site tag (gtag.js) - Google Analytics