This is a library for making custom shape for your image on your image view. If you want to make a custom shape for your image you need to pass two image, first one is original image and second one is for your shape. First one is your actual image, this image will get the shape as like second image.
簡單介紹它的功能即是,第一張圖片為顯示的圖片,第二張圖片作為整體顯示內容的裁剪圖形。源碼地址
運行效果如下:
源碼分析:
public class Shaper {
/**
* @param context you need to pass the context (ex: Your current activity's instance)
* @param shapedImage pass an image from your drawable folder (Ex: R.drawable.sample_image_name)
* which is shaped for your real image.Your expected image will look like this.
* @param originalImage pass your image from your drawable (Ex: R.drawable.your_image_name).
* This is your original image.
* @param imgView pass an ImageView in which you want to set your expected image.
* @param expectedHeight (int value) this is expected height for your image.
* @param expectedWidth (int value) this is expected width for your image.
*
* ***YOUR SHAPED IMAGE SIZE WILL BE FOR YOUR MDPI DEVICE.
* IF YOUR SHAPED IMAGE SIZE IS 100PX THEN YOU
* NEED TO PASS HEIGHT AND WIDTH 100 FOR YOUR MDPI DEVICE.
* ***100X1.5 FOR YOUR HDPI DEVICE
* ***100X2 FOR YOUR XHDPI DEVICE
* ***100X3 FOR YOUR XXHDPI DEVICE
* ***100X4 FOR YOUR XXXHDPI DEVICE
* ######## height and width can be different ########
* ***
* */
public static void shape(Context context, int originalImage, int shapedImage, ImageView imgView, int expectedHeight, int expectedWidth) {
Bitmap original = BitmapFactory.decodeResource(context.getResources(), originalImage);
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), shapedImage);
Bitmap mask = bitmap;
// original = getResizedBitmap(original, expectedHeight, expectedWidth);
original = getResizedBitmap(original, dipToPixels(context, expectedHeight), dipToPixels(context, expectedWidth));
// 獲取背景圖形的大小
int bitmapHeight = bitmap.getHeight();
int bitmapWidth = bitmap.getWidth();
// 創(chuàng)建背景畫布大小為背景圖片的大小
Bitmap result = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Bitmap.Config.ARGB_8888);
final Canvas mCanvas = new Canvas(result);
// 畫筆抗鋸齒
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
int widthMask = mask.getWidth();
int heightMask = mask.getHeight();
// 繪制顯示圖片時的偏移量
float centerX = (widthMask - original.getWidth()) * 0.5f;
float centerY = (heightMask - original.getHeight()) * 0.5f;
mCanvas.drawBitmap(original, centerX, centerY, null);
mCanvas.drawBitmap(mask, 0, 0, paint);
paint.setXfermode(null);
imgView.getLayoutParams().height = bitmapHeight;
imgView.getLayoutParams().width = bitmapWidth;
imgView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imgView.setImageBitmap(result);
// 調整ImageView的邊界并保持drawable的寬高比
imgView.setAdjustViewBounds(true);
}
/**
* By using this method you can resize your image
*
* @param image pass a bitmap image for resizing.
* @param newHeight pass your expected new height in px (int value).
* @param newWidth pass your expected new width in px (int value).
* */
public static Bitmap getResizedBitmap(Bitmap image, float newHeight, float newWidth) {
int width = image.getWidth();
int height = image.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// Matrix類用于對圖像進行變換,如:平移、錯切
Matrix matrix = new Matrix();
// 對圖像進行縮放
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(image, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
public static float dipToPixels(Context context, float dipValue) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
// TypedValue.applyDimesion可以將dp、sp轉換成px
// 參數1為轉換的單位,參數2要轉換的具體數值,參數3為屏幕密度
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics);
}
}
首先按照用戶指定的寬高來裁剪原始圖片
original = getResizedBitmap(original,
dipToPixels(context, expectedHeight),
dipToPixels(context, expectedWidth));
- getResizedBitmap()方法中使用了Matrix類具體介紹大家自行移步,Matrix類可以對圖片進行變換,包括:
Translate————平移變換
Scale————縮放變換
Rotate————旋轉變換
Skew————錯切變換
所以學到了一種新的縮放圖片的方法
Matrix matrix = new Matrix();
// 對圖像進行縮放
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap =
Bitmap.createBitmap(image, 0, 0, width, height, matrix, false);
接下來我們回到主方法再看這段代碼
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(
new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
第一句代碼設置畫筆的方鋸齒標志,第二句代碼setXfermode(Xfermode xfermode)該方法用來設置兩張圖片相交時的模式,系統(tǒng)已經實現(xiàn)的Xfermode子類有以下三個:
1、AvoidXfermode 指定了一個顏色和容差,強制Paint避免在它上面繪圖(或者只在它上面繪圖)。
2、PixelXorXfermode 當覆蓋已有的顏色時,應用一個簡單的像素XOR操作。
3、PorterDuffXfermode 這是一個非常強大的轉換模式,使用它,可以使用圖像合成的16條Porter-Duff規(guī)則的任意一條來控制Paint如何與已有的Canvas圖像進行交互
即Canvas的圖像作為背景,在它上面繪制時顯示的效果。
canvas原有的圖片 可以理解為背景 就是dst
新畫上去的圖片 可以理解為前景 就是src
不同的模式效果如下:

所以該框架的源碼采用了DstIn的模式,它的繪制圖片的具體方法:
mCanvas.drawBitmap(original, centerX, centerY, null);
mCanvas.drawBitmap(mask, 0, 0, paint);
paint.setXfermode(null);
先繪制背景既要顯示的original圖片,在繪制需要裁減時使用的圖形圖片。
最后即是對ImageView的布局了,代碼如下:
imgView.getLayoutParams().height = bitmapHeight;
imgView.getLayoutParams().width = bitmapWidth;
imgView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imgView.setImageBitmap(result);
// 調整ImageView的邊界并保持drawable的寬高比
imgView.setAdjustViewBounds(true);
使用方式也很簡單Demo中就有它的使用方法我這里也將代碼貼出來,XML視圖布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
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.mafstech.imagelibrary.MainActivity">
<ImageView
android:id="@+id/ivOne"
android:layout_width="150dp"
android:layout_height="150dp"/>
<ImageView
android:id="@+id/ivTwo"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="114dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp" />
<ImageView
android:id="@+id/ivThree"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_below="@+id/ivOne"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="66dp" />
</RelativeLayout>
MainActivity:
public class MainActivity extends AppCompatActivity {
ImageView ivOne, ivTwo, ivThree;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ivOne = (ImageView) findViewById(R.id.ivOne);
ivTwo = (ImageView) findViewById(R.id.ivTwo);
ivThree = (ImageView) findViewById(R.id.ivThree);
/**
* This tasks are only for HDPI device. You need to convert all height and width to any other dpi as your expectation
* */
Shaper.shape(MainActivity.this, R.drawable.flag, R.drawable.tri, ivOne, 150, 150);
Shaper.shape(MainActivity.this, R.drawable.flag, R.drawable.pro_pic, ivTwo, 100, 100);
Shaper.shape(MainActivity.this, R.drawable.flag, R.drawable.shape2, ivThree, 150, 150);
}
}
好了學習該框架的源碼即到這里,希望有一天開發(fā)當中能夠使用。