android listview edgeeffect,Android的边缘效应的相关类EdgeEffectCompat学习

Android的边缘效应的相关类EdgeEffectCompat学习

Android中可以的ListView,ScrollView,RecyclerView等滑动到界面的边界的时候会出现一个半透明的颜色边

框。这个边框就是Android的边缘效果。主要是类EdgeEffect,EdgeEffectCompat管理。效果如下图

b9cf933e456e

边缘效应效果图

1,EdgeEffectCompat类的学习

源码学习:

/**

* 构造一个新的对象

*

*

Note: 对于不支持的版本,将会没有效果

*

* @param 上下文

*/

public EdgeEffectCompat(Context context) {

mEdgeEffect = IMPL.newEdgeEffect(context);

}

/**

* Set the size of this edge effect in pixels.

* 设置边框的大小像素

*

* @param width Effect width in pixels

* @param height Effect height in pixels

*/

public void setSize(int width, int height) {

IMPL.setSize(mEdgeEffect, width, height);

}

/**

* Reports if this EdgeEffectCompat's animation is finished. If this method returns false

* after a call to {@link #draw(Canvas)} the host widget should schedule another

* drawing pass to continue the animation.

*

* 边缘的显示动画是否结束

*

* @return true if animation is finished, false if drawing should continue on the next frame.

*

*/

public boolean isFinished() {

return IMPL.isFinished(mEdgeEffect);

}

/**

* Immediately finish the current animation.

* After this call {@link #isFinished()} will return true.

* 立刻结束显示动画

*/

public void finish() {

IMPL.finish(mEdgeEffect);

}

/**

* 在处理滑动的时候调用

* A view should call this when content is pulled away from an edge by the user.

* This will update the state of the current visual effect and its associated animation.

* The host view should always {@link android.view.View#invalidate()} if this method

* returns true and draw the results accordingly.

*

* @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to

* 1.f (full length of the view) or negative values to express change

* back toward the edge reached to initiate the effect.

* 范围:[-1,1],是要移动的距里在View的边长的占比

* @param displacement The displacement from the starting side of the effect of the point

* initiating the pull. In the case of touch this is the finger position.

* Values may be from 0-1.

* 范围[0,1],手指所在的位置在非移动边的位置占比

* @return true if the host view should call invalidate, false if it should not.

* 如果返回为true就表示会重新刷新View。

*/

public boolean onPull(float deltaDistance, float displacement) {

return IMPL.onPull(mEdgeEffect, deltaDistance, displacement);

}

/**

* Call when the object is released after being pulled.

* This will begin the "decay" phase of the effect. After calling this method

* the host view should {@link android.view.View#invalidate()} if this method

* returns true and thereby draw the results accordingly.

* 是否被释放

* @return true if the host view should invalidate, false if it should not.

*/

public boolean onRelease() {

return IMPL.onRelease(mEdgeEffect);

}

/**

* Call when the effect absorbs an impact at the given velocity.

* Used when a fling reaches the scroll boundary.

*

* 吸收一个速度,当到View的边界的时候会显示相应的动画

*

When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller},

* the method getCurrVelocity will provide a reasonable approximation

* to use here.

*

* @param velocity Velocity at impact in pixels per second.

* @return true if the host view should invalidate, false if it should not.

*/

public boolean onAbsorb(int velocity) {

return IMPL.onAbsorb(mEdgeEffect, velocity);

}

/**

* 关键方法,在View的onDraw方法中调用会显示相应的动画,在调用这个方法之前要计算相应的

* 平移,旋转的量。

* Draw into the provided canvas. Assumes that the canvas has been rotated

* accordingly and the size has been set. The effect will be drawn the full

* width of X=0 to X=width, beginning from Y=0 and extending to some factor 小于

* 1.f of height.

*

* @param canvas Canvas to draw into

* @return true if drawing should continue beyond this frame to continue the

* animation

*/

public boolean draw(Canvas canvas) {

return IMPL.draw(mEdgeEffect, canvas);

}

EdgeEffectCompat实现原理:

EdgeEffcetCompat的实现就是在滑动控件滑动到边界的时候在边界画一个圆弧,然后根据

滑动的位置(滑动方向的偏移量,非滑动方向坐标的位置)进行缩放平移,同时进行动画的播放。

具体如下图(蓝色部分):

b9cf933e456e

原理图

2,EdgeEffectCompat类的应用

这里我用ScrollView的相关源码进行学习,展示EdgeEffectCompat是如何应用到View中的。

