概述:
此部分內容涉及到android的自定義View、自定義屬性和Android圖形圖像處理的綜合應用:Bitmap、Path、Matrix、Canvas。
圖片打碼以及如何緩存打碼後的圖片都是日常極有可能用到的,而刮圖也並不是用不到。
下面的demo寫的是一個的刮刮樂例程,裏面涉及到如何自定義控件屬性,以及如何存儲處理後的圖片,註釋很詳細,看註釋即可。
結果演示:
文件保存後的結果:
Demo
新建一個自定義View:
public class MyBitMapViewSec extends View {
private int width;
private int height;
private float x;
private float y;
private float old_x;
private float old_y;
private Paint mPaintCircle;
private Paint mPaintRect;
private Bitmap mBitmap;
private Bitmap mBitmapGround;
private Matrix matrix;
private Path mPath;
private Canvas mCanvasBm;
public MyBitMapViewSec(Context context) {
super(context);
}
//
public MyBitMapViewSec(Context context, AttributeSet attrs) {
//attrs是這個View在xml佈局中的所有屬性的集合
super(context, attrs);
//將attrs解析爲TypedArray類的對象
final TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.selfish);
//得到xml中本自定義View的self_background屬性的內容,並強制轉換爲BitmapDrawable類型
BitmapDrawable dra = (BitmapDrawable) a.getDrawable(R.styleable.selfish_self_background);
if(dra!=null){
//如果dra不爲空,就將dra賦值給mBitmapGround
mBitmapGround = dra.getBitmap();
}else {
//mBitmapGround裏傳入的是一張圖片
mBitmapGround = BitmapFactory.decodeResource(getResources(),R.mipmap.qingxin);
}
//得到xml中本自定義View的self_paintWidth屬性中的內容,如果得不到就給個默認值30
float paintWidth = a.getDimension(R.styleable.selfish_self_paintWidth,30);
mPaintCircle = new Paint();
mPaintCircle.setColor(Color.YELLOW);
mPaintRect = new Paint();
//XOR:交疊和被交疊部分均不顯示;DST_OVER:自身交疊部分不顯示;SRC_OVER交疊部分只顯示自己
PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.XOR);
mPaintRect.setXfermode(mode);
mPaintRect.setStrokeWidth(paintWidth);
mPaintRect.setStrokeJoin(Paint.Join.ROUND);//設置聯接部分樣式
mPaintRect.setStrokeCap(Paint.Cap.ROUND);//設置中間部分樣式:圓形
mPaintRect.setStyle(Paint.Style.FILL_AND_STROKE);
mPath = new Path();
matrix = new Matrix();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
//這一句不能放到構造方法中,是因爲還沒有得到width和height的值
mBitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
mCanvasBm = new Canvas(mBitmap);//自定義一個畫布,畫布材料是Bitmap對象
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
matrix.reset();
//下面兩行的作用是放大圖片,並繪製出來
matrix.postScale((float)width/mBitmapGround.getWidth(),(float)height/mBitmapGround.getHeight());
canvas.drawBitmap(mBitmapGround,matrix,null);
//畫一個蒙板
mCanvasBm.drawRect(0,0,width,height,mPaintCircle);
//將path畫出,因爲mPaintRect的模式爲PorterDuff.Mode.XOR,所以畫圖時會讓交疊部分都不顯示,從而顯示出底部圖片來
mCanvasBm.drawPath(mPath,mPaintRect);
//這一步的意義是:將mCanvasBm在mBitmap上繪製的內容畫出
canvas.drawBitmap(mBitmap,0,0,null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
y = event.getY();
x = event.getX();
//CW是Path移動方向:順時針
//mPath.addCircle(x,y,50,Path.Direction.CW);
mPath.moveTo(x,y);
//重新繪製,就是重新調用onDraw()方法
invalidate();
//更新old_x、old_y的值
old_x = x;
old_y = y;
return true;
case MotionEvent.ACTION_MOVE:
y = event.getY();
x = event.getX();
//將mPath移動到上一個位置
mPath.moveTo(old_x, old_y);
//繪製貝塞爾曲線,((x + old_x) / 2, (y + old_y) / 2)作爲控制點,(x, y)作爲結束點
mPath.quadTo((x + old_x) / 2, (y + old_y) / 2, x, y);
invalidate();
old_x = x;
old_y = y;
return true;
}
return super.onTouchEvent(event);
}
}
如果用的是android studio,在res/value路徑下新建一個文件,命名隨意,我這裏叫selfish,內容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="selfish" >
<attr name="self_background" format="reference"></attr>
<attr name="self_paintWidth" format="dimension|reference"></attr>
</declare-styleable>
</resources>
上面的打碼中:attr代表我的自定View的屬性,我這裏添加了兩個屬性;declare-styleabl是給自定義控件添加自定義屬性用的,它是一個屬性集。
這個文件以及它的屬性會在佈局文件中用到,用它之前必須要聲明:
xmlns:selfish=”http://schemas.android.com/apk/res-auto”
之後我就可以在我的自定義View——com.example.administrator.selfdefinedview.widget.MyBitMapViewSec中調用selfish屬性集中的兩個屬性:在代碼中可以看到他們:
*selfish:self_background=”@mipmap/aa”
selfish:self_paintWidth=”100dp”*
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:selfish="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:orientation="vertical">
<Button
android:id="@+id/button_resolve"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save Picture"/>
<com.example.administrator.selfdefinedview.widget.MyBitMapViewSec
android:id="@+id/my_slider"
android:layout_width="match_parent"
android:layout_height="match_parent"
selfish:self_background="@mipmap/aa"
selfish:self_paintWidth="100dp"/>
</LinearLayout>
關於緩存View中的圖片的打碼,在主函數中寫出:
public class TimerActivity extends Activity {
private Button mButtonResolve;
private MyBitMapViewSec myBitMapViewSec;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
mButtonResolve = (Button) findViewById(R.id.button_resolve);
myBitMapViewSec = (MyBitMapViewSec) findViewById(R.id.my_slider);
mButtonResolve.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//將緩存開啓
myBitMapViewSec.setDrawingCacheEnabled(true);
//getDrawingCache(true)得到當前myBitMapViewSec的緩存
Bitmap bitmap = myBitMapViewSec.getDrawingCache(true);
//得到存儲這個位圖文件bitmap的路徑
File file = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");
if (!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
//將bitmap轉爲JPEG格式,保持原來大小寫入file文件
bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
});
}
}
至於圖片打碼該怎麼寫呢?很簡單,只需修改onDraw()方法,把美女圖畫到自己聲明的畫布上,然後把黃色背景用onDraw()方法自帶的canvas上,最後位置互換即可,這樣,滑動頻幕的地方會顯示出底部的黃色,代碼如下:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//畫一個蒙板
canvas.drawRect(0, 0, width, height, mPaintCircle);
//將path畫出,因爲mPaintRect的模式爲PorterDuff.Mode.XOR,所以畫圖時會讓交疊部分都不顯示,從而顯示出底部圖片來
matrix.reset();
//下面兩行的作用是放大圖片,並繪製出來
matrix.postScale((float) width / mBitmapGround.getWidth(), (float) height / mBitmapGround.getHeight());
mCanvasBm.drawBitmap(mBitmapGround, matrix, null);
mCanvasBm.drawPath(mPath, mPaintRect);
//這一步的意義是:將mCanvasBm在mBitmap上繪製的內容畫出
canvas.drawBitmap(mBitmap,0,0,null);
}
結果演示:
我們猿類工作壓力大,很需要有自己的樂趣,於是乎,我開通了音樂人賬號,以後的作品將會上傳到我的音樂人小站上。如果這篇博客幫助到您,希望您能多關注,支持,鼓勵我將創作進行下去,同時也祝你能在工作和生活樂趣兩發麪都能出彩!