android群英传学习笔记-自定义ScrollView

自定义ViewGroup通常需要重写onMeasure()、onLayout()、onTouchEvent()方法。本文实现一个继承自ScrollView的自定义ViewGroup,监听手势添加一个惯性及回弹效果。

1、首先重写onMeasure()方法来测量ViewGroup的子View,遍历ViewGroup的子View,并调用measureChild()方法进行测量。

  
  
  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  4. int count = getChildCount();
  5. for (int i = 0; i < count; ++i) {
  6. View childView = getChildAt(i);
  7. measureChild(childView,
  8. widthMeasureSpec, heightMeasureSpec);
  9. }
  10. }
2、测量完子View需要对其进行摆放,即设定子View在ViewGroup的位置。这里将子View设为全屏便于滑动操作,一般需要根据子View的属性WrapContent/FillParent来确定其布局位置。
  
  
  1. @Override
  2. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  3. int childCount = getChildCount();
  4. // 设置ViewGroup的高度
  5. MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
  6. mlp.height = mScreenHeight * childCount;
  7. setLayoutParams(mlp);
  8. for (int i = 0; i < childCount; i++) {
  9. View child = getChildAt(i);
  10. if (child.getVisibility() != View.GONE) {
  11. child.layout(l, i * mScreenHeight,
  12. r, (i + 1) * mScreenHeight);
  13. }
  14. }
  15. }

3、监听手势,重写onTouchEvent()事件

  
  
  1. @Overridepublic
  2. boolean onTouchEvent(MotionEvent event) {
  3. int y = (int) event.getY();
  4. switch (event.getAction()) {
  5. case MotionEvent.ACTION_DOWN: //手指放下,记录放下y坐标及View滑动y坐标
  6. mLastY = y;
  7. mStart = getScrollY();
  8. break;
  9. case MotionEvent.ACTION_MOVE: //手指移动,
  10. if (!mScroller.isFinished()) { //滑动动画未结束,则终止动画
  11. mScroller.abortAnimation();
  12. }
  13. int dy = mLastY - y;
  14. //若已经到顶部且手指下滑,则不进行位移动画,即到顶不允许下拉动画
  15. if (getScrollY() < 0) {
  16. dy = 0;
  17. }
  18. //到底不允许上拉动画
  19. if (getScrollY() > getHeight() - mScreenHeight) {
  20. dy = 0;
  21. }
  22. scrollBy(0, dy);//View随手势滑动
  23. mLastY = y;
  24. break;
  25. case MotionEvent.ACTION_UP://手指松开
  26. mEnd = getScrollY();
  27. int dScrollY = mEnd - mStart;
  28. if (dScrollY > 0) {//手势向上滑动
  29. if (dScrollY < mScreenHeight / 3) {//滑动距离未超过屏幕1/3,则回弹
  30. mScroller.startScroll( 0, getScrollY(), 0, -dScrollY);
  31. } else {//滑动超过1/3,继续惯性滑动剩余距离
  32. mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - dScrollY);
  33. }
  34. } else {//手势向下滑动
  35. if (-dScrollY < mScreenHeight / 3) {
  36. mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
  37. } else {
  38. mScroller.startScroll( 0, getScrollY(),0, -mScreenHeight - dScrollY);
  39. }
  40. }
  41. break;
  42. }
  43. postInvalidate();//更新UI,显示动画
  44. return true;
  45. }

4、重写computeScroll(),ViewGroup滑动到指定位置

  
  
  1. @Override
  2. public void computeScroll() {
  3. super.computeScroll();
  4. if (mScroller.computeScrollOffset()) {
  5. scrollTo(0, mScroller.getCurrY());
  6. postInvalidate();
  7. }
  8. }

5、初始化View

  
  
  1. private void initView(Context context) {
  2. WindowManager wm = (WindowManager) context.getSystemService(
  3. Context.WINDOW_SERVICE);
  4. DisplayMetrics dm = new DisplayMetrics();
  5. wm.getDefaultDisplay().getMetrics(dm);
  6. mScreenHeight = dm.heightPixels;//获取当前手机屏幕高度
  7. mScroller = new Scroller(context);//初始化Scroller辅助类
  8. }

6、startScroll方法API

  
  
  1. public void startScroll (int startX, int startY, int dx, int dy)

    以提供的起始点和将要滑动的距离开始滚动,默认持续时间250ms。控制ViewGroup的内容进行滑动而非ViewGroup本身,且dx正值表示左滑,负值表示右滑。

参数:

    startX    当前水平方向滑动偏移值,即当前ScrollY值,正值表明向左滑

    startY    当前垂直方向滑动偏移值,即当前ScrollX值,正值表明向上滑

    dx    水平方向滑动距离,正值表明向左滑动

    dy    垂直方向滑动距离,正值表明向上滑动




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值