仿写第三篇之仿写scrollview
来源:互联网 发布:nginx 日志配置 编辑:程序博客网 时间:2024/04/29 08:15
前言
读完自定义viewgroup实践之仿写LinearLayout和自定义虚线两篇文章,相信你对自定义view和自定义viewgroup有一定的了解了。今天带大家实现垂直滚动的viewgroup。
对scrollview滚动原理的思考:首先scrollview有子view,所以其必是一个viewgroup。而其可上下滚动,这就说明肯定是在onTouchEvent方法中调了scrollTo或scrollBy方法。
好了,知道了其骨架。接下来看源码进一步分析:
1.看继承关系:
scrollview继承自framelayout,既然是viewgroup子孙,那么重要的也就是onmeasure、onlayou和LayoutParam了。看scrollview的addview()方法:
@Override public void addView(View child, ViewGroup.LayoutParams params) { if (getChildCount() > 0) { throw new IllegalStateException("ScrollView can host only one direct child"); } super.addView(child, params); }它没写自己的LayoutParam,用的是viewgroup的LayoutParam。所以我写的也就没写LayoutParam。
2.onMeasure()
其首先调用父类的onmeasure方法。由于是framelayout,其measure子view时调用了measureChildWithMargins方法,而scrollview重写了该方法。看重写代码:
@Override protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( lp.topMargin + lp.bottomMargin, MeasureSpec.UNSPECIFIED); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
其给子view的childHeightMeasureSpec 是以 MeasureSpec.UNSPECIFIED生成的。所以子view想要多高就可以多高。说个题外话,平常我们测量一个view的宽高时总是这样调用view.measure(0,0),而MeasureSpec.UNSPECIFIED的值就是0,也就是测量view有多大就多大,调用后就可以getMeasuredWidth和getMeasuredHeight获取宽高。
3.onlayout方法
由于其只有一个子view,也就是linearlayout,所以super.onLayout(changed, l, t, r, b),这里没啥可说的。
接下来是核心部分:
onInterceptTouchEvent ------- true为截取事件,该方法返回的是mIsBeingDragged,
我们依据事件的整个过程来说明,首先触发ACTION_DOWN事件,如果还在滚动,则mIsBeingDragged为true。在ACTION_MOVE中,如果y方向的偏移大于了mTouchSlop(滚动之前可以滑动的距离),则mIsBeingDragged为true。
在滚动中了
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { return true; }最后ACTION_UP,mIsBeingDragged为false。
onTouchEvent------ 具体的滚动逻辑在其中
@Override protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { // Treat animating scrolls differently; see #computeScroll() for why. if (!mScroller.isFinished()) { final int oldX = mScrollX; final int oldY = mScrollY; mScrollX = scrollX; mScrollY = scrollY; invalidateParentIfNeeded(); onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (clampedY) { mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange()); } } else { super.scrollTo(scrollX, scrollY); } awakenScrollBars(); }也就是其调用了scrollTo方法。
flying --- 其中使用了scroller
public void fling(int velocityY) { if (getChildCount() > 0) { int height = getHeight() - mPaddingBottom - mPaddingTop; int bottom = getChildAt(0).getHeight(); mScroller.fling(mScrollX, mScrollY, 0, velocityY, 0, 0, 0, Math.max(0, bottom - height), 0, height/2); if (mFlingStrictSpan == null) { mFlingStrictSpan = StrictMode.enterCriticalSpan("ScrollView-fling"); } postInvalidateOnAnimation(); } }而view重绘时会调用computeScroll()方法。computeScroll一般与scroller一起使用,不熟悉的百度。
- 仿写第三篇之仿写scrollview
- Hadoop之仿写搜索引擎
- 仿写“同行说”之界面分析篇
- struts2源码之仿写struts2
- 自定义viewgroup实践之仿写LinearLayout
- 仿写复杂页面之学习心得
- android之仿豆瓣写日志
- web前端之百度首页仿写
- web前端之千牛网首页仿写
- 可变参数之仿写printf函数
- 仿写cp命令
- java仿写计算器
- 古文仿写:桂娘传
- wxpython仿写记事本
- 仿写strcmp函数
- 仿写jquery
- ActionSheetDialog仿写
- 仿写礼物说
- 指针与引用
- centos 7 virtualbox guest additions installation centos minimal
- Logistic回归模型的Python及C++实现
- 第十六篇 休闲的星期一
- 动作源码分析2Classes/ui/MainInterfaceUI.cpp
- 仿写第三篇之仿写scrollview
- UVa 1220 Party at Hali-Bula
- keras中的优化算法
- SQL 拼接多个字段的值&一个字段多条记录的拼接
- MEF装载dll
- week14----6月2日
- VirtualBox在CentOS中安装VBOXADDITIONS出现Building the OpenGL support module FAILED
- 12个有趣的C语言面试题
- 单例模式