推荐阅读:
鸿洋:Android BitmapShader 实战 实现圆形、圆角图片
鸿洋:Android Xfermode 实战 实现圆形、圆角图片
依赖
自定义CircleImageView
> /** * 圆图片View */
> public class CircleImageView extends ImageView {
>
> private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
>
> private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
> private static final int COLORDRAWABLE_DIMENSION = 1;
>
> private static final int DEFAULT_BORDER_WIDTH = 0;
> private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
>
> private final RectF mDrawableRect = new RectF();
> private final RectF mBorderRect = new RectF();
>
> private final Matrix mShaderMatrix = new Matrix();
> private final Paint mBitmapPaint = new Paint();
> private final Paint mBorderPaint = new Paint();
>
> private int mBorderColor = DEFAULT_BORDER_COLOR;
> private int mBorderWidth = DEFAULT_BORDER_WIDTH;
>
> private Bitmap mBitmap;
> private BitmapShader mBitmapShader;
> private int mBitmapWidth;
> private int mBitmapHeight;
>
> private float mDrawableRadius;
> private float mBorderRadius;
>
> private boolean mReady;
> private boolean mSetupPending;
>
> public CircleImageView(Context context) {
> super(context);
> }
>
> public CircleImageView(Context context, AttributeSet attrs) {
> this(context, attrs, 0);
> }
>
> public CircleImageView(Context context, AttributeSet attrs, int defStyle) {
> super(context, attrs, defStyle);
> super.setScaleType(SCALE_TYPE);
>
> TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0);
>
> mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width,
> DEFAULT_BORDER_WIDTH);
> mBorderColor = a.getColor(R.styleable.CircleImageView_border_color,
> DEFAULT_BORDER_COLOR);
>
> a.recycle();
>
> mReady = true;
>
> if (mSetupPending) {
> setup();
> mSetupPending = false;
> }
> }
>
> @Override
> public ScaleType getScaleType() {
> return SCALE_TYPE;
> }
>
> @Override
> public void setScaleType(ScaleType scaleType) {
> if (scaleType != SCALE_TYPE) {
> throw new IllegalArgumentException(String.format("ScaleType %s not supported.",
> scaleType));
> }
> }
>
> @Override
> protected void onDraw(Canvas canvas) {
> if (getDrawable() == null) {
> return;
> }
>
> canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint);
> canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint);
> }
>
> @Override
> protected void onSizeChanged(int w, int h, int oldw, int oldh) {
> super.onSizeChanged(w, h, oldw, oldh);
> setup();
> }
>
> public int getBorderColor() {
> return mBorderColor;
> }
>
> public void setBorderColor(int borderColor) {
> if (borderColor == mBorderColor) {
> return;
> }
>
> mBorderColor = borderColor;
> mBorderPaint.setColor(mBorderColor);
> invalidate();
> }
>
> public int getBorderWidth() {
> return mBorderWidth;
> }
>
> public void setBorderWidth(int borderWidth) {
> if (borderWidth == mBorderWidth) {
> return;
> }
>
> mBorderWidth = borderWidth;
> setup();
> }
>
> @Override
> public void setImageBitmap(Bitmap bm) {
> super.setImageBitmap(bm);
> mBitmap = bm;
> setup();
> }
>
> @Override
> public void setImageDrawable(Drawable drawable) {
> super.setImageDrawable(drawable);
> mBitmap = getBitmapFromDrawable(drawable);
> setup();
> }
>
> @Override
> public void setImageResource(int resId) {
> super.setImageResource(resId);
> mBitmap = getBitmapFromDrawable(getDrawable());
> setup();
> }
>
> private Bitmap getBitmapFromDrawable(Drawable drawable) {
> if (drawable == null) {
> return null;
> }
>
> if (drawable instanceof BitmapDrawable) {
> return ((BitmapDrawable) drawable).getBitmap();
> }
>
> try {
> Bitmap bitmap;
>
> if (drawable instanceof ColorDrawable) {
> bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
> } else {
> bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
> drawable.getIntrinsicHeight(), BITMAP_CONFIG);
> }
>
> Canvas canvas = new Canvas(bitmap);
> drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
> drawable.draw(canvas);
> return bitmap;
> } catch (OutOfMemoryError e) {
> return null;
> }
> }
>
> private void setup() {
> if (!mReady) {
> mSetupPending = true;
> return;
> }
>
> if (mBitmap == null) {
> return;
> }
>
> mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
>
> mBitmapPaint.setAntiAlias(true);
> mBitmapPaint.setShader(mBitmapShader);
>
> mBorderPaint.setStyle(Paint.Style.STROKE);
> mBorderPaint.setAntiAlias(true);
> mBorderPaint.setColor(mBorderColor);
> mBorderPaint.setStrokeWidth(mBorderWidth);
>
> mBitmapHeight = mBitmap.getHeight();
> mBitmapWidth = mBitmap.getWidth();
>
> mBorderRect.set(0, 0, getWidth(), getHeight());
> mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2);
>
> mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() -
> mBorderWidth);
> mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2);
>
> updateShaderMatrix();
> invalidate();
> }
>
> private void updateShaderMatrix() {
> float scale;
> float dx = 0;
> float dy = 0;
>
> mShaderMatrix.set(null);
>
> if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
> scale = mDrawableRect.height() / (float) mBitmapHeight;
> dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
> } else {
> scale = mDrawableRect.width() / (float) mBitmapWidth;
> dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
> }
>
> mShaderMatrix.setScale(scale, scale);
> mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth);
>
> mBitmapShader.setLocalMatrix(mShaderMatrix);
> }
>
> }
- MyApp中初始化fresco和UIL:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
Fresco.initialize(this);
initUIL();
}
private void initUIL() {
File cacheFile = StorageUtils.getCacheDirectory(this); //缓存文件夹路径
Log.e("MyApplication", "initImageLoader:cacheDir===" + cacheFile);
//cacheFile为:/storage/emulated/0/Android/data/com.example.administrator.myglide/cache
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
.memoryCacheExtraOptions(480, 800) // default = device screen dimensions 内存缓存文件的最大长宽
.diskCacheExtraOptions(480, 800, null) // 本地缓存的详细信息(缓存的最大长宽),最好不要设置这个
.threadPoolSize(3) // default 线程池内加载的数量
.threadPriority(Thread.NORM_PRIORITY - 2) // default 设置当前线程的优先级
.tasksProcessingOrder(QueueProcessingType.FIFO) // default
.denyCacheImageMultipleSizesInMemory()
.memoryCache(new LruMemoryCache(2 * 1024 * 1024)) //可以通过自己的内存缓存实现
.memoryCacheSize(2 * 1024 * 1024) // 内存缓存的最大值
.memoryCacheSizePercentage(13) // default
.diskCache(new UnlimitedDiskCache(cacheFile)) // default 可以自定义缓存路径
.diskCacheSize(50 * 1024 * 1024) // 50 Mb sd卡(本地)缓存的最大值
.diskCacheFileCount(100) // 可以缓存的文件数量
// default为使用HASHCODE对UIL进行加密命名, 还可以用MD5(new Md5FileNameGenerator())加密
.diskCacheFileNameGenerator(new HashCodeFileNameGenerator())
.imageDownloader(new BaseImageDownloader(this)) // default
.imageDecoder(new BaseImageDecoder(true)) // default
// default,可以自定义defaultOptions来设置是否缓存:cacheInMemory(true)缓存内存和cacheOnDisc(true)缓存硬盘
.defaultDisplayImageOptions(DisplayImageOptions.createSimple())
.discCache(new LimitedAgeDiskCache(cacheFile, 7 * 24 * 60 * 60))// 自定义缓存路径,7天后自动清除缓存
.writeDebugLogs() // 打印debug log
.build(); //开始构建
ImageLoader.getInstance().init(config); // 初始化
}
}
- 在Manifest中添加权限和注册app:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
***android:name=".MyApp"***
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
- 布局文件:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#99eace31"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.administrator.myglide.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_diy_iv"
android:onClick="clickbutton"
android:text="下载图片并加载到自定义的圆形图片"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.example.administrator.myglide.views.CircleImageView
android:id="@+id/diy_iv"
android:src="@mipmap/ic_launcher"
android:layout_width="match_parent"
android:layout_height="300dp" />
<!-->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-->
<TextView
android:id="@+id/uil_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffffffff"
android:text="UIL加载网络图片" />
<ImageView
android:id="@+id/uil_iv"
android:layout_width="match_parent"
android:layout_height="300dp "
android:scaleType="centerInside"
android:src="@mipmap/ic_launcher" />
<!-->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-->
<TextView
android:id="@+id/glide_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffffffff"
android:text="glide加载网络图片" />
<ImageView
android:id="@+id/glide_iv"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerInside"
android:src="@mipmap/ic_launcher" />
<!-->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-->
<TextView
android:id="@+id/picasso_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffffffff"
android:text="Picasso加载网络图片" />
<ImageView
android:id="@+id/picasso_iv"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerInside"
android:src="@mipmap/ic_launcher" />
<!-->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-->
<TextView
android:id="@+id/fresco_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffffffff"
android:text="fresco加载网络图片" />
<!--
// com.facebook.drawee.view.SimpleDraweeView的宽度和高度
不支持wrap_content, 如果要设置宽高比, 需要在Java代码中指定setAspectRatio(float ratio);
-->
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/fresco_iv"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerInside"
android:src="@mipmap/ic_launcher"
fresco:backgroundImage="@color/blue"
fresco:failureImage="@drawable/first_icon25"
fresco:failureImageScaleType="centerInside"
fresco:placeholderImage="@color/wait_color"
fresco:placeholderImageScaleType="fitCenter"
fresco:pressedStateOverlayImage="@color/red"
fresco:progressBarAutoRotateInterval="1000"
fresco:progressBarImage="@drawable/first_icon11"
fresco:progressBarImageScaleType="centerInside"
fresco:retryImage="@drawable/first_icon19"
fresco:retryImageScaleType="centerCrop"
fresco:roundAsCircle="true"
fresco:roundBottomLeft="true"
fresco:roundBottomRight="true"
fresco:roundTopLeft="true"
fresco:roundTopRight="true"
fresco:roundedCornerRadius="1dp"
fresco:roundingBorderColor="@color/border_color"
fresco:roundingBorderWidth="2dp" />
</LinearLayout>
</ScrollView>
- MainActivity:
public class MainActivity extends AppCompatActivity {
String url = "http://image.codes51.com/Article/image/20150730/20150730121119_3945.gif";
String net_url = "http://img2.3lian.com/2014/f6/173/d/51.jpg";
String gif_url = " http://img15.3lian.com/2015/gif/1/78/1.gif";
private ImageView glide_iv;
private ImageView picasso_iv;
private SimpleDraweeView fresco_iv;
private ImageView uil_iv;
private DisplayImageOptions options;
private CircleImageView diy_iv;
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
// 加载圆角图片
useUIL();
usePicasso();
useFresco();
useGlide();
}
//自定义的圆形图片
public void clickbutton(View view) {
Bitmap bitmap = FileUtils.readImage(net_url);
if (bitmap != null) {//读取sd图片
Toast.makeText(this, "sd卡的路径:" + Environment
.getExternalStorageDirectory() + "/xq_caches/images" + url.substring(url.lastIndexOf("/") + 1)
, Toast.LENGTH_LONG).show(); //路径为:/storage/emulated/0 /qf_caches/images/ 51.jpg
diy_iv.setImageBitmap(bitmap);
} else {
// 发送异步请求
new MyAsyncTask(this).execute(net_url);
}
}
private void useGlide() {
Glide.with(this)
.load("http://img2.3lian.com/2014/f6/173/d/51.jpg")// 加载图片资源
.skipMemoryCache(false)//是否将图片放到内存中
.diskCacheStrategy(DiskCacheStrategy.ALL)//磁盘图片缓存策略
.dontAnimate()//不执行淡入淡出动画
.crossFade(100)// 默认淡入淡出动画300ms
.placeholder(R.mipmap.ic_launcher)// 占位图片
.error(R.mipmap.ic_launcher)//图片加载错误显示
.centerCrop()// 或者 fitCenter()
.transform(new GlideCircleTransform(this))//圆角图片
.into(glide_iv); //更新ui
}
private void useFresco() {
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setUri(Uri.parse(net_url))
.setAutoPlayAnimations(true) 自动播放动画,比如:gif
.build();
fresco_iv.setController(controller);
}
private void usePicasso() {
Picasso.with(this)
.load("http://img2.3lian.com/2014/f6/173/d/51.jpg")
.transform(new PicassoCircleTransform())//圆角
.placeholder(R.drawable.first_icon26)
.error(R.drawable.first_icon25)
.into(picasso_iv);
}
/**
* UIL
*/
private void useUIL() {
options = new DisplayImageOptions.Builder()//构造者模式,option可以放在Application中
.showStubImage(R.mipmap.ic_launcher)//缓冲过程中图片
.showImageForEmptyUri(R.mipmap.ic_launcher)// 设置图片Uri为空或是错误的时候显示的图片
.showImageOnFail(R.drawable.first_icon11)// 设置图片加载或解码过程中发生错误显示的图片
.cacheInMemory(true)//缓存到内存
.cacheOnDisc(true)//缓存到硬盘
.bitmapConfig(Bitmap.Config.ARGB_8888) //设置图片的解码类型
.displayer(new UILCircleBitmapDisplayer())//自定义圆形图片,与默认区别在于圆心坐标移到了ImageView的中心
// .displayer(new RoundedBitmapDisplayer(60))//默认圆角图片,弧度
// .displayer(new CircleBitmapDisplayer(R.color.corner_color))//默认圆形图片,颜色
// .displayer(new FadeInBitmapDisplayer(2000))//默认渐明效果,时间
.build();
ImageLoader.getInstance().displayImage("http://img2.3lian.com/2014/f6/173/d/51.jpg", uil_iv, options);
/* ImageLoader.getInstance()
.loadImage("http://img2.3lian.com/2014/f6/173/d/51.jpg", options, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
});*/
}
private void initViews() {
diy_iv = ((CircleImageView) findViewById(R.id.diy_iv));
glide_iv = ((ImageView) findViewById(R.id.glide_iv));
picasso_iv = ((ImageView) findViewById(R.id.picasso_iv));
fresco_iv = ((SimpleDraweeView) findViewById(R.id.fresco_iv));
uil_iv = (ImageView) findViewById(R.id.uil_iv);
}
class MyAsyncTask extends AsyncTask<String, Void, byte[]> {
private ProgressDialog pDialog;
public MyAsyncTask(Context context) {
pDialog = new ProgressDialog(context);
pDialog.setIcon(R.mipmap.ic_launcher);
pDialog.setTitle("提示");
pDialog.setMessage("The data is loading...");
// 如果没有图标,可以像下面这样构建ProgressDialog:参数为:上下文,title,content
// ProgressDialog pDialog = ProgressDialog.show(context, null, "加载中...");
}
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog.show();
}
@Override
protected byte[] doInBackground(String... params) {
URL url;
Bitmap bitmap = null;
try {
url = new URL(params[0]);
//获得连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置超时时间为6000毫秒,conn.setConnectionTiem(0);表示没有时间限制
conn.setConnectTimeout(6000);
//连接设置获得数据流
conn.setDoInput(true);
//不使用缓存
conn.setUseCaches(false);
//这句可有可无,没有影响
conn.connect();
//得到数据流
InputStream is = conn.getInputStream();
//解析得到图片
bitmap = BitmapFactory.decodeStream(is);
//关闭数据流
is.close();
if (conn.getResponseCode() == 200) {
// 缓存工具类:保存图片
Utilsfile.saveImage(params[0], bitmap);// url:params[0]
//返回字符数组
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
return byteArray;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(byte[] result) {
super.onPostExecute(result);
if (result != null) {
Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0,
result.length);
diy_iv.setImageBitmap(bitmap);
}
pDialog.dismiss();
}
}
}
- 自定义GlideCircleTransform:
public class GlideCircleTransform extends BitmapTransformation {
public GlideCircleTransform(Context context) {
super(context);
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return circleCrop(pool,toTransform);
}
private Bitmap circleCrop(BitmapPool pool, Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int width = (source.getWidth() - size) / 2;
int height = (source.getHeight() - size) / 2;
Bitmap bitmap = pool.get(size, size, Bitmap.Config.ARGB_8888);
if (bitmap == null) {
bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader =
new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
if (width != 0 || height != 0) {
// source isn't square, move viewport to center
Matrix matrix = new Matrix();
matrix.setTranslate(-width, -height);
shader.setLocalMatrix(matrix);
}
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
return bitmap;
}
@Override
public String getId() {
return getClass().getName();
}
}
- 自定义PicassoCircleTransform:
public class PicassoCircleTransform implements Transformation {
@Override
public Bitmap transform(Bitmap source) {
/**
* 求出宽和高的哪个小
*/
int size = Math.min(source.getWidth(), source.getHeight());
/**
* 求中心点
*/
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
/**
* 生成BitMap
*/
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
//释放
source.recycle();
}
/**
* 建立新的Bitmap
*/
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
/**
* 画布画笔
*/
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap,
BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
/**
* 画圆
*/
canvas.drawCircle(r, r, r, paint);
squaredBitmap.recycle();
return bitmap;
}
@Override
public String key() {
return "circle";
}
}
- 自定义UILCircleBitmapDisplayer:
/**
* 自定义圆形图片,与默认圆形图片区别在于圆心坐标移到了ImageView的中心
*/
public class UILCircleBitmapDisplayer implements BitmapDisplayer {
protected final Integer strokeColor;
protected final float strokeWidth;
public UILCircleBitmapDisplayer() {
this(null);
}
public UILCircleBitmapDisplayer(Integer strokeColor) {
this(strokeColor, 0);
}
public UILCircleBitmapDisplayer(Integer strokeColor, float strokeWidth) {
this.strokeColor = strokeColor;
this.strokeWidth = strokeWidth;
}
@Override
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
if (!(imageAware instanceof ImageViewAware)) {
throw new IllegalArgumentException("ImageAware should wrap ImageView. ImageViewAware is expected.");
}
imageAware.setImageDrawable(new CircleDrawable(bitmap, strokeColor, strokeWidth));
}
public static class CircleDrawable extends Drawable {
protected float radius;
protected final RectF mRect = new RectF();
protected final RectF mBitmapRect;
protected final BitmapShader bitmapShader;
protected final Paint paint;
protected final Paint strokePaint;//描边的画笔
protected final float strokeWidth;//描边的宽度
protected float strokeRadius;//描边的半径
public CircleDrawable(Bitmap bitmap, Integer strokeColor, float strokeWidth) {
radius = Math.min(bitmap.getWidth(), bitmap.getHeight()) / 2;//宽高中较小值的一半为半径
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapRect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());//imageview的框架为矩形
paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(bitmapShader);
paint.setFilterBitmap(true);
paint.setDither(true);
if (strokeColor == null) {
strokePaint = null;
} else {
strokePaint = new Paint();
strokePaint.setStyle(Paint.Style.STROKE); //设置paint的风格为“空心”
// 设置画笔的样式,为FILL,FILL_OR_STROKE,或STROKE
strokePaint.setColor(strokeColor);
strokePaint.setStrokeWidth(strokeWidth); // 设置“空心”的外框的宽度
// 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
strokePaint.setAntiAlias(true);
}
this.strokeWidth = strokeWidth;
strokeRadius = radius - strokeWidth / 2;
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRect.set(0, 0, bounds.width(), bounds.height());
radius = Math.min(bounds.width(), bounds.height()) / 2;
strokeRadius = radius - strokeWidth / 2;
// Resize the original bitmap to fit the new bound
Matrix shaderMatrix = new Matrix();
shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
bitmapShader.setLocalMatrix(shaderMatrix);
}
@Override
public void draw(Canvas canvas) {
//自定义圆形图片,与默认区别在于圆心坐标移到了ImageView的中心
Rect bounds = getBounds();//画一个圆圈
//getBounds() 方法与 getRect() 方法类似,返回一个矩形,
//getBounds() 方法返回的矩形包括形状的所有笔触,然而 getRect() 方法返回的矩形则不包括
//getRect() 方法返回的值等于或小于由 getBounds() 方法返回的值。
canvas.drawCircle(bounds.width() / 2F, bounds.height() / 2F, radius, paint);
if (strokePaint != null) {
canvas.drawCircle(bounds.width() / 2F, bounds.height() / 2F, strokeRadius, strokePaint);
}
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
}
}
- 利用到的文件工具类:
public class FileUtils {
private static final String CACHE_DIR = Environment
.getExternalStorageDirectory() + "/qf_caches/images";// 缓存文件夹
/**
* 判断sdcard是否挂载
*
* @return
*/
public static boolean isMounted() {
String state = Environment.getExternalStorageState();
return state.equals(Environment.MEDIA_MOUNTED);
}
/**
* 获取sdcard的根目录
*
* @return
*/
public static String getSDCARDDir() {
return Environment.getExternalStorageDirectory().getAbsolutePath();
}
/**
* 存储图片一
*
* @param url
* : 图片的http网络地址
* @param data
* @throws IOException
*/
public static void saveImage(String url, byte[] data) throws IOException {
// 1. 判断是否有sdcard
if (!isMounted()) {
return;
}
// 2. 判断是否有缓存的文件夹
File dir = new File(CACHE_DIR);
if (!dir.exists()) {
dir.mkdirs();// 多层文件夹
}
// 3. 存储图片到sdcard
File file = new File(dir, getFilename(url));
FileOutputStream fos = new FileOutputStream(file);
fos.write(data);
fos.close();
}
/**
* 保存图片二
*
* @param url
* : 图片的http网络地址
* @param bitmap
* @throws IOException
*/
public static void saveImage(String url, Bitmap bitmap) throws IOException {
// 1. 判断是否有sdcard
if (!isMounted()) {
return;
}
// 2. 判断是否有缓存的文件夹
File dir = new File(CACHE_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
// 3. 存储图片到sdcard
File file = new File(dir, getFilename(url));
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
}
/**
* 获取图片名
*
* @param url
* @return
*/
public static String getFilename(String url) {
return url.substring(url.lastIndexOf("/") + 1);
}
/**
* 读图片
*
* @param url
* @return
*/
public static Bitmap readImage(String url) {
// 判断是否有sdcard
if (!isMounted()) {
return null;
}
File file = new File(CACHE_DIR, getFilename(url));
if (file.exists()) {
// file->bitmap
return BitmapFactory.decodeFile(file.getAbsolutePath());
}
return null;
}
/**
* 清空缓存目录
*/
public void clearCaches() {
File dir = new File(CACHE_DIR);
File[] allfiles = dir.listFiles();
for (File file : allfiles) {
file.delete();
}
}
}
欢迎交流。