程序的实现
主程序
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()),width,height),null);
// 注意画的顺序,这是进行蒙版的画制
mBitmapCanvas.drawRect(0,mPaintCircle);
//则是进行上面点触的重叠图层进行绘制
mBitmapCanvas.drawPath(mPathPicture,mPaintRec);
canvas.drawBitmap(mBitmap,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,null);