欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android仿QQ圓形頭像個(gè)性名片

 更新時(shí)間:2016年11月04日 13:06:15   作者:cj_286  
這篇文章主要為大家詳細(xì)介紹了Android仿QQ圓形頭像個(gè)性名片的制作方法,涉及圓形頭像和光環(huán)波形設(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

先看看效果圖:


中間的圓形頭像和光環(huán)波形講解請(qǐng)看:http://www.dbjr.com.cn/article/96508.htm
周圍的氣泡布局,因?yàn)椴季諶atioLayout是繼承自ViewGroup,所以布局layout就可以根據(jù)自己的需求來布局其子view,view.layout(int l,int t,int r,int b);用于布局子view在父ViewGroup中的位置(相對(duì)于父容器),所以在RatioLayout中計(jì)算所有子view的left,top,right,bottom。那么頭像的周圍的氣泡view是如何計(jì)算它的left,top,right,bottom的呢,這些氣泡view是坐落在頭像外圍的圓環(huán)上,只要知道這個(gè)圓環(huán)的半徑,然后再根據(jù)氣泡的個(gè)數(shù),計(jì)算每個(gè)氣泡之間的角度,半徑加角度就可以計(jì)算每個(gè)氣泡坐落的位置。

/** 
 * 計(jì)算氣泡的布局位置 
 * @param textViews 
 */ 
 private void calculateRatioFrame(List<BubbleView> textViews){ 
 if(textViews.size() == 0) return; 
 mRatioFrameList.clear(); 
 
 double angle = 0;//記錄每個(gè)氣泡的角度,正上方的為0° 
 double grad = Math.PI * 2 / textViews.size();//梯度,每個(gè)TextView之間的角度 (Math.PI 是數(shù)學(xué)中的90°) 
 double rightAngle = Math.PI / 2;//一圈為360°,一共四個(gè)方向,每個(gè)方向90°,我們按照小于等于90°來計(jì)算,然后再放到相應(yīng)的方向上 
 
 //cx,cy是容器的中心點(diǎn),也是圓形頭像的中心點(diǎn),計(jì)算氣泡的位置就是已cx,cy為基準(zhǔn)來計(jì)算的 
 int cx = mWidth / 2;//容器中心x坐標(biāo) 
 int cy = mHeight / 2;//容器中心y坐標(biāo) 
 
 int radius = mMinSize / 2 / 2 / 2 + mMinSize / 2 / 2 ;//動(dòng)態(tài)氣泡的組成圓的半徑 
 
 int left = 0; 
 int top = 0; 
 int right = 0; 
 int bottom = 0; 
 int a = 0,b = 0;//a是基于cx的偏移量,b是基于cy的偏移量, 
 //int r = mMinSize / 6 / 2;//氣泡半徑 
 for (int i = 0; i < textViews.size(); i++) { 
 int r = textViews.get(i).getMeasuredWidth() / 2;//計(jì)算得來//固定死的mMinSize / 6 / 2;//氣泡半徑 
 if(angle >= 0 && angle < rightAngle){ //0 - 90度是計(jì)算偏移量 
 //保持角度在 0 - 90 
 a = (int)(radius * Math.sin(Math.abs(angle % rightAngle))); 
 b = (int)(radius * Math.cos(Math.abs(angle % rightAngle))); 
 
 left = cx + a - r;//cx + a為氣泡的中心點(diǎn),要想得到left,還需減去半徑r 
 top = cy - b - r; 
 right = left + 2 * r; 
 bottom = top + 2 * r; 
 
 
 }else if(angle >= rightAngle && angle < rightAngle * 2){ // 90 - 180 
 a = (int)(radius * Math.sin(Math.abs(angle % rightAngle))); 
 b = (int)(radius * Math.cos(Math.abs(angle % rightAngle))); 
 left = cx + b - r; 
 top = cy + a - r; 
 right = left + 2 * r; 
 bottom = top + 2 * r; 
 
 
 }else if(angle >= rightAngle * 2 && angle < rightAngle * 3){ // 180 - 270 
 a = (int)(radius * Math.sin(Math.abs(angle % rightAngle))); 
 b = (int)(radius * Math.cos(Math.abs(angle % rightAngle))); 
 left = cx - a - r; 
 top = cy + b - r; 
 right = left + 2 * r; 
 bottom = top + 2 * r; 
 
 }else if(angle >= rightAngle * 3 && angle < rightAngle * 4){ //270 - 360 
 a = (int)(radius * Math.sin(Math.abs(angle % rightAngle))); 
 b = (int)(radius * Math.cos(Math.abs(angle % rightAngle))); 
 left = cx - b - r; 
 top = cy - a - r; 
 right = left + 2 * r; 
 bottom = top + 2 * r; 
 
 } 
 
 //將計(jì)算好的left, top, right,bottom,angle保存起來 
 mRatioFrameList.add(new RatioFrame(left, top, right,bottom,angle)); 
 //角度再加一個(gè)梯度值 
 angle += grad; 
 
 } 
 } 

