亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android自定義ViewGroup實現絢麗的仿支付寶咻一咻雷達脈沖效果

2019-12-12 05:03:13
字體:
來源:轉載
供稿:網友

去年春節的時候支付寶推行的集福娃活動著實火的不能再火了,更給力的是春晚又可以全民參與咻一咻集福娃活動,集齊五福就可平分億元大紅包,只可惜沒有敬業?!菚r候在家沒事寫了個咻一咻插件,只要到了咻一咻的時間點插件就可以自動的點擊咻一咻來咻紅包,當時只是純粹練習這部分技術代碼沒有公開,后續計劃寫篇關于插件這方面的文章,扯遠了(*^__^*) ……我們知道在支付寶的咻一咻頁面有個雷達擴散的動畫效果,當時感覺動畫效果非常棒,于是私下嘗試著實現了類似的效果,后來在github發現有大神也寫有類似效果,于是讀了一下大神的代碼發現我們的核心思想都是一樣的,只是細節不同,然后我就擇其善者而從之,把兩份代碼整合了一下......整合之后的運行效果如下所示:

開始講解實現之前我們先分析一下支付寶的咻一咻效果,進入支付寶咻一咻頁面后點擊了咻一咻按鈕,屏幕上先出現一個圓在不斷的進行放大操作,在該圓進行放大操作的同時其透明度也在由大到小進行變化,接著該圓沒有消失之前又會出現新的圓也在進行同樣的動畫操作……通過觀察我們發現這些圓都是按照固定的時間間隔在依次的執行放大和透明度漸變的動畫操作,所以要實現同樣的效果,首先要有一個ViewGroup,然后給這個ViewGroup添加固定數量的子View,最后讓這些子View執行放大和透明度漸變動畫就可以實現該效果了。清楚了這個大綱流程,實現起來就好辦了。

首先定義我們的ViewGroup,由于該ViewGroup僅僅是添加固定數量的子View,然后讓這些子View執行一系列動畫,所以可以直接繼承FrameLayout,代碼如下所示:

public class RadarLayout extends FrameLayout { public RadarLayout(Context context) { super(context); } public RadarLayout(Context context, AttributeSet attrs) { super(context, attrs); } public RadarLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } }

我們為自己的咻一咻效果控件取名為RadarLayout,radar為雷達的意思,RadarLayout就表示在不斷的進行掃描的意思。通過前邊的分析我們知道RadarLayout是由固定數量的子View組成的,因此RadarLayout需要有表示子View數量的屬性并且該屬性外界可訪問可修改;由于子View的執行動畫是放縮和透明度漸變同時進行的,所以RadarLayout需要用動畫集來組裝各個動畫;由于動畫執行時需要知道執行時間所以RadarLayout需要有表示執行時間的屬性并且該屬性外界可訪問可修改;由于RadarLayout的動畫效果是子View來執行的,在咻一咻頁面是個圓,所以需要定義子View并畫在屏幕上,而畫在屏幕上需要有畫筆,畫筆需要有顏色,還需要知道畫在哪,所以可定義我們的RadarLayout定義如下所示:

