创建EdgeEffect

    private EdgeEffect leftEdgeEffect;private void init(Context context) {leftEdgeEffect = new EdgeEffect(context);leftEdgeEffect.setColor(Color.RED);}

设置宽高:

    @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);leftEdgeEffect.setSize(getHeight(),getWidth());}

监听滑动事件:

    @Overridepublic boolean onTouchEvent(MotionEvent event) {int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:lastY = event.getY();return true;case MotionEvent.ACTION_MOVE:if (lastY - event.getY() > 10) {if (onDisMissCb != null) {onDisMissCb.onDisMiss();}}//第一个//第二个参数表示偏移量 0.5表示手指在中间  如果大于0.5 则表示在上方拉伸  leftEdgeEffect.onPull(0.1f,0.5f);invalidate();break;case MotionEvent.ACTION_UP:leftEdgeEffect.onRelease();invalidate();break;}return super.onTouchEvent(event);}

进行绘制:

    @Overridepublic void dispatchDraw(Canvas canvas) {super.dispatchDraw(canvas);if (!leftEdgeEffect.isFinished()) {int save = canvas.save();//竖直方向绘制canvas.rotate(90);canvas.translate(-0,-getWidth());leftEdgeEffect.draw(canvas);canvas.restoreToCount(save);postInvalidateOnAnimation();}}

一些分析:

1.EdgeEffect 如果你想要绘制左右方向的效果,那么需要你在draw的时候,对画布进行旋转。
2.

    private static final double ANGLE = Math.PI / 6;private static final float SIN = (float) Math.sin(ANGLE);private static final float COS = (float) Math.cos(ANGLE);private static final float RADIUS_FACTOR = 0.6f;

Math.PI / 6 表示 30 度,这里的PI 代表的是弧度。 2PI r = 360 度。
所以(float) Math.sin(ANGLE); 是0.5.
3.setSize 方法的一些图解

    /*** 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) {final float r = width * RADIUS_FACTOR / SIN;final float y = COS * r;final float h = r - y;final float or = height * RADIUS_FACTOR / SIN;final float oy = COS * or;final float oh = or - oy;mRadius = r;mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f;mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));}


绘制是有依据的,整体设计为,圆与宽度相交之后,角度为60度,垂直与宽度之后,为30度,所以才有了上面设置宽高之后的计算代码。

但是他不是完全和宽度相交的,会往相交的宽度上移动一段距离,所有有个变量叫做RADIUS_FACTOR,就是用来做这个的。


边缘效果就是这样。

源码复制:

因为源码有些地方不好调试,而且不好修改他定义的一些final 变量,所有,我手动copy 一份出来,供大家参考。

package com.example.view;/*** =======================================================================================* Author:caoxinyu* createTime:2021_4/1/21_2:59 PM* intent:* revision history:* =======================================================================================*//** Copyright (C) 2010 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;import androidx.annotation.ColorInt;/*** This class performs the graphical effect used at the edges of scrollable widgets* when the user scrolls beyond the content bounds in 2D space.** <p>EdgeEffect is stateful. Custom widgets using EdgeEffect should create an* instance for each edge that should show the effect, feed it input data using* the methods {@link #onAbsorb(int)}, {@link #onPull(float)}, and {@link #onRelease()},* and draw the effect using {@link #draw(Canvas)} in the widget's overridden* {@link android.view.View#draw(Canvas)} method. If {@link #isFinished()} returns* false after drawing, the edge effect's animation is not yet complete and the widget* should schedule another drawing pass to continue the animation.</p>** <p>When drawing, widgets should draw their main content and child views first,* usually by invoking <code>super.draw(canvas)</code> from an overridden <code>draw</code>* method. (This will invoke onDraw and dispatch drawing to child views as needed.)* The edge effect may then be drawn on top of the view's content using the* {@link #draw(Canvas)} method.</p>*/
public class EdgeEffectCopyView {@SuppressWarnings("UnusedDeclaration")private static final String TAG = "EdgeEffect";// Time it will take the effect to fully recede in msprivate static final int RECEDE_TIME = 600;// Time it will take before a pulled glow begins receding in msprivate static final int PULL_TIME = 167;// Time it will take in ms for a pulled glow to decay to partial strength before releaseprivate static final int PULL_DECAY_TIME = 2000;private static final float MAX_ALPHA = 0.15f;private static final float GLOW_ALPHA_START = .09f;private static final float MAX_GLOW_SCALE = 2.f;private static final float PULL_GLOW_BEGIN = 0.f;// Minimum velocity that will be absorbedprivate static final int MIN_VELOCITY = 100;// Maximum velocity, clamps at this valueprivate static final int MAX_VELOCITY = 10000;private static final float EPSILON = 0.001f;private static final double ANGLE = Math.PI / 6;private static final float SIN = (float) Math.sin(ANGLE);private static final float COS = (float) Math.cos(ANGLE);private static final float RADIUS_FACTOR = 0.6f;private float mGlowAlpha;private float mGlowScaleY;private float mGlowAlphaStart;private float mGlowAlphaFinish;private float mGlowScaleYStart;private float mGlowScaleYFinish;private long mStartTime;private float mDuration;private final Interpolator mInterpolator;private static final int STATE_IDLE = 0;private static final int STATE_PULL = 1;private static final int STATE_ABSORB = 2;private static final int STATE_RECEDE = 3;private static final int STATE_PULL_DECAY = 4;private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f;private static final int VELOCITY_GLOW_FACTOR = 6;private int mState = STATE_IDLE;private float mPullDistance;private final Rect mBounds = new Rect();private final Paint mPaint = new Paint();private float mRadius;private float mBaseGlowScale;private float mDisplacement = 0.5f;private float mTargetDisplacement = 0.5f;/*** Construct a new EdgeEffect with a theme appropriate for the provided context.* @param context Context used to provide theming and resource information for the EdgeEffect*/public EdgeEffectCopyView(Context context) {mPaint.setAntiAlias(true);
//        final TypedArray a = context.obtainStyledAttributes(
//                com.android.internal.R.styleable.EdgeEffect);
//        final int themeColor = a.getColor(
//                com.android.internal.R.styleable.EdgeEffect_colorEdgeEffect, 0xff666666);
//        a.recycle();mPaint.setColor(0x33000000);mPaint.setStyle(Paint.Style.FILL);mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));mInterpolator = new DecelerateInterpolator();}/*** 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) {final float r = width * RADIUS_FACTOR / SIN;final float y = COS * r;final float h = r - y;final float or = height * RADIUS_FACTOR / SIN;final float oy = COS * or;final float oh = or - oy;mRadius = r;mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f;mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));}/*** Reports if this EdgeEffect'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 mState == STATE_IDLE;}/*** Immediately finish the current animation.* After this call {@link #isFinished()} will return true.*/public void finish() {mState = STATE_IDLE;}/*** 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()} after this* and draw the results accordingly.** <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement* of the pull point is known.</p>** @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.*/public void onPull(float deltaDistance) {onPull(deltaDistance, 0.5f);}/*** 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()} after this* 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.* @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.*/public void onPull(float deltaDistance, float displacement) {final long now = AnimationUtils.currentAnimationTimeMillis();mTargetDisplacement = displacement;if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) {return;}if (mState != STATE_PULL) {mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY);}mState = STATE_PULL;mStartTime = now;mDuration = PULL_TIME;mPullDistance += deltaDistance;final float absdd = Math.abs(deltaDistance);mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR));if (mPullDistance == 0) {mGlowScaleY = mGlowScaleYStart = 0;} else {final float scale = (float) (Math.max(0, 1 - 1 /Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d);mGlowScaleY = mGlowScaleYStart = scale;}mGlowAlphaFinish = mGlowAlpha;mGlowScaleYFinish = mGlowScaleY;}/*** 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()} and thereby* draw the results accordingly.*/public void onRelease() {mPullDistance = 0;if (mState != STATE_PULL && mState != STATE_PULL_DECAY) {return;}mState = STATE_RECEDE;mGlowAlphaStart = mGlowAlpha;mGlowScaleYStart = mGlowScaleY;mGlowAlphaFinish = 0.f;mGlowScaleYFinish = 0.f;mStartTime = AnimationUtils.currentAnimationTimeMillis();mDuration = RECEDE_TIME;}/*** Call when the effect absorbs an impact at the given velocity.* Used when a fling reaches the scroll boundary.** <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller},* the method <code>getCurrVelocity</code> will provide a reasonable approximation* to use here.</p>** @param velocity Velocity at impact in pixels per second.*/public void onAbsorb(int velocity) {mState = STATE_ABSORB;velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY);mStartTime = AnimationUtils.currentAnimationTimeMillis();mDuration = 0.15f + (velocity * 0.02f);// The glow depends more on the velocity, and therefore starts out// nearly invisible.mGlowAlphaStart = GLOW_ALPHA_START;mGlowScaleYStart = Math.max(mGlowScaleY, 0.f);// Growth for the size of the glow should be quadratic to properly// respond// to a user's scrolling speed. The faster the scrolling speed, the more// intense the effect should be for both the size and the saturation.mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f);// Alpha should change for the glow as well as size.mGlowAlphaFinish = Math.max(mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA));mTargetDisplacement = 0.5f;}/*** Set the color of this edge effect in argb.** @param color Color in argb*/public void setColor(@ColorInt int color) {mPaint.setColor(color);}/*** Return the color of this edge effect in argb.* @return The color of this edge effect in argb*/@ColorIntpublic int getColor() {return mPaint.getColor();}/*** 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) {update();final int count = canvas.save();final float centerX = mBounds.centerX();final float centerY = mBounds.height() - mRadius;canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, centerX, 0);final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f;float translateX = mBounds.width() * displacement / 2;canvas.clipRect(mBounds);canvas.translate(translateX, 0);mPaint.setAlpha((int) (0xff * mGlowAlpha));canvas.drawCircle(centerX, centerY, mRadius, mPaint);canvas.restoreToCount(count);boolean oneLastFrame = false;if (mState == STATE_RECEDE && mGlowScaleY == 0) {mState = STATE_IDLE;oneLastFrame = true;}return mState != STATE_IDLE || oneLastFrame;}/*** Return the maximum height that the edge effect will be drawn at given the original* {@link #setSize(int, int) input size}.* @return The maximum height of the edge effect*/public int getMaxHeight() {return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f);}private void update() {final long time = AnimationUtils.currentAnimationTimeMillis();final float t = Math.min((time - mStartTime) / mDuration, 1.f);final float interp = mInterpolator.getInterpolation(t);mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp;mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp;mDisplacement = (mDisplacement + mTargetDisplacement) / 2;if (t >= 1.f - EPSILON) {switch (mState) {case STATE_ABSORB:mState = STATE_RECEDE;mStartTime = AnimationUtils.currentAnimationTimeMillis();mDuration = RECEDE_TIME;mGlowAlphaStart = mGlowAlpha;mGlowScaleYStart = mGlowScaleY;// After absorb, the glow should fade to nothing.mGlowAlphaFinish = 0.f;mGlowScaleYFinish = 0.f;break;case STATE_PULL:mState = STATE_PULL_DECAY;mStartTime = AnimationUtils.currentAnimationTimeMillis();mDuration = PULL_DECAY_TIME;mGlowAlphaStart = mGlowAlpha;mGlowScaleYStart = mGlowScaleY;// After pull, the glow should fade to nothing.mGlowAlphaFinish = 0.f;mGlowScaleYFinish = 0.f;break;case STATE_PULL_DECAY:mState = STATE_RECEDE;break;case STATE_RECEDE:mState = STATE_IDLE;break;}}}
}

android 绘图

https://zhidao.baidu.com/question/2118105468575080787.html

Android EdgeEffect 使用 和 源码解析相关推荐

  1. android handler2--消息队列源码解析

    android handler2–消息队列源码解析 1.Looper 对于Looper主要是prepare()和loop()两个方法. 首先看prepare()方法 public static fin ...

  2. Android Hawk数据库的源码解析,Github开源项目,基于SharedPreferences的的存储框架

    今天看了朋友一个项目用到了Hawk,然后写了这边文章 一.了解一下概念 Android Hawk数据库github开源项目 Hawk是一个非常便捷的数据库.操作数据库只需一行代码,能存任何数据类型. ...

  3. android网络框架retrofit源码解析二

    注:源码解析文章参考了该博客:http://www.2cto.com/kf/201405/305248.html 前一篇文章讲解了retrofit的annotation,既然定义了,那么就应该有解析的 ...

  4. Android手游 “2048” 源码解析

    转载请写明出处:http://blog.csdn.net/big_heart_c 下面所解析的源码是来自极客学院"Android 2048 "中的源码,读者可以从 https:// ...

  5. Android之EventBus框架源码解析下(源码解析)

    转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! 前言 EventBus是典型的发布订阅模式,多个订阅者可以订阅某个事件,发布者通过 ...

  6. Android 常用开源框架源码解析 系列 (四)Glide

    一.定义  Glide 一个被google所推荐的图片加载库,作者是bumptech.对Android SDk 最低要求是 API 10  与之功能类似的是Square公司的picasso  二.基本 ...

  7. Android 常用开源框架源码解析 系列 (九)dagger2 呆哥兔 依赖注入库

    一.前言 依赖注入定义 目标类中所依赖的其他的类的初始化过程,不是通过手动编码的方式创建的. 是将其他的类已经初始化好的实例自动注入的目标类中. "依赖注入"也是面向对象编程的 设 ...

  8. Android存储之SharedPreferences源码解析

    个人博客:haichenyi.com.感谢关注 1. 目录 1–目录 2–简介 3–getSharedPreferences会不会阻塞线程,为什么? 4–get操作,为什么有时候会卡顿? 5–comm ...

  9. Android SharedPreferences 详解 源码解析

    1.实现类 SharedPreferences 只是一个接口,其实现类是SharedPreferencesImpl. 工作流程分析: 创建sp 的时候,会去查看是否有bak文件,如果有的话,把bak文 ...

最新文章

  1. PYTHON 写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者...
  2. 洛谷U4807抽水机[最小生成树]
  3. 事务概念和事务四大特性和隔离级别
  4. Android中让Service被关闭后再重新启动
  5. appium自动化测试_Appium自动化测试入门教程No.1—— Appium介绍
  6. 一篇关于Dataset与泛型、自定义集合的讨论
  7. NLP算法面试的一些个人建议
  8. Oracle 9i所有版本的最新下载地址(已验证!)
  9. python写入access_使用Python对Access读写操作方法详解
  10. 【模拟电子技术Analog Electronics Technology 14】——集成运放中的单元电路 之 集成运放的输入级:长尾式差放各种接法的参数分析
  11. 个性字体头像在线图片生成下载网址
  12. 最佳Android模拟器,你值得拥有
  13. 怎么用c语言表示素数,用C语言编写判断一个数是否是素数的程序
  14. 作业收集小程序推荐|视频作业收集、图片作业收集、文档作业收集
  15. java json 解析字符串_java-解析JSON字符串的最简单方法
  16. xp桌面图标阴影解决方案
  17. 小白 0-1 学习 app 开发,从配置到 hello world
  18. MySQL创建用户,授权
  19. 阿里巴巴Java开发手册 (Alibaba Java Coding Guidelines)
  20. oracle中12560,Oracle ORA-12560解决方法

热门文章

  1. oracle asm clsecho,ASM磁盘组一点管理
  2. 2012年1月java_全国2012年1月自考Java语言程序设计(一)试题及答案.doc
  3. mysql随机查询 uuid_mysql实现随机查询经验谈
  4. python获取用户输入中文_python中的用户输入
  5. C/C++栈溢出的几种解决办法
  6. python制作网页的步骤_使用httplib模块来制作Python下HTTP客户端的方法
  7. Ajax——从服务器获取各种文件
  8. 推断给定的IP地址是否是内网IP
  9. JS-匀速运动-运动停止
  10. Docker Container同时启动多服务 supervisor