計(jì)算好氣泡的布局left,  top, right,bottom,下面就開始布局這起氣泡,布局中的代碼就簡單的多了

@Override 
 protected void onLayout(boolean changed, int l, int t, int r, int b) { 
 if(mImageView == null) return; 
 
 int width = mImageView.getMeasuredWidth();//計(jì)算圓形頭像的寬 
 int height = mImageView.getMeasuredHeight();//計(jì)算圓形頭像的高 
 //計(jì)算圓形頭像的left, top, right,bottom 
 int left = mWidth / 2 - width / 2; 
 int top = mHeight / 2 - height / 2; 
 int right = mWidth / 2 + width / 2; 
 int bottom = mHeight / 2 + height / 2; 
 //開始布局 
 mImageView.layout(left,top,right,bottom); 
 //布局愛心動(dòng)畫 
 for (int i = 0; i < mLoveXinList.size(); i++) { 
 ImageView imageView = mLoveXinList.get(i); 
 left = mWidth / 2 + width / 4 - imageView.getMeasuredWidth() / 2; 
 bottom = mHeight / 2 + height / 3; 
 top = bottom - imageView.getMeasuredHeight(); 
 right = left + imageView.getMeasuredWidth(); 
 
 imageView.layout(left,top,right,bottom); 
 } 
 
 //布局所有氣泡 
 for (int i = 0; i < mTextViews.size(); i++) { 
 
 TextView textView = mTextViews.get(i); 
 
 //RatioFrame ratioFrame = mRatioFrameList.get(i);//無動(dòng)畫時(shí)使用 
 //有動(dòng)畫的時(shí)候,執(zhí)行期間left, top, right,bottom都在變 
 if(mCurrentRatioFrameList != null){ 
 //ValueAnimator執(zhí)行動(dòng)畫是所產(chǎn)生的所有氣泡left, top, right,bottom 
 RatioFrame ratioFrame = mCurrentRatioFrameList.get(i); 
 textView.layout(ratioFrame.mLeft,ratioFrame.mTop,ratioFrame.mRight,ratioFrame.mBottom); 
 } 
 
 } 
 
 } 

好了,靜態(tài)的氣泡排版到這里就好了,下面的問題是,展開時(shí)如何使氣泡從中心點(diǎn),以弧形的路徑展開,并且氣泡的大小也是由小到大變化。這里就用到的動(dòng)畫類ValueAnimator和ScaleAnimation,詳解請(qǐng)參考:http://www.dbjr.com.cn/article/96509.htm
向外展開的效果我們可以使用view.layout()不斷的重新布局氣泡view,讓其產(chǎn)生一個(gè)平移的效果,下面的一個(gè)問題就是如何計(jì)算平移軌道上面的left,  top, right,bottom,然后重新請(qǐng)求布局就可以了,那么下面就解決如何計(jì)算這個(gè)軌跡,分析

弧形軌跡計(jì)算,其實(shí)就是在直線軌跡的基礎(chǔ)上加上偏移量(moveX和moveY),就形成了弧形軌跡,直線軌跡很好計(jì)算,關(guān)鍵的就是這個(gè)偏移量,因?yàn)樵谑孜坏钠屏啃?,而在中間的偏移量大,且在不同的方向上,moveX和moveY的值的正負(fù)也不一樣。偏移的距離因?yàn)槭怯尚〉酱笤儆纱蟮叫。晕覀冇枚魏瘮?shù)( -2 * Math.pow(fraction,2) + 2 * fraction)來計(jì)算距離,用此二次函數(shù)得到的值乘以一個(gè)設(shè)定的最大值,這個(gè)最大值的就會(huì)是由小到大再由大到小的變化,然后再用不同的角度來計(jì)算它的正負(fù)

