Android自定义进度条样式

来源:互联网 发布:淘宝盗图被投诉处罚 编辑:程序博客网 时间:2024/05/19 23:12

相信很多人在项目里都想过自定义进度条,不是那种普通的,看看上面的截图,没错,就是这样。前段时间项目刚好需要做这样的进度条,可惜没有什么头绪,思前顾后只有两个方法。

方法一:这张进度条的图片1进度条部分镂空,其他部分显示一个没有透明度的颜色,在该图片里底部放一个底色图片2,图片1和图片2之间放一张宽度为0的图片3,图片3的宽度等于进度*图片1的宽度。通过这样来实现进度条变化的动画;

方法二:进度条图片1进度条部分不镂空,其他部分为空,进度变化时对图片1进行从左到右的垂直颜色变化。

看到这两个方法后相信大家肯定觉得方法二比较好,可是方法二怎么做呢?是的,小编开始也纠结了很久,鉴于网上实现方法二的例子非常少,最后还是采用了方法一;不过方法一有个很致命的缺点,就是图片1非镂空部分不能为有透明度,不然很容易和后面的图片2、3叠加在一起。还好,黄天不负有心人,最后还是实现了方法二。下面我给大家分别细细讲解下方法一和方法二的实现:


方法一:

该方法依赖于布局:这里我弄了一个FrameLayout,这个是我做其他事情需要用到的。该布局需要使用3个view,而且也需要这个进度条镂空才行,镂空后该进度条其余部分必须使用非透明色值。这个是它的缺陷。

<RelativeLayout        android:id="@+id/lay"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@+id/progress_seek_bar"        android:layout_centerHorizontal="true"        android:layout_gravity="center"        android:layout_marginTop="8dp"        android:background="@drawable/progress_hud_bg"        android:paddingBottom="40dp"        android:paddingLeft="60dp"        android:paddingRight="60dp"        android:paddingTop="40dp" >        <ImageView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignBottom="@+id/lay1"            android:layout_alignLeft="@+id/lay1"            android:layout_alignRight="@+id/lay1"            android:layout_alignTop="@+id/lay1"            android:background="#ffffff" />        <ImageView            android:id="@+id/background"            android:layout_width="0dip"            android:layout_height="wrap_content"            android:layout_alignBottom="@+id/lay1"            android:layout_alignLeft="@+id/lay1"            android:layout_alignTop="@+id/lay1"            android:background="#26a390" />        <FrameLayout            android:id="@+id/lay1"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerHorizontal="true" >            <ImageView                android:id="@+id/spinnerImageView"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:background="@drawable/icon_normal" />        </FrameLayout>    </RelativeLayout>

其中id为background的这个ImageView宽度设置0,在代码中动态设置他的宽度。

private void init() {mImageView = (ImageView) findViewById(R.id.spinnerImageView);mBackground = (ImageView) findViewById(R.id.background);mimageView = (ImageView) findViewById(R.id.imageview);// 绘制完view后取得mImageView的宽度ViewTreeObserver vto2 = mImageView.getViewTreeObserver();vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@SuppressWarnings("deprecation")@Overridepublic void onGlobalLayout() {mImageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);mWidth = mImageView.getWidth();}});SeekBar progressSeekBar = (SeekBar) findViewById(R.id.progress_seek_bar);progressSeekBar.setOnSeekBarChangeListener(this);}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {// TODO Auto-generated method stub// 取得宽度的值int bgWidth = (progress * mWidth) / 100;// 设置宽度RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mBackground.getLayoutParams();params.width = bgWidth;mBackground.setLayoutParams(params);// 方法二设置进度Bitmap bitmap = setVolume(progress);mimageView.setImageBitmap(bitmap);}


方法一就不多说,实现很简单,童鞋们就自己去体验了。


方法二:

方法二的处理就灵活多了。

在进入该activity时调用该方法初始化一张bitmap,并复制一张可修改的bitmap。之后我们就以该bitmap进行操作了。

private void initBitmap() {// 在这里创建了一张bitmapmBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.normal);mBitmap.getConfig();// 复制一张可修改的bitmapmBitmapCp = mBitmap.copy(Config.ARGB_8888, true);// 将这张bitmap设置为背景图片BitmapDrawable bd = new BitmapDrawable(mBitmapCp);bd.setAntiAlias(true);bd.setFilterBitmap(true);mBitmapWidth = mBitmap.getWidth();mBitmapHeight = mBitmap.getHeight();}

之后我们就可以调用setVolume方法,volume是进度。如果童鞋们根据我的步骤做,这时会发现return回来的bitmap有很严重的锯齿,我那时也是卡在这里一段时间。后来我想到一个方法,通过蒙版来处理
// 通过百分比 根据图片宽高算出实际填充宽度public int getValue(int volume) {return mBitmapWidth - (mBitmapWidth * volume / 100);}// 修改图片颜色@SuppressWarnings("deprecation")public Bitmap setVolume(int volume) {int startX = 0;int endX = 0;if (mBackVolume < volume) {startX = getValue(volume);endX = getValue(mBackVolume);}// 从左到右填充颜色,如改为for (int i = startX; i < endX; i++) 则为从右到左for (int i = mBitmapWidth - endX; i < mBitmapWidth - startX; i++) {for (int j = 0; j < mBitmapHeight; j++) {// 将需要填充的颜色值如果不是// 在这说明一下 如果color 是全透明 或者全黑 返回值为 0// getPixel()不带透明通道 getPixel32()才带透明部分 所以全透明是0x00000000// 而不透明黑色是0xFF000000 如果不计算透明部分就都是0了int color = mBitmapCp.getPixel(i, j);if (color != 0) {mBitmapCp.setPixel(i, j, 0xff26a390);}}}mBackVolume = volume;return mBitmapCp;}
把上面的return mBitmapCp;改成
Bitmap mask = BitmapFactory.decodeResource(getResources(),R.drawable.normal);return MaskBitmap(mBitmapCp, mask, mask.getWidth(), mask.getHeight(),new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

使用PorterDuffXfermode对图片进行蒙版处理,删去对比原图多出来的部分,并且使用Canvas和Paint,这时我们就可以设置防止锯齿。

/** * 蒙版去除锯齿 *  * @param bitmap * @param mask * @param size * @param mode * @return */private static Bitmap MaskBitmap(Bitmap bitmap, Bitmap mask, int width,int height, Xfermode mode) {if (null == bitmap || mask == null) {return null;}// 定义期望大小的bitmapBitmap dstBmp = Bitmap.createBitmap(width, height, Config.ARGB_8888);// 定义一个画布Canvas canvas = new Canvas(dstBmp);// 创建一个取消锯齿画笔Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);// 定义需要绘制的某图片上的那一部分矩形空间Rect src = new Rect(0, 0, mask.getWidth(), mask.getHeight());// 定义需要将上面的矩形绘制成新的矩形大小Rect dst = new Rect(0, 0, width, height);// 将蒙版图片绘制成imageview本身的大小,这样从大小才会和UE标注的一样大canvas.drawBitmap(mask, src, dst, paint);// 设置两张图片的相交模式paint.setXfermode(mode);// 将src修改为需要添加mask的bitmap大小,因为是要将此bitmap整个添加上蒙版src.right = bitmap.getWidth();src.bottom = bitmap.getHeight();// 在已经绘制的mask上叠加bitmapcanvas.drawBitmap(bitmap, src, dst, paint);return dstBmp;}

好,本次讲解基本完成,有什么问题或者不懂的,欢迎留言。

demo下载地址

欢迎大家加我,相互学习,相互讨论

如有转载,请注明出处:http://blog.csdn.net/hjhrq1991


0 0
原创粉丝点击