scrollTo,scrollBy
程序员文章站
2022-05-05 08:55:03
...
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
/**
* Used to indicate that the parent of this view should clear its caches. This functionality
* is used to force the parent to rebuild its display list (when hardware-accelerated),
* which is necessary when various parent-managed properties of the view change, such as
* alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only
* clears the parent caches and does not causes an invalidate event.
*
* @hide
*/
//父容器清楚它的缓存,这个方法强制父容器重建显示列表(使用硬件加速的情况下)。
//该功能是必须的,让有View属性改变时
//例如 alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y.
//该方法智慧清楚父类换曾,不会引起重绘操作
invalidateParentCaches();
//滚动时调用监听
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
//核心代码1
//
//
if (!awakenScrollBars()) {
//核心代码2
//
//
postInvalidateOnAnimation();
}
}
}
从中我们可以发现scrollBy调用scrollTo,且scrollTo会记录原来的位置坐标,如果位置参数一样每次调用都会不执行操作,而scrollBy会累加位置坐标。
用法总结
scrollTo移动到某位置,scrollBy 移动多少位置。
PS:
这就和英语中To 和By的用法一样
reduce the price to 2 yuan 降到2元
reduce the price by 2 yuan 降低了2元
我们接着看源码核心代码1的源码
protected boolean awakenScrollBars() {
return mScrollCache != null &&
awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true);
}
protected boolean awakenScrollBars(int startDelay, boolean invalidate) {
final ScrollabilityCache scrollCache = mScrollCache;
if (scrollCache == null || !scrollCache.fadeScrollBars) {
return false;
}
if (scrollCache.scrollBar == null) {
scrollCache.scrollBar = new ScrollBarDrawable();
scrollCache.scrollBar.setState(getDrawableState());
scrollCache.scrollBar.setCallback(this);
}
if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) {
if (invalidate) {
// Invalidate to show the scrollbars
postInvalidateOnAnimation();
}
if (scrollCache.state == ScrollabilityCache.OFF) {
// FIXME: this is copied from WindowManagerService.
// We should get this value from the system when it
// is possible to do so.
final int KEY_REPEAT_FIRST_DELAY = 750;
startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay);
}
// Tell mScrollCache when we should start fading. This may
// extend the fade start time if one was already scheduled
long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay;
scrollCache.fadeStartTime = fadeStartTime;
scrollCache.state = ScrollabilityCache.ON;
// Schedule our fader to run, unscheduling any old ones first
if (mAttachInfo != null) {
mAttachInfo.mHandler.removeCallbacks(scrollCache);
mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime);
}
return true;
}
return false;
}
你会发现,如果需要绘制scrollBar会调用postInvalidateOnAnimation 函数返回true,之后跳过最外层的postInvalidateOnAnimation的调用,如果不需要绘制scrollBar直接返回false,反而调用最外层的postInvalidateOnAnimation。
所以最后都会调用postInvalidateOnAnimation函数
public void postInvalidateOnAnimation() {
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this);
}
}
最后我们会看见调用mViewRootImpl的dispatchInvalidateOnAnimation函数,这个mViewRootImpl学过View绘制流程的人都知道,他是控制着根View,且把要移动的View当参数传递进去。现在来看ViewRootImpl类。
public void dispatchInvalidateOnAnimation(View view) {
mInvalidateOnAnimationRunnable.addView(view);
}
final InvalidateOnAnimationRunnable mInvalidateOnAnimationRunnable =
new InvalidateOnAnimationRunnable();
final class InvalidateOnAnimationRunnable implements Runnable {
private boolean mPosted;
//mViews 是一个数组,存储着需要滚动的View
private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<AttachInfo.InvalidateInfo> mViewRects =
new ArrayList<AttachInfo.InvalidateInfo>();
private View[] mTempViews;
private AttachInfo.InvalidateInfo[] mTempViewRects;
public void addView(View view) {
synchronized (this) {
mViews.add(view);
postIfNeededLocked();
}
}
//。。。。
@Override
public void run() {
final int viewCount;
final int viewRectCount;
synchronized (this) {
mPosted = false;
viewCount = mViews.size();
if (viewCount != 0) {
mTempViews = mViews.toArray(mTempViews != null
? mTempViews : new View[viewCount]);
mViews.clear();
}
viewRectCount = mViewRects.size();
if (viewRectCount != 0) {
mTempViewRects = mViewRects.toArray(mTempViewRects != null
? mTempViewRects : new AttachInfo.InvalidateInfo[viewRectCount]);
mViewRects.clear();
}
}
//核心代码
//
//
for (int i = 0; i < viewCount; i++) {
mTempViews[i].invalidate();
mTempViews[i] = null;
}
for (int i = 0; i < viewRectCount; i++) {
final View.AttachInfo.InvalidateInfo info = mTempViewRects[i];
info.target.invalidate(info.left, info.top, info.right, info.bottom);
info.recycle();
}
}
private void postIfNeededLocked() {
//mPosted初始值是false,这里保证该方法只被执行一次.再run方法执行之后会被重新赋值成false.
if (!mPosted) {
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
mPosted = true;
}
}
}
mViews时一个数组,存储着需要被滚动的View,拖过异步消息,最后UI线程会进行跟新,通过invalidate方法。
这个方法最终会进行组建的测量,布局,绘制过程。
上一篇: 锤子子弹短信中如何打开悬浮球?子弹短信打开全局悬浮球的方法
下一篇: Java8排序
推荐阅读
-
支持scrollTo的RecycleView
-
scrollTo不起作用
-
Android getScrollX() 、scrollBy()、 scrollTo() 、getX、getRawX、getTranslationX等的图形表示
-
scroll(),scrollTop(),scrollBy()无效问题的总结
-
mui scrollTo到指定位置,出现空白页及拉不动的问题解决
-
Window scrollTo() 方法
-
Window scrollBy() 方法
-
Ext、js中定位跳转scrollTo的兼容写法
-
jQuery定位跳转插件(jquery.scrollto.js)
-
scrollTo、scrollBy、smoothScrollTo和smoothScrollBy