if(endRatioFrame.mAngle >0 && endRatioFrame.mAngle <= rightAngle){//(0 < angle <= 90)上移,左移 
 moveX = (int)(temp * Math.abs(Math.cos(endRatioFrame.mAngle)));//上移就應(yīng)該在原本的軌跡上減去moveX 
 moveY = (int)(temp * Math.abs(Math.sin(endRatioFrame.mAngle))); 
 }else if(endRatioFrame.mAngle > rightAngle && endRatioFrame.mAngle <= rightAngle * 2){//(90 < angle <= 180)右移,上移 
 moveX = (int)(-temp * Math.abs(Math.cos(endRatioFrame.mAngle))); 
 moveY = (int)(temp * Math.abs(Math.sin(endRatioFrame.mAngle))); 
 }else if(endRatioFrame.mAngle > rightAngle * 2 && endRatioFrame.mAngle <= rightAngle * 3){//(180 < angle <= 2700)下移,右移 
 moveX = (int)(-temp * Math.abs(Math.cos(endRatioFrame.mAngle))); 
 moveY = (int)(-temp * Math.abs(Math.sin(endRatioFrame.mAngle))); 
 }else if(endRatioFrame.mAngle > rightAngle * 3 && endRatioFrame.mAngle <= rightAngle * 4 || endRatioFrame.mAngle == 0){//(270 < angle <= 360 或者 angle == 0) 左移,下移 
 moveX = (int)(temp * Math.abs(Math.cos(endRatioFrame.mAngle))); 
 moveY = (int)(-temp * Math.abs(Math.sin(endRatioFrame.mAngle))); 
 } 

根據(jù)三角函數(shù)的變化值,上面的代碼可以簡化為

moveX = (int)(temp * Math.cos(endRatioFrame.mAngle)); 
moveY = (int)(temp * Math.sin(endRatioFrame.mAngle)); 

通過上面的計(jì)算公式邏輯,就可以得到氣泡展開時(shí)的類型估算器的實(shí)現(xiàn)類,退出氣泡就將邏輯反一下就可以了

package com.cj.dynamicavatarview.ratio; 
 
import android.animation.TypeEvaluator; 
import android.content.Context; 
import android.util.TypedValue; 
 
import java.util.ArrayList; 
import java.util.List; 
 
/** 
 * Created by chenj on 2016/10/19. 
 */ 
public class EnterRatioFrameEvaluator implements TypeEvaluator { 
 
 public static final int OFFSET_DISTANCE = 80; 
 
 private Context mContext; 
 
 private int mOffsetDistance; 
 
 public EnterRatioFrameEvaluator(Context context){ 
 this.mContext = context; 
 mOffsetDistance = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,OFFSET_DISTANCE,mContext.getResources().getDisplayMetrics()); 
 } 
 
 
 @Override 
 public Object evaluate(float fraction, Object startValue, Object endValue) { 
 List<RatioFrame> startRatioFrameList = (List<RatioFrame>) startValue;//開始值 
 List<RatioFrame> endRatioFrameList = (List<RatioFrame>) endValue;//結(jié)束值 
 List<RatioFrame> ratioFrameList = new ArrayList<>();//產(chǎn)生的新值 
 
 for (int i = 0; i < endRatioFrameList.size(); i++) { 
 RatioFrame endRatioFrame = endRatioFrameList.get(i); 
 RatioFrame startRatioFrame = startRatioFrameList.get(i); 
 //計(jì)算left,top,right,bottom 
 
 double t = ( -2 * Math.pow(fraction,2) + 2 * fraction);//傾斜變化率 
 
 int temp = (int)((mOffsetDistance) * t); 
 double rightAngle = Math.PI / 2; 
 
 int moveX = 0,moveY = 0; 
 //讓氣泡上、下、左、右平移,形成弧度的平移路線 
 moveX = (int)(temp * Math.cos(endRatioFrame.mAngle)); 
 moveY = (int)(temp * Math.sin(endRatioFrame.mAngle)); 
 //重新得到left ,top,right,bottom 
 int left = (int)(startRatioFrame.mLeft + ((endRatioFrame.mLeft - startRatioFrame.mLeft) * fraction) - moveX); 
 int top = (int)(startRatioFrame.mTop + ((endRatioFrame.mTop - startRatioFrame.mTop) * fraction) - moveY) ; 
 int right = (int)(startRatioFrame.mRight + ((endRatioFrame.mRight - startRatioFrame.mRight) * fraction) - moveX); 
 int bottom = (int)(startRatioFrame.mBottom + ((endRatioFrame.mBottom - startRatioFrame.mBottom) * fraction) - moveY) ; 
 ratioFrameList.add(new RatioFrame(left,top,right,bottom)); 
 } 
 return ratioFrameList; 
 } 
} 

