Android 开发第三弹:自定义左右菜单(滑动动画+蒙版效果)

下面的截图……哎,因为1080P在Windows 10上虽然适配了,但大部分软件并没有跟上,比如某个录制GIF的软件,所以这里有一定的偏移导致画面不完整,但效果大概就是这么一个效果了。

MainUI.java

首先需要这么一个类,在这里一些UI的滑动呀之类的都会定义。首先吧,定义好这些变量,当然了,实际开发过程中肯定需要哪一个就添加上哪一个的。

    private Context context;  // 上下文
    private FrameLayout leftMenu;    // 左边部分
    private FrameLayout middleMenu;  // 中间部分
    private FrameLayout rightMenu;   // 右边部分
    private FrameLayout middleMask;  // 蒙版效果
    private Scroller mScroller;    // 滑动动画
    public static final int ID = 0;    // ID
    public static final int LEFT_ID = ID+0xaabbcc;
    public static final int MIDDLE_ID = ID+0xaaccbb;
    public static final int RIGHT_ID = ID+0xccbbaa;

构造函数也是不能少的。

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

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

initView就是用来初始化视图的,相应的功能我都写在注释上了,就不多废话了。

    // 初始化视图
    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);
        middleMask.setBackgroundColor(0x88000000);
        leftMenu.setId(LEFT_ID);
        middleMenu.setId(MIDDLE_ID);
        rightMenu.setId(RIGHT_ID);
        addView(leftMenu);   // 添加至View
        addView(middleMenu);
        addView(rightMenu);
        addView(middleMask);
        middleMask.setAlpha(0);  // 设置middleMask的透明度
    }

然后就是它们的一些布局呀,balabala……

    @Override
    protected void onMeasure(int widthMeasureSepc, int heightMeasureSpec){
        super.onMeasure(widthMeasureSepc, heightMeasureSpec);
        middleMenu.measure(widthMeasureSepc, heightMeasureSpec);
        middleMask.measure(widthMeasureSepc,heightMeasureSpec);
        int realWidth = MeasureSpec.getSize(widthMeasureSepc);  // 获取实际(屏幕)宽度
        int tempWidthMeasure = MeasureSpec.makeMeasureSpec(
                (int)(realWidth*0.7f), MeasureSpec.EXACTLY);  // 左右侧的宽度为中间宽度的0.7
        leftMenu.measure(tempWidthMeasure, heightMeasureSpec);  // 左右侧的高度和中间的一样
        rightMenu.measure(tempWidthMeasure, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r,int b){  // l,t,r,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, r, b); // 左侧部分的左边边界等于中间部分的左边边界减去左侧部分的宽度
        rightMenu.layout(l + middleMenu.getMeasuredWidth(), t,  // 右侧部分的左边边界则等于中间部分的左边边界加上中间部分的宽度
                l + middleMenu.getMeasuredWidth() +   // 右侧部分的右边边界等于中间部分的左边边界加上中间部分的宽度加上右侧部分的宽度
                        rightMenu.getMeasuredWidth(), b);
    }
    public float onMiddleMask(){
        System.out.println("透明度"+middleMask.getAlpha());
        return middleMask.getAlpha();
    }

    @Override
    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);
    }

再用两个布尔值来确定是否在左右滑动等。

    private boolean isTestComete;  // 测试是否完成
    private boolean isleftrightevent;  // 判断是否是左右滑动
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev){
        if(!isTestComete){  // 没有完成滑动动作
            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;
                    isTestComete = false;
                    break;
            }
        }else{
            switch (ev.getActionMasked()){
                case MotionEvent.ACTION_UP:
                    isleftrightevent = false;
                    isTestComete = false;
                    break;
                default:
                    break;
            }
        }
        return super.dispatchTouchEvent(ev);
    }
@Override
    public void computeScroll(){
        super.computeScroll();
        if(!mScroller.computeScrollOffset()){
            return;
        }
        int tempX = mScroller.getCurrX();
        scrollTo(tempX, 0);
    }

    private Point point = new Point();
    private static final int TEST_DIS = 20;
    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;
                    isTestComete = true;
                    point.x = (int)ev.getX();
                    point.y = (int)ev.getY();
                }else if(dY>=TEST_DIS && dY>dX ){   // 上下滑动
                    isleftrightevent = false;
                    isTestComete = true;
                    point.x = (int)ev.getX();
                    point.y = (int)ev.getY();
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                super.dispatchTouchEvent(ev);
                isleftrightevent = false;
                isTestComete = false;
                break;
        }
    }

LeftMenu.java

下面继续看看如何在左侧的目录中添加一个Button。

你需要创建一个LeftMenu类,并扩展Fragment,因此你需要

import android.support.v4.app.Fragment;

如果你不知道如何添加,请看这里:

在下面这段代码之前你需要再新建一个left.xml布局文件,其中添加一个Button1。

    @Override
      public View onCreateView(LayoutInflater inflater,
                               @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.left, container,false);
        v.findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                System.out.println("Hello nomasp");
            }
        });
        return v;
    }

MainActivity.java

现在你就需要来create它们了。

    private MainUI mainUI;
    private LeftMenu leftMenu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainUI = new MainUI(this);
        setContentView(mainUI);
        leftMenu = new LeftMenu();
        getSupportFragmentManager().beginTransaction()
                .add(MainUI.LEFT_ID, leftMenu).commit();
    }