public class RadarLayout extends FrameLayout { 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 int DEFAULT_STROKE_WIDTH = 2; private int mCount; private int mDuration; private int mRepeat; private AnimatorSet mAnimatorSet; private Paint mPaint; private int mColor; private float mRadius; private float mCenterX; private float mCenterY; private int mStrokeWidth; private boolean mIsStarted; private boolean mUseRing; public RadarLayout(Context context) { super(context); initGlobalparams(); } public RadarLayout(Context context, AttributeSet attrs) { super(context, attrs); initGlobalparams(); } public RadarLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initGlobalparams(); } private void initGlobalparams() { mColor = DEFAULT_COLOR; mCount = DEFAULT_COUNT; mDuration = DEFAULT_DURATION; mRepeat = DEFAULT_REPEAT; mUseRing = false; mStrokeWidth = dip2px(DEFAULT_STROKE_WIDTH); build(); } public synchronized void start() { if (mAnimatorSet == null || mIsStarted) { return; } mAnimatorSet.start(); } public synchronized void stop() { if (mAnimatorSet == null || !mIsStarted) { return; } mAnimatorSet.end(); } public synchronized boolean isStarted() { return (mAnimatorSet != null && mIsStarted); } public int getCount() { return mCount; } public int getDuration() { return mDuration; } public void setCount(int count) { if (count < 0) { throw new IllegalArgumentException("Count cannot be negative"); } if (count != mCount) { mCount = count; reset(); invalidate(); } } public void setDuration(int millis) { if (millis < 0) { throw new IllegalArgumentException("Duration cannot be negative"); } if (millis != mDuration) { mDuration = millis; reset(); invalidate(); } } public void setColor(int color) { if (mColor != color) { mColor = color; reset(); invalidate(); } } public void setUseRing(boolean useRing) { if (mUseRing != useRing) { mUseRing = useRing; reset(); invalidate(); } } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); int height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); // 確定圓的圓點坐標及半徑 mCenterX = width * 0.5f; mCenterY = height * 0.5f; mRadius = Math.min(width, height) * 0.5f; } private void clear() { stop(); removeAllViews(); } private void build() { LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT); int repeatCount = (mRepeat == INFINITE) ? ObjectAnimator.INFINITE : mRepeat; List<Animator> animators = new ArrayList<Animator>(); for (int index = 0; index < mCount; index++) { RadarView radarView = new RadarView(getContext()); radarView.setScaleX(0); radarView.setScaleY(0); radarView.setAlpha(1); addView(radarView, index, params); // 計算時間間隔 long delay = index * mDuration / mCount; // 屬性動畫 animators.add(create(radarView, "scaleX", repeatCount, delay, 0, 1)); animators.add(create(radarView, "scaleY", repeatCount, delay, 0, 1)); animators.add(create(radarView, "alpha", repeatCount, delay, 1, 0)); } mAnimatorSet = new AnimatorSet(); mAnimatorSet.playTogether(animators); mAnimatorSet.setInterpolator(new LinearInterpolator()); mAnimatorSet.setDuration(mDuration); mAnimatorSet.addListener(mAnimatorListener); } private ObjectAnimator create(View target, String propertyName, int repeatCount, long delay, float from, float to) { ObjectAnimator animator = ObjectAnimator.ofFloat(target, propertyName, from, to); animator.setRepeatCount(repeatCount); animator.setRepeatMode(ObjectAnimator.RESTART); animator.setStartDelay(delay); return animator; } private void reset() { boolean isStarted = isStarted(); clear(); build(); if (isStarted) { start(); } } private class RadarView extends View { public RadarView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { if (null == mPaint) { mPaint = new Paint(); mPaint.setColor(mColor); mPaint.setAntiAlias(true); // 注意Style的用法,【STROKE:畫環】【FILL:畫圓】 mPaint.setStyle(mUseRing ? Style.STROKE : Style.FILL); mPaint.setStrokeWidth(mUseRing ? mStrokeWidth : 0); } // 畫圓或環 canvas.drawCircle(mCenterX, mCenterY, mUseRing ? mRadius - mStrokeWidth : mRadius, mPaint); } } private int dip2px(float dpValue) { final float scale = getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } 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) { } }; }

