Android自定義view實(shí)現(xiàn)阻尼效果的加載動(dòng)畫
效果:
需要知識(shí):
1. 二次貝塞爾曲線
2. 動(dòng)畫知識(shí)
3. 基礎(chǔ)自定義view知識(shí)
先來解釋下什么叫阻尼運(yùn)動(dòng)
阻尼振動(dòng)是指,由于振動(dòng)系統(tǒng)受到摩擦和介質(zhì)阻力或其他能耗而使振幅隨時(shí)間逐漸衰減的振動(dòng),又稱減幅振動(dòng)、衰減振動(dòng)。[1] 不論是彈簧振子還是單擺由于外界的摩擦和介質(zhì)阻力總是存在,在振動(dòng)過程中要不斷克服外界阻力做功,消耗能量,振幅就會(huì)逐漸減小,經(jīng)過一段時(shí)間,振動(dòng)就會(huì)完全停下來。這種振幅隨時(shí)間減小的振動(dòng)稱為阻尼振動(dòng).因?yàn)檎穹c振動(dòng)的能量有關(guān),阻尼振動(dòng)也就是能量不斷減少的振動(dòng).阻尼振動(dòng)是非簡(jiǎn)諧運(yùn)動(dòng).阻尼振動(dòng)系統(tǒng)屬于耗散系統(tǒng)。這里的阻尼是指任何振動(dòng)系統(tǒng)在振動(dòng)中,由于外界作用或系統(tǒng)本身固有的原因引起的振動(dòng)幅度逐漸下降的特性,以及此一特性的量化表征。
本例中文字部分凹陷就是這種效果,當(dāng)然這篇文章知識(shí)帶你簡(jiǎn)單的使用.
跳動(dòng)的水果效果實(shí)現(xiàn)
剖析:從上面的效果圖中很面就是從頂端向下掉落然后再向上 期間旋轉(zhuǎn)即可.
那么我們首先自定義一個(gè)view繼承FrameLayout
public class My extends FrameLayout { public My(Context context) { super(context); } public My(Context context, AttributeSet attrs) { super(context, attrs); } }
需要素材如下三張圖片:
也許有人會(huì)問我看到你效果圖到頂部或者底部就變成向上或者向下了.你三張夠嗎?
答:到頂部或者底部旋轉(zhuǎn)180度即可
我們現(xiàn)在自定義中定義幾個(gè)變量
//用于記錄當(dāng)前圖片使用數(shù)組中的哪張 int indexImgFlag = 0; //下沉圖片 前面三個(gè)圖片的id int allImgDown [] = {R.mipmap.p2,R.mipmap.p4,R.mipmap.p6,R.mipmap.p8}; //動(dòng)畫效果一次下沉或上彈的時(shí)間 animationDuration*2=一次完整動(dòng)畫時(shí)間 int animationDuration = 1000; //彈起來的圖片 ImageView iv; //圖片下沉高度(即從最高點(diǎn)到最低點(diǎn)的距離) int downHeight = 2; //掉下去的動(dòng)畫 private Animation translateDown; //彈起動(dòng)畫 private Animation translateUp; //旋轉(zhuǎn)動(dòng)畫 private ObjectAnimator rotation;
我們?cè)賮砜纯闯跏蓟瘎?dòng)畫的方法(此方法使用了遞歸思想,實(shí)現(xiàn)無限播放動(dòng)畫,大家可以看看哪里不理解)
//初始化彈跳動(dòng)畫 public void MyAnmation(){ //下沉效果動(dòng)畫 translateDown = new TranslateAnimation( Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0, Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,downHeight); translateDown.setDuration(animationDuration); //設(shè)置一個(gè)插值器 動(dòng)畫將會(huì)播放越來越快 模擬重力 translateDown.setInterpolator(new AccelerateInterpolator()); //上彈動(dòng)畫 translateUp = new TranslateAnimation( Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0, Animation.RELATIVE_TO_SELF,downHeight,Animation.RELATIVE_TO_SELF,0 ); translateUp.setDuration(animationDuration); ////設(shè)置一個(gè)插值器 動(dòng)畫將會(huì)播放越來越慢 模擬反重力 translateUp.setInterpolator(new DecelerateInterpolator()); //當(dāng)下沉動(dòng)畫完成時(shí)播放啟動(dòng)上彈 translateDown.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { iv.setImageResource(allImgDown[indexImgFlag]); rotation = ObjectAnimator.ofFloat(iv, "rotation", 180f, 360f); rotation.setDuration(1000); rotation.start(); } @Override public void onAnimationEnd(Animation animation) { iv.startAnimation(translateUp); } @Override public void onAnimationRepeat(Animation animation) { } }); //當(dāng)上移動(dòng)畫完成時(shí) 播放下移動(dòng)畫 translateUp.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { indexImgFlag = 1+indexImgFlag>=allImgDown.length?0:1+indexImgFlag; iv.setImageResource(allImgDown[indexImgFlag]); rotation = ObjectAnimator.ofFloat(iv, "rotation", 0.0f, 180f); rotation.setDuration(1000); rotation.start(); } @Override public void onAnimationEnd(Animation animation) { //遞歸 iv.startAnimation(translateDown); } @Override public void onAnimationRepeat(Animation animation) { } }); }
以上代碼知識(shí):
插值器:會(huì)讓一個(gè)動(dòng)畫在播放時(shí)在某一時(shí)間段加快動(dòng)畫或者減慢
//設(shè)置一個(gè)插值器 動(dòng)畫將會(huì)播放越來越快 模擬重力
1.translateDown.setInterpolator(new AccelerateInterpolator());
這個(gè)插值器 速率表示圖:
可以從斜率看到使用此插值器 動(dòng)畫將越來越快.意義在于模仿下落時(shí)重力的影響
////設(shè)置一個(gè)插值器 動(dòng)畫將會(huì)播放越來越慢 模擬反重力
2. translateUp.setInterpolator(new DecelerateInterpolator());
速率圖:
最后我們初始化下圖片控件到我們的自定義view
private void init() { //初始化彈跳圖片 控件 iv = new ImageView(getContext()); ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); iv.setLayoutParams(params); iv.setImageResource(allImgDown[0]); this.addView(iv); iv.measure(0,0); iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (!flagMeure) { flagMeure =true; //由于畫文字是由基準(zhǔn)線開始 path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight()); //計(jì)算最大彈力 maxElasticFactor = (float) (textHeight / elastic); //初始化貝塞爾曲線 path.rQuadTo(textWidth / 2, 0, textWidth, 0); //初始化上彈和下沉動(dòng)畫 MyAnmation(); iv.startAnimation(translateDown); } } }); }
上面的知識(shí):
1. iv.measure(0,0);主動(dòng)通知系統(tǒng)去測(cè)量此控件 不然iv.getwidth = 0; //下面這個(gè)是同理 等iv測(cè)量完時(shí)回調(diào) 不然iv.getwidth = 0; 2. iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){ … }
原因:TextView tv = new TextView() 或者 LayoutInflat 填充布局都是
異步所以你在new出來或者填充時(shí)直接獲取自然返回0
到現(xiàn)在為止你只需要在自定義view 的onSizeChanged回調(diào)方法中調(diào)用init()即可看到動(dòng)畫的彈動(dòng)
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); init(); }
此方法會(huì)在onmesure方法執(zhí)行完成后回調(diào) 這樣你就可以在此方法獲得自定義view的寬高了
效果圖:
畫文字成u形
首先你得知道如下知識(shí)
貝塞爾曲線:具體學(xué)習(xí)
這里我們用到2此貝塞爾曲線
我們看看大概是什么叫2次貝塞爾曲線
我們看看 三個(gè)點(diǎn) p0 p1 p2 我們 把p0 稱為 開始點(diǎn) p1 為控制點(diǎn) p2 結(jié)束點(diǎn),那么可以用貝塞爾公式畫出如圖曲線
這里大家沒必要深究怎么畫出來. 也不需要你懂 這個(gè)要數(shù)學(xué)基礎(chǔ)的
那么我們?cè)诎沧恐性趺串嬆?#63;
Path path = new Path(); //p0的x y坐標(biāo) path.moveTo(p0.x,y); path.rQuadTo(p1.x,p1.y,p2.x,p2.y);
這就是API調(diào)用方法是不是很簡(jiǎn)單?那么你又會(huì)問那么怎么畫出來呢?
很簡(jiǎn)單在 dispatchDraw方法 或者onDraw中 調(diào)用
@Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); canvas.drawPath(path,paint); }
那么你畫出來的效果應(yīng)該和在Ps用鋼筆畫出來的差不多 ps中鋼筆工具就是二次貝塞爾曲線
(借用下圖片)
如果你的三個(gè)點(diǎn)的位置如剛開的圖片 p0 p1 p2 (p1在p0右上方并且 p1在p2左上方)一樣那么在屏幕中的顯示效果如下
這里隨擴(kuò)張下dispatchDraw和ondraw的區(qū)別
如果你的自定義view 是繼承view 那么 會(huì)先調(diào)用 ondraw->>dispatchDraw
如果你的自定義view 是繼承viewgroup那么會(huì)跳過ondraw方法直接調(diào)用dispathchDraw這里特別注意!!我們這個(gè)案例中繼承的是FrameLayout, 而frameLayout又是繼承自viewgroup所以….
那么我們回到主題 如何畫一個(gè)U形文字?簡(jiǎn)單就是說按照我們畫出來的曲線在上面寫字 如: 文字是”CSDN開源中國(guó)” 如何讓這幾個(gè)字貼著我們的曲線寫出來?
這里介紹一個(gè)API
canvas.drawTextOnPath()
第一個(gè)參數(shù):文字 類型為字符串
第二個(gè)參數(shù):路徑 也就是我們前面的二次貝塞爾曲線
第三個(gè)參數(shù):沿著路徑文字開始的位置 說白了偏移量
第四個(gè)參數(shù):貼著路徑的高度的偏移量
hOffset:
The distance along the path to add to the text's starting position
vOffset:
The distance above(-) or below(+) the path to position the text
//ok我們看看他可以畫出什么樣子的文字
這種看大家對(duì)貝塞爾曲線的理解,你理解的越深那么你可以畫出的圖像越多,當(dāng)然不一定要用貝塞爾曲線
確定貝塞爾曲線的起點(diǎn)
我們?cè)诨剡^頭來看看我們的效果圖
我們可以看到文字應(yīng)該是在iv(彈跳的圖片中央位置且正好在 iv彈到底部的位置)
這里我們先補(bǔ)充知識(shí)在考慮計(jì)算
我們來學(xué)習(xí)一下文字的測(cè)量我們來看幅圖
我們調(diào)用畫文字的API時(shí)
canvas.drawTextOnPath或者canvas.drawText 是從基準(zhǔn)線開始畫的也就是說途中的baseline開始畫.
如:
canvas.drawText(“FMY”,0,0,paint);
那么你將看不到文字 只能在屏幕看到文字底部如下圖:
另一個(gè)同理API drawTextOnPath 也是
再看看幾個(gè)簡(jiǎn)單的API
1 . paint.measureText(“FMY”);返回在此畫筆paint下寫FMY文字的寬度
下面的API會(huì)把文字的距離左邊left 上邊top 右邊right 底部的bottom的值寫入此矩形 那么
rect.right-rect.left=文字寬度 rect.bottom-rect.top=文字高度 //矩形 Rect rect = new Rect(); //將文字畫入矩形目的是為了測(cè)量高度 paint.getTextBounds(printText, 0, printText.length(), rect);
那么請(qǐng)看:
private void init() { //初始化彈跳圖片 控件 iv = new ImageView(getContext()); ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); iv.setLayoutParams(params); iv.setImageResource(allImgDown[0]); this.addView(iv); //畫筆的初始化 paint = new Paint(); paint.setStrokeWidth(1); paint.setColor(Color.CYAN); paint.setStyle(Paint.Style.FILL); paint.setTextSize(50); paint.setAntiAlias(true); //矩形 Rect rect = new Rect(); //將文字畫入矩形目的是為了測(cè)量高度 paint.getTextBounds(printText, 0, printText.length(), rect); //文本寬度 textWidth = paint.measureText(printText); //獲得文字高度 textHeight = rect.bottom - rect.top; //初始化路徑 path = new Path(); iv.setX(getWidth()/2); iv.measure(0,0); iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (!flagMeure) { flagMeure =true; //由于畫文字是由基準(zhǔn)線開始 path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight()); //計(jì)算最大彈力 maxElasticFactor = (float) (textHeight / elastic); //初始化貝塞爾曲線 path.rQuadTo(textWidth / 2, 0, textWidth, 0); //初始化上彈和下沉動(dòng)畫 MyAnmation(); iv.startAnimation(translateDown); } } }); }
我們現(xiàn)在寫一個(gè)類當(dāng)iv圖片(彈跳圖)碰到文字頂部時(shí)設(shè)置一個(gè)監(jiān)聽器 時(shí)間正好是彈圖向上到頂部的時(shí)間 期間不斷讓文字凹陷在恢復(fù)正常
//用于播放文字下沉和上浮動(dòng)畫傳入的數(shù)值必須是 圖片下沉和上升的一次時(shí)間 public void initAnimation(int duration){ //這里為什maxElasticFactor/4 好看...另一個(gè)同理 這個(gè)數(shù)值大家自行調(diào)整 ValueAnimator animator = ValueAnimator.ofFloat(maxElasticFactor/4, (float) (maxElasticFactor / 1.5),0); animator.setDuration(duration/2); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { calc();//重新畫路徑 nowElasticFactor= (float) animation.getAnimatedValue(); postInvalidate(); } }); animator.start(); }
再來一個(gè)重新繪畫路徑計(jì)算的方法
public void calc(){ //重置路徑 path.reset(); //由于畫文字是由基準(zhǔn)線開始 path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight()); //畫二次貝塞爾曲線 path.rQuadTo(textWidth / 2, nowElasticFactor, textWidth, 0); }
好了到這里我們看看完整源碼吧:
package com.example.administrator.myapplication; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.util.AttributeSet; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.DecelerateInterpolator; import android.view.animation.TranslateAnimation; import android.widget.FrameLayout; import android.widget.ImageView; public class My extends FrameLayout { //畫筆 private Paint paint; //路徑 private Path path; //要輸入的文本 private String printText = "正在加載"; //文本寬 private float textWidth; //文本高 private float textHeight; //測(cè)量文字寬高的時(shí)候使用的矩形 private Rect rect; //最大彈力系數(shù) private float elastic = 1.5f; //最大彈力 private float maxElasticFactor; //當(dāng)前彈力 private float nowElasticFactor; //用于記錄當(dāng)前圖片使用數(shù)組中的哪張 int indexImgFlag = 0; //下沉圖片 int allImgDown [] = {R.mipmap.p2,R.mipmap.p4,R.mipmap.p6,R.mipmap.p8}; //動(dòng)畫效果一次下沉或上彈的時(shí)間 animationDuration*2=一次完整動(dòng)畫時(shí)間 int animationDuration = 1000; //彈起來的圖片 ImageView iv; //圖片下沉高度(即從最高點(diǎn)到最低點(diǎn)的距離) int downHeight = 2; private Animation translateDown; private Animation translateUp; private ObjectAnimator rotation; public My(Context context) { super(context); } public My(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); canvas.drawTextOnPath(printText, path, 0, 0, paint); } //用于播放文字下沉和上浮動(dòng)畫傳入的數(shù)值必須是 圖片下沉和上升的一次時(shí)間 public void initAnimation(int duration){ //這里為什maxElasticFactor/4為什么 ValueAnimator animator = ValueAnimator.ofFloat(maxElasticFactor/4, (float) (maxElasticFactor / 1.5),0); animator.setDuration(duration/2); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { calc(); nowElasticFactor= (float) animation.getAnimatedValue(); postInvalidate(); } }); animator.start(); } public void calc(){ //重置路徑 path.reset(); //由于畫文字是由基準(zhǔn)線開始 path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight()); //畫二次貝塞爾曲線 path.rQuadTo(textWidth / 2, nowElasticFactor, textWidth, 0); } //初始化彈跳動(dòng)畫 public void MyAnmation(){ //下沉效果動(dòng)畫 translateDown = new TranslateAnimation( Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0, Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,downHeight); translateDown.setDuration(animationDuration); //設(shè)置一個(gè)插值器 動(dòng)畫將會(huì)播放越來越快 模擬重力 translateDown.setInterpolator(new AccelerateInterpolator()); //上彈動(dòng)畫 translateUp = new TranslateAnimation( Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0, Animation.RELATIVE_TO_SELF,downHeight,Animation.RELATIVE_TO_SELF,0 ); translateUp.setDuration(animationDuration); ////設(shè)置一個(gè)插值器 動(dòng)畫將會(huì)播放越來越慢 模擬反重力 translateUp.setInterpolator(new DecelerateInterpolator()); //當(dāng)下沉動(dòng)畫完成時(shí)播放啟動(dòng)上彈 translateDown.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { iv.setImageResource(allImgDown[indexImgFlag]); rotation = ObjectAnimator.ofFloat(iv, "rotation", 180f, 360f); rotation.setDuration(1000); rotation.start(); } @Override public void onAnimationEnd(Animation animation) { iv.startAnimation(translateUp); initAnimation(animationDuration); } @Override public void onAnimationRepeat(Animation animation) { } }); //當(dāng)上移動(dòng)畫完成時(shí) 播放下移動(dòng)畫 translateUp.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { indexImgFlag = 1+indexImgFlag>=allImgDown.length?0:1+indexImgFlag; iv.setImageResource(allImgDown[indexImgFlag]); rotation = ObjectAnimator.ofFloat(iv, "rotation", 0.0f, 180f); rotation.setDuration(1000); rotation.start(); } @Override public void onAnimationEnd(Animation animation) { //遞歸 iv.startAnimation(translateDown); } @Override public void onAnimationRepeat(Animation animation) { } }); } boolean flagMeure; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); init(); } private void init() { //初始化彈跳圖片 控件 iv = new ImageView(getContext()); ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); iv.setLayoutParams(params); iv.setImageResource(allImgDown[0]); this.addView(iv); //畫筆的初始化 paint = new Paint(); paint.setStrokeWidth(1); paint.setColor(Color.CYAN); paint.setStyle(Paint.Style.FILL); paint.setTextSize(50); paint.setAntiAlias(true); //矩形 rect = new Rect(); //將文字畫入矩形目的是為了測(cè)量高度 paint.getTextBounds(printText, 0, printText.length(), rect); //文本寬度 textWidth = paint.measureText(printText); //獲得文字高度 textHeight = rect.bottom - rect.top; //初始化路徑 path = new Path(); iv.setX(getWidth()/2); iv.measure(0,0); iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (!flagMeure) { flagMeure =true; //由于畫文字是由基準(zhǔn)線開始 path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight()); //計(jì)算最大彈力 maxElasticFactor = (float) (textHeight / elastic); //初始化貝塞爾曲線 path.rQuadTo(textWidth / 2, 0, textWidth, 0); //初始化上彈和下沉動(dòng)畫 MyAnmation(); iv.startAnimation(translateDown); } } }); } }
小人奉上源碼一封供大家 參考github源碼下載地址
以上所述是小編給大家介紹的Android自定義view實(shí)現(xiàn)阻尼效果的加載動(dòng)畫,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Android實(shí)現(xiàn)可以展開的TextView
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)可以展開的TextView,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11Android中invalidate()和postInvalidate() 的區(qū)別及使用方法
Android中實(shí)現(xiàn)view的更新有兩組方法,一組是invalidate,另一組是postInvalidate,其中前者是在UI線程自身中使用,而后者在非UI線程中使用。本文給大家介紹Android中invalidate()和postInvalidate() 的區(qū)別及使用方法,感興趣的朋友一起學(xué)習(xí)吧2016-05-05淺析Android 手機(jī)衛(wèi)士設(shè)備管理權(quán)限鎖屏
這篇文章主要介紹了淺析Android 手機(jī)衛(wèi)士設(shè)備管理權(quán)限鎖屏的相關(guān)資料,需要的朋友可以參考下2016-04-04Android開發(fā)之關(guān)于項(xiàng)目
本文是此系列文章的第二篇,給大家介紹的是項(xiàng)目相關(guān)的內(nèi)容,非常的細(xì)致全面,有需要的小伙伴可以參考下2016-02-02Android定時(shí)器實(shí)現(xiàn)的幾種方式整理及removeCallbacks失效問題解決
本文為大家詳細(xì)介紹下Android 定時(shí)器實(shí)現(xiàn)的幾種方式:Handler + Runnable、Timer的方式、Handle與線程的sleep(long )方法和removeCallbacks失效問題如何解決2013-06-06Android 實(shí)現(xiàn)兩個(gè)Activity跳轉(zhuǎn)實(shí)例
本文主要介紹Android 多個(gè)Activity相互之間的跳轉(zhuǎn),認(rèn)識(shí)Activity生命周期,在做Android編程的時(shí)候用處很大,希望能幫助有需要的小伙伴2016-07-07Android 開發(fā)中l(wèi)ayout下的子文件夾
這篇文章主要介紹了android 開發(fā)中l(wèi)ayout下的子文件夾,需要的朋友可以參考下2017-12-12Android采取ContentObserver方式自動(dòng)獲取驗(yàn)證碼
這篇文章主要為大家詳細(xì)介紹了Android采取ContentObserver方式自動(dòng)獲取驗(yàn)證碼,感興趣的小伙伴們可以參考一下2016-08-08淺談Android Studio如何Debug對(duì)應(yīng)so文件C/C++代碼
本篇文章主要介紹了淺談Android Studio如何Debug對(duì)應(yīng)so文件C/C++代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12Android中協(xié)調(diào)滾動(dòng)布局的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android中協(xié)調(diào)滾動(dòng)常用的布局實(shí)現(xiàn),類似這樣的協(xié)調(diào)滾動(dòng)布局,當(dāng)?shù)撞苛斜砘瑒?dòng)的時(shí)候,頂部的布局做響應(yīng)的動(dòng)作,我們都可以通過?AppBarLayout?和?MotionLayout?來實(shí)現(xiàn),本文通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友參考下吧2022-06-06