android 动画滚动条,Android   Animation(一)

a4c26d1e5885305701be709a3d33442f.png动画的绘制原理

Android的动画是通过View绘制来实现的,通过对不同时刻View的绘制,实现动画的效果。

在View绘制过程中通过变换Tranformation控制View的位置,缩放等。Animation对象规定了动画的变换

规则,animation对象本身不进行动画的绘制,只会提供动画所需要的变换信息、进度信息等

a4c26d1e5885305701be709a3d33442f.pngView制步骤:

背景绘制

是否有fadingedge,保存edge layer

绘制自身 onDraw

绘制子View dispatchDraw

绘制fading 效果

附属绘制,滚动条等

public void draw(Canvas canvas) {

if (ViewDebug.TRACE_HIERARCHY) {

ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);

}

final int privateFlags =

mPrivateFlags;

final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) ==

DIRTY_OPAQUE &&

(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);

mPrivateFlags = (privateFlags & ~DIRTY_MASK) | DRAWN;

// Step 1, draw the background, if

needed

int saveCount;

if (!dirtyOpaque) {

final Drawable background = mBGDrawable;

if (background != null) {

final int scrollX = mScrollX;

final int scrollY = mScrollY;

if (mBackgroundSizeChanged) {

background.setBounds(0, 0, mRight - mLeft,

mBottom - mTop);

mBackgroundSizeChanged = false;

}

if ((scrollX | scrollY) == 0) {

background.draw(canvas);

} else {

canvas.translate(scrollX, scrollY); background.draw(canvas);

canvas.translate(-scrollX, -scrollY);

//和save restore功能一样???

}

}

}

// skip step 2 & 5 if possible

(common case)

final int viewFlags = mViewFlags;

boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL)

!= 0;

boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) !=

0;

if (!verticalEdges && !horizontalEdges) {

// Step 3, draw the content

if (!dirtyOpaque) onDraw(canvas);

// Step 4, draw the children

dispatchDraw(canvas);

// Step 6, draw decorations

(scrollbars)

onDrawScrollBars(canvas);

// we're done...

return;

}

boolean drawTop = false;

boolean drawBottom = false;

boolean drawLeft = false;

boolean drawRight = false;

float topFadeStrength = 0.0f;

float bottomFadeStrength = 0.0f;

float leftFadeStrength = 0.0f;

float rightFadeStrength = 0.0f;

// Step 2, save the canvas'

layers

int paddingLeft = mPaddingLeft;

int paddingTop = mPaddingTop;

final boolean offsetRequired =

isPaddingOffsetRequired();

if (offsetRequired) {

paddingLeft += getLeftPaddingOffset();

paddingTop += getTopPaddingOffset();

}

int left = mScrollX +

paddingLeft;

int right = left + mRight - mLeft - mPaddingRight -

paddingLeft;

int top = mScrollY + paddingTop;

int bottom = top + mBottom - mTop - mPaddingBottom -

paddingTop;

if (offsetRequired) {

right += getRightPaddingOffset();

bottom += getBottomPaddingOffset();

}

final ScrollabilityCache

scrollabilityCache = mScrollCache;

int length = scrollabilityCache.fadingEdgeLength;

// clip the fade length if top and

bottom fades overlap

// overlapping fades produce odd-looking artifacts

if (verticalEdges && (top + length > bottom - length))

{

length = (bottom - top) / 2;

}

// also clip horizontal fades if

necessary

if (horizontalEdges && (left + length > right - length))

{

length = (right - left) / 2;

}

if (verticalEdges) {

topFadeStrength = Math.max(0.0f, Math.min(1.0f,

getTopFadingEdgeStrength()));

drawTop = topFadeStrength >= 0.0f;

bottomFadeStrength = Math.max(0.0f, Math.min(1.0f,

getBottomFadingEdgeStrength()));

drawBottom = bottomFadeStrength >= 0.0f;

}

if (horizontalEdges) {

leftFadeStrength = Math.max(0.0f, Math.min(1.0f,

getLeftFadingEdgeStrength()));

drawLeft = leftFadeStrength >= 0.0f;

rightFadeStrength = Math.max(0.0f, Math.min(1.0f,

getRightFadingEdgeStrength()));

drawRight = rightFadeStrength >= 0.0f;

}

saveCount = canvas.getSaveCount();

int solidColor = getSolidColor();

