Android自定義view實(shí)現(xiàn)阻尼效果的加載動(dòng)畫(huà)
效果:

需要知識(shí):
1. 二次貝塞爾曲線
2. 動(dòng)畫(huà)知識(shí)
3. 基礎(chǔ)自定義view知識(shí)
先來(lái)解釋下什么叫阻尼運(yùn)動(dòng)
阻尼振動(dòng)是指,由于振動(dòng)系統(tǒng)受到摩擦和介質(zhì)阻力或其他能耗而使振幅隨時(shí)間逐漸衰減的振動(dòng),又稱(chēng)減幅振動(dòng)、衰減振動(dòng)。[1] 不論是彈簧振子還是單擺由于外界的摩擦和介質(zhì)阻力總是存在,在振動(dòng)過(guò)程中要不斷克服外界阻力做功,消耗能量,振幅就會(huì)逐漸減小,經(jīng)過(guò)一段時(shí)間,振動(dòng)就會(huì)完全停下來(lái)。這種振幅隨時(shí)間減小的振動(dòng)稱(chē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ì)問(wèn)我看到你效果圖到頂部或者底部就變成向上或者向下了.你三張夠嗎?
答:到頂部或者底部旋轉(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)畫(huà)效果一次下沉或上彈的時(shí)間 animationDuration*2=一次完整動(dòng)畫(huà)時(shí)間
int animationDuration = 1000;
//彈起來(lái)的圖片
ImageView iv;
//圖片下沉高度(即從最高點(diǎn)到最低點(diǎn)的距離)
int downHeight = 2;
//掉下去的動(dòng)畫(huà)
private Animation translateDown;
//彈起動(dòng)畫(huà)
private Animation translateUp;
//旋轉(zhuǎn)動(dòng)畫(huà)
private ObjectAnimator rotation;
我們?cè)賮?lái)看看初始化動(dòng)畫(huà)的方法(此方法使用了遞歸思想,實(shí)現(xiàn)無(wú)限播放動(dòng)畫(huà),大家可以看看哪里不理解)
//初始化彈跳動(dòng)畫(huà)
public void MyAnmation(){
//下沉效果動(dòng)畫(huà)
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à)將會(huì)播放越來(lái)越快 模擬重力
translateDown.setInterpolator(new AccelerateInterpolator());
//上彈動(dòng)畫(huà)
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à)將會(huì)播放越來(lái)越慢 模擬反重力
translateUp.setInterpolator(new DecelerateInterpolator());
//當(dāng)下沉動(dòng)畫(huà)完成時(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)畫(huà)完成時(shí) 播放下移動(dòng)畫(huà)
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)畫(huà)在播放時(shí)在某一時(shí)間段加快動(dòng)畫(huà)或者減慢
//設(shè)置一個(gè)插值器 動(dòng)畫(huà)將會(huì)播放越來(lái)越快 模擬重力
1.translateDown.setInterpolator(new AccelerateInterpolator());
這個(gè)插值器 速率表示圖:

可以從斜率看到使用此插值器 動(dòng)畫(huà)將越來(lái)越快.意義在于模仿下落時(shí)重力的影響
////設(shè)置一個(gè)插值器 動(dòng)畫(huà)將會(huì)播放越來(lái)越慢 模擬反重力
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;
//由于畫(huà)文字是由基準(zhǔn)線開(kāi)始
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)畫(huà)
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出來(lái)或者填充時(shí)直接獲取自然返回0
到現(xiàn)在為止你只需要在自定義view 的onSizeChanged回調(diào)方法中調(diào)用init()即可看到動(dòng)畫(huà)的彈動(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的寬高了
效果圖:

畫(huà)文字成u形
首先你得知道如下知識(shí)
貝塞爾曲線:具體學(xué)習(xí)
這里我們用到2此貝塞爾曲線
我們看看大概是什么叫2次貝塞爾曲線
我們看看 三個(gè)點(diǎn) p0 p1 p2 我們 把p0 稱(chēng)為 開(kāi)始點(diǎn) p1 為控制點(diǎn) p2 結(jié)束點(diǎn),那么可以用貝塞爾公式畫(huà)出如圖曲線
這里大家沒(méi)必要深究怎么畫(huà)出來(lái). 也不需要你懂 這個(gè)要數(shù)學(xué)基礎(chǔ)的
那么我們?cè)诎沧恐性趺串?huà)呢?
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ì)問(wèn)那么怎么畫(huà)出來(lái)呢?
很簡(jiǎn)單在 dispatchDraw方法 或者onDraw中 調(diào)用
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.drawPath(path,paint);
}
那么你畫(huà)出來(lái)的效果應(yīng)該和在Ps用鋼筆畫(huà)出來(lái)的差不多 ps中鋼筆工具就是二次貝塞爾曲線
(借用下圖片)
如果你的三個(gè)點(diǎn)的位置如剛開(kāi)的圖片 p0 p1 p2 (p1在p0右上方并且 p1在p2左上方)一樣那么在屏幕中的顯示效果如下
這里隨擴(kuò)張下dispatchDraw和ondraw的區(qū)別
如果你的自定義view 是繼承view 那么 會(huì)先調(diào)用 ondraw->>dispatchDraw
如果你的自定義view 是繼承viewgroup那么會(huì)跳過(guò)ondraw方法直接調(diào)用dispathchDraw這里特別注意!!我們這個(gè)案例中繼承的是FrameLayout, 而frameLayout又是繼承自viewgroup所以….
那么我們回到主題 如何畫(huà)一個(gè)U形文字?簡(jiǎn)單就是說(shuō)按照我們畫(huà)出來(lái)的曲線在上面寫(xiě)字 如: 文字是”CSDN開(kāi)源中國(guó)” 如何讓這幾個(gè)字貼著我們的曲線寫(xiě)出來(lái)?
這里介紹一個(gè)API
canvas.drawTextOnPath()
第一個(gè)參數(shù):文字 類(lèi)型為字符串
第二個(gè)參數(shù):路徑 也就是我們前面的二次貝塞爾曲線
第三個(gè)參數(shù):沿著路徑文字開(kāi)始的位置 說(shuō)白了偏移量
第四個(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我們看看他可以畫(huà)出什么樣子的文字

這種看大家對(duì)貝塞爾曲線的理解,你理解的越深那么你可以畫(huà)出的圖像越多,當(dāng)然不一定要用貝塞爾曲線
確定貝塞爾曲線的起點(diǎn)
我們?cè)诨剡^(guò)頭來(lái)看看我們的效果圖

我們可以看到文字應(yīng)該是在iv(彈跳的圖片中央位置且正好在 iv彈到底部的位置)
這里我們先補(bǔ)充知識(shí)在考慮計(jì)算
我們來(lái)學(xué)習(xí)一下文字的測(cè)量我們來(lái)看幅圖

我們調(diào)用畫(huà)文字的API時(shí)
canvas.drawTextOnPath或者canvas.drawText 是從基準(zhǔn)線開(kāi)始畫(huà)的也就是說(shuō)途中的baseline開(kāi)始畫(huà).
如:
canvas.drawText(“FMY”,0,0,paint);
那么你將看不到文字 只能在屏幕看到文字底部如下圖:

另一個(gè)同理API drawTextOnPath 也是
再看看幾個(gè)簡(jiǎn)單的API
1 . paint.measureText(“FMY”);返回在此畫(huà)筆paint下寫(xiě)FMY文字的寬度
下面的API會(huì)把文字的距離左邊left 上邊top 右邊right 底部的bottom的值寫(xiě)入此矩形 那么
rect.right-rect.left=文字寬度 rect.bottom-rect.top=文字高度 //矩形 Rect rect = new Rect(); //將文字畫(huà)入矩形目的是為了測(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);
//畫(huà)筆的初始化
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();
//將文字畫(huà)入矩形目的是為了測(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;
//由于畫(huà)文字是由基準(zhǔn)線開(kāi)始
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)畫(huà)
MyAnmation();
iv.startAnimation(translateDown);
}
}
});
}
我們現(xiàn)在寫(xiě)一個(gè)類(lèi)當(dāng)iv圖片(彈跳圖)碰到文字頂部時(shí)設(shè)置一個(gè)監(jiān)聽(tīng)器 時(shí)間正好是彈圖向上到頂部的時(shí)間 期間不斷讓文字凹陷在恢復(fù)正常
//用于播放文字下沉和上浮動(dòng)畫(huà)傳入的數(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();//重新畫(huà)路徑
nowElasticFactor= (float) animation.getAnimatedValue();
postInvalidate();
}
});
animator.start();
}
再來(lái)一個(gè)重新繪畫(huà)路徑計(jì)算的方法
public void calc(){
//重置路徑
path.reset();
//由于畫(huà)文字是由基準(zhǔn)線開(kāi)始
path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight());
//畫(huà)二次貝塞爾曲線
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 {
//畫(huà)筆
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)畫(huà)效果一次下沉或上彈的時(shí)間 animationDuration*2=一次完整動(dòng)畫(huà)時(shí)間
int animationDuration = 1000;
//彈起來(lái)的圖片
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)畫(huà)傳入的數(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();
//由于畫(huà)文字是由基準(zhǔn)線開(kāi)始
path.moveTo(iv.getX()-textWidth/2+iv.getWidth()/2, textHeight+iv.getHeight()+downHeight*iv.getHeight());
//畫(huà)二次貝塞爾曲線
path.rQuadTo(textWidth / 2, nowElasticFactor, textWidth, 0);
}
//初始化彈跳動(dòng)畫(huà)
public void MyAnmation(){
//下沉效果動(dòng)畫(huà)
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à)將會(huì)播放越來(lái)越快 模擬重力
translateDown.setInterpolator(new AccelerateInterpolator());
//上彈動(dòng)畫(huà)
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à)將會(huì)播放越來(lái)越慢 模擬反重力
translateUp.setInterpolator(new DecelerateInterpolator());
//當(dāng)下沉動(dòng)畫(huà)完成時(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)畫(huà)完成時(shí) 播放下移動(dòng)畫(huà)
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);
//畫(huà)筆的初始化
paint = new Paint();
paint.setStrokeWidth(1);
paint.setColor(Color.CYAN);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(50);
paint.setAntiAlias(true);
//矩形
rect = new Rect();
//將文字畫(huà)入矩形目的是為了測(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;
//由于畫(huà)文字是由基準(zhǔn)線開(kāi)始
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)畫(huà)
MyAnmation();
iv.startAnimation(translateDown);
}
}
});
}
}
小人奉上源碼一封供大家 參考github源碼下載地址
以上所述是小編給大家介紹的Android自定義view實(shí)現(xiàn)阻尼效果的加載動(dòng)畫(huà),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Android實(shí)現(xiàn)可以展開(kāi)的TextView
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)可以展開(kāi)的TextView,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
Android中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-04
Android開(kāi)發(fā)之關(guān)于項(xiàng)目
本文是此系列文章的第二篇,給大家介紹的是項(xiàng)目相關(guān)的內(nèi)容,非常的細(xì)致全面,有需要的小伙伴可以參考下2016-02-02
Android定時(shí)器實(shí)現(xiàn)的幾種方式整理及removeCallbacks失效問(wèn)題解決
本文為大家詳細(xì)介紹下Android 定時(shí)器實(shí)現(xiàn)的幾種方式:Handler + Runnable、Timer的方式、Handle與線程的sleep(long )方法和removeCallbacks失效問(wèn)題如何解決2013-06-06
Android 實(shí)現(xiàn)兩個(gè)Activity跳轉(zhuǎn)實(shí)例
本文主要介紹Android 多個(gè)Activity相互之間的跳轉(zhuǎn),認(rèn)識(shí)Activity生命周期,在做Android編程的時(shí)候用處很大,希望能幫助有需要的小伙伴2016-07-07
Android 開(kāi)發(fā)中l(wèi)ayout下的子文件夾
這篇文章主要介紹了android 開(kāi)發(fā)中l(wèi)ayout下的子文件夾,需要的朋友可以參考下2017-12-12
Android采取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++代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
Android中協(xié)調(diào)滾動(dòng)布局的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android中協(xié)調(diào)滾動(dòng)常用的布局實(shí)現(xiàn),類(lèi)似這樣的協(xié)調(diào)滾動(dòng)布局,當(dāng)?shù)撞苛斜砘瑒?dòng)的時(shí)候,頂部的布局做響應(yīng)的動(dòng)作,我們都可以通過(guò)?AppBarLayout?和?MotionLayout?來(lái)實(shí)現(xiàn),本文通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友參考下吧2022-06-06