我們的RadarLayout已經完成了,代碼很簡單,相信小伙伴們都看的懂,需要注意屬性mUseRing的含義,當mUserRing為true時表示使用環形雷達脈沖,否則使用圓形雷達脈沖。其次是屬性動畫的使用,如果有不明白的請自行查閱,這里就不再多多介紹了。接下來編寫我們的activity_main.xml布局文件,如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.llew.wb.MainActivity" > <View android:id="@+id/holder" android:layout_width="@dimen/activity_horizontal_margin" android:layout_height="10dp" android:layout_centerHorizontal="true" /> <com.llew.wb.RadarLayout android:id="@+id/radarlayout1" android:layout_width="match_parent" android:layout_height="150dp" android:layout_toLeftOf="@id/holder" android:background="#bbaacc" > </com.llew.wb.RadarLayout> <com.llew.wb.RadarLayout android:id="@+id/radarlayout2" android:layout_width="match_parent" android:layout_height="150dp" android:layout_toRightOf="@id/holder" android:background="#bbaacc" > </com.llew.wb.RadarLayout> <com.llew.wb.RadarLayout android:id="@+id/radarlayout3" android:layout_width="match_parent" android:layout_height="150dp" android:layout_below="@id/radarlayout1" android:layout_marginTop="@dimen/activity_horizontal_margin" android:layout_toLeftOf="@id/holder" android:background="#bbaacc" > </com.llew.wb.RadarLayout> <com.llew.wb.RadarLayout android:id="@+id/radarlayout4" android:layout_width="match_parent" android:layout_height="150dp" android:layout_below="@id/radarlayout1" android:layout_marginTop="@dimen/activity_horizontal_margin" android:layout_toRightOf="@id/holder" android:background="#bbaacc" > </com.llew.wb.RadarLayout> <Button android:layout_width="100dp" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="20dp" android:onClick="start" android:text="開始" /> </RelativeLayout>

在activity_main.xml布局中我們添加了4個RadarLayout,目的是對比他們的差異,接下編寫我們的MainActivity,代碼如下:

public class MainActivity extends Activity { private RadarLayout layout1; private RadarLayout layout2; private RadarLayout layout3; private RadarLayout layout4; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); layout1 = (RadarLayout) findViewById(R.id.radarlayout1); layout2 = (RadarLayout) findViewById(R.id.radarlayout2); layout2.setUseRing(true); layout2.setCount(2); layout3 = (RadarLayout) findViewById(R.id.radarlayout3); layout3.setUseRing(false); layout3.setColor(Color.RED); layout4 = (RadarLayout) findViewById(R.id.radarlayout4); layout4.setCount(7); layout4.setColor(Color.BLUE); layout4.setUseRing(true); } public void start(View view) { layout1.start(); layout2.start(); layout3.start(); layout4.start(); } }

在MainActivity中我們設置了layout1為默認值效果,layout2設置了使用環形效果并且設置了數量為2個;layout3設置為使用圓形并設置圓形的顏色為紅色,layout3我們設置了使用環形,設置了環形數量為7個并設置顏色給藍色。當點擊了開始按鈕后,我們打開每一個RadarLayout的動畫,運行效果如下所示:

運行效果看起來還不錯,基本上實現了仿支付的咻一咻的雷達脈沖效果,主要原理就是利用了屬性動畫并把這些屬性動畫集合起來一塊播放即可。需要注意的是如果想在低版本兼容屬性動畫可以使用Jake Wharton大神開源的著名動畫兼容庫NineOldAndroids,最后感謝收看(*^__^*) ……