当然了,这里的MainActivity也需要扩展FragmentActivity,也就是要导入android?support?v4.jar,至于如何导入请看前文的导航链接。

当然了,完整的代码你可以从这里Fork:GitHub

版权声明:本文为 NoMasp柯于旺 原创文章,未经许可严禁转载!欢迎访问我的博客:http://blog.csdn.net/nomasp

时间: 2024-08-03 08:17:26

Android 开发第三弹:自定义左右菜单(滑动动画+蒙版效果)的相关文章

Android 开发第六弹:简易时钟(计时器)

接上篇Android 开发第五弹:简易时钟(闹钟) ,这次是一个时钟类应用,目前依旧是主要的功能,长得还是很挫.当然了,核心功能是有的-- 时钟 先把简单的时钟给列出来吧,这里都写的很简单,即便要用世界各个城市的话,也只是相应的加上或减去几个小时. 新建TimeView类,并扩展自LinearLayout,然后布局文件和上一篇中那么写就好了. <myapplication.nomasp.com.clock.TimeView android : id = "@+id/tabTime"

Android 开发第七弹:简易时钟(秒表)

本文承接,Android 开发第五弹:简易时钟(闹钟) 和 Android 开发第六弹:简易时钟(计时器),这一部分是关于秒表的. 布局 同样是新建一个类(StopWatchView)并扩展自LinearLayout,并将其用作布局. <myapplication.nomasp.com.clock.StopWatchView android : id = "@+id/tabStopWatch" android : layout_width = "match_parent

Android自定义控件系列三:自定义开关按钮(三)--- 自定义属性

尊重原创,转载请注明出处:http://blog.csdn.net/cyp331203/article/details/40855377 接之前的:Android自定义控件系列二:自定义开关按钮(一)和Android自定义控件系列三:自定义开关按钮(二)继续,今天要讲的就是如何在自定义控件中使用自定义属性,实际上这里有两种方法,一种是配合XML属性资源文件的方式,另一种是不需要XML资源文件的方式:下面我们分别来看看: 一.配合XML属性资源文件来使用自定义属性: 那么还是针对我们之前写的自定义

【转】Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果

原文网址:http://blog.csdn.net/xiaanming/article/details/17539199 我在上一篇文章中Android 带你从源码的角度解析Scroller的滚动实现原理从源码的角度介绍了Scroller的滚动实现原理,相信大家对Scroller的使用有一定的了解,这篇文章就给大家带来使用Scroller的小例子,来帮助大家更加熟悉的掌握Scroller的使用,掌握好了Scroller的使用我们就能实现很多滑动的效果.例如侧滑菜单,launcher,ListVi

[转]Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果

我在上一篇文章中Android 带你从源码的角度解析Scroller的滚动实现原理从源码的角度介绍了Scroller的滚动实现原理,相信大家对Scroller的使用有一定的了解,这篇文章就给大家带来使用Scroller的小例子,来帮助大家更加熟悉的掌握Scroller的使用,掌握好了Scroller的使用我们就能实现很多滑动的效果.例如侧滑菜单,launcher,ListView的下拉刷新等等效果,我今天实现的是ListView的item的左右滑动删除item的效果,现在很多朋友看到这个效果应该

Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果

我在上一篇文章中Android 带你从源码的角度解析Scroller的滚动实现原理从源码的角度介绍了Scroller的滚动实现原理,相信大家对Scroller的使用有一定的了解,这篇文章就给大家带来使用Scroller的小例子,来帮助大家更加熟悉的掌握Scroller的使用,掌握好了Scroller的使用我们就能实现很多滑动的效果.例如侧滑菜单,launcher,ListView的下拉刷新等等效果,我今天实现的是ListView的item的左右滑动删除item的效果,现在很多朋友看到这个效果应该

本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/18311877)Android 使用NineOldAndroids实现绚丽的ListView左右滑动删除Item效果

今天还是给大家带来自定义控件的编写,自定义一个ListView的左右滑动删除Item的效果,这个效果之前已经实现过了,有兴趣的可以看下Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果,之前使用的是滑动类Scroller来实现的,但是看了下通知栏的左右滑动删除效果,确实很棒,当我们滑动Item超过一半的时候,item的透明度就变成了0,我们就知道抬起手指的时候item就被删除了,当item的透明度不为0的时候,我们抬起手指Item会回到起始位置,这样我们就知道

Android 使用NineOldAndroids实现绚丽的ListView左右滑动删除Item效果

今天还是给大家带来自定义控件的编写,自定义一个ListView的左右滑动删除Item的效果,这个效果之前已经实现过了,有兴趣的可以看下Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果, 之前使用的是滑动类Scroller来实现的,但是看了下通知栏的左右滑动删除效果,确实很棒,当我们滑动Item超过一半的时候,item的透明度就变 成了0,我们就知道抬起手指的时候item就被删除了,当item的透明度不为0的时候,我们抬起手指Item会回到起始位置,这样我们就

导航菜单滑动动画

用jquery实现百度新闻导航菜单滑动动画 前言 前两天,群里有人问百度新闻导航是如何实现的,当时由于忙于工作,没有来得及细看,恰好今天有空闲时间,索性就实现一下这个效果吧: 思路与步骤 1.利用UL创建简单横向导航: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&g