套路一:
- 無圖無真相
- 這里要感謝兩位大神的博客 參照很多
- 下面的4個小球完全參照 Android仿百度貼吧客戶端Loading小球 實現(xiàn) 有意向的同學可以點擊過去看看
#######套路二:
- 分析
頂部有水波紋不斷的浮動
頭像跟著水波紋的浮動而浮動
- 解決
- 先到網(wǎng)上百度一番 結果還真有: 仿百度外賣的酷炫水波紋效果及解析
于是馬上看源碼
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.setDrawFilter(mDrawFilter);
mAbovePath.reset();
mBelowWavePath.reset();
φ-=0.1f;
float y,y2;
double ω = 2*Math.PI / getWidth();
mAbovePath.moveTo(getLeft(),getBottom());
mBelowWavePath.moveTo(getLeft(),getBottom());
for (float x = 0; x <= getWidth(); x += 20) {
/**
* y=Asin(ωx+φ)+k
* A—振幅越大发魄,波形在y軸上最大與最小值的差值越大
* ω—角速度, 控制正弦周期(單位角度內震動的次數(shù))
* φ—初相欢策,反映在坐標系上則為圖像的左右移動赏淌。這里通過不斷改變φ,達到波浪移動效果
* k—偏距,反映在坐標系上則為圖像的上移或下移六水。
*/
y = (float) (8 * Math.cos(ω * x + φ) +8);
y2 = (float) (8 * Math.sin(ω * x + φ));
mAbovePath.lineTo(x, y);
mBelowWavePath.lineTo(x, y2);
//回調 把y坐標的值傳出去(在activity里面接收讓小機器人隨波浪一起搖擺)
mWaveAnimationListener.OnWaveAnimation(y);
}
mAbovePath.lineTo(getRight(),getBottom());
mBelowWavePath.lineTo(getRight(),getBottom());
canvas.drawPath(mAbovePath,mAboveWavePaint);
canvas.drawPath(mBelowWavePath,mBelowWavePaint);
postInvalidateDelayed(20);
}
What掷贾?ω φ 這些是什么意思啊 奈何這個大神內功太深厚 這一招一式打出來實在是參悟不透啊 估計再看下去會走火入魔,趕緊離開。
但是心有不甘,于是靜坐冥想1小時场靴。港准。。浅缸。
1.水波紋 不就是貝塞爾曲線嘛 用path.quadTo()能解決 再借鑒下Android仿百度貼吧客戶端Loading小球中的周期函數(shù)思想 讓水波紋不斷的浮動起來
2.圖片隨水波紋的浮動而浮動 圖片在x軸是固定不變得 只是在y軸有上下的波動 只要能獲取貝塞爾曲線中 path經(jīng)過與圖片x軸重合的y軸的坐標點就ok 剛好Android中有PathMeasure類結合Path 可以做到
想好這些 就開始擼碼
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path fulPath = getActionFulPath(currentPercent);
canvas.drawPath(fulPath,fulPaint);
Path idmPath=getActionDimPath(currentPercent);
canvas.drawPath(idmPath,dimPaint);
}
private Path getActionDimPath(float percent) {
int quadWidth = width / 4;
int quadHeight = height/3;
Path path=new Path();
int x=-width;
x+=percent*width;
path.moveTo(x,height/2);
//第一段
path.rQuadTo(quadWidth,-quadHeight,quadWidth*2,0);
path.rQuadTo(quadWidth,quadHeight,quadWidth*2,0);
//第二段
path.rQuadTo(quadWidth,-quadHeight,quadWidth*2,0);
path.rQuadTo(quadWidth,quadHeight,quadWidth*2,0);
//閉合
path.lineTo(x+width*2,height);
path.lineTo(x,height);
path.close();
//關聯(lián)一個path
measure.setPath(path,true);
//獲取path到view中心的長度
float length = Math.abs(x)+ (width / 2);
//獲取該path該位置時的坐標值
measure.getPosTan(length,pos,null);
//將y坐標的值通過接口傳遞出去
onWaveAnimationListener.onWaveAnimation(pos[1]+currentPercent);
return path;
}
注意這里是使用的path.rQuadTo() 是相對上次結束坐標來進行二次貝塞爾曲線的 不是相對于原點
上面的path差不多是這樣的(ps:實在不會用AI繪圖 若侵權了立馬刪除)
聲明傳遞數(shù)據(jù)的接口
public void setOnWaveAnimationListener(OnWaveAnimationListener listener){
onWaveAnimationListener =listener;
}
//接口
public interface OnWaveAnimationListener{
void onWaveAnimation(float y);
}
仔細看效果圖 有2個貝塞爾曲線 所以這個貝塞爾曲線與上面那個是相反的
public Path getActionFulPath(float percent) {
int quadWidth = width / 4;
int quadHeight = height/3;
Path path=new Path();
int x=-width;
x+=percent*width;
path.moveTo(x,height/2);
path.rQuadTo(quadWidth,quadHeight,quadWidth*2,0);
path.rQuadTo(quadWidth,-quadHeight,quadWidth*2,0);
path.rQuadTo(quadWidth,quadHeight,quadWidth*2,0);
path.rQuadTo(quadWidth,-quadHeight,quadWidth*2,0);
path.lineTo(x+width*2,height);
path.lineTo(x,height);
path.close();
return path;
}
在初始化的時候 啟動屬性動畫 讓水波紋浮動起來
private void init() {
fulPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
fulPaint.setColor(Color.parseColor("#fafafa"));
fulPaint.setStyle(Paint.Style.FILL);
dimPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dimPaint.setColor(Color.parseColor("#fafafa"));
dimPaint.setAlpha(80);
dimPaint.setStyle(Paint.Style.FILL);
//畫布抗鋸齒
//mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
measure = new PathMeasure();
ValueAnimator animator=ValueAnimator.ofFloat(0,1);
animator.setDuration(3000);
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//不斷改變currentPercent的值 讓水波紋不斷的浮動起來
currentPercent=animation.getAnimatedFraction();
invalidate();
}
});
animator.start();
}
最后布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.sharemodule.LoadingActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#29a3fe">
<com.example.sharemodule.widget.BaiduTopView
android:id="@+id/waveView"
android:layout_width="match_parent"
android:layout_height="15dp"
android:layout_gravity="bottom" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text="百度外賣"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/image"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="bottom|center_horizontal"
android:scaleType="centerCrop" />
</FrameLayout>
Activity中實現(xiàn)
public class LoadingActivity extends AppCompatActivity {
private static final String TAG= LoadingView.class.getSimpleName();
@BindView(R.id.image)
ImageView imageView;
@BindView(R.id.waveView)
BaiduTopView waveView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loading);
ButterKnife.bind(this);
Glide.with(this).load(R.drawable.head_gif).asGif().into(imageView);
}
@Override
protected void onResume() {
super.onResume();
final FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) imageView.getLayoutParams();
waveView.setOnWaveAnimationListener(new BaiduTopView.OnWaveAnimationListener() {
@Override
public void onWaveAnimation(float y) {
Log.e(TAG,"坐標:"+y);
layoutParams.bottomMargin= (int)y;
imageView.setLayoutParams(layoutParams);
}
});
}
}
哎 先去找AI畫圖教程學習下 不然還有諸多不方便 如果有什么疑問的地方請隨時留言苟弛。