以上所述是小編給大家介紹的Android自定義ViewGroup實現絢麗的仿支付寶咻一咻雷達脈沖效果,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩经典中文字幕| 色综合久久久888| 国产精品91在线| 在线a欧美视频| 精品久久久一区| 性色av一区二区三区红粉影视| 岛国精品视频在线播放| 国产精品自在线| 亚洲欧洲视频在线| 黑人极品videos精品欧美裸| 国产成人精彩在线视频九色| 亚洲视频一区二区| 国模精品视频一区二区| 亚洲欧美激情四射在线日| 国产精品女人久久久久久| 欧美性猛交xxxxx免费看| 一区二区三区天堂av| 自拍偷拍亚洲精品| 亚洲国产女人aaa毛片在线| 亚洲午夜国产成人av电影男同| 国产精品国产亚洲伊人久久| 日韩免费av一区二区| 欧美大肥婆大肥bbbbb| 中文字幕免费精品一区高清| 国产一区深夜福利| 日韩精品在线免费| 亚洲一区二区三区在线免费观看| 国产精品日韩在线一区| 亚洲性视频网址| 亚洲变态欧美另类捆绑| 欧美激情亚洲综合一区| 麻豆一区二区在线观看| 久久精品视频在线| 久久久亚洲成人| 亚洲精品成人久久久| 欧美美女操人视频| 国产亚洲精品久久久久动| 国产精品小说在线| 揄拍成人国产精品视频| 欧美亚洲成人精品| 日韩视频免费中文字幕| 日本精品久久久久久久| 久久精品国产一区二区电影| 亚洲精品视频网上网址在线观看| 2019中文字幕在线免费观看| 久久九九国产精品怡红院| 在线观看欧美视频| 国产成人精品视频| 国产欧美一区二区三区久久人妖| 操91在线视频| 欧美尺度大的性做爰视频| 亚洲人成网站在线播| 国产一区二区三区视频免费| 国产精品日韩一区| 国产精品视频专区| 在线国产精品视频| 国产成人福利视频| 国产一区二区三区18| 欧美激情国内偷拍| 性欧美亚洲xxxx乳在线观看| 欧美在线视频在线播放完整版免费观看| 久久久精品一区二区| 亚洲国产小视频在线观看| 不卡在线观看电视剧完整版| 国产精品高精视频免费| 欧美区二区三区| 久久影院中文字幕| 一区二区三区四区视频| 中文字幕免费精品一区| 日韩网站免费观看高清| 国产成人在线播放| 高清视频欧美一级| 在线视频欧美性高潮| 亚洲激情自拍图| 欧美性猛交xxxx免费看久久久| 国产成人亚洲综合青青| 亚洲欧美国产另类| 亚洲男人av在线| 日韩av网址在线| 欧美超级免费视 在线| 欧美另类精品xxxx孕妇| 欧美激情视频三区| 欧美日韩国产黄| 亚洲jizzjizz日本少妇| 一区二区三区在线播放欧美| 欧美中文字幕在线视频| 亚洲国产精品电影在线观看| 国产99久久精品一区二区永久免费| 操人视频在线观看欧美| 国产精品久久久av久久久| 最近2019年日本中文免费字幕| 欧美电影在线观看高清| 欧美有码在线视频| 欧美国产欧美亚洲国产日韩mv天天看完整| 国产精品一区二区久久国产| 日韩视频在线一区| 国产精品户外野外| 国产精品免费一区| 欧美体内谢she精2性欧美| 日韩中文字幕第一页| 国产精品国产自产拍高清av水多| 久久精品亚洲热| 九九精品视频在线| zzijzzij亚洲日本成熟少妇| 欧美精品性视频| 九九视频这里只有精品| 26uuu另类亚洲欧美日本一| 亚洲第一级黄色片| 欧美午夜丰满在线18影院| 亚洲成人亚洲激情| 亚洲第一国产精品| 欧美精品久久久久久久免费观看| 激情av一区二区| 91精品国产自产91精品| 黑人巨大精品欧美一区二区免费| 欧美大片在线免费观看| 久久久av亚洲男天堂| 欧美日韩成人在线视频| 国产精品第8页| 亚洲qvod图片区电影| 91精品久久久久久久久久| 日韩网站免费观看高清| 欧美视频不卡中文| 久久久久久成人精品| 欧美精品999| 国语对白做受69| 国产国产精品人在线视| 91福利视频在线观看| 亚洲精品美女久久| 欧美亚洲视频在线观看| 91成人在线视频| 亚州成人av在线| 久久久久国产精品一区| 国产亚洲成av人片在线观看桃| 4p变态网欧美系列| 国产亚洲一区二区精品| 国产精品免费久久久久影院| 成人免费看片视频| 欧美激情视频在线观看| 亚洲美女精品成人在线视频| 欧美激情久久久久| 91精品国产91久久| 久久久久国产精品免费| 国产日韩精品入口| 国产欧美日韩免费看aⅴ视频| 国产欧美va欧美va香蕉在| 亚洲成人久久久久| 久久躁狠狠躁夜夜爽| 亚洲一区二区三区在线免费观看| 一个色综合导航| 亚洲天堂免费视频| 九色91av视频| 欧美人与物videos| 久久久久久成人| 日韩成人av在线| 色综合色综合网色综合| 91国产中文字幕| 亚洲精品天天看| 日韩中文字幕不卡视频| 国产成人短视频| 91亚洲一区精品| 日韩视频一区在线| 色偷偷偷综合中文字幕;dd| 日韩欧美亚洲国产一区|