Android仿直播特效之點(diǎn)贊飄心效果
本文實(shí)例為大家分享了Android實(shí)現(xiàn)點(diǎn)贊飄心效果的具體代碼,供大家參考,具體內(nèi)容如下
一、概述
老規(guī)矩先上圖
好了,基本就是這個(gè)樣子,錄完的視頻用格式工廠轉(zhuǎn)換完就這個(gè)樣子了,將就看吧
二、定義我們自己的Layout
/** * @author 劉洋巴金 * @date 2017-4-27 * * 定義我們自己的布局 * */ public class LoveLayout extends RelativeLayout{ private Context context; private LayoutParams params; private Drawable[] icons = new Drawable[4]; private Interpolator[] interpolators = new Interpolator[4]; private int mWidth; private int mHeight; public LoveLayout(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; initView(); } private void initView() { // 圖片資源 icons[0] = getResources().getDrawable(R.drawable.green); icons[1] = getResources().getDrawable(R.drawable.purple); icons[2] = getResources().getDrawable(R.drawable.red); icons[3] = getResources().getDrawable(R.drawable.yellow); // 插值器 interpolators[0] = new AccelerateDecelerateInterpolator(); // 在動(dòng)畫開始與結(jié)束的地方速率改變比較慢,在中間的時(shí)候加速 interpolators[1] = new AccelerateInterpolator(); // 在動(dòng)畫開始的地方速率改變比較慢,然后開始加速 interpolators[2] = new DecelerateInterpolator(); // 在動(dòng)畫開始的地方快然后慢 interpolators[3] = new LinearInterpolator(); // 以常量速率改變 int width = icons[0].getIntrinsicWidth(); int height = icons[0].getIntrinsicWidth(); params = new LayoutParams(width, height); params.addRule(CENTER_HORIZONTAL, TRUE); params.addRule(ALIGN_PARENT_BOTTOM, TRUE); }
基本就是做了初始化,聲明了4個(gè)drawable,也就是4個(gè)顏色的心,4個(gè)插值器,用于控制動(dòng)畫速率的改變,設(shè)置初始位置為屏幕的下邊中點(diǎn)處。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); } public void addLoveView() { // TODO Auto-generated method stub final ImageView iv = new ImageView(context); iv.setLayoutParams(params); iv.setImageDrawable(icons[new Random().nextInt(4)]); addView(iv); // 開啟動(dòng)畫,并且用完銷毀 AnimatorSet set = getAnimatorSet(iv); set.start(); set.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // TODO Auto-generated method stub super.onAnimationEnd(animation); removeView(iv); } }); }
用于添加心型效果。動(dòng)畫結(jié)束后,再移除
/** * 獲取動(dòng)畫集合 * @param iv * */ private AnimatorSet getAnimatorSet(ImageView iv) { // 1.alpha動(dòng)畫 ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha", 0.3f, 1f); // 2.縮放動(dòng)畫 ObjectAnimator scaleX = ObjectAnimator.ofFloat(iv, "scaleX", 0.2f, 1f); ObjectAnimator scaleY = ObjectAnimator.ofFloat(iv, "scaleY", 0.2f, 1f); // 動(dòng)畫集合 AnimatorSet set = new AnimatorSet(); set.playTogether(alpha, scaleX, scaleY); set.setDuration(500); // 貝塞爾曲線動(dòng)畫 ValueAnimator bzier = getBzierAnimator(iv); AnimatorSet set2 = new AnimatorSet(); set2.playSequentially(set, bzier); set2.setTarget(iv); return set2; }
playTogether:幾個(gè)動(dòng)畫同時(shí)執(zhí)行
ObjectAnimator為屬性動(dòng)畫,不熟悉可以百度了解下
然后是設(shè)置貝塞爾曲線動(dòng)畫
playSequentially:動(dòng)畫依次執(zhí)行
/** * 貝塞爾動(dòng)畫 * */ private ValueAnimator getBzierAnimator(final ImageView iv) { // TODO Auto-generated method stub PointF[] PointFs = getPointFs(iv); // 4個(gè)點(diǎn)的坐標(biāo) BasEvaluator evaluator = new BasEvaluator(PointFs[1], PointFs[2]); ValueAnimator valueAnim = ValueAnimator.ofObject(evaluator, PointFs[0], PointFs[3]); valueAnim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // TODO Auto-generated method stub PointF p = (PointF) animation.getAnimatedValue(); iv.setX(p.x); iv.setY(p.y); iv.setAlpha(1- animation.getAnimatedFraction()); // 透明度 } }); valueAnim.setTarget(iv); valueAnim.setDuration(3000); valueAnim.setInterpolator(interpolators[new Random().nextInt(4)]); return valueAnim; } private PointF[] getPointFs(ImageView iv) { // TODO Auto-generated method stub PointF[] PointFs = new PointF[4]; PointFs[0] = new PointF(); // p0 PointFs[0].x = (mWidth- params.width)/ 2; PointFs[0].y = mHeight - params.height; PointFs[1] = new PointF(); // p1 PointFs[1].x = new Random().nextInt(mWidth); PointFs[1].y = new Random().nextInt(mHeight /2) + mHeight / 2 + params.height; PointFs[2] = new PointF(); // p2 PointFs[2].x = new Random().nextInt(mWidth); PointFs[2].y = new Random().nextInt(mHeight /2); PointFs[3] = new PointF(); // p3 PointFs[3].x = new Random().nextInt(mWidth); PointFs[3].y = 0; return PointFs; }
先獲得4個(gè)點(diǎn)的坐標(biāo)
p0坐標(biāo):x坐標(biāo)((布局的寬-心形圖片寬)除以2),y坐標(biāo)(布局的高 -心形圖片高),這樣獲得的是頂部部水平中心點(diǎn)的坐標(biāo)。
p1坐標(biāo):x坐標(biāo)(橫坐標(biāo)中的隨機(jī)位置),y坐標(biāo)(布局一半的高度 加上 0到一半高度范圍內(nèi)的隨機(jī)坐標(biāo)+心形的高度的一半)。這樣取到的橫坐標(biāo)是在布局寬度之內(nèi)的隨機(jī)坐標(biāo),縱坐標(biāo)為整個(gè)路徑高度中部以上的隨機(jī)坐標(biāo)。
p2坐標(biāo):與p1類似,橫坐標(biāo)是在布局寬度之內(nèi)的隨機(jī)坐標(biāo),縱坐標(biāo)為整個(gè)路徑高度中部以下的隨機(jī)坐標(biāo)。
p3坐標(biāo):控件底部中心點(diǎn)
好了知道4個(gè)坐標(biāo)了,那么開始計(jì)算路徑
首先為了計(jì)算貝塞爾曲線,我們先寫一個(gè)估值器
/** * @author 劉洋巴金 * @date 2017-4-27 * * 估值器,計(jì)算路徑 * */ public class BasEvaluator implements TypeEvaluator<PointF> { private PointF p1; private PointF p2; public BasEvaluator(PointF p1, PointF p2) { super(); this.p1 = p1; this.p2 = p2; } @Override public PointF evaluate(float fraction, PointF p0, PointF p3) { // TODO Auto-generated method stub PointF pointf = new PointF(); // 貝塞爾曲線公式 p0*(1-t)^3 + 3p1*t*(1-t)^2 + 3p2*t^2*(1-t) + p3^3 pointf.x = p0.x * (1-fraction) *(1-fraction ) * (1-fraction) +3*p1.x * fraction *(1-fraction )*(1-fraction ) +3*p2.x *fraction *fraction *(1-fraction ) +p3.x*fraction *fraction *fraction ; pointf.y = p0.y * (1-fraction ) *(1-fraction ) * (1-fraction ) +3*p1.y * fraction *(1-fraction )*(1-fraction ) +3*p2.y *fraction *fraction *(1-fraction ) +p3.y*fraction *fraction *fraction ; return pointf; } }
TypeEvaluator:估值器回調(diào)evaluate方法,用于動(dòng)態(tài)的改變動(dòng)畫的屬性值。
evaluate三個(gè)參數(shù):
1.fraction,默認(rèn)傳入的就是(currentTime - startTime) / duration,動(dòng)畫執(zhí)行的時(shí)間除以總的時(shí)間比值,可以理解為變化率。當(dāng)duration到了的時(shí)候,正好,起始點(diǎn)變到終點(diǎn)。
2.起始點(diǎn)
3.終點(diǎn)
根據(jù)三個(gè)參數(shù),計(jì)算點(diǎn)的根據(jù)每毫秒的變化率,計(jì)算點(diǎn)的路徑軌跡。
好了貝塞爾曲線動(dòng)畫就講完了,然后再把動(dòng)畫綁定到控件上。
最后在MainActivity中根據(jù)點(diǎn)擊事件,進(jìn)行增加心型就好了。
btn_press = (Button)findViewById(R.id.btn_press); ll_love = (LoveLayout)findViewById(R.id.ll_love); btn_press.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub ll_love.addLoveView(); } });
三、Demo
Android實(shí)現(xiàn)點(diǎn)贊飄心效果
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android高級(jí)UI特效仿直播點(diǎn)贊動(dòng)畫效果
- android實(shí)現(xiàn)直播點(diǎn)贊飄心動(dòng)畫效果
- Android控件實(shí)現(xiàn)直播App點(diǎn)贊飄心動(dòng)畫
- Android貝塞爾曲線實(shí)現(xiàn)直播點(diǎn)贊效果
- Android 仿微信朋友圈點(diǎn)贊和評(píng)論彈出框功能
- 簡單實(shí)用的Android UI微博動(dòng)態(tài)點(diǎn)贊效果
- Android自定義view實(shí)現(xiàn)仿抖音點(diǎn)贊效果
- Android仿微信朋友圈點(diǎn)贊和評(píng)論功能
- Android自定義View實(shí)現(xiàn)點(diǎn)贊控件
- Android自定義View實(shí)現(xiàn)直播點(diǎn)贊特效
相關(guān)文章
Android View.onMeasure方法詳解及實(shí)例
這篇文章主要介紹了Android View.onMeasure方法詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05Flutter啟動(dòng)頁(閃屏頁)的具體實(shí)現(xiàn)及原理詳析
這篇文章主要給大家介紹了關(guān)于Flutter啟動(dòng)頁(閃屏頁)的具體實(shí)現(xiàn)及原理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Flutter具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Android Studio 3.6 調(diào)試 smali的全過程
這篇文章主要介紹了Android Studio 3.6 調(diào)試 smali, 目前最新版的 Android Studio 利用附加功能調(diào)試 smali 非常方便,具體操作步驟跟隨小編一起看看吧2020-02-02關(guān)于Fragment?already?added問題的解決方案
這篇文章主要介紹了關(guān)于Fragment?already?added問題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10Android最簡單的限制輸入方法(只包含數(shù)字、字母和符號(hào))
這篇文章主要給大家介紹了關(guān)于Android最簡單的限制輸入的實(shí)現(xiàn)方法,限制輸入框只能輸入數(shù)字、字母和符號(hào),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看 吧2018-11-11ViewPager和SlidingPaneLayout的滑動(dòng)事件沖突解決方法
下面小編就為大家分享一篇ViewPager和SlidingPaneLayout的滑動(dòng)事件沖突解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01Android?WebView升級(jí)詳細(xì)操作指南
Android的WebView差異化很嚴(yán)重,下面這篇文章主要給大家介紹了關(guān)于Android?WebView升級(jí)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-07-07