Android自定义LinearLayout实现左右侧滑菜单,完美兼容ListView、ScrollView、ViewPager等滑动控件

国际惯例,先来效果图



在阅读本文章之前,请确定熟悉【Scroller】相关的知识,如果不熟悉,请小伙伴儿先百度后再来吧。

假如你已经知道【Scroller】了,那么就接着往下看吧。

首先,我们把侧拉菜单的构造给解析出来。多次观看上面的效果图,我们可以得出以下的结论。

  • 整体可以看做是一个ViewGroup,这个ViewGroup包含了最多三个子View(分别是左菜单的红色View、中间正文内容的白色View、右菜单的蓝色View);
  • 三个子View(我称为UI界面,因为代码中的Java类就取名这个)的移动是在ViewGroup的onTouchEvent方法中控制;
  • 每个UI界面都拥有独特的东西,比如子控件布局,因此我们希望用R.layout.*的方式引入;
  • 每个UI界面又都拥有相同的属性,比如都有宽度属性,滑动临界值属性,那么就可以用一个超类来封装所有相似的东西;
  • 最最重要的地方,动态计算出scrollX的值,然后用Scroller来滑动。
理清楚了结构后,我们来开始第一步的设计,也就是封装超类,首先给出代码:
/**
 * Created by ccwxf on 2016/6/14.
 */
public abstract class UI {

    protected Context context;
    //当前UI界面的布局文件
    protected View contentView;
    //当前UI界面在父控件的起点X坐标
    protected int startX;
    //当前UI界面在父控件的终点X坐标
    protected int stopX;
    //当前UI界面的宽度
    protected int width;

    protected UI(Context context, View contentView){
        this.context = context;
        this.contentView = contentView;
    }

    protected abstract void calculate(float leftScale, float rightScale);

    protected void show(Scroller mScroller){
        if(mScroller != null){
            mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), startX - mScroller.getFinalX(), 0);
        }
    }
}

这个UI超类就用于模拟每一个界面,其中主要封装了内容View的设置、跳转界面的逻辑代码,以及暴露出去需要子类实现的calculate方法,这个calculate方法主要是要计算startX、stopX、width以及各子类独有的属性。


接下来展示左菜单的实现类LeftMenuUI:
/**
 * Created by ccwxf on 2016/6/14.
 */
public class LeftMenuUI extends UI {
    // 是指要打开该UI界面所需要滚动的X坐标临界值
    public int openX;
    // 是指要关闭该UI界面所需要的滚动的X坐标临界值
    public int closeX;

    public LeftMenuUI(Context context, View contentView) {
        super(context, contentView);
    }

    @Override
    protected void calculate(float leftScale, float rightScale) {
        startX = 0;
        stopX = (int) (Util.getScreenWidth(context) * leftScale);
        this.width = stopX - startX;
        this.openX = (int) (startX + (1 - SideLayout.DEFAULT_SIDE) * this.width);
        this.closeX = (int) (startX + SideLayout.DEFAULT_SIDE * this.width);
    }

}

代码那是相当的简洁,在calculate方法中除了计算startX和stopX和width之外,还计算了openX和closeX的值。那么问题来了,此处的openX和closeX的什么东西呢?先看下图所示。


首先黑色框代表的是整个的布局,被分为了三个部分,分别是左菜单、正文内容、右菜单。红色框代表的是手机的屏幕,默认手机屏幕的宽高和正文内容的宽高都是一样的。因此图上所示是重合的。
那么问题来了,途中所示的绿色横线代表的openX和closeX分别是什么意思呢?我们假想一下,我们现在正处于正文的内容,此时手指向右滑屏,将滑出左菜单的部分,此时红框代表的屏幕就会向左移动(如果听不懂就真的需要先了解Scroller的使用哟),如果红色框移动到openX这个绿线的左边,我们就认为超出了滑动的临界值,判断为显示左菜单的操作,现在应该明白了openX的意思了吧,就是超过这个值就显示左菜单。
那么问题又来了,closeX怎么解释呢?我们再次假象一下,我们现在正处于左菜单,此时我们向左滑动屏幕,如果红色框从0开始向右移动,如果超出了closeX这个临界值,就代表我们要滑出左菜单进入正文内容,这就是closeX的意思。

好了,理解了左菜单这个类,那么正文内容和右菜单也同样好理解了。接下来给出正文类:ContentUI
public class ContentUI extends UI {

    public ContentUI(Context context, View contentView) {
        super(context, conten
  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值