下面就可以用ValueAnimator來實(shí)現(xiàn)弧形平移軌跡了

ValueAnimator mAnimatorEnetr = ValueAnimator.ofObject(new EnterRatioFrameEvaluator(getContext()), getRatioFrameCenterList(mRatioFrameCenter,mRatioFrameList),mRatioFrameList); 
 mAnimatorEnetr.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
 @Override 
 public void onAnimationUpdate(ValueAnimator animation) { 
 //獲取新的布局值 
 mCurrentRatioFrameList = (List<RatioFrame>) animation.getAnimatedValue(); 
 //請(qǐng)求重新布局 
 requestLayout(); 
 } 
 }); 
 mAnimatorEnetr.setDuration(OPEN_BUBBLE_TIME); 
 
 mAnimatorEnetr.start(); 

好了,從中心點(diǎn)向外展開的弧形動(dòng)畫到這就實(shí)現(xiàn)了,然后再加上縮放的動(dòng)畫就可以了,縮放的動(dòng)畫使用View動(dòng)畫就可以實(shí)現(xiàn)。

/** 
 * 氣泡由小到大縮放 
 * @param textViews 
 */ 
 private void scaleSmallToLarge(List<BubbleView> textViews){ 
 // 以view中心為縮放點(diǎn),由初始狀態(tài)縮小到看不間 
 ScaleAnimation animation = new ScaleAnimation( 
 0.0f, 1.0f,//一點(diǎn)點(diǎn)變小知道看不見為止 
 0.0f, 1.0f, 
 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f//中間縮放 
 ); 
 animation.setDuration(OPEN_BUBBLE_TIME);//要和平移的時(shí)間一致 
 for (int i = 0; i < textViews.size(); i++) { 
 //再執(zhí)行動(dòng)畫 
 textViews.get(i).startAnimation(animation); 
 } 
 
 } 

下面解決的就是展開后,氣泡開始浮動(dòng),點(diǎn)擊氣泡后停止浮動(dòng),滑動(dòng)手指的之后氣泡跟著手指移動(dòng),松開手指后氣泡返回到原來的位置,返回時(shí)的動(dòng)畫效果和氣泡展開的動(dòng)畫效果非常的類似,氣泡跟著手指移動(dòng)也很好實(shí)現(xiàn),只需要將氣泡view設(shè)置onTouch事件,再onTouch中計(jì)算滑動(dòng)的距離,然后重新view.layout()就可以了,所以這里我們解決浮動(dòng)問題就可以了。浮動(dòng)是不規(guī)則的,并且浮動(dòng)的距離和速度也是不一樣的,我用View動(dòng)畫實(shí)現(xiàn)的效果不是很好,然后就改用了屬性動(dòng)畫來實(shí)現(xiàn)。只需要將view平移x軸和y軸,讓其平移的距離和時(shí)間都不同,看上去就像無規(guī)則的移動(dòng),讓其反復(fù)的做這樣的平移就可以實(shí)現(xiàn)浮動(dòng)的效果。

