水波纹
来源:互联网 发布:文明5 mac 语言 编辑:程序博客网 时间:2024/06/11 20:55
公司中项目中看到,学习下源码。
// 使用
<xx.xxx.view.extend.PulsatorLayout android:id="@+id/wait" android:layout_width="200dp" android:layout_height="200dp" android:layout_gravity="center" android:layout_marginTop="@dimen/margin_2xxl" app:pulse_color="@color/colorAccent" app:pulse_count="4" app:pulse_duration="5000" app:pulse_repeat="0" app:pulse_startFromScratch="false"> </xx.xxx.view.extend.PulsatorLayout>
// 源码import android.animation.Animator;import android.animation.AnimatorSet;import android.animation.ObjectAnimator;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.view.View;import android.view.animation.LinearInterpolator;import android.widget.RelativeLayout;import java.util.ArrayList;import java.util.List;/** * 水波纹 */public class PulsatorLayout extends RelativeLayout { public static final int INFINITE = 0; private static final int DEFAULT_COUNT = 4; private static final int DEFAULT_COLOR = Color.rgb(0, 116, 193); private static final int DEFAULT_DURATION = 7000; private static final int DEFAULT_REPEAT = INFINITE; private static final boolean DEFAULT_START_FROM_SCRATCH = true; private int mCount; private int mDuration; private int mRepeat; private boolean mStartFromScratch; private final List<View> mViews = new ArrayList<>(); private AnimatorSet mAnimatorSet; private Paint mPaint; private float mRadius; private float mCenterX; private float mCenterY; private boolean mIsStarted; /** * Simple constructor to use when creating a view from code. * * @param context The Context the view is running in, through which it can access the current * theme, resources, etc. */ public PulsatorLayout(Context context) { this(context, null, 0); } /** * Constructor that is called when inflating a view from XML. * * @param context The Context the view is running in, through which it can access the current * theme, resources, etc. * @param attrs The attributes of the XML tag that is inflating the view. */ public PulsatorLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } /** * Perform inflation from XML and apply a class-specific base style from a theme attribute. * * @param context The Context the view is running in, through which it can access the current * theme, resources, etc. * @param attrs The attributes of the XML tag that is inflating the view. * @param defStyleAttr An attribute in the current theme that contains a reference to a style * resource that supplies default values for the view. Can be 0 to not look * for defaults. */ public PulsatorLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // get attributes TypedArray attr = context.getTheme().obtainStyledAttributes( attrs, R.styleable.Pulsator4Droid, 0, 0); mCount = DEFAULT_COUNT; mDuration = DEFAULT_DURATION; mRepeat = DEFAULT_REPEAT; mStartFromScratch = DEFAULT_START_FROM_SCRATCH; int color = DEFAULT_COLOR; try { mCount = attr.getInteger(R.styleable.Pulsator4Droid_pulse_count, DEFAULT_COUNT); mDuration = attr.getInteger(R.styleable.Pulsator4Droid_pulse_duration, DEFAULT_DURATION); mRepeat = attr.getInteger(R.styleable.Pulsator4Droid_pulse_repeat, DEFAULT_REPEAT); mStartFromScratch = attr.getBoolean(R.styleable.Pulsator4Droid_pulse_startFromScratch, DEFAULT_START_FROM_SCRATCH); color = attr.getColor(R.styleable.Pulsator4Droid_pulse_color, DEFAULT_COLOR); } finally { attr.recycle(); } // create paint mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(color); // create views build(); } /** * Start pulse animation. */ public synchronized void start() { if (mAnimatorSet == null || mIsStarted) { return; } mAnimatorSet.start(); if (!mStartFromScratch) { ArrayList<Animator> animators = mAnimatorSet.getChildAnimations(); for (Animator animator : animators) { ObjectAnimator objectAnimator = (ObjectAnimator) animator; long delay = objectAnimator.getStartDelay(); objectAnimator.setStartDelay(0); objectAnimator.setCurrentPlayTime(mDuration - delay); } } } /** * Stop pulse animation. */ public synchronized void stop() { if (mAnimatorSet == null || !mIsStarted) { return; } mAnimatorSet.end(); } public synchronized boolean isStarted() { return (mAnimatorSet != null && mIsStarted); } /** * Get number of pulses. * * @return Number of pulses */ public int getCount() { return mCount; } /** * Get pulse duration. * * @return Duration of single pulse in milliseconds */ public int getDuration() { return mDuration; } /** * Set number of pulses. * * @param count Number of pulses */ public void setCount(int count) { if (count < 0) { throw new IllegalArgumentException("Count cannot be negative"); } if (count != mCount) { mCount = count; reset(); invalidate(); } } /** * Set single pulse duration. * * @param millis Pulse duration in milliseconds */ public void setDuration(int millis) { if (millis < 0) { throw new IllegalArgumentException("Duration cannot be negative"); } if (millis != mDuration) { mDuration = millis; reset(); invalidate(); } } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom(); mCenterX = width * 0.5f; mCenterY = height * 0.5f; mRadius = Math.min(width, height) * 0.5f; super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** * Remove all views and animators. */ private void clear() { // remove animators stop(); // remove old views for (View view : mViews) { removeView(view); } mViews.clear(); } /** * Build pulse views and animators. */ private void build() { // create views and animators LayoutParams layoutParams = new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); int repeatCount = (mRepeat == INFINITE) ? ObjectAnimator.INFINITE : mRepeat; List<Animator> animators = new ArrayList<>(); for (int index = 0; index < mCount; index++) { // setup view PulseView pulseView = new PulseView(getContext()); pulseView.setScaleX(0); pulseView.setScaleY(0); pulseView.setAlpha(1); addView(pulseView, index, layoutParams); mViews.add(pulseView); long delay = index * mDuration / mCount; // setup animators ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(pulseView, "ScaleX", 0f, 1f); scaleXAnimator.setRepeatCount(repeatCount); scaleXAnimator.setRepeatMode(ObjectAnimator.RESTART); scaleXAnimator.setStartDelay(delay); animators.add(scaleXAnimator); ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(pulseView, "ScaleY", 0f, 1f); scaleYAnimator.setRepeatCount(repeatCount); scaleYAnimator.setRepeatMode(ObjectAnimator.RESTART); scaleYAnimator.setStartDelay(delay); animators.add(scaleYAnimator); ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(pulseView, "Alpha", 1f, 0f); alphaAnimator.setRepeatCount(repeatCount); alphaAnimator.setRepeatMode(ObjectAnimator.RESTART); alphaAnimator.setStartDelay(delay); animators.add(alphaAnimator); } mAnimatorSet = new AnimatorSet(); mAnimatorSet.playTogether(animators); mAnimatorSet.setInterpolator(new LinearInterpolator()); mAnimatorSet.setDuration(mDuration); mAnimatorSet.addListener(mAnimatorListener); } /** * Reset views and animations. */ private void reset() { boolean isStarted = isStarted(); clear(); build(); if (isStarted) { start(); } } private class PulseView extends View { public PulseView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { canvas.drawCircle(mCenterX, mCenterY, mRadius, mPaint); } } private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { mIsStarted = true; } @Override public void onAnimationEnd(Animator animator) { mIsStarted = false; } @Override public void onAnimationCancel(Animator animator) { mIsStarted = false; } @Override public void onAnimationRepeat(Animator animator) { } };}
// attr.xml文件<declare-styleable name="Pulsator4Droid"> <attr name="pulse_count" format="integer"/> <attr name="pulse_duration" format="integer"/> <attr name="pulse_color" format="color"/> <attr name="pulse_repeat" format="integer"/> <attr name="pulse_startFromScratch" format="boolean"/> </declare-styleable>
阅读全文
0 0
- 水波纹
- 水波纹
- 水波纹
- 水波纹
- 水波纹
- 水波纹效果原理
- 水波纹屏保原理
- 水波纹特效
- 水波纹效果原理
- Android 实现水波纹
- IOS 水波纹 ripple
- objective-水波纹实现
- cocos2dx 水波纹Shader
- 水波纹效果
- 水波纹控件分析
- 7 Meth水波纹
- 水波纹效果
- Android水波纹实现
- Android Studio常用工具类
- Hibernate基础---增、删、改、Query对象
- Tensorflow中下划线 _ 的作用
- boost库学习总结
- 获取本地图片展示在页面上
- 水波纹
- fst
- 数据库操作
- JQuery进行添加删除
- Shell Script总结
- 【1027】正整数每位数累加
- MySQL慢查询
- Webservice与Servlet
- PalindromePartitioningLi