安卓动画基础–画板
最近今天学习了下安卓的绘图类基础 Canvas类 Path类 Paint类这三种基础绘图类,本来是想学动画的,但是这个绘画类的基础就是这三个,动画只是加入了循环播放和旋转什么的
Canvas类 :就是画布,简单的来说就是创建一个画布,拿出一张纸,可以自定义这张在这张纸上任意地方画东西。
Paint类:就是画笔,画笔在Canvas上画东西,可以自定义画笔的大小,颜色,粗细等
path:就是路径,代表任意多的直线连接成图形
做出来的效果如下:
主要的功能有:
1.绘图
2.修改画笔的粗细
3.修改画笔的颜色
4.撤回最近画的那笔
5.恢复撤回的那笔
6.橡皮擦功能
实现的逻辑顺序:
1.自定义一个画布类继承View类
2.利用双缓冲原理实现画板的手绘功能:当看起来是用户在屏幕上画曲线时候,其实是先监听那个人按下去的起始的坐标,然后每次拖动时候,距离太小,然后将很多小直线连接起来就好了,但是为了记住上次那个小直线,就需要双缓冲技术,讲用户绘制的东西先存在一个Bithmap上面,等这个画好之后,直接绘制到自定义画板上。
3.在删除路径和恢复路径的实现也蛮简单的,记录下每次的小线段的path和paint,然后放在LIst里面,对这两个list进行操作
4.修改颜色这个,就是把各种颜色放在一个数组里面,每次点击时候,替换一下,画笔的大小同理。
5.实现布局页面,安排各种按钮的位置
4.美化界面
activity_main.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hasee.canvas.MainActivity"
android:background="@mipmap/back">
<LinearLayout
android:id="@+id/Lin"
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal"
android:weightSum="3">
<Button
android:layout_weight="1"
android:id="@+id/but_last"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="撤销"
android:background="@drawable/shapecircle" />
<Button
android:id="@+id/but_redo"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/shapecircle"
android:text="重画"/>
<Button
android:id="@+id/but_recove"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/shapecircle"
android:text="恢复"/>
</LinearLayout>
<FrameLayout
android:layout_below="@id/Lin"
android:id="@+id/br"
android:layout_width="match_parent"
android:layout_height="400dp">
</FrameLayout>
<SeekBar
android:id="@+id/seekbar"
android:layout_below="@id/br"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="30"
android:progress="5"/>
<LinearLayout
android:layout_below="@id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="3">
<Button
android:id="@+id/paint_style"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/shapecircle"
android:text="画笔的格式" />
<Button
android:id="@+id/paint_color"
android:layout_weight="1"
android:text="画笔的颜色"
android:layout_width="0dp"
android:background="@drawable/shapecircle"
android:layout_height="match_parent" />
<Button
android:id="@+id/paint_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/shapecircle"
android:text="画笔的大小" />
</LinearLayout>
</RelativeLayout>
自定义按钮格式shapecircle.xml
在res/drawable/
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- Corner的属性是设置圆角的半径的-->
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="25dp"
android:radius="20dp"
android:topLeftRadius="10dp"
android:topRightRadius="15dp" />
<!-- Button里面的文字与Button边界的间隔-->
<padding
android:bottom="10dp"
android:left="10dp"
android:right="10dp"
android:top="10dp" />
<solid android:color="#FFCC99" />
</shape>
自定义画板类
package com.example.hasee.canvas;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Created by hasee on 2018/4/11.
*/
public class TuyaView extends View {
private Context context;
private Bitmap mBithmap; //缓存的图片
private Canvas mCanvas; //画布
private Path mPath; //路径
private Paint mPaint; //真实的画笔
private Paint mBithmapPaint; //画布的画笔
private float mX,mY; //临时的坐标
private static final float TOUCH_TOLERANCE = 4;
private static List<DrawPath> savePath; //保存path的路径的集合
private static List<DrawPath> deletePath; //保存删除的path的路径
private DrawPath dp; //路径的的对象
private int screenWidth, screenHeight; //屏幕的
private int currentColor = Color.RED;
private int currentSize = 5;
private int currentStyle = 1;
private int[] paintColor;//颜色集合
private class DrawPath{
public Path path; //路径
public Paint paint; //画笔
}
public TuyaView(Context context, int x,int y) {
super(context);
this.context = context;
screenWidth = x;
screenHeight = y;
paintColor = new int[]{
Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.BLACK, Color.GRAY, Color.CYAN
};
setLayerType(LAYER_TYPE_HARDWARE,null);//设置格式
initCanvas();
savePath = new ArrayList<DrawPath>();
deletePath = new ArrayList<DrawPath>();
}
/**
* 初始化画布和缓冲区图片
*/
private void initCanvas(){
setPaintStyle();
mBithmap = Bitmap.createBitmap(screenWidth,screenHeight,Bitmap.Config.ARGB_8888);//缓冲区
mBithmap.eraseColor(Color.argb(0,0,0,0)); //颜色
mCanvas = new Canvas(mBithmap); //把所有的画布的东西放在图片中
mCanvas.drawColor(Color.TRANSPARENT);
}
/**
* 初始话画笔的样式
*/
private void setPaintStyle(){
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setDither(true);
if (currentStyle==1){
mPaint.setStrokeWidth(currentSize);
mPaint.setColor(currentColor);
}else {
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setColor(Color.TRANSPARENT);
mPaint.setStrokeWidth(100);
}
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBithmap, 0, 0, mBithmapPaint);//将之前的显示出来
if (mPath != null){
//实时的显示
canvas.drawPath(mPath,mPaint);
}
}
/**
* 获取初始
* @param x
* @param y
*/
private void touch_srart(float x,float y){
mPath.moveTo(x,y);
mX = x;
mY = y;
}
private void touch_move(float x,float y){
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
if(dx>=TOUCH_TOLERANCE||dy>=TOUCH_TOLERANCE){
mPath.quadTo(mX,mY,(x+mX)/2,(y+mY)/2);
mX = x;
mY = y;
}
}
private void touch_up(){
mPath.lineTo(mX,mY);
mCanvas.drawPath(mPath,mPaint);//将完整的路径保存下了
savePath.add(dp);
mPath = null; //清空
}
/**
* 撤销
* 将保存的最后一个Path路径移除
* 重新画在画布上
*/
public void undo(){
if (savePath!=null&&savePath.size()>0){
DrawPath drawPath = savePath.get(savePath.size()-1);
deletePath.add(drawPath);
savePath.remove(savePath.size()-1);
redrawOnBitmap();
}
}
/**
* 重新写
* 将其清空然后重新画
*/
public void redo(){
if (savePath!=null&&savePath.size()>0){
savePath.clear(); //把路径全清空
redrawOnBitmap();//重新画
}
}
/**
* 重新画
*/
private void redrawOnBitmap(){
initCanvas();
Iterator<DrawPath> iter = savePath.iterator();
while (iter.hasNext()) {
DrawPath drawPath = iter.next();
mCanvas.drawPath(drawPath.path, drawPath.paint);
}
invalidate();// 刷新
}
/**
* 恢复
* 就是将删除的那个路径重新加载到savaPath里面
*/
public void recover(){
if (deletePath.size()>0){
DrawPath dp = deletePath.get(deletePath.size()-1);
savePath.add(dp);
//重新画一下
mCanvas.drawPath(dp.path,dp.paint);
deletePath.remove(deletePath.size()-1);
invalidate();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY(); //获取目前的坐标
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mPath = new Path();
dp = new DrawPath();
dp.paint = mPaint;
dp.path = mPath;
touch_srart(x,y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x,y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
/**
* 画笔的样式
* @param which
*/
public void selectPaintStyle(int which){
if (which == 0){
currentStyle =1;
setPaintStyle();
}
if (which == 1){
currentStyle = 2;
setPaintStyle();
}
}
/**
* 画笔的大小
* @param which
*/
public void selectPaintSize(int which){
currentSize = which;
setPaintStyle();
}
/**
* 画笔的颜色
* @param which
*/
public void selectPaintColor(int which){
currentColor = paintColor[which];
setPaintStyle();
}
}
MainActivity类
package com.example.hasee.canvas;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.Display;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.SeekBar;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TuyaView tuyaView; //自定义画版
private FrameLayout frameLayout;
private Button btn_undo;
private Button btn_redo;
private Button btn_recover;
private Button btn_paintcolor;
private Button btn_paintsize;
private Button btn_paintstyle;
private SeekBar sb_size;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
initListener();
sb_size.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
tuyaView.selectPaintSize(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
private void initView() {
frameLayout = (FrameLayout) findViewById(R.id.br);
btn_undo = (Button) findViewById(R.id.but_last);
btn_redo = (Button) findViewById(R.id.but_redo);
btn_recover = (Button) findViewById(R.id.but_recove);
btn_paintcolor = (Button) findViewById(R.id.paint_color);
btn_paintsize = (Button) findViewById(R.id.paint_size);
btn_paintstyle = (Button) findViewById(R.id.paint_style);
sb_size = (SeekBar) findViewById(R.id.seekbar);
}
private void initListener(){
btn_paintcolor.setOnClickListener(this);
btn_paintsize.setOnClickListener(this);
btn_paintstyle.setOnClickListener(this);
btn_recover.setOnClickListener(this);
btn_redo.setOnClickListener(this);
btn_undo.setOnClickListener(this);
sb_size = (SeekBar)findViewById(R.id.seekbar);
}
private void initData() {
//虽然此时获取的是屏幕宽高,但是我们可以通过控制framlayout来实现控制涂鸦板大小
Display defaultDisplay = getWindowManager().getDefaultDisplay();
int screenWidth = defaultDisplay.getWidth();
int screenHeight = defaultDisplay.getHeight();
tuyaView = new TuyaView(this,screenWidth,screenHeight);
frameLayout.addView(tuyaView);
tuyaView.requestFocus();
tuyaView.selectPaintSize(sb_size.getProgress());
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.but_last: //撤销
tuyaView.undo();
break;
case R.id.but_redo: //重做
tuyaView.redo();
break;
case R.id.but_recove: //恢复
tuyaView.recover();
break;
case R.id.paint_size:
sb_size.setVisibility(View.VISIBLE);
break;
case R.id.paint_color:
sb_size.setVisibility(View.GONE);
showPaintColorDialog(v);
break;
case R.id.paint_style:
sb_size.setVisibility(View.GONE);
showMoreDialog(v);
break;
}
}
private int select_paint_color_index = 0;
private int select_paint_style_index = 0;
public void showPaintColorDialog(View parent){
final String[] paintColor = new String[]{
"红色","蓝色", "橙色", "黄色", "黑色", "灰色", "青色"
};
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle("选择画笔颜色:");
alertDialogBuilder.setSingleChoiceItems(paintColor, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
select_paint_color_index = which;
tuyaView.selectPaintColor(which);
dialog.dismiss();
}
});
alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialogBuilder.create().show();
}
//弹出选择画笔或橡皮擦的对话框
public void showMoreDialog(View parent){
final String[] paintstyle = new String[]{"画笔","橡皮擦"};
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle("选择画笔或橡皮擦:");
alertDialogBuilder.setSingleChoiceItems(paintstyle, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
select_paint_style_index = which;
tuyaView.selectPaintStyle(which);
dialog.dismiss();
}
});
alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialogBuilder.create().show();
}
}
总结
这个就是按网上一个大佬博客写的东西,熟悉熟悉下绘图的基本类的用法,写个简单的小东西,,,然后继续写项目了,,,产品经理太可怕了哇咔咔