安卓侧边栏实现

原创 2016年06月01日 15:31:26

安卓侧滑布局实现

来,先上效果图
这里写图片描述

package xiaolin.widget;

import android.content.Context;;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

import xiaolin.utils.Utils;

/**
 * 只有平移效果的侧边栏
 * Created by XiaoLin on 2016/1/14.
 */
public class ATranslationLayout extends ViewGroup {

    public static final String TAG = "ATranslationLayout";
    private static final int MININERCEPTXVILOCITY = 8;   // 最小拦截速度(dp)
    private static final int MINTOUCHVILOCITY = 300;     // 最小触发速度(dp)
    private static final float drawerTime = 2.5f;       // 动画时间

    private Scroller mScroller = null;
    private VelocityTracker mVelocity = null;
    private OnTranslationListener mOnTranslationListener = null;

    private boolean isTouchRight = false;
    private boolean isBeingDragged = false;
    private boolean isUnableToDragged = false;
    private PointF mLastInterceptPointF = new PointF();
    private float mLastTouchX = 0;
    private float mFirstTouchX = 0;

    protected int menuWidth = 0;                    // 菜单宽度
    protected boolean mIsOpenMenu = false;       // 是否显示菜单
    protected boolean isDraggedToRight = false;            // 是否向右边移动

    public ATranslationLayout(Context context) {
        super(context);
        init();
    }

