可以在上面随便画,还可以撤销。
MainActivity 类
public class MainActivity extends AppCompatActivity implements View.OnClickListener, ColorView.OnColorSelectListener, SeekBar.OnSeekBarChangeListener {
DrawView drawView;
ImageView ivMenu;
boolean isStart;
boolean isReform;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ivMenu = (ImageView) findViewById(R.id.iv_menu);
drawView = (DrawView) findViewById(R.id.drawview);
ivMenu.setOnClickListener(this);
drawView.setOnDrawStateChangedListener(new DrawView.OnDrawStateChangedListener() {
@Override
public void startDraw() {
isStart = true;
isReform = false;
}
@Override
public void clearDraw() {
isStart = false;
}
@Override
public void reform(boolean b) {
isReform = b;
}
});
}
PopupWindow popupWindow;
@Override
public void onClick(View v) {
View layout = View.inflate(this, R.layout.popup_layout, null);
TextView tvColor = (TextView) layout.findViewById(R.id.pop_tv_color);
TextView tvWidth = (TextView) layout.findViewById(R.id.pop_tv_width);
TextView tvClear = (TextView) layout.findViewById(R.id.pop_tv_clear);
TextView tvCa = (TextView) layout.findViewById(R.id.pop_tv_ca);
TextView tvRepeal = (TextView) layout.findViewById(R.id.pop_tv_repeal);
TextView tvReform = (TextView) layout.findViewById(pop_tv_reform);
TextView tvSave = (TextView) layout.findViewById(R.id.pop_tv_save);
tvRepeal.setEnabled(isStart);
tvReform.setEnabled(isReform);
tvSave.setEnabled(isStart);
tvCa.setOnClickListener(popwindowClick);
tvColor.setOnClickListener(popwindowClick);
tvWidth.setOnClickListener(popwindowClick);
tvClear.setOnClickListener(popwindowClick);
tvRepeal.setOnClickListener(popwindowClick);
tvReform.setOnClickListener(popwindowClick);
tvSave.setOnClickListener(popwindowClick);
popupWindow = new PopupWindow(layout);
popupWindow.setWidth(getResources().getDisplayMetrics().widthPixels / 3);
popupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
popupWindow.setFocusable(true);
popupWindow.setOutsideTouchable(true);
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupWindow.showAsDropDown(ivMenu, 0, 20);
}
private View.OnClickListener popwindowClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.pop_tv_color:
SelectColorDialog dialog = new SelectColorDialog(MainActivity.this, MainActivity.this);
dialog.show();
break;
case R.id.pop_tv_width:
WidthDialog dialog2 = new WidthDialog(MainActivity.this, MainActivity.this);
dialog2.show();
break;
case R.id.pop_tv_clear:
drawView.clear();
break;
case R.id.pop_tv_ca:
drawView.ca();
break;
case R.id.pop_tv_repeal:
drawView.repeal();
break;
case R.id.pop_tv_reform:
drawView.reform();
break;
case R.id.pop_tv_save:
drawView.saveBitmap(Environment.getExternalStorageDirectory().getAbsolutePath() + "/test.png");
break;
}
popupWindow.dismiss();
}
};
@Override
public void onColorSelect(int color) {
drawView.setColor(color);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
drawView.setWidth(progress + 1);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
ColorDialog 类
public class ColorDialog extends Dialog {
List colors = new ArrayList<>();
public ColorDialog(Context context) {
super(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
setTitle("颜色选择");
super.onCreate(savedInstanceState);
GridView gv = new GridView(getContext());
gv.setNumColumns(20);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
for (int k = 0; k < 16; k++) {
colors.add(Color.rgb(i * i, j * j, k * k));
}
}
}
gv.setHorizontalSpacing(10);
gv.setVerticalSpacing(10);
gv.setGravity(Gravity.CENTER);
gv.setAdapter(adapter);
setContentView(gv);
}
private BaseAdapter adapter = new BaseAdapter() {
@Override
public int getCount() {
return colors.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = new View(getContext());
GridView.LayoutParams params = new GridView.LayoutParams(10, 10);
convertView.setLayoutParams(params);
convertView.setBackgroundColor(colors.get(position));
return convertView;
}
};
}
ColorView 类
public class ColorView extends View {
Bitmap bitmap;
public ColorView(Context context) {
super(context);
init();
}
public ColorView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void init() {
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.sepan);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.e("TAG", bitmap.getWidth() + " " + bitmap.getHeight());
super.onMeasure(MeasureSpec.makeMeasureSpec(bitmap.getWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(bitmap.getHeight(), MeasureSpec.AT_MOST));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, 0, 0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
Log.e("TAG", x + " " + y);
if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {
int color = bitmap.getPixel((int) x, (int) y);
setBackgroundColor(color);
if (onColorSelectListener != null) {
onColorSelectListener.onColorSelect(color);
}
}
return true;
}
public interface OnColorSelectListener {
void onColorSelect(int color);
}
OnColorSelectListener onColorSelectListener;
public void setOnColorSelectListener(OnColorSelectListener onColorSelectListener) {
this.onColorSelectListener = onColorSelectListener;
}
}
DrawView 类
public class DrawView extends View {
Paint paint = new Paint();
int backgroundColor = Color.WHITE;
Path path;
Bitmap cacheBitmap;
Canvas cacheCanvas;
boolean isCa = false;
Paint caPaint = new Paint();
public DrawView(Context context) {
super(context);
init();
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
paint.setDither(true);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
path = new Path();
caPaint.setColor(backgroundColor);
caPaint.setStrokeWidth(20);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getWidth() != 0 && getHeight() != 0)
initBitmap();
}
public void initBitmap() {
cacheBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
cacheCanvas = new Canvas(cacheBitmap);
cacheCanvas.drawColor(backgroundColor);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(backgroundColor);
canvas.drawBitmap(cacheBitmap, 0, 0, paint);
if (isCa)
canvas.drawPath(path, caPaint);
else
canvas.drawPath(path, paint);
}
public void setColor(int color) {
paint.setColor(color);
}
public void setWidth(int width) {
paint.setStrokeWidth(width);
}
public void clear() {
cacheBitmap.recycle();
initBitmap();
invalidate();
if (onDrawStateChangedListener != null)
onDrawStateChangedListener.clearDraw();
}
public void ca() {
isCa = !isCa;
}
public void repeal() {
cacheCanvas.drawColor(backgroundColor);
if (lastPaths.size() > 0) {
removePaths.add(lastPaths.remove(lastPaths.size() - 1));
int color = paint.getColor();
float width = paint.getStrokeWidth();
for (LastPath lastPath : lastPaths) {
paint.setColor(lastPath.color);
paint.setStrokeWidth(lastPath.width);
cacheCanvas.drawPath(lastPath.path, paint);
}
paint.setColor(color);
paint.setStrokeWidth(width);
}
if (onDrawStateChangedListener != null)
onDrawStateChangedListener.reform(true);
invalidate();
}
public void reform() {
int color = paint.getColor();
float width = paint.getStrokeWidth();
if (removePaths.size() > 0) {
LastPath path = removePaths.remove(removePaths.size() - 1);
paint.setColor(path.color);
paint.setStrokeWidth(path.width);
cacheCanvas.drawPath(path.path, paint);
lastPaths.add(path);
}
paint.setColor(color);
paint.setStrokeWidth(width);
invalidate();
}
public void saveBitmap(final String path) {
new Thread() {
@Override
public void run() {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
cacheBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(x, y);
break;
case MotionEvent.ACTION_UP:
if (isCa) {
cacheCanvas.drawPath(path, caPaint);
path.reset();
} else {
cacheCanvas.drawPath(path, paint);
lastPaths.add(new LastPath(new Path(path), paint.getColor(), paint.getStrokeWidth()));
path.reset();
}
if (onDrawStateChangedListener != null)
onDrawStateChangedListener.startDraw();
removePaths.clear();
break;
}
invalidate();
return true;
}
List lastPaths = new ArrayList<>();
List removePaths = new ArrayList<>();
class LastPath {
Path path;
int color;
float width;
public LastPath(Path path, int color, float width) {
this.path = path;
this.color = color;
this.width = width;
}
}
public interface OnDrawStateChangedListener {
void startDraw();
void clearDraw();
void reform(boolean b);
}
OnDrawStateChangedListener onDrawStateChangedListener;
public void setOnDrawStateChangedListener(OnDrawStateChangedListener onDrawStateChangedListener) {
this.onDrawStateChangedListener = onDrawStateChangedListener;
}
}
SelectColorDialog 类
public class SelectColorDialog extends Dialog {
private final ColorView.OnColorSelectListener listener;
public SelectColorDialog(Context context, @NonNull ColorView.OnColorSelectListener listener) {
super(context);
this.listener = listener;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
ColorView view = new ColorView(getContext());
view.setOnColorSelectListener(listener);
setContentView(view);
}
}
WidthDialog 类
public class WidthDialog extends Dialog {
private final SeekBar.OnSeekBarChangeListener listener;
public WidthDialog(Context context, @NonNull SeekBar.OnSeekBarChangeListener listener) {
super(context);
this.listener = listener;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(getContext());
SeekBar seekBar = new SeekBar(getContext());
seekBar.setMax(9);
seekBar.setOnSeekBarChangeListener(listener);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(200, ViewGroup.LayoutParams.WRAP_CONTENT);
seekBar.setLayoutParams(params);
layout.addView(seekBar);
setContentView(layout);
}
}
activity_main.xml
<LinearLayout 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:orientation="vertical"
tools:context="com.example.administrator.lesson12_drawview.MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/colorPrimary">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="绘画板"
android:textColor="@android:color/white" />
<ImageView
android:id="@+id/iv_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:src="@mipmap/menu_wirte" />
RelativeLayout>
<com.example.administrator.lesson12_drawview.DrawView
android:id="@+id/drawview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/menu_item_bg"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/pop_tv_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="画笔颜色"
android:textColor="@android:color/white"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@android:color/white" />
<TextView
android:id="@+id/pop_tv_width"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="画笔粗细"
android:textColor="@android:color/white"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@android:color/white" />
<TextView
android:id="@+id/pop_tv_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="清除绘画"
android:textColor="@android:color/white"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@android:color/white" />
<TextView
android:id="@+id/pop_tv_ca"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="橡皮檫"
android:textColor="@android:color/white"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@android:color/white" />
<TextView
android:id="@+id/pop_tv_repeal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:padding="10dp"
android:text="撤销"
android:textColor="@color/textenable"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@android:color/white" />
<TextView
android:id="@+id/pop_tv_reform"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:padding="10dp"
android:text="重做"
android:textColor="@color/textenable"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@android:color/white" />
<TextView
android:id="@+id/pop_tv_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:padding="10dp"
android:text="保存绘制"
android:textColor="@color/textenable"
android:textSize="16sp" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@android:color/white" />
LinearLayout>