if (solidColor == 0) {

final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;

//有一句会执行??????

if (drawTop) {

canvas.saveLayer(left, top, right, top + length, null,

flags);

}

if (drawBottom) {

canvas.saveLayer(left, bottom - length, right, bottom, null,

flags);

}

if (drawLeft) {

canvas.saveLayer(left, top, left + length, bottom, null,

flags);

}

if (drawRight) {

canvas.saveLayer(right - length, top, right, bottom, null,

flags);

} } else {

scrollabilityCache.setFadeColor(solidColor);

}

// Step 3, draw the content

if (!dirtyOpaque) onDraw(canvas);

// Step 4, draw the children

dispatchDraw(canvas);

// Step 5, draw the fade effect and

restore layers

final Paint p = scrollabilityCache.paint;

final Matrix matrix = scrollabilityCache.matrix;

final Shader fade = scrollabilityCache.shader;

final float fadeHeight = scrollabilityCache.fadingEdgeLength;

if (drawTop) {

matrix.setScale(1, fadeHeight * topFadeStrength);

matrix.postTranslate(left, top);

fade.setLocalMatrix(matrix);

canvas.drawRect(left, top, right, top + length, p);

}

if (drawBottom) {

matrix.setScale(1, fadeHeight * bottomFadeStrength);

matrix.postRotate(180);

matrix.postTranslate(left, bottom);

fade.setLocalMatrix(matrix);

canvas.drawRect(left, bottom - length, right, bottom, p);

}

if (drawLeft) {

matrix.setScale(1, fadeHeight * leftFadeStrength);

matrix.postRotate(-90);

matrix.postTranslate(left, top);

fade.setLocalMatrix(matrix);

canvas.drawRect(left, top, left + length, bottom, p);

}

if (drawRight) {

matrix.setScale(1, fadeHeight * rightFadeStrength);

matrix.postRotate(90);

matrix.postTranslate(right, top);

fade.setLocalMatrix(matrix);

canvas.drawRect(right - length, top, right, bottom, p);

}

canvas.restoreToCount(saveCount);

// Step 6, draw decorations

(scrollbars)

onDrawScrollBars(canvas);

}

a4c26d1e5885305701be709a3d33442f.pngViewGroup

dispatchDraw

1、LayoutAnimation绘制

LayoutAnimationController文档

A layout

animation controller is used to animated a layout's, or a

view

* group's, children. Each child uses the same

animation but for every one of

* them, the animation starts at a different

time. A layout animation controller

* is used by {@link

android.view.ViewGroup} to compute the delay by which each

* child's animation start must be offset. The

delay is computed by using

* characteristics of each child, like its index

in the view group.

*

* This standard implementation computes the delay

by multiplying a fixed

* amount of miliseconds by the index of the child

in its parent view group.

* Subclasses are supposed to override

* {@link

#getDelayForView(android.view.View)} to implement a different

way

* of computing the delay. For instance, a

* {@link

android.view.animation.GridLayoutAnimationController} will compute

the

* delay based on the column and row indices of

the child in its parent view

* group.

*

* Information used to

compute the animation delay of each child are stored

* in an instance of

* {@link android.view.animation.LayoutAnimationController.AnimationParameters},

* itself stored in the {@link

android.view.ViewGroup.LayoutParams} of the

vi

2、DrawChild

protected void dispatchDraw(Canvas

canvas) {

final int count = mChildrenCount;

final View[] children = mChildren;

int flags = mGroupFlags;

if ((flags & FLAG_RUN_ANIMATION) !=

0 && canAnimate()) {

final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) ==

FLAG_ANIMATION_CACHE;

for (int i = 0; i < count; i++)

{

final View child = children[i];

if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {

final LayoutParams params =

child.getLayoutParams();

//设置params的layoutAnimationParameters属性

//LayoutAnimationController.AnimationParameters用于存储计算偏移时间的参数index和count

//LayoutAnimationController.AnimationParameters对象本身保存在View的LayoutParams 中,即

//layoutAnimationParameters属性 attachLayoutAnimationParameters(child,

params, i, count);

//为子View设置动画child.setAnimation bindLayoutAnimation(child); if (cache) {

child.setDrawingCacheEnabled(true);

child.buildDrawingCache(true);

}

}

}

final LayoutAnimationController

controller = mLayoutAnimationController;

if (controller.willOverlap()) {

mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;

}

//调用Animation.setStartTime

