安卓侧边 4000 栏实现
2016-06-01 15:31
369 查看
安卓侧滑布局实现
来,先上效果图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); c5c9 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>
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories