介紹一個QQ傳送圖片上傳的控制元件
如果你的應用中用到了傳送圖片這樣的功能那麼能夠像QQ發圖片那樣有個類似進度條的效果是很不錯的。現在就給大家介紹一個可以實現這樣效果的控制元件。
先說一下思路,首先顯示圖片我們一般用ImageView,這裡也是繼承ImageView,但是ImageView沒有上傳過程中的百分比顯示,想要在ImageView加一個半透明的遮罩效果就需要自己繪製,所以,我們需要複寫ImageView的onDraw方法,在這裡是控制元件繪製的所有操作。還有,要實現動態效果,那麼執行緒和重繪是必要的。
現在來整理一下實現步驟
1.繼承一個ImageView控制元件
2.複寫onDraw方法,加上半透明效果和百分比顯示
3.加上執行緒控制,把上傳進度傳送給控制元件,顯示出百分比並且重繪View
接下來上程式碼:
public class ProcessImageView extends ImageView { private Paint mPaint;// 畫筆 int width = 0; int height = 0; Context context = null; int progress = 0; public ProcessImageView(Context context) { super(context); // TODO Auto-generated constructor stub } public ProcessImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ProcessImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context = context; mPaint = new Paint(); } @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setAntiAlias(true); // 消除鋸齒 mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.parseColor("#70000000"));// 半透明 canvas.drawRect(0, 0, getWidth(), getHeight()- getHeight() * progress / 100, mPaint); mPaint.setColor(Color.parseColor("#00000000"));// 全透明 canvas.drawRect(0, getHeight() - getHeight() * progress / 100, getWidth(), getHeight(), mPaint); mPaint.setTextSize(30); mPaint.setColor(Color.parseColor("#FFFFFF")); mPaint.setStrokeWidth(2); Rect rect = new Rect(); mPaint.getTextBounds("100%", 0, "100%".length(), rect);// 確定文字的寬度 canvas.drawText(progress + "%", getWidth() / 2 - rect.width() / 2, getHeight() / 2, mPaint); } public void setProgress(int progress) { this.progress = progress; postInvalidate(); }; }
首先聲明瞭五個變數,實際上用到的只有三個,第一個是畫筆mPaint用來繪製View,第二個是上下文Context不用多解釋,第三個progress,進度這個必須有。其餘兩個暫時沒用到,忽略不計
接下來就是複寫ImageVie w的OnDraw方法,所有View都是在這裡繪製的,我們需要自己定義什麼繪製內容的時候就需要在這裡新增。
先是畫筆的設定
mPaint.setAntiAlias(true); // 消除鋸齒
mPaint.setStyle(Paint.Style.FILL);
接下來就是最重要的半透明層的繪製
mPaint.setColor(Color.parseColor("#70000000"));// 半透明
canvas.drawRect(0, 0, getWidth(), getHeight()- getHeight() * progress
/ 100, mPaint);
mPaint.setColor(Color.parseColor("#00000000"));// 全透明
canvas.drawRect(0, getHeight() - getHeight() * progress / 100,
getWidth(), getHeight(), mPaint);
設定畫筆的顏色,然後在畫布canvas上指定繪製的範圍按照左上右下四個引數分別傳入,下部的位置就是整個View的高度減去下面已經透明的高度,通過progress除以100得出的百分比來設定。最後一個引數是畫筆。
繪製透明部分的邏輯也是一樣。不多做解釋
最後,繪製文字,也就是顯示出來的百分比
mPaint.setTextSize(30);
mPaint.setColor(Color.parseColor("#FFFFFF"));
mPaint.setStrokeWidth(2);
Rect rect = new Rect();
mPaint.getTextBounds("100%", 0, "100%".length(), rect);// 確定文字的寬度
canvas.drawText(progress + "%", getWidth() / 2 - rect.width() / 2,
getHeight() / 2, mPaint);
只要是繪製內容,必定先設定畫筆屬性。這裡特別說明一下Rect的作用,Rect是一個矩形區域的意思,它作為獲取文字寬度的一個引數,意思是將文字區域的一些屬性放到rect裡,有人會問文字不是可以直接獲取長度等屬性嗎?抱歉,這裡文字只能得到長度,但是這裡我們不能把它認為成一個字串,我們是要繪製的,所以要把它當成一個圖片。把文字的一些資訊放到rect裡。同樣指定繪製的位置
現在我們會發現,這些都是靜態的,怎麼能讓他顯示出效果呢?這裡就用到我們的執行緒了,這裡需要複習一個方法,用來更新View
public void setProgress(int progress) {
this.progress = progress;
postInvalidate();
};
這裡的progress就是用來更新的。需要配合Activity裡的執行緒更新View,postInvalidate()就是通知更新View的方法
下面是Activity的內容
public class MainActivity extends Activity {
ProcessImageView processImageView =null;
private final int SUCCESS=0;
int progress=0;
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SUCCESS:
Toast.makeText(MainActivity.this, "圖片上傳完成", Toast.LENGTH_SHORT).show();
// processImageView.setVisibility(View.GONE);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
processImageView=(ProcessImageView) findViewById(R.id.image);
//模擬圖片上傳進度
new Thread(new Runnable() {
@Override
public void run() {
while (true){
if(progress==100){//圖片上傳完成
handler.sendEmptyMessage(SUCCESS);
return;
}
progress++;
processImageView.setProgress(progress);
try{
Thread.sleep(200); //暫停0.2秒
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}).start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
主要就是開一個執行緒不斷的用set方法重新整理VIew用Handler接收成功訊息
使用方法跟普通自定義元件一樣,還可以對其進行擴充套件,請發揮想象力吧。