1 收獲
說(shuō)實(shí)話今天沒(méi)有多少的新知識(shí)點(diǎn),但是今天做的東西是在昨天做的東西之上又實(shí)現(xiàn)了一些功能维贺,昨天最后的波浪時(shí)靜態(tài)的它掂,而今天我們將昨天做的最后一個(gè)靜態(tài)的波浪線是實(shí)現(xiàn)了動(dòng)態(tài),就在這里我們又重復(fù)用到了昨天學(xué)到的知識(shí)和以前學(xué)過(guò)的知識(shí)溯泣,包括自定義屬性虐秋,ObjectAnimator,ValueAnimator,RotateAnimation三種動(dòng)畫(huà)垃沦,這又給我們進(jìn)行復(fù)習(xí)的機(jī)會(huì)客给,說(shuō)實(shí)話我對(duì)于這些動(dòng)畫(huà)沒(méi)有了多大印象,除了ValueAnimator因?yàn)樽蛱觳艑W(xué)的肢簿,今天他們又出現(xiàn)在了我的眼前靶剑,我一定要好好的把握住他們蜻拨,不讓他們從我的手指間跑掉。這周又這樣結(jié)束了抬虽,時(shí)間轉(zhuǎn)瞬即逝官觅,好好珍惜眼下吧!2邸休涤!
2.技術(shù)
(1)ValueAnimator動(dòng)畫(huà)實(shí)現(xiàn)波浪線的動(dòng)畫(huà)
(2)利用畫(huà)筆繪制體格圓形和文本
(3)利用繼承ViewGroup實(shí)現(xiàn)布局和一些動(dòng)畫(huà)的組合
(4)利用ValueAnimator和RotateAnimation實(shí)現(xiàn)加載動(dòng)畫(huà)
3.技術(shù)實(shí)踐及其應(yīng)用
(1)ValueAnimator動(dòng)畫(huà)實(shí)現(xiàn)波浪線的動(dòng)畫(huà)
在利用ValueAnimator動(dòng)畫(huà)實(shí)現(xiàn)波浪線的動(dòng)畫(huà)之前為我們必須要做一些準(zhǔn)備工作
設(shè)置一些私有變量以及寫(xiě)出它們對(duì)應(yīng)的構(gòu)造方法,有利于外部對(duì)他們進(jìn)行設(shè)置
private ValueAnimator va;//動(dòng)畫(huà)
private Paint paint;//畫(huà)筆
private Path path;//路徑
float density=getResources().getDisplayMetrics().density;//密度
private int wavelength= (int) (100*density);//波長(zhǎng)
private int wavecrest= (int) (100*density);//波峰
private int speed;//變化動(dòng)畫(huà)的速度
private int lineColor=Color.BLACK;//線條顏色
private int linesize=20 ;//線條粗細(xì)
構(gòu)造方法
//通過(guò)set方法來(lái)實(shí)現(xiàn)外部對(duì)屬性值的設(shè)置
public void setWavelength(int wavelength) {
this.wavelength = wavelength;
}
public void setWavecrest(int wavecrest) {
this.wavecrest = wavecrest;
}
public void setLineColor(int lineColor) {
this.lineColor = lineColor;
paint.setColor(lineColor);
}
public void setLinesize(int linesize) {
this.linesize = linesize;
paint.setStrokeWidth(linesize);
}
接下來(lái)就是在外部的設(shè)置(通過(guò)自定義屬性)
首先我們先要自定義屬性
我們屬性定義完后我們可以在xml中進(jìn)行設(shè)置值
<swu.xcf.waveloading.Waveview
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent"
app:linecolor="@color/colorPrimaryDark"
app:linesize="10"
app:wavelength="50"
app:wavecrest="50"
/>
當(dāng)外部傳來(lái)值時(shí)笛辟,內(nèi)部就要進(jìn)行對(duì)值進(jìn)行處理
private void initAttr(Context context, AttributeSet attrs){
//讀取所有自定義屬性的值
TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.Waveview);
//讀取每一個(gè)屬性的值
wavelength=typedArray.getInteger(R.styleable.Waveview_wavelength, (int) (100*density));
wavecrest=typedArray.getInteger(R.styleable.Waveview_wavecrest,(int) (100*density));
linesize=typedArray.getInteger(R.styleable.Waveview_linesize,10);
lineColor=typedArray.getInteger(R.styleable.Waveview_linecolor,Color.BLACK);
}
接下來(lái)就是進(jìn)行繪制圖形了功氨,首先我們還是要進(jìn)行對(duì)畫(huà)筆進(jìn)行初始化
private void inite(){
paint=new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(lineColor);
paint.setStrokeWidth(linesize);
paint.setStyle(Paint.Style.STROKE);
}
由于這個(gè)繪制的圖形并不是規(guī)則的,所以我們要明確繪制的路徑手幢,我們要對(duì)路徑進(jìn)行初始化
private void initpath() {
//創(chuàng)造曲線
path=new Path();
//計(jì)算多少個(gè)周期(有幾個(gè)完整的波)
int count=getWidth()/wavelength;
//移動(dòng)設(shè)置起始點(diǎn) 距離x左邊的一個(gè)波長(zhǎng)
path.moveTo(-wavelength+speed,getHeight()/2);
//獲取中心的坐標(biāo)
int ceterY= (int) getPivotY();
//卻確定曲線的路徑
for(int start=-wavelength+speed;start<getWidth();start+=wavelength){
//畫(huà)上半周期
path.cubicTo(start,ceterY,start+wavelength/4,ceterY-wavecrest,start+wavelength/2,ceterY);
//畫(huà)下半周期
path.cubicTo(start+wavelength/2,ceterY,start+(wavelength/4)*3,ceterY+wavecrest,start+wavelength,ceterY);
}
}
現(xiàn)在筆有了捷凄,路徑有了,接下來(lái)我們就是進(jìn)行繪制了
@Override
protected void onDraw(Canvas canvas) {
//開(kāi)始繪制
initpath();
canvas.drawPath(path,paint);
}
但是當(dāng)我們運(yùn)行后發(fā)現(xiàn)這個(gè)波浪時(shí)靜態(tài)的围来,所以我們想到用一個(gè)動(dòng)畫(huà)來(lái)實(shí)現(xiàn)
//開(kāi)始動(dòng)畫(huà)
public void startWave(){
va=ValueAnimator.ofInt(0,wavelength);
va.setDuration(400);//動(dòng)畫(huà)間隔時(shí)間
va.setRepeatCount(ValueAnimator.INFINITE);//設(shè)置動(dòng)畫(huà)重復(fù)的次數(shù)
va.setRepeatMode(ValueAnimator.RESTART);//設(shè)置動(dòng)畫(huà)的類(lèi)型
va.setInterpolator(new LinearInterpolator());//使動(dòng)畫(huà)勻速
//設(shè)置更新的監(jiān)聽(tīng)器
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//獲取當(dāng)前值
speed= (int) valueAnimator.getAnimatedValue();
//刷新
invalidate();
}
});
va.start();//開(kāi)始動(dòng)畫(huà)
}
但是我們又發(fā)現(xiàn)當(dāng)我們我們進(jìn)度滿(mǎn)后跺涤,動(dòng)畫(huà)并沒(méi)有結(jié)束,所以我們寫(xiě)了一一個(gè)專(zhuān)門(mén)用來(lái)結(jié)束動(dòng)畫(huà)的函數(shù)
//暫停動(dòng)畫(huà)
public void stopWave(){
if(va!=null){
va.cancel();
}
效果:
(2)利用畫(huà)筆繪制體格圓形和文本
在這里并沒(méi)有什么新的知識(shí)和技術(shù)监透,都是在昨天的講過(guò)的桶错,不知道的可以看上一篇推文,那片推文中有詳細(xì)的介紹胀蛮。
首先我們還是要一些我們需要的屬性以及他們的set方法院刁,方便外部對(duì)這些屬性進(jìn)行設(shè)置值
Paint circlepaint;//畫(huà)圓的畫(huà)筆
Paint textcircle;//繪制文本的畫(huà)筆
private int centerYSpace;//和中心線的距離
private int linesize=20;//線條粗細(xì)
private int linecolor=Color.BLACK;//線條顏色
private int textcolor=Color.BLACK;//文本顏色
private int textsize=50;//文本大小
private float progress;//進(jìn)度
set方法
ublic void setLinesize(int linesize) {
this.linesize = linesize;
circlepaint.setStrokeWidth(linesize);
}
public void setLinecolor(int linecolor) {
this.linecolor = linecolor;
circlepaint.setColor(linecolor);
}
public void setTextcolor(int textcolor) {
this.textcolor = textcolor;
textcircle.setColor(textcolor);
}
public void setTextsize(int textsize) {
this.textsize = textsize;
textcircle.setTextSize(textsize);
}
public void setProgress(float progress) {
this.progress = progress;
//刷新
invalidate();
}
public void setCenterYSpace(int centerYSpace) {
this.centerYSpace = centerYSpace;
}
然后對(duì)兩種畫(huà)筆進(jìn)行初始化
private void inite() {
circlepaint=new Paint(Paint.ANTI_ALIAS_FLAG);//創(chuàng)建畫(huà)筆
circlepaint.setStrokeWidth(linesize);//畫(huà)筆的粗細(xì)
circlepaint.setColor(linecolor);//畫(huà)筆的顏色
circlepaint.setStyle(Paint.Style.STROKE);//畫(huà)筆的風(fēng)格(空心,實(shí)心)
textcircle=new Paint(Paint.ANTI_ALIAS_FLAG);//創(chuàng)建畫(huà)筆
textcircle.setStyle(Paint.Style.FILL);//畫(huà)筆的風(fēng)格(空心粪狼,實(shí)心)
textcircle.setColor(textcolor);//畫(huà)筆的顏色
textcircle.setTextSize(textsize);//畫(huà)筆的粗細(xì)
}
在onDraw方法中進(jìn)行一些位置的設(shè)置退腥,然后開(kāi)始進(jìn)行繪制
protected void onDraw(Canvas canvas) {
//確定半徑
int radius=Math.min(getWidth(),getHeight());
//畫(huà)圓
canvas.drawCircle(getPivotX(),getPivotX(),radius/2-linesize,circlepaint);
//畫(huà)文本
String text=(int)(progress*100)+"%";
//計(jì)算文本寬度
int width= (int) textcircle.measureText(text);
//獲取文字矩陣fontMetrics
Paint.FontMetricsInt fm=textcircle.getFontMetricsInt();
//開(kāi)始繪制
canvas.drawText(text,getPivotX()-width/2,getPivotY()+(-fm.ascent)/2+centerYSpace,textcircle);
}
效果:
(3)利用繼承ViewGroup實(shí)現(xiàn)布局和一些動(dòng)畫(huà)的組合
首先我們要先創(chuàng)建一個(gè)類(lèi),這個(gè)類(lèi)繼承于ViewGroup
創(chuàng)建后我們要實(shí)現(xiàn)ViewGroup里面的抽象方法
和自己的構(gòu)造方法(得到外部給自己的值)
//抽象方法
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
}
//構(gòu)造方法
public WaveLoadingView(Context context) {
super(context);
}
public WaveLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public float getProgress() {
return progress;
}
然后我們需要?jiǎng)?chuàng)建兩個(gè)視圖類(lèi)(動(dòng)畫(huà))的對(duì)象和一個(gè)進(jìn)度屬性
private Waveview wv;
private float progress;
private cricleview cv;
我們要實(shí)現(xiàn)具體類(lèi)的再榄,對(duì)類(lèi)的屬性進(jìn)行設(shè)置以及實(shí)現(xiàn)具體的布局
所以我們要在 onLayout() 抽象方法中去實(shí)現(xiàn)狡刘。
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
//創(chuàng)建原視圖
cv=new cricleview(getContext());
cv.setLinecolor(Color.RED);
cv.setLinesize(50);
cv.setTextcolor(Color.RED);
cv.setTextsize(60);
cv.setCenterYSpace(-50);
//對(duì)子視圖進(jìn)行布局
cv.layout(0,0,getWidth(),getHeight());
//將子視圖添加到容器中
addView(cv);
//創(chuàng)建Waveview
wv=new Waveview(getContext());
wv.setLineColor(Color.RED);
wv.setLinesize(5);
wv.setWavecrest(30);
wv.setWavelength(100);
//布局
wv.layout(getWidth()/4,getHeight()/2-30,getWidth()*3/4,getHeight()+30);
//添加視圖
addView(wv);
}
效果:
(4)利用ValueAnimator和RotateAnimation實(shí)現(xiàn)加載動(dòng)畫(huà)
首先我們需要兩張圖片,我們將看兩張圖片引到在
然后我們對(duì)兩張圖片添加到容器中去
private void inite() {
ImageView inner=new ImageView(getContext());
inner.setImageResource(R.drawable.m);
addView(inner);
outer=new ImageView(getContext());
outer.setImageResource(R.drawable.y);
addView(outer);
}
然后我們對(duì)里面的圖片進(jìn)行設(shè)置動(dòng)畫(huà)(兩種方式ValueAnimator和RotateAnimation)
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
/*
RotateAnimation ra=new RotateAnimation(0,720,outer.getPivotX(),outer.getPivotY());
ra.setDuration(300);
ra.setRepeatCount(Animation.INFINITE);
ra.setRepeatMode(Animation.RESTART);
ra.setInterpolator(new LinearInterpolator());
outer.startAnimation(ra);
*/
ObjectAnimator oa=ObjectAnimator.ofFloat(outer,"rotation",0,360);
oa.setDuration(1000);
oa.setRepeatMode(ObjectAnimator.RESTART);
oa.setRepeatCount(ObjectAnimator.INFINITE);
oa.setInterpolator(new LinearInterpolator());
oa.start();
}
效果: