Android自定義控件之仿京東商城下拉刷新
前面寫了4篇自定義控件的博客,并且開通了一個專欄,把4篇文章添加到專欄中了,耐心等待博客專欄的徽章出現,奈何等了幾周后還是沒有出現,后來發現至少需要5篇文章才能出現專欄徽章,于是有了這篇仿我大京東快遞小哥的下拉刷新。
直接上圖先!

分析
這個下拉刷新效果分為兩個部分:
step1:快遞小哥和快遞包裹的縮放效果,看上去就像是快遞小哥跑過來一手拿過快遞的樣子
step2:快遞小哥拿到包裹后,開啟暴走模式!玩命送快遞
</div>PS:不得不贊一下京東的快遞,真的很快!
</div>step1
好了馬屁拍完了,我們先來看一看第一部分的效果是怎么實現的。首先快遞小哥和包裹是兩張圖片


我們看到快遞小哥是從小變大的,快遞包裹也是從小變大的,所以我們要自定義一個控件,就起名為FirstStepView.java吧
</div>public class FirstSetpView extends View{ private Bitmap goods; private Bitmap people; private Bitmap peopleWithGoods; private int measuredWidth; private int measuredHeight; private float mCurrentProgress; private int mCurrentAlpha; private Paint mPaint; private Bitmap scaledPeople; private Bitmap scaledGoods; public FirstSetpView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public FirstSetpView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public FirstSetpView(Context context) { super(context); init(); } private void init(){ //包裹bitmap goods = BitmapFactory.decodeResource(getResources(), R.mipmap.app_refresh_goods_0); //快遞小哥bitmap people = BitmapFactory.decodeResource(getResources(), R.mipmap.app_refresh_people_0); //這是后面動畫中的最后一張圖片,拿這張圖片的作用是用它的寬高來測量 //我們這個自定義View的寬高 peopleWithGoods = BitmapFactory.decodeResource(getResources(), R.mipmap.app_refresh_people_3); //來個畫筆,我們注意到快遞小哥和包裹都有一個漸變效果的,我們用 //mPaint.setAlpha來實現這個漸變的效果 mPaint = new Paint(); //首先設置為完全透明 mPaint.setAlpha(0); } /**
- 測量方法
- @param widthMeasureSpec
- @param heightMeasureSpec / @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } //測量寬度 private int measureWidth(int widthMeasureSpec){ int result = 0; int size = MeasureSpec.getSize(widthMeasureSpec); int mode = MeasureSpec.getMode(widthMeasureSpec); if (MeasureSpec.EXACTLY == mode) { result = size; }else { result = peopleWithGoods.getWidth(); if (MeasureSpec.AT_MOST == mode) { result = Math.min(result, size); } } return result; } //測量高度 private int measureHeight(int heightMeasureSpec){ int result = 0; int size = MeasureSpec.getSize(heightMeasureSpec); int mode = MeasureSpec.getMode(heightMeasureSpec); if (MeasureSpec.EXACTLY == mode) { result = size; }else { result = peopleWithGoods.getHeight(); if (MeasureSpec.AT_MOST == mode) { result = Math.min(result, size); } } return result; } //在這里面拿到測量后的寬和高,w就是測量后的寬,h是測量后的高 @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); measuredWidth = w; measuredHeight = h; //根據測量后的寬高來對快遞小哥做一個縮放 scaledPeople = Bitmap.createScaledBitmap(people,measuredWidth,measuredHeight,true); //根據測量后的寬高來對快遞包裹做一個縮放 scaledGoods = Bitmap.createScaledBitmap(goods, scaledPeople.getWidth()10/27, scaledPeople.getHeight()/5, true); } /**
- 繪制方法
- @param canvas */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //由于包裹和快遞小哥要分別來畫,所以使用save和restore方法 //save //畫包裹 //restore //save //畫小哥 //restore canvas.save(); canvas.scale(mCurrentProgress, mCurrentProgress , measuredWidth-scaledGoods.getWidth()/2 , measuredHeight/2); mPaint.setAlpha(mCurrentAlpha); canvas.drawBitmap(scaledGoods, measuredWidth-scaledGoods.getWidth(), measuredHeight/2-scaledGoods.getHeight()/2, mPaint); canvas.restore(); canvas.save(); canvas.scale(mCurrentProgress, mCurrentProgress , 0 , measuredHeight/2); mPaint.setAlpha(mCurrentAlpha); canvas.drawBitmap(scaledPeople, 0,0,mPaint); canvas.restore(); } /**
- 根據進度來對小哥和包裹進行縮放
- @param currentProgress
/
public void setCurrentProgress(float currentProgress){
this.mCurrentProgress = currentProgress;
this.mCurrentAlpha = (int) (currentProgress255);
}
}</pre>
還是老方法,我們寫完這個效果,就先來測試一下吧,還是用一個SeekBar來模擬一個進度值public class MainActivity extends Activity { private SeekBar sb; private FirstSetpView mFirstStepView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sb = (SeekBar) findViewById(R.id.seekbar); mFirstStepView = (FirstSetpView) findViewById(R.id.firstview); sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress,
float currentProgress = (float)seekBar.getProgress()/(float)seekBar.getMax(); mFirstStepView.setCurrentProgress(currentProgress); mFirstStepView.invalidate(); } }); } }</pre>boolean fromUser) {
secondStepView = (SecondStepView) headerView.findViewById(R.id.second_step_view); secondStepView.setBackgroundResource(R.drawable.second_step_animation); secondAnimation = (AnimationDrawable) secondStepView.getBackground();
secondAnimation是一個AnimationDrawable對象,我們可以調用他的start方法開始幀動畫,調用stop結束幀動畫
secondAnimation.start(); secondAnimation.stop();
下拉刷新的實現
這一部分我在 Android自定義控件之仿美團下拉刷新 中已經詳細分析過了,所以這里就不再贅述了。
完整代碼
歡迎大家上我的 GitHub 上下載源碼
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!