相信很多人在项目里都想过自定义进度条,不是那种普通的,看看上面的截图,没错,就是这样。前段时间项目刚好需要做这样的进度条,可惜没有什么头绪,思前顾后只有两个方法。
方法一:这张进度条的图片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>
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") @Override public void onGlobalLayout() { mImageView.getViewTreeObserver().removeGlobalOnLayoutListener( this); mWidth = mImageView.getWidth(); } }); SeekBar progressSeekBar = (SeekBar) findViewById(R.id.progress_seek_bar); progressSeekBar.setOnSeekBarChangeListener(this); } @Override public 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() { // 在这里创建了一张bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.normal); mBitmap.getConfig(); // 复制一张可修改的bitmap mBitmapCp = mBitmap.copy(Config.ARGB_8888, true); // 将这张bitmap设置为背景图片 BitmapDrawable bd = new BitmapDrawable(mBitmapCp); bd.setAntiAlias(true); bd.setFilterBitmap(true); mBitmapWidth = mBitmap.getWidth(); mBitmapHeight = mBitmap.getHeight(); }
// 通过百分比 根据图片宽高算出实际填充宽度 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; } // 定义期望大小的bitmap Bitmap 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上叠加bitmap canvas.drawBitmap(bitmap, src, dst, paint); return dstBmp; }
demo下载地址
欢迎大家加我,相互学习,相互讨论
如有转载,请注明出处:http://blog.csdn.net/hjhrq1991