/** 
 * 給指定的View設(shè)置浮動(dòng)效果 
 * @param view 
 * @return 
 */ 
 private AnimatorSet setAnimFloat(View view ){ 
 List<Animator> animators = new ArrayList<>(); 
 //getRandomDp()得到一個(gè)隨機(jī)的值 
 ObjectAnimator translationXAnim = ObjectAnimator.ofFloat(view, "translationX", 0f,getRandomDp(),getRandomDp() , 0); 
 translationXAnim.setDuration(getRandomTime()); 
 translationXAnim.setRepeatCount(ValueAnimator.INFINITE);//無限循環(huán) 
 translationXAnim.setRepeatMode(ValueAnimator.INFINITE);// 
 translationXAnim.setInterpolator(new LinearInterpolator()); 
 translationXAnim.start(); 
 animators.add(translationXAnim); 
 // 
 ObjectAnimator translationYAnim = ObjectAnimator.ofFloat(view, "translationY", 0f,getRandomDp(),getRandomDp() , 0); 
 translationYAnim.setDuration(getRandomTime()); 
 translationYAnim.setRepeatCount(ValueAnimator.INFINITE); 
 translationYAnim.setRepeatMode(ValueAnimator.INFINITE); 
 translationXAnim.setInterpolator(new LinearInterpolator()); 
 translationYAnim.start(); 
 animators.add(translationYAnim); 
 
 AnimatorSet animatorSet = new AnimatorSet(); 
 animatorSet.playTogether(animators); 
 //animatorSet.setStartDelay(delay); 
 animatorSet.start(); 
 return animatorSet; 
 } 

按住停止浮動(dòng),松開的時(shí)候先歸位,然后再次的浮動(dòng),如果animator.end()方法,歸位后開始浮動(dòng)的時(shí)候會(huì)出現(xiàn)閃動(dòng)的現(xiàn)象,因?yàn)閷傩詣?dòng)畫,雖然可以改變view的位置,但是不會(huì)改變view的left,top,right,bottom,所以重新開始浮動(dòng)的時(shí)候會(huì)出現(xiàn)閃爍的現(xiàn)象,因?yàn)閤 = mLeft + translationX,當(dāng)重新開始的時(shí)候,屬性動(dòng)畫是重新創(chuàng)建的,translationX是從0開始的,因此會(huì)出現(xiàn)閃爍的現(xiàn)象。

final AnimatorSet animatorSet = mAnimatorSetList.get(position); 
 for (Animator animator : animatorSet.getChildAnimations()) { 
 //執(zhí)行到動(dòng)畫最后,恢復(fù)到初始位置,不然重新開始浮動(dòng)的時(shí)候,會(huì)有一個(gè)閃爍的bug 
 if(animator.isRunning()) { 
 animator.end();//執(zhí)行到動(dòng)畫最后 
 animator.cancel();//取消動(dòng)畫 
 } 
 } 

到這里流程已經(jīng)差不多了,但是當(dāng)氣泡移動(dòng)到圓形頭像的里面的時(shí)候松開,氣泡應(yīng)當(dāng)有一個(gè)縮放的效果后歸位,然后應(yīng)有一個(gè)接口回調(diào),告訴調(diào)用者,我到中間了松開了,你可以做一些相應(yīng)的處理?,F(xiàn)在我們看一下如何計(jì)算氣泡已經(jīng)移動(dòng)到頭像里了,其實(shí)通過圓形頭像中心點(diǎn)和氣泡的中心點(diǎn)構(gòu)成一個(gè)直接三角形,然后通過勾股定理,計(jì)算直角邊的長度和圓形頭像的半徑做比較,如果小于圓形頭像的半徑,就說明已經(jīng)到頭像里面了。

/** 
 * 判斷氣泡中心點(diǎn)是否在圖片內(nèi)部 
 * @param view 
 * @param current 當(dāng)前移動(dòng)到的位置 
 * @param endRatioFrame 如果在中間,該值用于復(fù)位到原本位置 
 * @return 
 */ 
 private boolean isInPictureCenter(int position,View view,RatioFrame current,RatioFrame endRatioFrame){ 
 RatioPoint centerPoint = new RatioPoint(mWidth/2,mHeight/2); 
 RatioPoint currentPoint = new RatioPoint(current.mLeft + ((current.mRight - current.mLeft) / 2),current.mTop + ((current.mBottom - current.mTop) / 2)); 
 int x = Math.abs(centerPoint.x - currentPoint.x); 
 int y = Math.abs(centerPoint.y - currentPoint.y); 
 //通過勾股定理計(jì)算兩點(diǎn)之間的距離 
 int edge = (int)Math.sqrt(Math.pow(x,2) + Math.pow(y,2)); 
 int pictureRadius = mImageView.getPictureRadius(); 
 //然后和內(nèi)部圖片的半斤比較,小于pictureRadius,就說明在內(nèi)部 
 if(pictureRadius > edge){//進(jìn)入到內(nèi)部 
 
 if(mInnerCenterListener != null){ 
 mInnerCenterListener.innerCenter(position,((TextView)view).getText().toString()); 
 } 
 
 //說明到中心了,執(zhí)行氣泡縮放 
 reveseScaleView(position ,view,current,endRatioFrame); 
 return true; 
 } 
 return false; 
 } 

