如果你的应用中用到了发送图片这样的功能那么能够像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接收成功消息
使用方法跟普通自定义组件一样,还可以对其进行扩展,请发挥想象力吧。