程序的實現
主程序
package com.test.mypathview;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private MyBitmip2 myView;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myView = (MyBitmip2) findViewById(R.id.bitmap);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 獲取cache通常會佔用一定的內存,所以通常不需要的時候有必要對其進行清理,
//通過destroyDrawingCache或setDrawingCacheEnabled(false)實現。
//這裏並未對其進行處理
//一定要調用setDrawingCacheEnabled(false)方法來清空緩存區
myView.setDrawingCacheEnabled(true);
Bitmap bitmap = myView.getDrawingCache(true);
//設置文件的路徑,對文件進行存儲
File file = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
//100是控制圖片的壓縮比率
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
});
}
}
繼承View的類
package com.test.mypathview;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MyBitmip2 extends View {
private int height;
private int width;
private Bitmap mBitmap;
private Bitmap mBitmapPicture;
private Canvas mBitmapCanvas;
private Paint mPaintCircle;
private Paint mPaintRec;
private Path mPathPicture;
public MyBitmip2(Context context, AttributeSet attrs) {
super(context, attrs);
mPaintCircle = new Paint();
mPaintCircle.setColor(Color.RED);
/**
* 必須自定義屬性
*/
//改變背景圖片,根據樣式中background的傳入值
final TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.myview);
//得到BitmapDrawable的myview_background
BitmapDrawable drawable=(BitmapDrawable) ta.getDrawable(R.styleable.myview_myview_background);
if(drawable!=null){
mBitmapPicture=drawable.getBitmap();
}else{
//當爲空時傳入默認圖片
mBitmapPicture=BitmapFactory.decodeResource(getResources(), R.drawable.a);
}
/**
* 在紅色圖層上描繪的線的設置,重疊部分則變爲透明
*/
mPaintRec = new Paint();
mPaintRec.setColor(Color.YELLOW);
//設置重疊則變爲透明
PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.XOR);
mPaintRec.setXfermode(mode);
// 設置畫筆畫出的是什麼樣式的線
mPaintRec.setStrokeJoin(Paint.Join.ROUND);
// 設置畫筆起始點的形狀
mPaintRec.setStrokeCap(Paint.Cap.ROUND);
// 設置畫筆寬度
int paintWidth=ta.getDimensionPixelOffset(R.styleable.myview_myview_paint_width, 30);
mPaintRec.setStrokeWidth(paintWidth);
//設置畫筆的樣式
mPaintRec.setStyle(Paint.Style.FILL_AND_STROKE);
//設置畫線的形式,具體參照http://www.cnblogs.com/tianzhijiexian/p/4297783.html
mPaintRec.setPathEffect(new CornerPathEffect(90));
//設置是否去除鋸齒
mPaintRec.setAntiAlias(true);
// //得到背景圖片
// mBitmapPicture = BitmapFactory.decodeResource(getResources(), R.drawable.a);
//設置記錄在上面畫線的路徑
mPathPicture = new Path();
}
public MyBitmip2(Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
//首先設置怎個屏幕爲畫板,並定義了畫板的顏色樣式
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mBitmapCanvas = new Canvas(mBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//mBitmapPicture既是背景圖,也是要截取的圖,第一個Rect是截取圖的大小,第二個則是把這個截取圖放在多大的畫布上
canvas.drawBitmap(mBitmapPicture, new Rect(0, 0, mBitmapPicture.getWidth(), mBitmapPicture.getHeight()),
new Rect(0, 0, width, height), null);
// 注意畫的順序,這是進行蒙版的畫制
mBitmapCanvas.drawRect(0, 0, width, height, mPaintCircle);
//則是進行上面點觸的重疊圖層進行繪製
mBitmapCanvas.drawPath(mPathPicture, mPaintRec);
canvas.drawBitmap(mBitmap, 0, 0, null);
}
private float downx;
private float downy;
private float oldx;
private float oldy;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downx = event.getX();
downy = event.getY();
//中間用path記錄點觸位置的變化
mPathPicture.moveTo(downx, downy);
invalidate();
oldx = downx;
oldy = downy;
invalidate();
return true;
case MotionEvent.ACTION_MOVE:
downx = event.getX();
downy = event.getY();
invalidate();
mPathPicture.moveTo(oldx, oldy);
//quadto是畫貝塞爾曲線
mPathPicture.quadTo((downx + oldx) / 2, (downy + oldy) / 2, downx, downy);
invalidate();
//保存此次的座標,以便之後直線的繪製
oldx = downx;
oldy = downy;
//通過返回true 結束本次事件
return true;
default:
break;
}
return super.onTouchEvent(event);
}
}
主佈局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:view="http://schemas.android.com/apk/res/com.test.mypathview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- 在上面導入自己的樣式,跟自己的包名,並定義名字,然後根據名字使用自己定義的屬性-->
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button"/>
<!--在佈局文件中使用自己定義的屬性-->
<com.test.mypathview.MyBitmip2
android:id="@+id/bitmap"
android:layout_width="match_parent"
android:layout_height="match_parent"
view:myview_background="@drawable/c"
view:myview_paint_width="100dp"/>
<TextView
android:id="@+id/textview"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"
android:gravity="center"
android:text="A"
android:textSize="100sp" />
</RelativeLayout>
自定義屬性文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 這個名爲樣式名就是根據R.styleable.myview尋找的名字 -->
<declare-styleable name="myview">
<!-- 設置其中各個屬性的名字,以及屬性的限定-->
<attr name="myview_background" format="reference" ></attr>
<attr name="myview_paint_width" format="dimension|reference"></attr>
</declare-styleable>
</resources>
參考
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="rightPadding" format="dimension" />
<declare-styleable name="SlidingMenu">
<attr name="rightPadding" />
</declare-styleable>
</resources>
另外注意
在本例中使用這個東東來使圖片適應整個屏幕,但是我們也可以使用matrix來放大圖片,使用時必須使用Matrix.reset()恢復正常,然後就可以放大圖片了。
canvas.drawBitmap(mBitmapPicture, new Rect(0, 0, mBitmapPicture.getWidth(), mBitmapPicture.getHeight()),
new Rect(0, 0, width, height), null);