氣泡執(zhí)行縮放

/** 
 * 縮放圖片(補(bǔ)間動(dòng)畫) 
 * @param view 
 * @param current 縮放后用于平移的起點(diǎn) 
 * @param endRatioFrame 縮放后用于平移的終點(diǎn) 
 */ 
 public void reveseScaleView(final int position , final View view, final RatioFrame current, final Object endRatioFrame) { 
 // 以view中心為縮放點(diǎn),由初始狀態(tài)縮小到看不間 
 ScaleAnimation animation = new ScaleAnimation( 
 1.0f, 0.0f,//一點(diǎn)點(diǎn)變小知道看不見為止 
 1.0f, 0.0f, 
 Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f//中間縮放 
 ); 
 animation.setDuration(BUBBLE_ENTER_CENTER_SCALE_TIME); 
 animation.setRepeatMode(Animation.REVERSE); 
 animation.setRepeatCount(1); 
 animation.setAnimationListener(new Animation.AnimationListener() { 
 @Override 
 public void onAnimationStart(Animation animation) { 
 } 
 
 @Override 
 public void onAnimationEnd(Animation animation) { 
 //執(zhí)行完縮放后,讓氣泡歸位,歸位結(jié)束后,執(zhí)行接口回調(diào) 
 homingBubbleView(true,position,view, current, endRatioFrame); 
 } 
 
 @Override 
 public void onAnimationRepeat(Animation animation) { 
 } 
 }); 
 view.startAnimation(animation); 
 } 

氣泡進(jìn)入中心的接口回調(diào)定義

public interface InnerCenterListener{ 
 //進(jìn)入中心,松開歸位后調(diào)用 
 void innerCenterHominged(int position, String text); 
 //進(jìn)入中心,松開時(shí)調(diào)用 
 void innerCenter(int position, String text); 
 } 

下面就剩執(zhí)行加1操作和播放愛心的動(dòng)畫,這兩個(gè)動(dòng)畫就是執(zhí)行兩個(gè)View動(dòng)畫,這里就不貼出來了,到這里高仿QQ個(gè)性名片就講解結(jié)束了,如果講的不好或有問題歡迎留言
源碼下載:GitHub
                 下載2

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android實(shí)現(xiàn)儀表盤控件開發(fā)

    Android實(shí)現(xiàn)儀表盤控件開發(fā)

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)儀表盤控件開發(fā),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • Android中invalidate()和postInvalidate() 的區(qū)別及使用方法

    Android中invalidate()和postInvalidate() 的區(qū)別及使用方法

    Android中實(shí)現(xiàn)view的更新有兩組方法,一組是invalidate,另一組是postInvalidate,其中前者是在UI線程自身中使用,而后者在非UI線程中使用。本文給大家介紹Android中invalidate()和postInvalidate() 的區(qū)別及使用方法,感興趣的朋友一起學(xué)習(xí)吧
    2016-05-05
  • Android自定義帶動(dòng)畫效果的圓形ProgressBar

    Android自定義帶動(dòng)畫效果的圓形ProgressBar

    這篇文章主要為大家詳細(xì)介紹了Android自定義帶動(dòng)畫效果的圓形ProgressBar,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • Flutter StreamBuilder組件實(shí)現(xiàn)局部刷新示例講解

    Flutter StreamBuilder組件實(shí)現(xiàn)局部刷新示例講解

    日常使用最多的局部刷新為Provider狀態(tài)管理 Selector,今天分享flutter框架自帶的StreamBuilder組件,該組件可做到局部刷新,使用簡單且輕便
    2022-11-11
  • 最新評(píng)論