在View的绘制过程中,通过EdgeEffectCompat.setSize(width,height)和EdgeEffectCompat.draw(canvas)两个方法来绘制效果图。相关的详细解释看注释:

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (mTopEdgeEffect != null) {

final int width = getWidth() - getPaddingRight() - getPaddingLeft();//内容的宽度

final int scrollY = getScrollY();//当前滑动的量

if (!mTopEdgeEffect.isFinished()) {//动画是否已经结束

int restoreCount = canvas.save();

canvas.translate(getPaddingLeft(), Math.min(0, scrollY));//画布向右平移,如果View有向下超过0的偏移量就要再向上偏移,超过上边界的平移量

mTopEdgeEffect.setSize(width , getHeight());//设置效果的展示范围(内容的宽度,和View的高度)

if (mTopEdgeEffect.draw(canvas)) {//绘制边缘效果图,如果绘制需要进行动画效果返回true

ViewCompat.postInvalidateOnAnimation(this);//进行动画

}

canvas.restoreToCount(restoreCount);

}

if (!mBottomEdgeEffect.isFinished()) {

int restoreCount = canvas.save();

//下面两行代码的作用就是把画布平移旋转到底部展示,并让效果向上显示

canvas.translate(getPaddingLeft() - width, Math.max(getScrollRange(), scrollY) + getHeight());

canvas.rotate(180, width, 0);

mBottomEdgeEffect.setSize(width, getHeight());

if (mBottomEdgeEffect.draw(canvas)) {

ViewCompat.postInvalidateOnAnimation(this);

}

canvas.restoreToCount(restoreCount);

}

}

}

在View.onTouchEvent()方法中调用EdgeEffectCompat.onPull方法详细见源码:

@Override

public boolean onTouchEvent(MotionEvent ev) {

final int actionMark = MotionEventCompat.getActionMasked(ev);

switch (actionMark) {

case MotionEvent.ACTION_MOVE:

final int pointIndex = ev.findPointerIndex(mActionPointerId);

if (pointIndex == -1) {

break;

}

final int y = (int) ev.getY(pointIndex);

int deltaY = mLastPointY - y;

if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {

ViewParent parent = getParent();

if (parent != null) {

parent.requestDisallowInterceptTouchEvent(true);

}

if (deltaY > 0) {//减去积累的量

deltaY -= mTouchSlop;

} else {

deltaY += mTouchSlop;

}

mIsBeingDragged = true;

}

if (mIsBeingDragged) {

final int oldY = getScrollY();

final int range = getScrollRange();

final int overMode = getOverScrollMode();

boolean canOverScroll = overMode == View.OVER_SCROLL_ALWAYS

|| (overMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);

//主要的代码

if (canOverScroll) {

// 边缘效果

ensureGlows();

final int pullToY = oldY + deltaY;

if (pullToY < 0) {//在顶部

mTopEdgeEffect.onPull((float) deltaY / getHeight(), ev.getX(pointIndex) / getWidth());

if (!mBottomEdgeEffect.isFinished()) {

mBottomEdgeEffect.onRelease();

}

} else if (pullToY > range) {//在底部

mBottomEdgeEffect.onPull((float) deltaY / getHeight(), 1.0f - ev.getX(pointIndex) / getWidth());

if (!mTopEdgeEffect.isFinished()) {

mTopEdgeEffect.onRelease();

}

}

if (mTopEdgeEffect != null && (!mTopEdgeEffect.isFinished() || !mBottomEdgeEffect.isFinished())) {

ViewCompat.postInvalidateOnAnimation(this);

}

}

mLastPointY = y;

}

break;

case MotionEvent.ACTION_CANCEL:

if (mTopEdgeEffect != null) {

mTopEdgeEffect.onRelease();

mBottomEdgeEffect.onRelease();

}

break;

case MotionEvent.ACTION_UP:

if (mTopEdgeEffect != null) {

mTopEdgeEffect.onRelease();

mBottomEdgeEffect.onRelease();

}

break;

}

return true;

}

private void ensureGlows() {

if (getOverScrollMode() != OVER_SCROLL_NEVER) {

Context context = getContext();

if (context != null && mTopEdgeEffect == null) {

mTopEdgeEffect = new EdgeEffectCompat(context);

mBottomEdgeEffect = new EdgeEffectCompat(context);

}

} else {

mTopEdgeEffect = null;

mBottomEdgeEffect = null;

}

}

在快速滑动View的时候,View会有一定的速度到达边界,这时候就要根据到达边界的速度进行显示。

一般View是用Scroller来进行Fling动画效果的。这时候就要在View.computeScroll方法中设置。详细如下:

@Override

public void computeScroll() {

if (mScroller.computeScrollOffset()) {

int oldX = getScrollX();

int oldY = getScrollY();

int newX = mScroller.getCurrX();

int newY = mScroller.getCurrY();

// Log.i(TAG, "computeScroll: oldY : " + oldY +" newY : "+newY);

if (oldX != newX || oldY != newY) {

final int range = getScrollRange();

final int overMode = getOverScrollMode();

boolean canOverScroll = overMode == View.OVER_SCROLL_ALWAYS

|| (overMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);

overScrollByCompat(newX - oldX, newY - oldY, oldX, oldY, 0, range, 0, 0);

if (canOverScroll) {//这部分是吓死边缘效果的

ensureGlows();

if (newY < 0 && oldY > 0) {//到达顶部,吸收速度

mTopEdgeEffect.onAbsorb((int) mScroller.getCurrVelocity());

} else if (newY > range && oldY < range) {//到达底部,吸收速度

mBottomEdgeEffect.onAbsorb((int) mScroller.getCurrVelocity());

}

}

}

}

}

Android的边缘效应的相关类EdgeEffectCompat学习就到这里。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值