//When this animation should start. When the start time is set

to

//

{@link

#START_ON_FIRST_FRAME}, the animation will

start the first time

//

{@link

#getTransformation(long, Transformation)} is

invoked

controller.start();

mGroupFlags &=

~FLAG_RUN_ANIMATION;

mGroupFlags &= ~FLAG_ANIMATION_DONE;

if (cache) {

mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;

}

if (mAnimationListener != null) {

mAnimationListener.onAnimationStart(controller.getAnimation());

}

}

int saveCount = 0;

final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) ==

CLIP_TO_PADDING_MASK;

if (clipToPadding) {

saveCount = canvas.save();

canvas.clipRect(mScrollX + mPaddingLeft, mScrollY +

mPaddingTop,

mScrollX + mRight - mLeft - mPaddingRight,

mScrollY + mBottom - mTop - mPaddingBottom);

}

// We will draw our child's animation,

let's reset the flag

mPrivateFlags &= ~DRAW_ANIMATION;

mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;

boolean more = false;

final long drawingTime = getDrawingTime();

if ((flags &

FLAG_USE_CHILD_DRAWING_ORDER) == 0) {

for (int i = 0; i < count; i++) {

final View child = children[i];

if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE ||

child.getAnimation() != null) {

more |= drawChild(canvas, child,

drawingTime); }

}

} else {

for (int i = 0; i < count; i++) {

final View child = children[getChildDrawingOrder(count, i)];

if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE ||

child.getAnimation() != null) {

more |= drawChild(canvas, child,

drawingTime); }

}

}

// Draw any disappearing views that

have animations

if (mDisappearingChildren != null) {

final ArrayList disappearingChildren = mDisappearingChildren;

final int disappearingCount = disappearingChildren.size() -

1;

// Go backwards -- we may delete as animations finish

for (int i = disappearingCount; i >= 0; i--) {

final View child = disappearingChildren.get(i);

more |= drawChild(canvas, child, drawingTime);

}

}

if (clipToPadding) {

canvas.restoreToCount(saveCount);

}

// mGroupFlags might have been updated

by drawChild()

flags = mGroupFlags;

if ((flags &

FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {

invalidate();

}

if ((flags & FLAG_ANIMATION_DONE)

== 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0

&&

mLayoutAnimationController.isDone() && !more) {

// We want to erase the drawing cache and notify the listener after

the

// next frame is drawn because one extra invalidate() is caused

by

// drawChild() after the animation is over

mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;

final Runnable end = new Runnable() {

public void run() {

notifyAnimationListener();

}

};

post(end);

}

}

DrawChild

动画信息准备

invalidate

滚动,transformation,透明度

protected boolean drawChild(Canvas

canvas, View child, long drawingTime) {

boolean more = false;

final int cl = child.mLeft;

final int ct = child.mTop;

final int cr = child.mRight;

final int cb = child.mBottom;

final int flags = mGroupFlags;

if ((flags &

FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {

if (mChildTransformation != null) {

mChildTransformation.clear();

}

mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;

}

Transformation transformToApply =

null;

final Animation a =

child.getAnimation(); boolean concatMatrix = false;

if (a != null) {

if (mInvalidateRegion == null) {

mInvalidateRegion = new RectF();

}

final RectF region = mInvalidateRegion;

final boolean initialized =

a.isInitialized();

if (!initialized) {

a.initialize(cr - cl, cb - ct, getWidth(), getHeight());

a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);

child.onAnimationStart();

}

if (mChildTransformation == null)

{

mChildTransformation = new Transformation();

}

//getTransformation动画的时间控制,调用 applyTransformation(interpolatedTime,

//outTransformation);outTransformation即mChildTransformation

//Animation的子类会实现 applyTransformation,对Transformation对象进行对应操作 more = a.getTransformation(drawingTime,

mChildTransformation); transformToApply =

mChildTransformation;

concatMatrix =

a.willChangeTransformationMatrix();

if (more) {

if (!a.willChangeBounds()) {

if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE))

==

FLAG_OPTIMIZE_INVALIDATE) {

mGroupFlags |= FLAG_INVALIDATE_REQUIRED;

} else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {

// The child need to draw an animation, potentially offscreen,

so

// make sure we do not cancel invalidate requests

mPrivateFlags |= DRAW_ANIMATION;

invalidate(cl, ct, cr,

cb); }

} else {

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值