安卓复习之旅—自定义view(二)
来源:互联网 发布:matlab for mac 2016 编辑:程序博客网 时间:2024/04/29 22:44
今天来看一下继承自ViewGroup的自定义view;看看效果先:
有点像垂直方向的viewpager吧,下面来一步一步实现它吧。
step1声明需要的一些成员变量
// 屏幕高度 private int mScreenHeight; private int mScrollStart; private int mScrollEnd; // 移动时的Y距离 private int mLastY; // 滚动辅助类 private Scroller mScroller; private boolean isScrolling; // 加速度检测 private VelocityTracker mVelocityTracker; private int currentPage = 0; private onPageChangeListener mOnPageChangeListener; private static final String TAG = "VerticalLinearLayout";
其中VelocityTracker 主要用跟踪触摸屏事件(flinging事件和其他gestures手势事件)的速率。用addMovement( MotionEvent)函数将Motion event加入到VelocityTracker类实例中.你可以使用getXVelocity() 或getXVelocity()获得横向和竖向的速率到速率时,但是使用它们之前请先调用computeCurrentVelocity(int) 来初始化速率的单位 。
onPageChangeListener 是自定义的回调接口
/** * 设置回调接口 */ public void SetOnPageChangeListener(onPageChangeListener listener) { this.mOnPageChangeListener = listener; } public interface onPageChangeListener { void onPageChange(int currentPage); }
step2 在构造方法中初始化成员变量
// 获取屏幕的高度 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(dm); mScreenHeight = dm.heightPixels; Log.e(TAG, "mScreenHeight= " + mScreenHeight); mScroller = new Scroller(context);
step3在onMeasure()方法中计算每个子view的尺寸
int count = getChildCount(); for (int i = 0; i < count; i++) { Log.e(TAG, "count= " + count); View childView = getChildAt(i); measureChild(childView, widthMeasureSpec, heightMeasureSpec); }
step4在onLayout()中确定子view的位置
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub if (changed) { int count = getChildCount(); // 设置主布局的高度 MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams(); mlp.height = mScreenHeight * count; setLayoutParams(mlp); // 设置每个子布局的位置 for (int i = 0; i < count; i++) { View childView = getChildAt(i); if (childView.getVisibility() != View.GONE) { childView.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight); } } } }
onLayout的几个参数说明: 1)参数changed表示view有新的尺寸或位置; 2)参数l表示相对于父view的Left位置; 3)参数t表示相对于父view的Top位置; 4)参数r表示相对于父view的Right位置; 5)参数b表示相对于父view的Bottom位置。.
MarginLayoutParams是继承自ViewGroup.LayoutParams
子类有 FrameLayout.LayoutParams,LinearLayout.LayoutParams, RelativeLayout.LayoutParams
step5 处理触摸事件
// 如果正在滑动,不做处理,调用父类的触摸事件 Log.e(TAG, "isScrolling=" + isScrolling); if (isScrolling) { return super.onTouchEvent(event); } initVelocityTracker(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // Return the scrolled top position of this view mScrollStart = getScrollY(); mLastY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: if (!mScroller.isFinished()) { // Stops the animation. mScroller.abortAnimation(); } int dy = mLastY - (int) event.getY(); int scrollY = getScrollY(); // 已经到达顶端 if (dy < 0 && scrollY + dy < 0) { dy = -scrollY;//此时dy=0 } // 已经到达底部 if (dy > 0 && scrollY + dy > getHeight() - mScreenHeight) { dy = getHeight() - mScreenHeight - scrollY;//此时dy=0 } scrollBy(0, dy); mLastY = (int) event.getY(); break; case MotionEvent.ACTION_UP: mScrollEnd = getScrollY(); Log.e(TAG, "mScrollStart=" + mScrollStart); Log.e(TAG, "mScrollEnd=" + mScrollEnd); int dScrollY = mScrollEnd - mScrollStart; if (dScrollY > 0) {// 往上滑动 if (shouldScrollToNext(dScrollY)) { mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - dScrollY); } else { mScroller.startScroll(0, getScrollY(), 0, -dScrollY); } } else {// 往上滑 if (shouldScrollToPre(dScrollY)) { mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight - dScrollY); } else { mScroller.startScroll(0, getScrollY(), 0, -dScrollY); } } isScrolling = true; postInvalidate(); //回收资源 recycleVelocity(); break; } return true;
step6需要重写computeScroll()方法
为了易于控制滑屏控制,Android框架提供了 computeScroll()方法去控制这个流程。在绘制View时,会在draw()过程调用该 方法。因此, 再配合使用Scroller实例,我们就可以获得当前应该的偏移坐,手动使View/ViewGroup偏移至该处。
@Override public void computeScroll() { // TODO Auto-generated method stub super.computeScroll(); // If it returns true, the animation is not yet finished.\ Log.e(TAG, "mScroller.computeScrollOffset()=" + mScroller.computeScrollOffset()); if (mScroller.computeScrollOffset()) {// 滑动结束的时候调用scrollTo() scrollTo(0, mScroller.getCurrY()); postInvalidate(); } else { int position = getScrollY() / mScreenHeight; Log.e(TAG, "position=" + position + ",currentPage=" + currentPage); if (position != currentPage) { if (mOnPageChangeListener != null) { currentPage = position; mOnPageChangeListener.onPageChange(currentPage); } } isScrolling = false; } }
一些小方法:
/** * 释放资源 */ private void recycleVelocity() { // TODO Auto-generated method stub if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } /** * 初始化加速度追踪器 * * @param event */ private void initVelocityTracker(MotionEvent event) { // TODO Auto-generated method stub if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); } /** * 滑动到下一页 * * @param dScrollY * @return */ private boolean shouldScrollToNext(int dScrollY) { // TODO Auto-generated method stub return dScrollY > mScreenHeight / 2 || Math.abs(getVelocity()) > 600; } /** * 滑动到上一页 * * @param dScrollY * @return */ private boolean shouldScrollToPre(int dScrollY) { // TODO Auto-generated method stub return -dScrollY > mScreenHeight / 2 || Math.abs(getVelocity()) > 600; } /** * 获取Y方向的加速度 * @return */ private double getVelocity() { // TODO Auto-generated method stub mVelocityTracker.computeCurrentVelocity(1000); return (int) mVelocityTracker.getYVelocity(); }
至此,基本工作就完成了;
看看MainActivity
mMianLayout = (VerticalLinearLayout) findViewById(R.id.id_main_ly); mMianLayout.SetOnPageChangeListener(this); @Override public void onPageChange(int currentPage) { // TODO Auto-generated method stub Toast.makeText(MainActivity.this, "第" + (currentPage + 1) + "页", Toast.LENGTH_SHORT).show(); }
下载地址:http://download.csdn.net/my
- 安卓复习之旅—自定义view(二)
- 安卓复习之旅—自定义view(一)
- 安卓复习之旅—工厂模式(二)
- 安卓开发中自定义View之onMeasure(),onLayout(),onDraw()讲解(二)
- 安卓复习之旅—View的工作流程1
- 安卓复习之旅—View的工作流程2
- android复习之自定义View
- 安卓之自定义view实现索引
- 安卓进阶之自定义View
- 安卓自定义View之进步曲线
- 安卓面试之=》自定义View
- 安卓自定义View之画图
- 安卓开发-自定义view(二)-自定义属性
- 自定义View(二)之自定义属性
- 安卓自定义View
- 安卓自定义view
- 安卓自定义View
- 安卓自定义View
- Canvas之粒子动画
- MyBatis学习总结(五)——实现关联表查询
- 我的2016——小程序员的碎碎念
- matplot 绘制图例和标注
- Coursera-ML:Week1-Octave/Matlab Tutorial
- 安卓复习之旅—自定义view(二)
- Android音频开发之使用OpenSL ES API
- ReactiveCocoa入门教程二
- 关于R与Tableau的集成----异常值检测
- 计算机是如何启动的
- jQuery AJAX实现调用页面后台方法
- Service服务:下载图片
- python中array和list的区别
- Java虚拟机-JVM各种参数配置大全详细