    public ATranslationLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ATranslationLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mScroller = new Scroller(getContext());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width, height);
        menuWidth = (int) (width * 0.75f);         // 菜单宽度
        int childCount = getChildCount();
        if (childCount == 0) {
            return;
        }
        View menuView = getChildAt(0);
        // 合成菜单的测量宽度
        int menuWidthSpec = MeasureSpec.makeMeasureSpec(menuWidth, MeasureSpec.EXACTLY);
        int menuheightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
        menuView.measure(menuWidthSpec, menuheightSpec);
        for (int i = 1; i < childCount; i++) {
            View childView1 = getChildAt(i);
            childView1.measure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        if (childCount == 0) {
            return;
        }
        View menuView = getChildAt(0);
        // 设置子视图的位置,左上角坐标,宽高
        menuView.layout(-menuView.getMeasuredWidth(), 0, 0, menuView.getMeasuredHeight());

        int left = 0;
        for (int i = 1; i < childCount; i++) {
            View childView = getChildAt(i);
            int w = childView.getMeasuredWidth();
            childView.layout(left, 0, left + w, childView.getMeasuredHeight());
            left += w;
        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            int x = mScroller.getCurrX();
            scrollTo(x, 0);
            // 调用invalidate()无效
            postInvalidate();
            if (mOnTranslationListener != null) {
                mOnTranslationListener.progress(isDraggedToRight, -x / (float)menuWidth);
            }
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        int action = event.getAction();
        PointF pointF = new PointF(event.getX(), event.getY());
        if (action != 0) {
            if (isBeingDragged) {
                return true;
            }
            if (isUnableToDragged) {
                return false;
            }
        }
        if (action == MotionEvent.ACTION_DOWN) {
            mLastInterceptPointF.set(pointF);
            isBeingDragged = false;
            isUnableToDragged = false;
            if(mScroller.isFinished()){
                isDraggedToRight = !isOpenMenu();
            }
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
                return true;
            } else if (mIsOpenMenu) {
                if (event.getX() > menuWidth) {
                    isBeingDragged = true;
                }
            }
        } else if (action == MotionEvent.ACTION_MOVE) {
            float dx = Math.abs(pointF.x - mLastInterceptPointF.x);
            float dy = Math.abs(pointF.y - mLastInterceptPointF.y);
            if (dy > dx) {  // 上下滑动
                isUnableToDragged = true;
            } else if (pointF.x < mLastInterceptPointF.x && !mIsOpenMenu) { // 往左滑动&&已关窗
                isUnableToDragged = true;
            } else if (pointF.x > mLastInterceptPointF.y && mIsOpenMenu) {    // 往右滑动&&已开窗
                isUnableToDragged = true;
            } else if (dx > dy && dx > Utils.dpToPx(MININERCEPTXVILOCITY, getResources())) {  // 往右并且大于一定速度
                isBeingDragged = true;
            }
            mLastInterceptPointF.x = pointF.x;
            mLastInterceptPointF.y = pointF.y;
        }
        return isBeingDragged;
    }

    // 触摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        float x = event.getX();
        if (mVelocity == null) {
            mVelocity = VelocityTracker.obtain();
            mLastTouchX = x;
            if (mIsOpenMenu && x > menuWidth) {
                isTouchRight = true;
                mFirstTouchX = x;
            } else {
                isTouchRight = false;
            }
        }
        mVelocity.addMovement(event);
        if (action == MotionEvent.ACTION_DOWN) {// 可能无此动作

        } else if (action == MotionEvent.ACTION_MOVE) { // 正在滑动
            float dx = x - mLastTouchX;
            drawerViewBy((int) dx);
            mLastTouchX = x;
        } else if (action == MotionEvent.ACTION_UP) {
            if (isTouchRight && mFirstTouchX == x) {
                openMenu(false);
                mVelocity.recycle();
                mVelocity = null;
                return true;
            } else {
                mVelocity.computeCurrentVelocity(1000);
                if (mVelocity.getXVelocity() < -Utils.dpToPx(MINTOUCHVILOCITY, getResources())) {
                    openMenu(false);
                } else if (mVelocity.getXVelocity() > Utils.dpToPx(MININERCEPTXVILOCITY, getResources())) {
                    openMenu(true);
                } else {
                    if (-getScrollX() > menuWidth / 2) {
                        openMenu(true);
                    } else {
                        openMenu(false);
                    }
                }
                mVelocity.recycle();
                mVelocity = null;
            }
        }
        return true;
    }

    // 按键监听
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        int code = event.getKeyCode();
        int action = event.getAction();
        if (code == KeyEvent.KEYCODE_BACK && action == KeyEvent.ACTION_UP) {
            if (mIsOpenMenu) {
                openMenu(false);
                return true;
            }
        }
        return super.dispatchKeyEvent(event);
    }

    // 滚动距离并判断范围
    protected void drawerViewBy(int dx) {
        dx = -dx;
        int x = getScrollX();
        if (x + dx > 0) {
            scrollTo(0, 0);
        } else if (x + dx < -menuWidth) {
            scrollTo(-menuWidth, 0);
        } else {
            scrollTo(x + dx, 0);
        }
        if (mOnTranslationListener != null) {
            mOnTranslationListener.progress(isDraggedToRight, -getScrollX() / (float) menuWidth);
        }
    }

    public void openMenu(Boolean isOpen) {
        mIsOpenMenu = isOpen;
        int x = getScrollX();
        if (isOpen) {
            int time = (int) (Math.abs(-menuWidth - x) / Utils.dpToPx(1f, getResources()) * drawerTime);
            mScroller.startScroll(x, 0, -menuWidth - x, 0, time);
            if (x == 0) {
                isDraggedToRight = true;
            }
        } else {
            int time = (int) (Math.abs(x) / Utils.dpToPx(1f, getResources()) * drawerTime);
            mScroller.startScroll(x, 0, -x, 0, time);
            if (x == -menuWidth) {
                isDraggedToRight = false;
            }
        }
        if (mOnTranslationListener != null) {
            mOnTranslationListener.fold(mIsOpenMenu);
        }
        postInvalidate();
    }

    // 是打开菜单
    public boolean isOpenMenu() {
        return mIsOpenMenu;
    }

    // 设置监听
    public void setFoldingListener(OnTranslationListener listener) {
        this.mOnTranslationListener = listener;
    }

    // 监听接口
    public interface OnTranslationListener {
        void fold(boolean isOpen);
        void progress(boolean isToRight, float progress);// 0.0f-1.0f
    }

}

package xiaolin.utils;

import android.content.res.Resources;
import android.util.TypedValue;

/**
 * Created by Administrator on 2016/1/17.
 */
public class Utils {

    /**
     * dp转为像素
     * @param dp
     * @param resources
     * @return
     */
    public static float dpToPx(float dp, Resources resources){
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.getDisplayMetrics());
    }
}


然后只要在xml里使用就行了,里面放的是侧边的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#cacaca">

    <xiaolin.widget.ATranslationLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/bg" />

    </xiaolin.widget.ATranslationLayout>

</LinearLayout>

效果图在上面

如果里面添加两个布局的话就会变成这样

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#cacaca">

    <xiaolin.widget.ATranslationLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/bg" />

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/img_bg"
            android:scaleType="centerCrop"/>

    </xiaolin.widget.ATranslationLayout>

</LinearLayout>

这里写图片描述
这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

Android开发--滑动侧边栏的实现

在Android应用开发中,滑动侧边栏经常使用,今天我也试着自己进行了一个简单的实践,虽然功能还不是很强大,但是可以保留下来为以后的开发使用,有需要时在进行简单的修改。实现一个滑动侧边栏思路也很简单:...
  • smbroe
  • smbroe
  • 2014年12月29日 10:35
  • 1961

Android学习之基于DrawerLayout的侧边栏实现

Android基于DrawerLayout的侧边栏实现
  • u012527802
  • u012527802
  • 2017年07月14日 11:15
  • 1665

Android 侧边栏

简介侧边栏,又叫侧滑菜单,又叫抽屉菜单,一般用于导航功能,侧边滑入或者从标题栏导航图标进入。跟据google设计建议,左侧边栏一般用于app导航,右侧边栏用于操作当前页面内容。 侧边栏由两个部分组成...
  • crazyman2010
  • crazyman2010
  • 2016年08月31日 17:49
  • 1012

Android侧边栏的自定义滑动实现(附源码)

本文要实现手指在手机上向左或向右移动时,能相应的移动左右两个视图。通过自定义来实现,不借助第三方插件。实现的思路很简单,通过判断手指滑动的距离和速度来决定是否要滚动显示菜单项。...
  • Evankaka
  • Evankaka
  • 2015年02月16日 13:14
  • 6977

android 滑动侧边栏 SlideMenu

还是先看效果图      支持点击按钮打开侧边栏,同时支持手势打开或是关闭侧边栏。 选择继承ViewGroup来实现。 首先是考虑子view的布局,其实就是怎样重写onLayout方法。 1...
  • luck_apple
  • luck_apple
  • 2013年06月30日 16:20
  • 48408

Android Studio精彩案例(四)《DrawerLayout使用详解仿网易新闻客户端侧边栏 》

转载本专栏文章,请注明出处,尊重原创 。文章博客地址:道龙的博客侧拉菜单在Android应用中非常常见,它的实现方式太多了,今天我们就说说使用Google提供的DrawerLayout来实现侧拉菜单效...
  • qq_32059827
  • qq_32059827
  • 2016年12月14日 22:44
  • 2421

Android侧边栏

http://blog.csdn.net/yangyu20121224/article/details/9258275 通过上一篇文章的讲解,相信大家对于开源项目SlidingMenu都有了...
  • h3c4lenovo
  • h3c4lenovo
  • 2013年07月10日 21:01
  • 22093

Android开发—Navigation Drawer(侧边栏菜单实现)

学习来源:Navigation Draw描述: http://developer.android.com/design/patterns/navigation-drawer.html         ...
  • very_caiing
  • very_caiing
  • 2014年12月10日 22:37
  • 31282

android学习之warmshowers学习——侧边栏切换实现

android学习之warmshowers学习——侧边栏切换实现
  • hoffman_n
  • hoffman_n
  • 2016年11月16日 23:18
  • 478

Android实现仿qq侧边栏效果

最近从github上看到一个关于侧边栏的项目,模仿的是qq侧边栏。这个项目是一个android studio项目,可以导入android studio中,也可以导入到Eclipse中。其中的Resid...
  • JerehEdu
  • JerehEdu
  • 2015年05月18日 14:41
  • 2376
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:安卓侧边栏实现
举报原因:
原因补充:

(最多只允许输入30个字)