Repository: guanpy/WhiteBoard
Branch: master
Commit: 12e47c0c320b
Files: 91
Total size: 209.6 KB
Directory structure:
gitextract_yv6_nzdc/
├── .gitignore
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── example/
│ │ └── gpy/
│ │ └── whiteboard/
│ │ └── ApplicationTest.java
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── gpy/
│ │ └── whiteboard/
│ │ ├── MainActivity.java
│ │ ├── SelfApplication.java
│ │ ├── bean/
│ │ │ └── WbInfo.java
│ │ ├── utils/
│ │ │ ├── FileUtil.java
│ │ │ ├── SdCardStatus.java
│ │ │ ├── StoreUtil.java
│ │ │ └── ToastUtils.java
│ │ └── view/
│ │ ├── WhiteBoardActivity.java
│ │ ├── base/
│ │ │ └── BaseActivity.java
│ │ └── widget/
│ │ └── floatingactionmenu/
│ │ ├── AddFloatingActionButton.java
│ │ ├── FloatingActionButton.java
│ │ ├── FloatingActionsMenu.java
│ │ ├── FloatingImageButton.java
│ │ └── TouchDelegateGroup.java
│ └── res/
│ ├── drawable/
│ │ ├── bg_white_board.xml
│ │ ├── common_cancel_selector.xml
│ │ ├── common_confirm_selector.xml
│ │ ├── draw_text_border.xml
│ │ ├── fab_label_background.xml
│ │ ├── ic_back_selector.xml
│ │ ├── white_board_add_selector.xml
│ │ ├── white_board_color_black_selector.xml
│ │ ├── white_board_color_green_selector.xml
│ │ ├── white_board_color_orange_selector.xml
│ │ ├── white_board_color_pink_selector.xml
│ │ ├── white_board_color_purple_selector.xml
│ │ ├── white_board_disable_selector.xml
│ │ ├── white_board_eraser_selected_selector.xml
│ │ ├── white_board_eraser_selector.xml
│ │ ├── white_board_export_selector.xml
│ │ ├── white_board_next_page_selector.xml
│ │ ├── white_board_pen_selected_selector.xml
│ │ ├── white_board_pen_selector.xml
│ │ ├── white_board_pre_page_selector.xml
│ │ ├── white_board_redo_selector.xml
│ │ ├── white_board_save_selector.xml
│ │ ├── white_board_text_bold_selected_selector.xml
│ │ ├── white_board_text_bold_selector.xml
│ │ ├── white_board_text_italics_selected_selector.xml
│ │ ├── white_board_text_italics_selector.xml
│ │ ├── white_board_text_selected_selector.xml
│ │ ├── white_board_text_selector.xml
│ │ ├── white_board_text_underline_selected_selector.xml
│ │ ├── white_board_text_underline_selector.xml
│ │ ├── white_board_undisable_selector.xml
│ │ └── white_board_undo_selector.xml
│ ├── layout/
│ │ ├── activity_main.xml
│ │ ├── activity_white_board.xml
│ │ ├── draw_text.xml
│ │ └── wb_item.xml
│ ├── values/
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── values-w820dp/
│ └── dimens.xml
├── build.gradle
├── gradle.properties
├── settings.gradle
└── wblib/
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src/
├── androidTest/
│ └── java/
│ └── com/
│ └── github/
│ └── guanpy/
│ └── wblib/
│ └── ApplicationTest.java
└── main/
├── AndroidManifest.xml
├── java/
│ └── com/
│ └── github/
│ └── guanpy/
│ └── wblib/
│ ├── bean/
│ │ ├── DrawPenPoint.java
│ │ ├── DrawPenStr.java
│ │ ├── DrawPoint.java
│ │ ├── DrawTextPoint.java
│ │ ├── Point.java
│ │ ├── WhiteBoardPoint.java
│ │ └── WhiteBoardPoints.java
│ ├── utils/
│ │ ├── AppContextUtil.java
│ │ ├── BeanUtil.java
│ │ ├── Events.java
│ │ ├── OperationUtils.java
│ │ └── WhiteBoardVariable.java
│ └── widget/
│ ├── DrawPenView.java
│ ├── DrawTextLayout.java
│ └── DrawTextView.java
└── res/
├── drawable/
│ └── draw_text_border.xml
├── layout/
│ └── draw_text.xml
└── values/
├── colors.xml
└── strings.xml
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
#Android generated
bin
gen
lint.xml
lint
#Eclipse
.project
.classpath
.settings
.checkstyle
#IntelliJ IDEA
.idea
*.iml
*.ipr
*.iws
classes
gen-external-apklibs
#gradle
.gradle
local.properties
gradlew
gradlew.bat
gradle/
build/
#vi
*.swp
#other editors
*.bak
#Maven
target
release.properties
pom.xml.*
#Ant
build.xml
ant.properties
local.properties
proguard.cfg
proguard-project.txt
#Other
.DS_Store
Thumbs.db
tmp
*.tgz
*.lock
*.lck
com_crashlytics_export_strings.xml
================================================
FILE: README.md
================================================
# WhiteBoard
- 1、涂鸦功能:包括画笔粗细选择、颜色选择、橡皮擦等;
- 2、文字输入:包括颜色选择、增、删、改等;
- 3、白板功能:包括撤销、重做、新增、锁屏、切换、保存为图片、保存到本地等功能

## 预览


## TODO
- 1、DrawTextView的接口化
- 2、白板数据结构重定义
- 3、markId的重新加载问题
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.example.gpy.whiteboard"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':wblib')
compile 'com.android.support:appcompat-v7:23.1.1'
compile'com.squareup.retrofit:converter-jackson:1.9.0'
compile 'com.jakewharton:butterknife:6.1.0'
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\software\Java\Android\sdk_studio/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: app/src/androidTest/java/com/example/gpy/whiteboard/ApplicationTest.java
================================================
package com.example.gpy.whiteboard;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* Testing Fundamentals
*/
public class ApplicationTest extends ApplicationTestCase {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/MainActivity.java
================================================
package com.example.gpy.whiteboard;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.example.gpy.whiteboard.utils.FileUtil;
import com.example.gpy.whiteboard.utils.StoreUtil;
import com.example.gpy.whiteboard.utils.ToastUtils;
import com.example.gpy.whiteboard.view.WhiteBoardActivity;
import com.example.gpy.whiteboard.view.base.BaseActivity;
import com.github.guanpy.wblib.utils.OperationUtils;
import java.io.File;
import java.util.ArrayList;
import butterknife.InjectView;
public class MainActivity extends BaseActivity {
@InjectView(R.id.lv_wb)
ListView mLv;
@InjectView(R.id.iv_wb_add)
ImageView mIvAdd;
private WbAdapter mWbAdapter;
ArrayList filenames;
ArrayList filepaths;
private long mBackPressedTime;
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
@Override
protected void afterCreate(Bundle savedInstanceState) {
loadData();
initView();
}
private void loadData() {
File folder = new File(StoreUtil.getWbPath());
if (!folder.exists()) {
folder.mkdirs();
}
final File[] files = folder.listFiles();
if (files.length > 0) {
filenames = new ArrayList();
filepaths = new ArrayList();
for (File f : files) {
filenames.add(FileUtil.getFileName(f));
filepaths.add(f.getAbsolutePath());
}
}
// mWbAdapter.notifyDataSetChanged();
}
private void initView() {
mWbAdapter = new WbAdapter();
mLv.setAdapter(mWbAdapter);
mIvAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
OperationUtils.getInstance().initDrawPointList();
navi2Page(WhiteBoardActivity.class);
}
});
}
@Override
public void onBackPressed() {
final long mCurrentTime = System.currentTimeMillis();
if (mCurrentTime - this.mBackPressedTime > 1000) {
ToastUtils.showToast(this, R.string.app_logout);
this.mBackPressedTime = mCurrentTime;
return;
}
super.onBackPressed();
System.exit(0);
}
private class WbAdapter extends BaseAdapter {
@Override
public int getCount() {
return filenames != null ? filenames.size() : 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
WbViewHolder holder = null;
if (convertView != null) {
holder = (WbViewHolder) convertView.getTag();
} else {
convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.wb_item, null);
if (convertView != null) {
convertView.setTag(
holder = new WbViewHolder(convertView)
);
}
if (holder != null) {
holder.nWbName.setText(filenames.get(position));
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
StoreUtil.readWhiteBoardPoints(filepaths.get(position));
navi2Page(WhiteBoardActivity.class);
}
});
}
}
return convertView;
}
}
private final class WbViewHolder {
final TextView nWbName;
public WbViewHolder(final View view) {
this.nWbName = (TextView) view.findViewById(R.id.tv_wb_name);
}
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/SelfApplication.java
================================================
package com.example.gpy.whiteboard;
import android.app.Application;
import com.example.gpy.whiteboard.utils.SdCardStatus;
import com.example.gpy.whiteboard.utils.StoreUtil;
import com.github.guanpy.wblib.utils.AppContextUtil;
import com.github.guanpy.wblib.utils.OperationUtils;
/**
* Created by gpy on 2015/8/17.
*/
public class SelfApplication extends Application{
@Override
public void onCreate() {
super.onCreate();
AppContextUtil.init(this);
SdCardStatus.init(StoreUtil.CACHE_DIR);
OperationUtils.getInstance().init();
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/bean/WbInfo.java
================================================
package com.example.gpy.whiteboard.bean;
import java.io.File;
/**
* Created by gpy on 2016/4/22.
*/
public class WbInfo {
/**
* 文件名
*/
private String mName;
/**
* 文件
*/
private File mFile;
/**
* 获得文件名
* Created 2016-3-22 18:30:34
*
* @return 文件名
* @author gpy
*/
public String getName() {
return mName;
}
/**
* 设置文件名
* Created 2016-3-22 18:30:34
*
* @param name 文件名
* @author gpy
*/
public void setName(String name) {
this.mName = name;
}
/**
* 获得文件
* Created 2016-3-22 18:30:34
*
* @return 文件
* @author gpy
*/
public File getFile() {
return mFile;
}
/**
* 设置文件
* Created 2016-3-22 18:30:34
*
* @param file 文件
* @author gpy
*/
public void setFile(File file) {
this.mFile = file;
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/utils/FileUtil.java
================================================
package com.example.gpy.whiteboard.utils;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.text.DecimalFormat;
/**
* Created by gpy on 2016/4/6.
*/
public class FileUtil {
public static final int SIZETYPE_B = 1;// 获取文件大小单位为B的double值
public static final int SIZETYPE_KB = 2;// 获取文件大小单位为KB的double值
public static final int SIZETYPE_MB = 3;// 获取文件大小单位为MB的double值
public static final int SIZETYPE_GB = 4;// 获取文件大小单位为GB的double值
/**
* 获取指定文件名字
*
* @param file
* @return
*/
public static String getFileName(File file) {
final String name = file.getName();
if (!TextUtils.isEmpty(name)) {
final int ext = name.lastIndexOf(".");
if (ext > 0) {
return name.substring(0, ext);
}
}
return name;
}
/**
* 调用此方法自动计算指定文件或指定文件夹的大小
*
* @param filePath 文件路径
* @return 计算好的带B、KB、MB、GB的字符串
*/
public static String getAutoFileOrFilesSize(String filePath) {
File file = new File(filePath);
long blockSize = 0;
try {
if (file.isDirectory()) {
blockSize = getFileSizes(file);
} else {
blockSize = getFileSize(file);
}
} catch (Exception e) {
e.printStackTrace();
Log.e("获取文件大小", "获取失败!");
}
return FormetFileSize(blockSize);
}
/**
* 获取文件指定文件的指定单位的大小
*
* @param filePath 文件路径
* @param sizeType 获取大小的类型1为B、2为KB、3为MB、4为GB
* @return double值的大小
*/
public static double getFileOrFilesSize(String filePath, int sizeType) {
File file = new File(filePath);
long blockSize = 0;
try {
if (file.isDirectory()) {
blockSize = getFileSizes(file);
} else {
blockSize = getFileSize(file);
}
} catch (Exception e) {
e.printStackTrace();
Log.e("获取文件大小", "获取失败!");
}
return FormetFileSize(blockSize, sizeType);
}
/**
* 获取指定文件大小
*
* @param file
* @return
* @throws Exception
*/
private static long getFileSize(File file) throws Exception {
long size = 0;
if (file.exists()) {
FileInputStream fis = null;
fis = new FileInputStream(file);
size = fis.available();
} else {
file.createNewFile();
Log.e("获取文件大小", "文件不存在!");
}
return size;
}
/**
* 获取指定文件夹
*
* @param f
* @return
* @throws Exception
*/
private static long getFileSizes(File f) throws Exception {
long size = 0;
File flist[] = f.listFiles();
for (int i = 0; i < flist.length; i++) {
if (flist[i].isDirectory()) {
size = size + getFileSizes(flist[i]);
} else {
size = size + getFileSize(flist[i]);
}
}
return size;
}
/**
* 转换文件大小
*
* @param fileS
* @return
*/
private static String FormetFileSize(long fileS) {
DecimalFormat df = new DecimalFormat("#.00");
String fileSizeString = "";
String wrongSize = "0B";
if (fileS == 0) {
return wrongSize;
}
if (fileS < 1024) {
fileSizeString = df.format((double) fileS) + "B";
} else if (fileS < 1048576) {
fileSizeString = df.format((double) fileS / 1024) + "KB";
} else if (fileS < 1073741824) {
fileSizeString = df.format((double) fileS / 1048576) + "MB";
} else {
fileSizeString = df.format((double) fileS / 1073741824) + "GB";
}
return fileSizeString;
}
/**
* 转换文件大小,指定转换的类型
*
* @param fileS
* @param sizeType
* @return
*/
private static double FormetFileSize(long fileS, int sizeType) {
DecimalFormat df = new DecimalFormat("#.00");
double fileSizeLong = 0;
switch (sizeType) {
case SIZETYPE_B:
fileSizeLong = Double.valueOf(df.format((double) fileS));
break;
case SIZETYPE_KB:
fileSizeLong = Double.valueOf(df.format((double) fileS / 1024));
break;
case SIZETYPE_MB:
fileSizeLong = Double.valueOf(df.format((double) fileS / 1048576));
break;
case SIZETYPE_GB:
fileSizeLong = Double.valueOf(df
.format((double) fileS / 1073741824));
break;
default:
break;
}
return fileSizeLong;
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/utils/SdCardStatus.java
================================================
package com.example.gpy.whiteboard.utils;
import android.os.Environment;
import java.io.File;
/**
* Created by gpy on 2015/10/20.
*/
public class SdCardStatus {
private static String CACHE_FOLDER_NAME;
private static String NONE_SD_CARD_PROMPT = "您的手机中sd卡不存在";
public static void init(String cacheFolderName) {
CACHE_FOLDER_NAME = cacheFolderName;
}
public static String getDefaulstCacheDirInSdCard() throws IllegalStateException {
String sdCardPath = null;
sdCardPath = getSDPath();
if (null == sdCardPath) {
throw new IllegalStateException(NONE_SD_CARD_PROMPT);
}
return sdCardPath + File.separator + CACHE_FOLDER_NAME;
}
/**
* when not exist sd card,return null.
*
* @return
*/
public static String getSDPath() {
boolean sdCardExist = Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
if (sdCardExist) {
return Environment.getExternalStorageDirectory().getAbsolutePath();
} else {
return null;
}
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/utils/StoreUtil.java
================================================
package com.example.gpy.whiteboard.utils;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.text.TextUtils;
import android.util.Log;
import com.example.gpy.whiteboard.R;
import com.github.guanpy.wblib.bean.DrawPenPoint;
import com.github.guanpy.wblib.bean.DrawPenStr;
import com.github.guanpy.wblib.bean.DrawPoint;
import com.github.guanpy.wblib.bean.Point;
import com.github.guanpy.wblib.bean.WhiteBoardPoint;
import com.github.guanpy.wblib.bean.WhiteBoardPoints;
import com.github.guanpy.wblib.utils.AppContextUtil;
import com.github.guanpy.wblib.utils.OperationUtils;
import com.google.gson.Gson;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;
/**
* 存储空间工具类
* Created by gpy on 2015/8/2.
*/
public class StoreUtil {
private static final String TAG = "StoreUtil";
private static final String CHARSET = "UTF-8";
public static final String CACHE_DIR = "WhiteBoard";
private static final String CACHE_DIR_PHOTO = "photo";
private static final String PHOTO_FORMAT_PNG = ".png";
private static final String CACHE_DIR_WB = "wb";
private static final String WB_FORMAT = ".wb";
/**
* 获取保存路径
*/
public static String getPhotoSavePath() {
return getPhotoPath() + File.separator + UUID.randomUUID().toString() + PHOTO_FORMAT_PNG;
}
public static String getPhotoPath() {
return SdCardStatus.getDefaulstCacheDirInSdCard() + File.separator + CACHE_DIR_PHOTO;
}
/**
* 获取保存路径
*/
public static String getWbSavePath() {
return getWbPath() + File.separator + UUID.randomUUID().toString() + WB_FORMAT;
}
public static String getWbPath() {
return SdCardStatus.getDefaulstCacheDirInSdCard() + File.separator + CACHE_DIR_WB;
}
/**
* 存储白板集
*/
public static void saveWhiteBoardPoints() {
WhiteBoardPoints whiteBoardPoints = OperationUtils.getInstance().getWhiteBoardPoints();
if (whiteBoardPoints == null || whiteBoardPoints.getWhiteBoardPoints() == null || whiteBoardPoints.getWhiteBoardPoints().isEmpty()) {
return;
}
for (WhiteBoardPoint whiteBoardPoint : whiteBoardPoints.getWhiteBoardPoints()) {//清除绘画路径,保留字符串形式就行
for (DrawPoint drawPoint : whiteBoardPoint.getSavePoints()) {
if (drawPoint.getType() == OperationUtils.DRAW_PEN) {
drawPoint.setDrawPen(null);
}
}
}
String strJson = new Gson().toJson(whiteBoardPoints);
StoreUtil.write(strJson, getWbSavePath());
convertWhiteBoardPoints(whiteBoardPoints);
OperationUtils.getInstance().setWhiteBoardPoints(whiteBoardPoints);
ToastUtils.showToast(AppContextUtil.getContext(), AppContextUtil.getContext().getString(R.string.white_board_save_sucess));
}
/**
* 读取白板集
*/
public static void readWhiteBoardPoints(String filePath) {
String strJson = StoreUtil.read(filePath);
if (!TextUtils.isEmpty(strJson)) {
WhiteBoardPoints whiteBoardPoints = new Gson().fromJson(strJson, WhiteBoardPoints.class);
convertWhiteBoardPoints(whiteBoardPoints);
OperationUtils.getInstance().setWhiteBoardPoints(whiteBoardPoints);
}
}
/**
* 从json字符中将Path、Paint系统类转换出来
*/
public static void convertWhiteBoardPoints(WhiteBoardPoints whiteBoardPoints) {
for (WhiteBoardPoint whiteBoardPoint : whiteBoardPoints.getWhiteBoardPoints()) {
whiteBoardPoint.getDeletePoints().clear();
for (DrawPoint drawPoint : whiteBoardPoint.getSavePoints()) {
if (drawPoint.getType() == OperationUtils.DRAW_PEN) {
DrawPenStr drawPenStr = drawPoint.getDrawPenStr();
Paint paint = new Paint();
paint.setAntiAlias(true);//是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢
paint.setDither(true);// 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
paint.setColor(drawPenStr.getColor());//设置绘制的颜色
paint.setStyle(Paint.Style.STROKE);//设置画笔的样式
paint.setStrokeJoin(Paint.Join.ROUND);//设置绘制时各图形的结合方式,如平滑效果等
paint.setStrokeCap(Paint.Cap.ROUND);//当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式 Cap.ROUND,或方形样式Cap.SQUARE
paint.setStrokeWidth(drawPenStr.getStrokeWidth());//当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
if (drawPenStr.getIsEraser()) {
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//擦除模式
}
Path path = new Path();
path.moveTo(drawPenStr.getMoveTo().getX(), drawPenStr.getMoveTo().getY());
for (int i = 0; i < drawPenStr.getQuadToA().size(); i++) {
Point pointA = drawPenStr.getQuadToA().get(i);
Point pointB = drawPenStr.getQuadToB().get(i);
path.quadTo(pointA.getX(), pointA.getY(), pointB.getX(), pointB.getY());
}
path.lineTo(drawPenStr.getLineTo().getX(), drawPenStr.getLineTo().getY());
path.offset(drawPenStr.getOffset().getX(), drawPenStr.getOffset().getY());
DrawPenPoint drawPenPoint = new DrawPenPoint();
drawPenPoint.setPaint(paint);
drawPenPoint.setPath(path);
drawPoint.setDrawPen(drawPenPoint);
}
}
}
}
/**
* 保存内容到文件中
*/
public static void write(String strWb, String path) {
if (TextUtils.isEmpty(strWb) || TextUtils.isEmpty(path)) {
Log.d(TAG, "Trying to save null or 0 length strWb or path");
return;
}
File toFile = new File(path);
if (!toFile.getParentFile().exists()) {
toFile.getParentFile().mkdirs();
}
if (toFile.exists()) {
toFile.delete();
}
try {
toFile.createNewFile();
} catch (IOException e) {
Log.e(TAG, "IOException:" + e.getMessage());
toFile = null;
} finally {
if (null != toFile && null != strWb) {
OutputStream outStream = null;
try {
outStream = new FileOutputStream(toFile);
} catch (FileNotFoundException e) {
Log.d(TAG, "FileNotFoundException:" + e.getMessage());
outStream = null;
} finally {
if (null != outStream) {
try {
outStream.write(strWb.getBytes("utf-8"));
outStream.flush();
} catch (IOException e) {
Log.e(TAG, "IOException:" + e.getMessage());
} finally {
try {
if (null != outStream) {
outStream.close();
}
} catch (IOException e) {
Log.d(TAG, "IOException" + e.getMessage());
}
}
}
}
}
}
}
/**
* 加载文件内容
*/
public static String read(String wbPath) {
File file = new File(wbPath);
if (file.exists()) {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
int len = fis.available();
if (len > 0) {
byte[] buf = new byte[len];
fis.read(buf);
String string = new String(buf, CHARSET);
return string;
}
} catch (Exception e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
e.printStackTrace();
} finally {
if (fis != null)
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/utils/ToastUtils.java
================================================
package com.example.gpy.whiteboard.utils;
import android.content.Context;
import android.widget.Toast;
/**
* Created by gpy on 2016/4/11.
*/
public class ToastUtils {
public static void showToast(Context context, String string) {
Toast.makeText(context, string, Toast.LENGTH_SHORT).show();
}
public static void showToast(Context context, int intStr) {
Toast.makeText(context, intStr, Toast.LENGTH_SHORT).show();
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/view/WhiteBoardActivity.java
================================================
package com.example.gpy.whiteboard.view;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.example.gpy.whiteboard.R;
import com.example.gpy.whiteboard.utils.StoreUtil;
import com.example.gpy.whiteboard.view.base.BaseActivity;
import com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu;
import com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton;
import com.github.guanpy.library.ann.ReceiveEvents;
import com.github.guanpy.wblib.bean.DrawPoint;
import com.github.guanpy.wblib.utils.Events;
import com.github.guanpy.wblib.utils.OperationUtils;
import com.github.guanpy.wblib.utils.WhiteBoardVariable;
import com.github.guanpy.wblib.widget.DrawPenView;
import com.github.guanpy.wblib.widget.DrawTextLayout;
import com.github.guanpy.wblib.widget.DrawTextView;
import java.io.File;
import java.io.FileOutputStream;
import butterknife.InjectView;
/**
* 白板工具
* Created by gpy on 2015/6/2.
*/
public class WhiteBoardActivity extends BaseActivity implements View.OnClickListener {
@InjectView(R.id.iv_white_board_book)
ImageView mIvWhiteBoardBook;
@InjectView(R.id.rl_head)
RelativeLayout mRlHead;
@InjectView(R.id.iv_white_board_back)
ImageView mIvWhiteBoardBack;
@InjectView(R.id.tv_white_board_head)
TextView mTvWhiteBoardHead;
@InjectView(R.id.iv_white_board_export)
ImageView mIvWhiteBoardExport;
@InjectView(R.id.iv_white_board_save)
ImageView mIvWhiteBoardSave;
@InjectView(R.id.fl_view)
FrameLayout mFlView;
@InjectView(R.id.db_view)
DrawPenView mDbView;
@InjectView(R.id.dt_view)
DrawTextLayout mDtView;
@InjectView(R.id.fab_menu_size)
FloatingActionsMenu mFabMenuSize;
@InjectView(R.id.bt_size_large)
FloatingImageButton mBtSizeLarge;
@InjectView(R.id.bt_size_middle)
FloatingImageButton mBtSizeMiddle;
@InjectView(R.id.bt_size_mini)
FloatingImageButton mBtSizeMini;
@InjectView(R.id.fab_menu_color)
FloatingActionsMenu mFabMenuColor;
@InjectView(R.id.bt_color_green)
FloatingImageButton mBtColorGreen;
@InjectView(R.id.bt_color_purple)
FloatingImageButton mBtColorPurple;
@InjectView(R.id.bt_color_pink)
FloatingImageButton mBtColorPink;
@InjectView(R.id.bt_color_orange)
FloatingImageButton mBtColorOrange;
@InjectView(R.id.bt_color_black)
FloatingImageButton mBtColorBlack;
@InjectView(R.id.fab_menu_text)
FloatingActionsMenu mFabMenuText;
@InjectView(R.id.bt_text_underline)
FloatingImageButton mBtTextUnderline;
@InjectView(R.id.bt_text_italics)
FloatingImageButton mBtTextItalics;
@InjectView(R.id.bt_text_bold)
FloatingImageButton mBtTextBold;
@InjectView(R.id.fab_menu_eraser)
FloatingActionsMenu mFabMenuEraser;
@InjectView(R.id.bt_eraser_large)
FloatingImageButton mBtEraserLarge;
@InjectView(R.id.bt_eraser_middle)
FloatingImageButton mBtEraserMiddle;
@InjectView(R.id.bt_eraser_mini)
FloatingImageButton mBtEraserMini;
@InjectView(R.id.iv_white_board_undo)
ImageView mIvWhiteBoardUndo;
@InjectView(R.id.iv_white_board_redo)
ImageView mIvWhiteBoardRedo;
@InjectView(R.id.ll_white_board_page)
LinearLayout mLlWhiteBoardPage;
@InjectView(R.id.iv_white_board_pre)
ImageView mIvWhiteBoardPre;
@InjectView(R.id.tv_white_board_page)
TextView mTvWhiteBoardPage;
@InjectView(R.id.iv_white_board_next)
ImageView mIvWhiteBoardNext;
@InjectView(R.id.iv_white_board_add)
ImageView mIvWhiteBoardAdd;
@InjectView(R.id.iv_white_board_disable)
ImageView mIvWhiteBoardDisable;
@InjectView(R.id.iv_white_board_quit)
ImageView mIvWhiteBoardQuit;
@InjectView(R.id.iv_white_board_confirm)
ImageView mIvWhiteBoardConfirm;
@InjectView(R.id.rl_content)
RelativeLayout mRlContent;
@InjectView(R.id.rl_bottom)
RelativeLayout mRlBottom;
@InjectView(R.id.v_bottom_back)
View mVBottomBack;
@InjectView(R.id.ll_white_board_pre)
LinearLayout mLlWhiteBoardPre;
@InjectView(R.id.ll_white_board_next)
LinearLayout mLlWhiteBoardNext;
@Override
protected void afterCreate(Bundle bundle) {
initView();
initEvent();
}
private void initView() {
changePenBack();
changeColorBack();
changeEraserBack();
ToolsOperation(WhiteBoardVariable.Operation.PEN_NORMAL);
mDbView.post(new Runnable() {
@Override
public void run() {
showPoints();
}
});
}
private void initEvent() {
//头部
mIvWhiteBoardBack.setOnClickListener(this);
mIvWhiteBoardExport.setOnClickListener(this);
mIvWhiteBoardSave.setOnClickListener(this);
mIvWhiteBoardQuit.setOnClickListener(this);
mIvWhiteBoardConfirm.setOnClickListener(this);
mVBottomBack.setOnClickListener(this);
//画笔尺寸大小
mFabMenuSize.setOnFloatingActionsMenuClickListener(new FloatingActionsMenu.OnFloatingActionsMenuClickListener() {
@Override
public void addButtonLister() {
ToolsOperation(WhiteBoardVariable.Operation.PEN_CLICK);
}
});
mBtSizeLarge.setOnClickListener(this);
mBtSizeMiddle.setOnClickListener(this);
mBtSizeMini.setOnClickListener(this);
//画笔或者文字颜色
mFabMenuColor.setOnFloatingActionsMenuClickListener(new FloatingActionsMenu.OnFloatingActionsMenuClickListener() {
@Override
public void addButtonLister() {
ToolsOperation(WhiteBoardVariable.Operation.COLOR_CLICK);
}
});
mBtColorGreen.setOnClickListener(this);
mBtColorPurple.setOnClickListener(this);
mBtColorPink.setOnClickListener(this);
mBtColorOrange.setOnClickListener(this);
mBtColorBlack.setOnClickListener(this);
//文字样式
mFabMenuText.setOnFloatingActionsMenuClickListener(new FloatingActionsMenu.OnFloatingActionsMenuClickListener() {
@Override
public void addButtonLister() {
ToolsOperation(WhiteBoardVariable.Operation.TEXT_CLICK);
}
});
mBtTextUnderline.setOnClickListener(this);
mBtTextItalics.setOnClickListener(this);
mBtTextBold.setOnClickListener(this);
//橡皮擦尺寸大小
mFabMenuEraser.setOnFloatingActionsMenuClickListener(new FloatingActionsMenu.OnFloatingActionsMenuClickListener() {
@Override
public void addButtonLister() {
ToolsOperation(WhiteBoardVariable.Operation.ERASER_CLICK);
}
});
mBtEraserLarge.setOnClickListener(this);
mBtEraserMiddle.setOnClickListener(this);
mBtEraserMini.setOnClickListener(this);
mIvWhiteBoardUndo.setOnClickListener(this);
mIvWhiteBoardRedo.setOnClickListener(this);
mLlWhiteBoardPre.setOnClickListener(this);
mIvWhiteBoardPre.setOnClickListener(this);
mLlWhiteBoardNext.setOnClickListener(this);
mIvWhiteBoardNext.setOnClickListener(this);
mIvWhiteBoardAdd.setOnClickListener(this);
mIvWhiteBoardDisable.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.iv_white_board_back://返回键
onBackPressed();
break;
case R.id.iv_white_board_quit://退出文字编辑
afterEdit(false);
break;
case R.id.iv_white_board_confirm://保存文字编辑
afterEdit(true);
break;
case R.id.iv_white_board_export://保存白板操作集到本地
ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);
StoreUtil.saveWhiteBoardPoints();
break;
case R.id.iv_white_board_save://保存白板为图片
ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);
saveImage();
break;
case R.id.v_bottom_back://点击挡板
ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);
break;
case R.id.bt_size_large://设置画笔尺寸-大号
setPenSize(WhiteBoardVariable.PenSize.LARRGE);
break;
case R.id.bt_size_middle://设置画笔尺寸-中号
setPenSize(WhiteBoardVariable.PenSize.MIDDLE);
break;
case R.id.bt_size_mini://设置画笔尺寸-小号
setPenSize(WhiteBoardVariable.PenSize.MINI);
break;
case R.id.bt_color_green://设置颜色-绿色
setColor(WhiteBoardVariable.Color.GREEN);
break;
case R.id.bt_color_purple://设置颜色-紫色
setColor(WhiteBoardVariable.Color.PURPLE);
break;
case R.id.bt_color_pink://设置颜色-粉色
setColor(WhiteBoardVariable.Color.PINK);
break;
case R.id.bt_color_orange://设置颜色-橙色
setColor(WhiteBoardVariable.Color.ORANGE);
break;
case R.id.bt_color_black://设置颜色-黑色
setColor(WhiteBoardVariable.Color.BLACK);
break;
case R.id.bt_text_underline://设置文字样式-下划线
setTextStyle(WhiteBoardVariable.TextStyle.CHANGE_UNDERLINE);
break;
case R.id.bt_text_italics://设置文字样式-斜体
setTextStyle(WhiteBoardVariable.TextStyle.CHANGE_ITALICS);
break;
case R.id.bt_text_bold://设置文字样式-粗体
setTextStyle(WhiteBoardVariable.TextStyle.CHANGE_BOLD);
break;
case R.id.bt_eraser_large://设置橡皮擦尺寸-大号
setEraserSize(WhiteBoardVariable.EraserSize.LARRGE);
break;
case R.id.bt_eraser_middle://设置橡皮擦尺寸-中号
setEraserSize(WhiteBoardVariable.EraserSize.MIDDLE);
break;
case R.id.bt_eraser_mini://设置橡皮擦尺寸-小号
setEraserSize(WhiteBoardVariable.EraserSize.MINI);
break;
case R.id.iv_white_board_undo://撤销
ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);
if (OperationUtils.getInstance().DISABLE) {
undo();
}
break;
case R.id.iv_white_board_redo://重做
ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);
if (OperationUtils.getInstance().DISABLE) {
redo();
}
break;
case R.id.ll_white_board_pre:
case R.id.iv_white_board_pre://上一页
ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);
prePage();
break;
case R.id.ll_white_board_next:
case R.id.iv_white_board_next://下一页
ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);
nextPage();
break;
case R.id.iv_white_board_add://新建白板
ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);
newPage();
break;
case R.id.iv_white_board_disable://禁止/解禁按钮
ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);
if (OperationUtils.getInstance().DISABLE) {
OperationUtils.getInstance().DISABLE = false;
mIvWhiteBoardDisable.setImageResource(R.drawable.white_board_undisable_selector);
mRlBottom.setVisibility(View.GONE);
} else {
OperationUtils.getInstance().DISABLE = true;
mIvWhiteBoardDisable.setImageResource(R.drawable.white_board_disable_selector);
mRlBottom.setVisibility(View.VISIBLE);
}
break;
}
}
/**
* 设置画笔尺寸
*/
private void setPenSize(int size) {
OperationUtils.getInstance().mCurrentPenSize = size;
changePenBack();
mDbView.setPenSize();
}
/**
* 切换画笔尺寸按按钮背景
*/
private void changePenBack() {
if (OperationUtils.getInstance().mCurrentPenSize == WhiteBoardVariable.PenSize.LARRGE) {
mBtSizeLarge.drawCircleAndRing(WhiteBoardVariable.PenSize.LARRGE, OperationUtils.getInstance().mCurrentColor);
mBtSizeMiddle.drawCircle(WhiteBoardVariable.PenSize.MIDDLE);
mBtSizeMini.drawCircle(WhiteBoardVariable.PenSize.MINI);
} else if (OperationUtils.getInstance().mCurrentPenSize == WhiteBoardVariable.PenSize.MIDDLE) {
mBtSizeLarge.drawCircle(WhiteBoardVariable.PenSize.LARRGE);
mBtSizeMiddle.drawCircleAndRing(WhiteBoardVariable.PenSize.MIDDLE, OperationUtils.getInstance().mCurrentColor);
mBtSizeMini.drawCircle(WhiteBoardVariable.PenSize.MINI);
} else if (OperationUtils.getInstance().mCurrentPenSize == WhiteBoardVariable.PenSize.MINI) {
mBtSizeLarge.drawCircle(WhiteBoardVariable.PenSize.LARRGE);
mBtSizeMiddle.drawCircle(WhiteBoardVariable.PenSize.MIDDLE);
mBtSizeMini.drawCircleAndRing(WhiteBoardVariable.PenSize.MINI, OperationUtils.getInstance().mCurrentColor);
}
}
/**
* 设置颜色
*/
private void setColor(int color) {
OperationUtils.getInstance().mCurrentColor = color;
changeColorBack();
setPenSize(OperationUtils.getInstance().mCurrentPenSize);
mDbView.setPenColor();
mDtView.setTextColor();
}
/**
* 切换颜色控制按钮背景
*/
private void changeColorBack() {
if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.BLACK) {
mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_black_selector);
} else if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.ORANGE) {
mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_orange_selector);
} else if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.PINK) {
mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_pink_selector);
} else if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.PURPLE) {
mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_purple_selector);
} else if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.GREEN) {
mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_green_selector);
}
}
/**
* 设置文字风格
*/
private void setTextStyle(int textStyle) {
mDtView.setTextStyle(textStyle);
changeTextBack();
}
/**
* 切换文字相关按钮背景
*/
private void changeTextBack() {
int size = OperationUtils.getInstance().getSavePoints().size();
if (size < 1) {
return;
}
DrawPoint dp = OperationUtils.getInstance().getSavePoints().get(size - 1);
if (dp.getType() != OperationUtils.DRAW_TEXT) {
return;
}
if (dp.getDrawText().getIsUnderline()) {
mBtTextUnderline.setBackgroundResource(R.drawable.white_board_text_underline_selected_selector);
} else {
mBtTextUnderline.setBackgroundResource(R.drawable.white_board_text_underline_selector);
}
if (dp.getDrawText().getIsItalics()) {
mBtTextItalics.setBackgroundResource(R.drawable.white_board_text_italics_selected_selector);
} else {
mBtTextItalics.setBackgroundResource(R.drawable.white_board_text_italics_selector);
}
if (dp.getDrawText().getIsBold()) {
mBtTextBold.setBackgroundResource(R.drawable.white_board_text_bold_selected_selector);
} else {
mBtTextBold.setBackgroundResource(R.drawable.white_board_text_bold_selector);
}
}
/**
* 设置橡皮擦尺寸
*/
private void setEraserSize(int size) {
OperationUtils.getInstance().mCurrentEraserSize = size;
changeEraserBack();
mDbView.setEraserSize();
}
/**
* 切换橡皮擦尺寸按钮背景
*/
private void changeEraserBack() {
if (OperationUtils.getInstance().mCurrentEraserSize == WhiteBoardVariable.EraserSize.LARRGE) {
mBtEraserLarge.drawCircleAndRing(WhiteBoardVariable.EraserSize.LARRGE, WhiteBoardVariable.Color.BLACK);
mBtEraserMiddle.drawCircle(WhiteBoardVariable.EraserSize.MIDDLE, WhiteBoardVariable.Color.BLACK);
mBtEraserMini.drawCircle(WhiteBoardVariable.EraserSize.MINI, WhiteBoardVariable.Color.BLACK);
} else if (OperationUtils.getInstance().mCurrentEraserSize == WhiteBoardVariable.EraserSize.MIDDLE) {
mBtEraserLarge.drawCircle(WhiteBoardVariable.EraserSize.LARRGE, WhiteBoardVariable.Color.BLACK);
mBtEraserMiddle.drawCircleAndRing(WhiteBoardVariable.EraserSize.MIDDLE, WhiteBoardVariable.Color.BLACK);
mBtEraserMini.drawCircle(WhiteBoardVariable.EraserSize.MINI, WhiteBoardVariable.Color.BLACK);
} else if (OperationUtils.getInstance().mCurrentEraserSize == WhiteBoardVariable.EraserSize.MINI) {
mBtEraserLarge.drawCircle(WhiteBoardVariable.EraserSize.LARRGE, WhiteBoardVariable.Color.BLACK);
mBtEraserMiddle.drawCircle(WhiteBoardVariable.EraserSize.MIDDLE, WhiteBoardVariable.Color.BLACK);
mBtEraserMini.drawCircleAndRing(WhiteBoardVariable.EraserSize.MINI, WhiteBoardVariable.Color.BLACK);
}
}
/**
* 新建白板
*/
private void newPage() {
OperationUtils.getInstance().newPage();
showPoints();
}
/**
* 上一页
*/
private void prePage() {
if (OperationUtils.getInstance().mCurrentIndex > 0) {
OperationUtils.getInstance().mCurrentIndex--;
showPoints();
}
}
/**
* 下一页
*/
private void nextPage() {
if (OperationUtils.getInstance().mCurrentIndex + 1 < OperationUtils.getInstance().getDrawPointSize()) {
OperationUtils.getInstance().mCurrentIndex++;
showPoints();
}
}
/**
* 重新显示白板
*/
private void showPoints() {
mDbView.showPoints();
mDtView.showPoints();
mTvWhiteBoardPage.setText("" + (OperationUtils.getInstance().mCurrentIndex + 1) + "/" + OperationUtils.getInstance().getDrawPointSize());
showPage();
showUndoRedo();
}
/**
* 显示上下页是否可点击
*/
private void showPage() {
if (OperationUtils.getInstance().mCurrentIndex + 1 == OperationUtils.getInstance().getDrawPointSize()) {
mIvWhiteBoardNext.setImageResource(R.drawable.white_board_next_page_click);
} else {
mIvWhiteBoardNext.setImageResource(R.drawable.white_board_next_page_selector);
}
if (OperationUtils.getInstance().mCurrentIndex == 0) {
mIvWhiteBoardPre.setImageResource(R.drawable.white_board_pre_page_click);
} else {
mIvWhiteBoardPre.setImageResource(R.drawable.white_board_pre_page_selector);
}
}
/**
* 撤销
*/
private void undo() {
int size = OperationUtils.getInstance().getSavePoints().size();
if (size == 0) {
return;
} else {
OperationUtils.getInstance().getDeletePoints().add(OperationUtils.getInstance().getSavePoints().get(size - 1));
OperationUtils.getInstance().getSavePoints().remove(size - 1);
size = OperationUtils.getInstance().getDeletePoints().size();
if (OperationUtils.getInstance().getDeletePoints().get(size - 1).getType() == OperationUtils.DRAW_PEN) {
mDbView.undo();
} else if (OperationUtils.getInstance().getDeletePoints().get(size - 1).getType() == OperationUtils.DRAW_TEXT) {
mDtView.undo();
}
showUndoRedo();
}
}
/**
* 重做
*/
private void redo() {
int size = OperationUtils.getInstance().getDeletePoints().size();
if (size == 0) {
return;
} else {
OperationUtils.getInstance().getSavePoints().add(OperationUtils.getInstance().getDeletePoints().get(size - 1));
OperationUtils.getInstance().getDeletePoints().remove(size - 1);
size = OperationUtils.getInstance().getSavePoints().size();
if (OperationUtils.getInstance().getSavePoints().get(size - 1).getType() == OperationUtils.DRAW_PEN) {
mDbView.redo();
} else if (OperationUtils.getInstance().getSavePoints().get(size - 1).getType() == OperationUtils.DRAW_TEXT) {
mDtView.redo();
}
showUndoRedo();
}
}
@Override
protected int getLayoutId() {
return R.layout.activity_white_board;
}
/**
* 文字编辑之后
*/
private void afterEdit(boolean isSave) {
mIvWhiteBoardBack.setVisibility(View.VISIBLE);
mIvWhiteBoardExport.setVisibility(View.VISIBLE);
mIvWhiteBoardSave.setVisibility(View.VISIBLE);
mRlBottom.setVisibility(View.VISIBLE);
mIvWhiteBoardDisable.setVisibility(View.VISIBLE);
// mLayoutParams = (RelativeLayout.LayoutParams) mRlContent.getLayoutParams();
// mLayoutParams.setMargins(OperationUtils.dip2px(24), 0, OperationUtils.dip2px(24), OperationUtils.dip2px(24));
// mRlContent.setLayoutParams(mLayoutParams);
mIvWhiteBoardQuit.setVisibility(View.GONE);
mIvWhiteBoardConfirm.setVisibility(View.GONE);
mDbView.showPoints();
mDtView.afterEdit(isSave);
}
/**
* 白板工具栏点击切换操作
*/
private void ToolsOperation(int currentOperation) {
setPenOperation(currentOperation);
setColorOperation(currentOperation);
setTextOperation(currentOperation);
setEraserOperation(currentOperation);
showOutSideView();
}
/**
* 显示挡板
*/
private void showOutSideView() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (OperationUtils.getInstance().mCurrentOPerationPen == WhiteBoardVariable.Operation.PEN_EXPAND
|| OperationUtils.getInstance().mCurrentOPerationColor == WhiteBoardVariable.Operation.COLOR_EXPAND
|| OperationUtils.getInstance().mCurrentOPerationText == WhiteBoardVariable.Operation.TEXT_EXPAND
|| OperationUtils.getInstance().mCurrentOPerationEraser == WhiteBoardVariable.Operation.ERASER_EXPAND) {
mVBottomBack.setVisibility(View.VISIBLE);
} else {
mVBottomBack.setVisibility(View.GONE);
}
}
}, 100);
}
/**
* 白板工具栏点击切换操作-画笔
*/
private void setPenOperation(int currentOperation) {
switch (currentOperation) {
case WhiteBoardVariable.Operation.PEN_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationPen) {
case WhiteBoardVariable.Operation.PEN_NORMAL:
OperationUtils.getInstance().mCurrentDrawType = OperationUtils.DRAW_PEN;
mDbView.setPaint(null);
mFabMenuSize.setAddButtonBackground(R.drawable.white_board_pen_selected_selector);
OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_CLICK;
break;
case WhiteBoardVariable.Operation.PEN_CLICK:
mFabMenuSize.expand();
changePenBack();
OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_EXPAND;
break;
case WhiteBoardVariable.Operation.PEN_EXPAND:
mFabMenuSize.collapse();
OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_CLICK;
break;
}
break;
case WhiteBoardVariable.Operation.TEXT_CLICK:
case WhiteBoardVariable.Operation.ERASER_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationPen) {
case WhiteBoardVariable.Operation.PEN_NORMAL:
break;
case WhiteBoardVariable.Operation.PEN_CLICK:
mFabMenuSize.clearDraw();
mFabMenuSize.setAddButtonBackground(R.drawable.white_board_pen_selector);
OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_NORMAL;
break;
case WhiteBoardVariable.Operation.PEN_EXPAND:
mFabMenuSize.collapse();
mFabMenuSize.clearDraw();
mFabMenuSize.setAddButtonBackground(R.drawable.white_board_pen_selector);
OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_NORMAL;
break;
}
break;
case WhiteBoardVariable.Operation.COLOR_CLICK:
case WhiteBoardVariable.Operation.OUTSIDE_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationPen) {
case WhiteBoardVariable.Operation.PEN_NORMAL:
break;
case WhiteBoardVariable.Operation.PEN_CLICK:
break;
case WhiteBoardVariable.Operation.PEN_EXPAND:
mFabMenuSize.collapse();
OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_CLICK;
break;
}
break;
}
}
/**
* 白板工具栏点击切换操作-颜色
*/
private void setColorOperation(int currentOperation) {
switch (currentOperation) {
case WhiteBoardVariable.Operation.PEN_CLICK:
case WhiteBoardVariable.Operation.TEXT_CLICK:
case WhiteBoardVariable.Operation.ERASER_CLICK:
case WhiteBoardVariable.Operation.OUTSIDE_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationColor) {
case WhiteBoardVariable.Operation.COLOR_NORMAL:
break;
case WhiteBoardVariable.Operation.COLOR_EXPAND:
mFabMenuColor.collapse();
OperationUtils.getInstance().mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_NORMAL;
break;
}
break;
case WhiteBoardVariable.Operation.COLOR_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationColor) {
case WhiteBoardVariable.Operation.COLOR_NORMAL:
mFabMenuColor.expand();
OperationUtils.getInstance().mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_EXPAND;
break;
case WhiteBoardVariable.Operation.COLOR_EXPAND:
mFabMenuColor.collapse();
OperationUtils.getInstance().mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_NORMAL;
break;
}
break;
}
}
/**
* 白板工具栏点击切换操作-文字
*/
private void setTextOperation(int currentOperation) {
switch (currentOperation) {
case WhiteBoardVariable.Operation.TEXT_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationText) {
case WhiteBoardVariable.Operation.TEXT_NORMAL:
OperationUtils.getInstance().mCurrentDrawType = OperationUtils.DRAW_TEXT;
mFabMenuText.setAddButtonBackground(R.drawable.white_board_text_selected_selector);
OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_CLICK;
break;
case WhiteBoardVariable.Operation.TEXT_CLICK:
int size = OperationUtils.getInstance().getSavePoints().size();
if (size > 0) {
DrawPoint dp = OperationUtils.getInstance().getSavePoints().get(size - 1);
if (dp.getType() == OperationUtils.DRAW_TEXT && dp.getDrawText().getStatus() == DrawTextView.TEXT_DETAIL) {
changeTextBack();
mFabMenuText.expand();
OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_EXPAND;
}
}
break;
case WhiteBoardVariable.Operation.TEXT_EXPAND:
mFabMenuText.collapse();
OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_CLICK;
break;
}
break;
case WhiteBoardVariable.Operation.PEN_CLICK:
case WhiteBoardVariable.Operation.ERASER_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationText) {
case WhiteBoardVariable.Operation.TEXT_NORMAL:
break;
case WhiteBoardVariable.Operation.TEXT_CLICK:
mFabMenuText.clearDraw();
mFabMenuText.setAddButtonBackground(R.drawable.white_board_text_selector);
OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_NORMAL;
break;
case WhiteBoardVariable.Operation.TEXT_EXPAND:
mFabMenuText.collapse();
mFabMenuText.clearDraw();
mFabMenuText.setAddButtonBackground(R.drawable.white_board_text_selector);
OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_NORMAL;
break;
}
break;
case WhiteBoardVariable.Operation.COLOR_CLICK:
case WhiteBoardVariable.Operation.OUTSIDE_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationText) {
case WhiteBoardVariable.Operation.TEXT_NORMAL:
break;
case WhiteBoardVariable.Operation.TEXT_CLICK:
break;
case WhiteBoardVariable.Operation.TEXT_EXPAND:
mFabMenuText.collapse();
OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_CLICK;
break;
}
break;
}
}
/**
* 白板工具栏点击切换操作-橡皮擦
*/
private void setEraserOperation(int currentOperation) {
switch (currentOperation) {
case WhiteBoardVariable.Operation.ERASER_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationEraser) {
case WhiteBoardVariable.Operation.ERASER_NORMAL:
OperationUtils.getInstance().mCurrentDrawType = OperationUtils.DRAW_ERASER;
mDbView.changeEraser();
mFabMenuEraser.setAddButtonBackground(R.drawable.white_board_eraser_selected_selector);
OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_CLICK;
break;
case WhiteBoardVariable.Operation.ERASER_CLICK:
mFabMenuEraser.expand();
changeEraserBack();
OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_EXPAND;
break;
case WhiteBoardVariable.Operation.ERASER_EXPAND:
mFabMenuEraser.collapse();
OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_CLICK;
break;
}
break;
case WhiteBoardVariable.Operation.TEXT_CLICK:
case WhiteBoardVariable.Operation.PEN_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationEraser) {
case WhiteBoardVariable.Operation.ERASER_NORMAL:
break;
case WhiteBoardVariable.Operation.ERASER_CLICK:
mFabMenuEraser.clearDraw();
mFabMenuEraser.setAddButtonBackground(R.drawable.white_board_eraser_selector);
OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_NORMAL;
break;
case WhiteBoardVariable.Operation.ERASER_EXPAND:
mFabMenuEraser.collapse();
mFabMenuEraser.clearDraw();
mFabMenuEraser.setAddButtonBackground(R.drawable.white_board_eraser_selector);
OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_NORMAL;
break;
}
break;
case WhiteBoardVariable.Operation.COLOR_CLICK:
case WhiteBoardVariable.Operation.OUTSIDE_CLICK:
switch (OperationUtils.getInstance().mCurrentOPerationEraser) {
case WhiteBoardVariable.Operation.ERASER_NORMAL:
break;
case WhiteBoardVariable.Operation.ERASER_CLICK:
break;
case WhiteBoardVariable.Operation.ERASER_EXPAND:
mFabMenuEraser.collapse();
OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_CLICK;
break;
}
break;
}
}
/**
* 保存当前白板为图片
*/
public void saveImage() {
String fileName = StoreUtil.getPhotoSavePath();
Log.e("gpy", fileName);
File file = new File(fileName);
try {
File directory = file.getParentFile();
if (!directory.exists() && !directory.mkdirs()) {
showMessage(getString(R.string.white_board_export_fail));
return;
}
file.createNewFile();
FileOutputStream out = new FileOutputStream(file);
mFlView.setDrawingCacheEnabled(true);
mFlView.buildDrawingCache();
Bitmap bitmap = mFlView.getDrawingCache();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
mFlView.destroyDrawingCache();
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
sendBroadcast(intent);//这个广播的目的就是更新图库
showMessage(getString(R.string.white_board_export_tip) + fileName);
} catch (Exception e) {
showMessage(getString(R.string.white_board_export_fail));
e.printStackTrace();
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@ReceiveEvents(name = Events.WHITE_BOARD_TEXT_EDIT)
private void textEdit() {//文字编辑
mIvWhiteBoardBack.setVisibility(View.GONE);
mIvWhiteBoardExport.setVisibility(View.GONE);
mIvWhiteBoardSave.setVisibility(View.GONE);
mRlBottom.setVisibility(View.GONE);
mIvWhiteBoardDisable.setVisibility(View.GONE);
// mLayoutParams = (RelativeLayout.LayoutParams) mRlContent.getLayoutParams();
// mLayoutParams.setMargins(OperationUtils.dip2px(24), 0, OperationUtils.dip2px(24), 0);
// mRlContent.setLayoutParams(mLayoutParams);
mIvWhiteBoardQuit.setVisibility(View.VISIBLE);
mIvWhiteBoardConfirm.setVisibility(View.VISIBLE);
}
@ReceiveEvents(name = Events.WHITE_BOARD_UNDO_REDO)
private void showUndoRedo() {//是否显示撤销、重装按钮
if (OperationUtils.getInstance().getSavePoints().isEmpty()) {
mIvWhiteBoardUndo.setVisibility(View.INVISIBLE);
mIvWhiteBoardExport.setVisibility(View.INVISIBLE);
mIvWhiteBoardSave.setVisibility(View.INVISIBLE);
} else {
mIvWhiteBoardUndo.setVisibility(View.VISIBLE);
mIvWhiteBoardExport.setVisibility(View.VISIBLE);
mIvWhiteBoardSave.setVisibility(View.VISIBLE);
}
if (OperationUtils.getInstance().getDeletePoints().isEmpty()) {
mIvWhiteBoardRedo.setVisibility(View.INVISIBLE);
} else {
mIvWhiteBoardRedo.setVisibility(View.VISIBLE);
}
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/view/base/BaseActivity.java
================================================
package com.example.gpy.whiteboard.view.base;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.widget.Toast;
import com.github.guanpy.library.EventBus;
import butterknife.ButterKnife;
/**
* Created by gpy on 2016/2/17.
*/
public abstract class BaseActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(this.getLayoutId());
ButterKnife.inject(this);
this.afterCreate(savedInstanceState);
}
protected abstract int getLayoutId();
protected abstract void afterCreate(Bundle savedInstanceState);
protected void showMessage(CharSequence msg) {
Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
}
@Override
protected void onResume() {
super.onResume();
EventBus.registerAnnotatedReceiver(this);
}
@Override
protected void onPause() {
super.onPause();
EventBus.unregisterAnnotatedReceiver(this);
}
public void navi2Page(final Class> page) {
this.navi2Page(page, false);
}
public void navi2Page(final Class> page, final boolean shut) {
this.navi2Page(page, null, shut);
}
public void navi2Page(final Class> page, final Bundle data, final boolean shut) {
final Intent intent = new Intent(this, page);
if (null != data) {
intent.putExtras(data);
}
this.startActivity(intent);
if (shut) {
this.finish();
}
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/AddFloatingActionButton.java
================================================
package com.example.gpy.whiteboard.view.widget.floatingactionmenu;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.Shape;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.util.AttributeSet;
import com.example.gpy.whiteboard.R;
public class AddFloatingActionButton extends FloatingActionButton {
int mPlusColor;
public AddFloatingActionButton(Context context) {
this(context, null);
}
public AddFloatingActionButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AddFloatingActionButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
void init(Context context, AttributeSet attributeSet) {
TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.AddFloatingActionButton, 0, 0);
mPlusColor = attr.getColor(R.styleable.AddFloatingActionButton_fab_plusIconColor, getColor(android.R.color.white));
attr.recycle();
super.init(context, attributeSet);
}
/**
* @return the current Color of plus icon.
*/
public int getPlusColor() {
return mPlusColor;
}
public void setPlusColorResId(@ColorRes int plusColor) {
setPlusColor(getColor(plusColor));
}
public void setPlusColor(int color) {
if (mPlusColor != color) {
mPlusColor = color;
updateBackground();
}
}
@Override
public void setIcon(@DrawableRes int icon) {
throw new UnsupportedOperationException("Use FloatingActionButton if you want to use custom icon");
}
@Override
Drawable getIconDrawable() {
final float iconSize = getDimension(R.dimen.fab_icon_size);
final float iconHalfSize = iconSize / 2f;
final float plusSize = getDimension(R.dimen.fab_plus_icon_size);
final float plusHalfStroke = getDimension(R.dimen.fab_plus_icon_stroke) / 2f;
final float plusOffset = (iconSize - plusSize) / 2f;
final Shape shape = new Shape() {
@Override
public void draw(Canvas canvas, Paint paint) {
canvas.drawRect(plusOffset, iconHalfSize - plusHalfStroke, iconSize - plusOffset, iconHalfSize + plusHalfStroke, paint);
canvas.drawRect(iconHalfSize - plusHalfStroke, plusOffset, iconHalfSize + plusHalfStroke, iconSize - plusOffset, paint);
}
};
ShapeDrawable drawable = new ShapeDrawable(shape);
final Paint paint = drawable.getPaint();
paint.setColor(mPlusColor);
paint.setStyle(Style.FILL);
paint.setAntiAlias(true);
return drawable;
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/FloatingActionButton.java
================================================
package com.example.gpy.whiteboard.view.widget.floatingactionmenu;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.ShapeDrawable.ShaderFactory;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.support.annotation.ColorRes;
import android.support.annotation.DimenRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.widget.TextView;
import com.example.gpy.whiteboard.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class FloatingActionButton extends FloatingImageButton {
public static final int SIZE_NORMAL = 0;
public static final int SIZE_MINI = 1;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ SIZE_NORMAL, SIZE_MINI })
public @interface FAB_SIZE {
}
int mColorNormal;
int mColorPressed;
int mColorDisabled;
String mTitle;
@DrawableRes
private int mIcon;
private Drawable mIconDrawable;
private int mSize;
private float mCircleSize;
private float mShadowRadius;
private float mShadowOffset;
private int mDrawableSize;
boolean mStrokeVisible;
public FloatingActionButton(Context context) {
this(context, null);
}
public FloatingActionButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public FloatingActionButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
void init(Context context, AttributeSet attributeSet) {
TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionButton, 0, 0);
mColorNormal = attr.getColor(R.styleable.FloatingActionButton_fab_colorNormal, getColor(android.R.color.holo_blue_dark));
mColorPressed = attr.getColor(R.styleable.FloatingActionButton_fab_colorPressed, getColor(android.R.color.holo_blue_light));
mColorDisabled = attr.getColor(R.styleable.FloatingActionButton_fab_colorDisabled, getColor(android.R.color.darker_gray));
mSize = attr.getInt(R.styleable.FloatingActionButton_fab_size, SIZE_NORMAL);
mIcon = attr.getResourceId(R.styleable.FloatingActionButton_fab_icon, 0);
mTitle = attr.getString(R.styleable.FloatingActionButton_fab_title);
mStrokeVisible = attr.getBoolean(R.styleable.FloatingActionButton_fab_stroke_visible, true);
attr.recycle();
updateCircleSize();
mShadowRadius = getDimension(R.dimen.fab_shadow_radius);
mShadowOffset = getDimension(R.dimen.fab_shadow_offset);
updateDrawableSize();
updateBackground();
}
private void updateDrawableSize() {
mDrawableSize = (int) (mCircleSize + 2 * mShadowRadius);
}
private void updateCircleSize() {
mCircleSize = getDimension(mSize == SIZE_NORMAL ? R.dimen.fab_size_normal : R.dimen.fab_size_mini);
}
public void setSize(@FAB_SIZE int size) {
if (size != SIZE_MINI && size != SIZE_NORMAL) {
throw new IllegalArgumentException("Use @FAB_SIZE constants only!");
}
if (mSize != size) {
mSize = size;
updateCircleSize();
updateDrawableSize();
updateBackground();
}
}
@FAB_SIZE
public int getSize() {
return mSize;
}
public void setIcon(@DrawableRes int icon) {
if (mIcon != icon) {
mIcon = icon;
mIconDrawable = null;
updateBackground();
}
}
public void setIconDrawable(@NonNull Drawable iconDrawable) {
if (mIconDrawable != iconDrawable) {
mIcon = 0;
mIconDrawable = iconDrawable;
updateBackground();
}
}
/**
* @return the current Color for normal state.
*/
public int getColorNormal() {
return mColorNormal;
}
public void setColorNormalResId(@ColorRes int colorNormal) {
setColorNormal(getColor(colorNormal));
}
public void setColorNormal(int color) {
if (mColorNormal != color) {
mColorNormal = color;
updateBackground();
}
}
/**
* @return the current color for pressed state.
*/
public int getColorPressed() {
return mColorPressed;
}
public void setColorPressedResId(@ColorRes int colorPressed) {
setColorPressed(getColor(colorPressed));
}
public void setColorPressed(int color) {
if (mColorPressed != color) {
mColorPressed = color;
updateBackground();
}
}
/**
* @return the current color for disabled state.
*/
public int getColorDisabled() {
return mColorDisabled;
}
public void setColorDisabledResId(@ColorRes int colorDisabled) {
setColorDisabled(getColor(colorDisabled));
}
public void setColorDisabled(int color) {
if (mColorDisabled != color) {
mColorDisabled = color;
updateBackground();
}
}
public void setStrokeVisible(boolean visible) {
if (mStrokeVisible != visible) {
mStrokeVisible = visible;
updateBackground();
}
}
public boolean isStrokeVisible() {
return mStrokeVisible;
}
int getColor(@ColorRes int id) {
return getResources().getColor(id);
}
float getDimension(@DimenRes int id) {
return getResources().getDimension(id);
}
public void setTitle(String title) {
mTitle = title;
TextView label = getLabelView();
if (label != null) {
label.setText(title);
}
}
TextView getLabelView() {
return (TextView) getTag(R.id.fab_label);
}
public String getTitle() {
return mTitle;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(mDrawableSize, mDrawableSize);
}
void updateBackground() {
final float strokeWidth = getDimension(R.dimen.fab_stroke_width);
final float halfStrokeWidth = strokeWidth / 2f;
LayerDrawable layerDrawable = new LayerDrawable(
new Drawable[] {
getResources().getDrawable(mSize == SIZE_NORMAL ? R.drawable.fab_bg_normal : R.drawable.fab_bg_mini),
createFillDrawable(strokeWidth),
createOuterStrokeDrawable(strokeWidth),
getIconDrawable()
});
int iconOffset = (int) (mCircleSize - getDimension(R.dimen.fab_icon_size)) / 2;
int circleInsetHorizontal = (int) (mShadowRadius);
int circleInsetTop = (int) (mShadowRadius - mShadowOffset);
int circleInsetBottom = (int) (mShadowRadius + mShadowOffset);
layerDrawable.setLayerInset(1,
circleInsetHorizontal,
circleInsetTop,
circleInsetHorizontal,
circleInsetBottom);
layerDrawable.setLayerInset(2,
(int) (circleInsetHorizontal - halfStrokeWidth),
(int) (circleInsetTop - halfStrokeWidth),
(int) (circleInsetHorizontal - halfStrokeWidth),
(int) (circleInsetBottom - halfStrokeWidth));
layerDrawable.setLayerInset(3,
circleInsetHorizontal + iconOffset,
circleInsetTop + iconOffset,
circleInsetHorizontal + iconOffset,
circleInsetBottom + iconOffset);
setBackgroundCompat(layerDrawable);
}
Drawable getIconDrawable() {
if (mIconDrawable != null) {
return mIconDrawable;
} else if (mIcon != 0) {
return getResources().getDrawable(mIcon);
} else {
return new ColorDrawable(Color.TRANSPARENT);
}
}
private StateListDrawable createFillDrawable(float strokeWidth) {
StateListDrawable drawable = new StateListDrawable();
drawable.addState(new int[] { -android.R.attr.state_enabled }, createCircleDrawable(mColorDisabled, strokeWidth));
drawable.addState(new int[] { android.R.attr.state_pressed }, createCircleDrawable(mColorPressed, strokeWidth));
drawable.addState(new int[] { }, createCircleDrawable(mColorNormal, strokeWidth));
return drawable;
}
private Drawable createCircleDrawable(int color, float strokeWidth) {
int alpha = Color.alpha(color);
int opaqueColor = opaque(color);
ShapeDrawable fillDrawable = new ShapeDrawable(new OvalShape());
final Paint paint = fillDrawable.getPaint();
paint.setAntiAlias(true);
paint.setColor(opaqueColor);
Drawable[] layers = {
fillDrawable,
createInnerStrokesDrawable(opaqueColor, strokeWidth)
};
LayerDrawable drawable = alpha == 255 || !mStrokeVisible
? new LayerDrawable(layers)
: new TranslucentLayerDrawable(alpha, layers);
int halfStrokeWidth = (int) (strokeWidth / 2f);
drawable.setLayerInset(1, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth);
return drawable;
}
private static class TranslucentLayerDrawable extends LayerDrawable {
private final int mAlpha;
public TranslucentLayerDrawable(int alpha, Drawable... layers) {
super(layers);
mAlpha = alpha;
}
@Override
public void draw(Canvas canvas) {
Rect bounds = getBounds();
canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, mAlpha, Canvas.ALL_SAVE_FLAG);
super.draw(canvas);
canvas.restore();
}
}
private Drawable createOuterStrokeDrawable(float strokeWidth) {
ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());
final Paint paint = shapeDrawable.getPaint();
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(Style.STROKE);
paint.setColor(Color.BLACK);
paint.setAlpha(opacityToAlpha(0.02f));
return shapeDrawable;
}
private int opacityToAlpha(float opacity) {
return (int) (255f * opacity);
}
private int darkenColor(int argb) {
return adjustColorBrightness(argb, 0.9f);
}
private int lightenColor(int argb) {
return adjustColorBrightness(argb, 1.1f);
}
private int adjustColorBrightness(int argb, float factor) {
float[] hsv = new float[3];
Color.colorToHSV(argb, hsv);
hsv[2] = Math.min(hsv[2] * factor, 1f);
return Color.HSVToColor(Color.alpha(argb), hsv);
}
private int halfTransparent(int argb) {
return Color.argb(
Color.alpha(argb) / 2,
Color.red(argb),
Color.green(argb),
Color.blue(argb)
);
}
private int opaque(int argb) {
return Color.rgb(
Color.red(argb),
Color.green(argb),
Color.blue(argb)
);
}
private Drawable createInnerStrokesDrawable(final int color, float strokeWidth) {
if (!mStrokeVisible) {
return new ColorDrawable(Color.TRANSPARENT);
}
ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());
final int bottomStrokeColor = darkenColor(color);
final int bottomStrokeColorHalfTransparent = halfTransparent(bottomStrokeColor);
final int topStrokeColor = lightenColor(color);
final int topStrokeColorHalfTransparent = halfTransparent(topStrokeColor);
final Paint paint = shapeDrawable.getPaint();
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(Style.STROKE);
shapeDrawable.setShaderFactory(new ShaderFactory() {
@Override
public Shader resize(int width, int height) {
return new LinearGradient(width / 2, 0, width / 2, height,
new int[] { topStrokeColor, topStrokeColorHalfTransparent, color, bottomStrokeColorHalfTransparent, bottomStrokeColor },
new float[] { 0f, 0.2f, 0.5f, 0.8f, 1f },
TileMode.CLAMP
);
}
});
return shapeDrawable;
}
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
private void setBackgroundCompat(Drawable drawable) {
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
setBackground(drawable);
} else {
setBackgroundDrawable(drawable);
}
}
@Override
public void setVisibility(int visibility) {
TextView label = getLabelView();
if (label != null) {
label.setVisibility(visibility);
}
super.setVisibility(visibility);
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/FloatingActionsMenu.java
================================================
package com.example.gpy.whiteboard.view.widget.floatingactionmenu;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.gpy.whiteboard.R;
import com.github.guanpy.wblib.utils.AppContextUtil;
import com.github.guanpy.wblib.utils.WhiteBoardVariable;
public class FloatingActionsMenu extends ViewGroup {
public static final int STYLE_DEFAULT = 0;
public static final int STYLE_CUSTOM = 1;
public static final int EXPAND_UP = 0;
public static final int EXPAND_DOWN = 1;
public static final int EXPAND_LEFT = 2;
public static final int EXPAND_RIGHT = 3;
public static final int LABELS_ON_LEFT_SIDE = 0;
public static final int LABELS_ON_RIGHT_SIDE = 1;
private static final int ANIMATION_DURATION = 300;
private static final float COLLAPSED_PLUS_ROTATION = 0f;
private static final float EXPANDED_PLUS_ROTATION = 90f + 45f;
private Drawable mAddButtonBackground;
private float mAddButtonWidth;
private float mAddButtonHeight;
private int mAddButtonStyle;
private int mAddButtonPlusColor;
private int mAddButtonColorNormal;
private int mAddButtonColorPressed;
private int mAddButtonSize;
private boolean mAddButtonStrokeVisible;
private int mExpandDirection;
private int mButtonSpacing;
private int mLabelsMargin;
private int mLabelsVerticalOffset;
private boolean mExpanded;
private AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
private AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);
// private AddFloatingActionButton mAddButton;
private FloatingImageButton mAddButton;
private RotatingDrawable mRotatingDrawable;
private int mMaxButtonWidth;
private int mMaxButtonHeight;
private int mLabelsStyle;
private int mLabelsPosition;
private int mButtonsCount;
private TouchDelegateGroup mTouchDelegateGroup;
private OnFloatingActionsMenuUpdateListener mListener;
private OnFloatingActionsMenuClickListener mClickListener;
public interface OnFloatingActionsMenuUpdateListener {
void onMenuExpanded();
void onMenuCollapsed();
}
public FloatingActionsMenu(Context context) {
this(context, null);
}
public FloatingActionsMenu(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public FloatingActionsMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
public interface OnFloatingActionsMenuClickListener{
void addButtonLister();
}
public void setOnFloatingActionsMenuClickListener(OnFloatingActionsMenuClickListener flLister){
mClickListener = flLister;
}
/**
* 在图片中间画圆环
* @param size 圆的半径
* @param color 圆的颜色
* */
/**控制按钮外圈*/
public void drawRing(int color){
mAddButton.drawRing(WhiteBoardVariable.RingSize.LARRGE, color);
}
/**
* 清除绘画
* */
public void clearDraw(){
mAddButton.clearDraw();
}
/**
* 切换控制按钮背景图
* */
public void setAddButtonBackground(int drawable){
mAddButton.setBackgroundResource(drawable);
}
/**
* dip转px
*/
private int dip2px(float dpValue) {
final float scale = AppContextUtil.getContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
private void init(Context context, AttributeSet attributeSet) {
// mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing) - getResources().getDimension(R.dimen.fab_shadow_radius) - getResources().getDimension(R.dimen.fab_shadow_offset));
mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset);
mTouchDelegateGroup = new TouchDelegateGroup(this);
setTouchDelegate(mTouchDelegateGroup);
TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0);
mButtonSpacing =dip2px(attr.getDimension(R.styleable.FloatingActionsMenu_fab_buttonSpacing, 4));
mAddButtonBackground = attr.getDrawable(R.styleable.FloatingActionsMenu_fab_addButtonBackground);
mAddButtonWidth = attr.getDimension(R.styleable.FloatingActionsMenu_fab_addButtonWidth, 0);
mAddButtonHeight = attr.getDimension(R.styleable.FloatingActionsMenu_fab_addButtonHeight, 0);
mAddButtonStyle = attr.getInt(R.styleable.FloatingActionsMenu_fab_addButtonStyle, STYLE_DEFAULT);
mAddButtonPlusColor = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonPlusIconColor, getColor(android.R.color.white));
mAddButtonColorNormal = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorNormal, getColor(android.R.color.holo_blue_dark));
mAddButtonColorPressed = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorPressed, getColor(android.R.color.holo_blue_light));
mAddButtonSize = attr.getInt(R.styleable.FloatingActionsMenu_fab_addButtonSize, FloatingActionButton.SIZE_NORMAL);
mAddButtonStrokeVisible = attr.getBoolean(R.styleable.FloatingActionsMenu_fab_addButtonStrokeVisible, true);
mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP);
mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0);
mLabelsPosition = attr.getInt(R.styleable.FloatingActionsMenu_fab_labelsPosition, LABELS_ON_LEFT_SIDE);
attr.recycle();
if (mLabelsStyle != 0 && expandsHorizontally()) {
throw new IllegalStateException("Action labels in horizontal expand orientation is not supported.");
}
createAddButton(context);
}
public void setOnFloatingActionsMenuUpdateListener(OnFloatingActionsMenuUpdateListener listener) {
mListener = listener;
}
private boolean expandsHorizontally() {
return mExpandDirection == EXPAND_LEFT || mExpandDirection == EXPAND_RIGHT;
}
private static class RotatingDrawable extends LayerDrawable {
public RotatingDrawable(Drawable drawable) {
super(new Drawable[]{drawable});
}
private float mRotation;
@SuppressWarnings("UnusedDeclaration")
public float getRotation() {
return mRotation;
}
@SuppressWarnings("UnusedDeclaration")
public void setRotation(float rotation) {
mRotation = rotation;
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
canvas.save();
canvas.rotate(mRotation, getBounds().centerX(), getBounds().centerY());
super.draw(canvas);
canvas.restore();
}
}
/**
* 增加菜单的控制按钮
*/
private void createAddButton(Context context) {
if (mAddButtonStyle == STYLE_DEFAULT) {
mAddButton = new AddFloatingActionButton(context) {
@Override
void updateBackground() {
mPlusColor = mAddButtonPlusColor;
mColorNormal = mAddButtonColorNormal;
mColorPressed = mAddButtonColorPressed;
mStrokeVisible = mAddButtonStrokeVisible;
super.updateBackground();
}
@Override
Drawable getIconDrawable() {
final RotatingDrawable rotatingDrawable = new RotatingDrawable(super.getIconDrawable());
mRotatingDrawable = rotatingDrawable;
final OvershootInterpolator interpolator = new OvershootInterpolator();
final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION);
final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION);
collapseAnimator.setInterpolator(interpolator);
expandAnimator.setInterpolator(interpolator);
mExpandAnimation.play(expandAnimator);
mCollapseAnimation.play(collapseAnimator);
return rotatingDrawable;
}
};
mAddButton.setId(R.id.fab_expand_menu_button);
((AddFloatingActionButton) mAddButton).setSize(mAddButtonSize);
} else if (mAddButtonStyle == STYLE_CUSTOM) {
mAddButton = new FloatingImageButton(context);
mAddButton.setId(R.id.fab_expand_menu_button);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(dip2px(mAddButtonWidth), dip2px(mAddButtonHeight));
mAddButton.setLayoutParams(layoutParams);
mAddButton.setBackgroundDrawable(mAddButtonBackground);
mAddButton.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
mAddButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(null!=mClickListener){
mClickListener.addButtonLister();
}else{
toggle();
}
}
});
addView(mAddButton, super.generateDefaultLayoutParams());
}
private int getColor(@ColorRes int id) {
return getResources().getColor(id);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
int width = 0;
int height = 0;
mMaxButtonWidth = 0;
mMaxButtonHeight = 0;
int maxLabelWidth = 0;
for (int i = 0; i < mButtonsCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
switch (mExpandDirection) {
case EXPAND_UP:
case EXPAND_DOWN:
mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());
height += child.getMeasuredHeight();
break;
case EXPAND_LEFT:
case EXPAND_RIGHT:
width += child.getMeasuredWidth();
mMaxButtonHeight = Math.max(mMaxButtonHeight, child.getMeasuredHeight());
break;
}
if (!expandsHorizontally()) {
TextView label = (TextView) child.getTag(R.id.fab_label);
if (label != null) {
maxLabelWidth = Math.max(maxLabelWidth, label.getMeasuredWidth());
}
}
}
if (!expandsHorizontally()) {
width = mMaxButtonWidth + (maxLabelWidth > 0 ? maxLabelWidth + mLabelsMargin : 0);
} else {
height = mMaxButtonHeight;
}
switch (mExpandDirection) {
case EXPAND_UP:
case EXPAND_DOWN:
height += mButtonSpacing * (getChildCount() - 1);
height = adjustForOvershoot(height);
break;
case EXPAND_LEFT:
case EXPAND_RIGHT:
width += mButtonSpacing * (getChildCount() - 1);
width = adjustForOvershoot(width);
break;
}
setMeasuredDimension(width, height);
}
private int adjustForOvershoot(int dimension) {
return dimension * 12 / 10;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
switch (mExpandDirection) {
case EXPAND_UP:
case EXPAND_DOWN:
boolean expandUp = mExpandDirection == EXPAND_UP;
if (changed) {
mTouchDelegateGroup.clearTouchDelegates();
}
int addButtonY = expandUp ? b - t - mAddButton.getMeasuredHeight() : 0;
// Ensure mAddButton is centered on the line where the buttons should be
int buttonsHorizontalCenter = mLabelsPosition == LABELS_ON_LEFT_SIDE
? r - l - mMaxButtonWidth / 2
: mMaxButtonWidth / 2;
int addButtonLeft = buttonsHorizontalCenter - mAddButton.getMeasuredWidth() / 2;
mAddButton.layout(addButtonLeft, addButtonY, addButtonLeft + mAddButton.getMeasuredWidth(), addButtonY + mAddButton.getMeasuredHeight());
int labelsOffset = mMaxButtonWidth / 2 + mLabelsMargin;
int labelsXNearButton = mLabelsPosition == LABELS_ON_LEFT_SIDE
? buttonsHorizontalCenter - labelsOffset
: buttonsHorizontalCenter + labelsOffset;
int nextY = expandUp ?
addButtonY - mButtonSpacing :
addButtonY + mAddButton.getMeasuredHeight() + mButtonSpacing;
for (int i = mButtonsCount - 1; i >= 0; i--) {
final View child = getChildAt(i);
if (child == mAddButton || child.getVisibility() == GONE) continue;
int childX = buttonsHorizontalCenter - child.getMeasuredWidth() / 2;
int childY = expandUp ? nextY - child.getMeasuredHeight() : nextY;
child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight());
float collapsedTranslation = addButtonY - childY;
float expandedTranslation = 0f;
child.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation);
child.setAlpha(mExpanded ? 1f : 0f);
LayoutParams params = (LayoutParams) child.getLayoutParams();
params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);
params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);
params.setAnimationsTarget(child);
View label = (View) child.getTag(R.id.fab_label);
if (label != null) {
int labelXAwayFromButton = mLabelsPosition == LABELS_ON_LEFT_SIDE
? labelsXNearButton - label.getMeasuredWidth()
: labelsXNearButton + label.getMeasuredWidth();
int labelLeft = mLabelsPosition == LABELS_ON_LEFT_SIDE
? labelXAwayFromButton
: labelsXNearButton;
int labelRight = mLabelsPosition == LABELS_ON_LEFT_SIDE
? labelsXNearButton
: labelXAwayFromButton;
int labelTop = childY - mLabelsVerticalOffset + (child.getMeasuredHeight() - label.getMeasuredHeight()) / 2;
label.layout(labelLeft, labelTop, labelRight, labelTop + label.getMeasuredHeight());
Rect touchArea = new Rect(
Math.min(childX, labelLeft),
childY - mButtonSpacing / 2,
Math.max(childX + child.getMeasuredWidth(), labelRight),
childY + child.getMeasuredHeight() + mButtonSpacing / 2);
mTouchDelegateGroup.addTouchDelegate(new TouchDelegate(touchArea, child));
label.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation);
label.setAlpha(mExpanded ? 1f : 0f);
LayoutParams labelParams = (LayoutParams) label.getLayoutParams();
labelParams.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);
labelParams.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);
labelParams.setAnimationsTarget(label);
}
nextY = expandUp ?
childY - mButtonSpacing :
childY + child.getMeasuredHeight() + mButtonSpacing;
}
break;
case EXPAND_LEFT:
case EXPAND_RIGHT:
boolean expandLeft = mExpandDirection == EXPAND_LEFT;
int addButtonX = expandLeft ? r - l - mAddButton.getMeasuredWidth() : 0;
// Ensure mAddButton is centered on the line where the buttons should be
int addButtonTop = b - t - mMaxButtonHeight + (mMaxButtonHeight - mAddButton.getMeasuredHeight()) / 2;
mAddButton.layout(addButtonX, addButtonTop, addButtonX + mAddButton.getMeasuredWidth(), addButtonTop + mAddButton.getMeasuredHeight());
int nextX = expandLeft ?
addButtonX - mButtonSpacing :
addButtonX + mAddButton.getMeasuredWidth() + mButtonSpacing;
for (int i = mButtonsCount - 1; i >= 0; i--) {
final View child = getChildAt(i);
if (child == mAddButton || child.getVisibility() == GONE) continue;
int childX = expandLeft ? nextX - child.getMeasuredWidth() : nextX;
int childY = addButtonTop + (mAddButton.getMeasuredHeight() - child.getMeasuredHeight()) / 2;
child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight());
float collapsedTranslation = addButtonX - childX;
float expandedTranslation = 0f;
child.setTranslationX(mExpanded ? expandedTranslation : collapsedTranslation);
child.setAlpha(mExpanded ? 1f : 0f);
LayoutParams params = (LayoutParams) child.getLayoutParams();
params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);
params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);
params.setAnimationsTarget(child);
nextX = expandLeft ?
childX - mButtonSpacing :
childX + child.getMeasuredWidth() + mButtonSpacing;
}
break;
}
}
@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(super.generateDefaultLayoutParams());
}
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(super.generateLayoutParams(attrs));
}
@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(super.generateLayoutParams(p));
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return super.checkLayoutParams(p);
}
private static Interpolator sExpandInterpolator = new OvershootInterpolator();
private static Interpolator sCollapseInterpolator = new DecelerateInterpolator(3f);
private static Interpolator sAlphaExpandInterpolator = new DecelerateInterpolator();
private class LayoutParams extends ViewGroup.LayoutParams {
private ObjectAnimator mExpandDir = new ObjectAnimator();
private ObjectAnimator mExpandAlpha = new ObjectAnimator();
private ObjectAnimator mCollapseDir = new ObjectAnimator();
private ObjectAnimator mCollapseAlpha = new ObjectAnimator();
private boolean animationsSetToPlay;
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
mExpandDir.setInterpolator(sExpandInterpolator);
mExpandAlpha.setInterpolator(sAlphaExpandInterpolator);
mCollapseDir.setInterpolator(sCollapseInterpolator);
mCollapseAlpha.setInterpolator(sCollapseInterpolator);
mCollapseAlpha.setProperty(View.ALPHA);
mCollapseAlpha.setFloatValues(1f, 0f);
mExpandAlpha.setProperty(View.ALPHA);
mExpandAlpha.setFloatValues(0f, 1f);
switch (mExpandDirection) {
case EXPAND_UP:
case EXPAND_DOWN:
mCollapseDir.setProperty(View.TRANSLATION_Y);
mExpandDir.setProperty(View.TRANSLATION_Y);
break;
case EXPAND_LEFT:
case EXPAND_RIGHT:
mCollapseDir.setProperty(View.TRANSLATION_X);
mExpandDir.setProperty(View.TRANSLATION_X);
break;
}
}
public void setAnimationsTarget(View view) {
mCollapseAlpha.setTarget(view);
mCollapseDir.setTarget(view);
mExpandAlpha.setTarget(view);
mExpandDir.setTarget(view);
// Now that the animations have targets, set them to be played
if (!animationsSetToPlay) {
mCollapseAnimation.play(mCollapseAlpha);
mCollapseAnimation.play(mCollapseDir);
mExpandAnimation.play(mExpandAlpha);
mExpandAnimation.play(mExpandDir);
animationsSetToPlay = true;
}
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
bringChildToFront(mAddButton);
mButtonsCount = getChildCount();
}
public void collapse() {
if (mExpanded) {
mExpanded = false;
mTouchDelegateGroup.setEnabled(false);
mCollapseAnimation.start();
mExpandAnimation.cancel();
if (mListener != null) {
mListener.onMenuCollapsed();
}
}
}
public void toggle() {
if (mExpanded) {
collapse();
} else {
expand();
}
}
public void expand() {
if (!mExpanded) {
mExpanded = true;
mTouchDelegateGroup.setEnabled(true);
mCollapseAnimation.cancel();
mExpandAnimation.start();
if (mListener != null) {
mListener.onMenuExpanded();
}
}
}
public boolean isExpanded() {
return mExpanded;
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState savedState = new SavedState(superState);
savedState.mExpanded = mExpanded;
return savedState;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if (state instanceof SavedState) {
SavedState savedState = (SavedState) state;
mExpanded = savedState.mExpanded;
mTouchDelegateGroup.setEnabled(mExpanded);
if (mRotatingDrawable != null) {
mRotatingDrawable.setRotation(mExpanded ? EXPANDED_PLUS_ROTATION : COLLAPSED_PLUS_ROTATION);
}
super.onRestoreInstanceState(savedState.getSuperState());
} else {
super.onRestoreInstanceState(state);
}
}
public static class SavedState extends BaseSavedState {
public boolean mExpanded;
public SavedState(Parcelable parcel) {
super(parcel);
}
private SavedState(Parcel in) {
super(in);
mExpanded = in.readInt() == 1;
}
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(mExpanded ? 1 : 0);
}
public static final Creator CREATOR = new Creator() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/FloatingImageButton.java
================================================
package com.example.gpy.whiteboard.view.widget.floatingactionmenu;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.ImageButton;
import com.github.guanpy.wblib.utils.OperationUtils;
import com.github.guanpy.wblib.utils.WhiteBoardVariable;
/**
* FloatingActionButton 不具备的功能
*/
public class FloatingImageButton extends ImageButton {
Paint mPaint;
/**不做绘画操作*/
static final int DRAW_NULL = 0;
/**画圆环*/
static final int DRAW_RING = 1;
/**画圆*/
static final int DRAW_CIRCLE= 2;
/**画圆和圆环*/
static final int DRAW_CIRCLE_AND_RING= 3;
int mDrawType ;
public FloatingImageButton(Context context) {
this(context, null);
}
public FloatingImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public FloatingImageButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context){
mPaint = new Paint();
mPaint.setAntiAlias(true); //消除锯齿
}
/**
* 在图片中间画圆环(按钮小圆环)
* @param color 圆的颜色
* */
public void drawMiniRing(int color){
drawRing(WhiteBoardVariable.RingSize.MINI, color);
}
/**
* 在图片中间画圆环(按钮大圆环)
* @param color 圆的颜色
* */
public void drawLargeRing(int color){
drawRing(WhiteBoardVariable.RingSize.LARRGE, color);
}
/**
* 在图片中间画圆环
* @param size 圆的半径
* @param color 圆的颜色
* */
public void drawRing(int size,int color){
mPaint.setColor(color);
mPaint.setStrokeWidth(size);
mPaint.setStyle(Paint.Style.STROKE); //绘制空心圆
mDrawType = DRAW_RING;
postInvalidate();
}
/**
* 在图片中间画圆
* @param size 圆的半径
* */
public void drawCircle(int size){
drawCircle(size, OperationUtils.getInstance().mCurrentColor);
}
/**
* 在图片中间画圆
* @param size 圆的半径
* @param color 圆的颜色
* */
public void drawCircle(int size,int color){
mPaint.setColor(color);
mPaint.setStrokeWidth(size);
mPaint.setStyle(Paint.Style.FILL); //绘制实心圆
mDrawType = DRAW_CIRCLE;
postInvalidate();
}
/**
* 在图片中间画圆和外圈圆环
* @param size 圆的半径
* @param color 圆的颜色
* */
public void drawCircleAndRing(int size,int color){
mPaint.setColor(color);
mPaint.setStrokeWidth(size);
mPaint.setStyle(Paint.Style.FILL); //绘制实心圆
mDrawType = DRAW_CIRCLE_AND_RING;
postInvalidate();
}
/**
* 清除绘画
* */
public void clearDraw(){
mDrawType = DRAW_NULL;
postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int center = getWidth()/2;
if(mDrawType==DRAW_RING){
canvas.drawCircle(center, center, center - mPaint.getStrokeWidth(),mPaint);
}else if(mDrawType==DRAW_CIRCLE){
canvas.drawCircle(center, center, mPaint.getStrokeWidth(),mPaint);
}else if(mDrawType==DRAW_CIRCLE_AND_RING){
canvas.drawCircle(center, center, mPaint.getStrokeWidth(), mPaint);
mPaint.setStrokeWidth(WhiteBoardVariable.RingSize.MINI);
mPaint.setStyle(Paint.Style.STROKE); //绘制空心圆
canvas.drawCircle(center, center, center - WhiteBoardVariable.RingSize.MINI, mPaint);
}
}
}
================================================
FILE: app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/TouchDelegateGroup.java
================================================
package com.example.gpy.whiteboard.view.widget.floatingactionmenu;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.view.MotionEvent;
import android.view.TouchDelegate;
import android.view.View;
import java.util.ArrayList;
public class TouchDelegateGroup extends TouchDelegate {
private static final Rect USELESS_HACKY_RECT = new Rect();
private final ArrayList mTouchDelegates = new ArrayList();
private TouchDelegate mCurrentTouchDelegate;
private boolean mEnabled;
public TouchDelegateGroup(View uselessHackyView) {
super(USELESS_HACKY_RECT, uselessHackyView);
}
public void addTouchDelegate(@NonNull TouchDelegate touchDelegate) {
mTouchDelegates.add(touchDelegate);
}
public void removeTouchDelegate(TouchDelegate touchDelegate) {
mTouchDelegates.remove(touchDelegate);
if (mCurrentTouchDelegate == touchDelegate) {
mCurrentTouchDelegate = null;
}
}
public void clearTouchDelegates() {
mTouchDelegates.clear();
mCurrentTouchDelegate = null;
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
if (!mEnabled) return false;
TouchDelegate delegate = null;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
for (int i = 0; i < mTouchDelegates.size(); i++) {
TouchDelegate touchDelegate = mTouchDelegates.get(i);
if (touchDelegate.onTouchEvent(event)) {
mCurrentTouchDelegate = touchDelegate;
return true;
}
}
break;
case MotionEvent.ACTION_MOVE:
delegate = mCurrentTouchDelegate;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
delegate = mCurrentTouchDelegate;
mCurrentTouchDelegate = null;
break;
}
return delegate != null && delegate.onTouchEvent(event);
}
public void setEnabled(boolean enabled) {
mEnabled = enabled;
}
}
================================================
FILE: app/src/main/res/drawable/bg_white_board.xml
================================================
================================================
FILE: app/src/main/res/drawable/common_cancel_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/common_confirm_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/draw_text_border.xml
================================================
================================================
FILE: app/src/main/res/drawable/fab_label_background.xml
================================================
================================================
FILE: app/src/main/res/drawable/ic_back_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_add_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_color_black_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_color_green_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_color_orange_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_color_pink_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_color_purple_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_disable_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_eraser_selected_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_eraser_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_export_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_next_page_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_pen_selected_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_pen_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_pre_page_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_redo_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_save_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_text_bold_selected_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_text_bold_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_text_italics_selected_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_text_italics_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_text_selected_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_text_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_text_underline_selected_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_text_underline_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_undisable_selector.xml
================================================
================================================
FILE: app/src/main/res/drawable/white_board_undo_selector.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_white_board.xml
================================================
================================================
FILE: app/src/main/res/layout/draw_text.xml
================================================
================================================
FILE: app/src/main/res/layout/wb_item.xml
================================================
================================================
FILE: app/src/main/res/values/attrs.xml
================================================
================================================
FILE: app/src/main/res/values/colors.xml
================================================
#3F51B5
#303F9F
#FF4081
#DDDDDD
#ffffff
#00000000
#7f000000
#cc2c1670
#B2000000
#3e3e3e
#3e3e3e
#ff6a00
#f54983
#663fde
#24a8a3
#f7f7f7
================================================
FILE: app/src/main/res/values/dimens.xml
================================================
16dp
16dp
100sp
80sp
40sp
36sp
30sp
22sp
20sp
18sp
16sp
15sp
14sp
12sp
11sp
10sp
56dp
30dp
24dp
14dp
2dp
3dp
9dp
1dp
16dp
8dp
================================================
FILE: app/src/main/res/values/ids.xml
================================================
================================================
FILE: app/src/main/res/values/strings.xml
================================================
WhiteBoard
白板工具
导出
保存
画笔设置
文本设置
双击修改
橡皮擦
全部清除
导出成功,该页已保存图片至
导出失败,请稍后重试!
保存成功!
继续按返回键退出
本地资源
载入中...
================================================
FILE: app/src/main/res/values/styles.xml
================================================
================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
64dp
================================================
FILE: build.gradle
================================================
buildscript {
repositories {
maven { url 'http://maven.oschina.net/content/groups/public/' }
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0'
}
}
allprojects {
repositories {
maven { url 'http://maven.oschina.net/content/groups/public/' }
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
================================================
FILE: settings.gradle
================================================
include ':app', ':wblib'
================================================
FILE: wblib/.gitignore
================================================
/build
================================================
FILE: wblib/build.gradle
================================================
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.github.guanpy:eventbus:1.0.0'
}
================================================
FILE: wblib/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\software\Java\Android\sdk_studio/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: wblib/src/androidTest/java/com/github/guanpy/wblib/ApplicationTest.java
================================================
package com.github.guanpy.wblib;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* Testing Fundamentals
*/
public class ApplicationTest extends ApplicationTestCase {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: wblib/src/main/AndroidManifest.xml
================================================
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/bean/DrawPenPoint.java
================================================
package com.github.guanpy.wblib.bean;
import android.graphics.Paint;
import android.graphics.Path;
/**
* 绘画存储-画笔路径
* Created 2015-7-13 10:36:1
*
* @author gpy
*/
public class DrawPenPoint {
/**
* 绘画路径
*/
private Path mPath;
/**
* 画笔
*/
private Paint mPaint;
/**
* 获得绘画路径
* Created 2015-7-13 10:36:1
*
* @return 绘画路径
* @author gpy
*/
public Path getPath() {
return mPath;
}
/**
* 设置绘画路径
* Created 2015-7-13 10:36:1
*
* @param path 绘画路径
* @author gpy
*/
public void setPath(Path path) {
this.mPath = path;
}
/**
* 获得画笔
* Created 2015-7-13 10:36:1
*
* @return 画笔
* @author gpy
*/
public Paint getPaint() {
return mPaint;
}
/**
* 设置画笔
* Created 2015-7-13 10:36:1
*
* @param paint 画笔
* @author gpy
*/
public void setPaint(Paint paint) {
this.mPaint = paint;
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/bean/DrawPenStr.java
================================================
package com.github.guanpy.wblib.bean;
import java.util.ArrayList;
import java.util.List;
/**
* 绘画存储-画笔路径(字符串格式,方便储存)
* Created 2015-7-13 10:36:1
*
* @author gpy
*/
public class DrawPenStr {
/**画笔颜色*/
private int mColor;
/**画笔粗细*/
private float mStrokeWidth;
/**是否橡皮擦*/
private boolean mIsEraser;
/**移动到初始点坐标*/
private Point mMoveTo;
/**移动中A集*/
private List mQuadToA;
/**移动中B集*/
private List mQuadToB;
/**移动到终点坐标*/
private Point mLineTo;
/**所在界面高距坐标*/
private Point mOffset;
/**
*获得画笔颜色
*Created 2015-7-21 18:11:48
*@return 画笔颜色
*@author gpy
*/
public int getColor() {
return mColor;
}
/**
*设置画笔颜色
*Created 2015-7-21 18:11:48
*@param color 画笔颜色
*@author gpy
*/
public void setColor(int color) {
this.mColor = color;
}
/**
*获得画笔粗细
*Created 2015-7-21 18:11:48
*@return 画笔粗细
*@author gpy
*/
public float getStrokeWidth() {
return mStrokeWidth;
}
/**
*设置画笔粗细
*Created 2015-7-21 18:11:48
*@param strokeWidth 画笔粗细
*@author gpy
*/
public void setStrokeWidth(float strokeWidth) {
this.mStrokeWidth = strokeWidth;
}
/**
*获得是否橡皮擦
*Created 2015-7-21 18:11:48
*@return 是否橡皮擦
*@author gpy
*/
public boolean getIsEraser() {
return mIsEraser;
}
/**
*设置是否橡皮擦
*Created 2015-7-21 18:11:48
*@param isEraser 是否橡皮擦
*@author gpy
*/
public void setIsEraser(boolean isEraser) {
this.mIsEraser = isEraser;
}
/**
*获得移动到初始点坐标
*Created 2015-7-21 18:11:48
*@return 移动到初始点坐标
*@author gpy
*/
public Point getMoveTo() {
return mMoveTo;
}
/**
*设置移动到初始点坐标
*Created 2015-7-21 18:11:48
*@param moveTo 移动到初始点坐标
*@author gpy
*/
public void setMoveTo(Point moveTo) {
this.mMoveTo = moveTo;
}
/**
*获得移动中A集
*Created 2015-7-21 18:11:48
*@return 移动中A集
*@author gpy
*/
public List getQuadToA() {
if(null==mQuadToA){
mQuadToA = new ArrayList();
}
return mQuadToA;
}
/**
*设置移动中A集
*Created 2015-7-21 18:11:48
*@param quadToA 移动中A集
*@author gpy
*/
public void setQuadToA(List quadToA) {
this.mQuadToA = quadToA;
}
/**
*获得移动中B集
*Created 2015-7-21 18:11:48
*@return 移动中B集
*@author gpy
*/
public List getQuadToB() {
if(null==mQuadToB){
mQuadToB = new ArrayList();
}
return mQuadToB;
}
/**
*设置移动中B集
*Created 2015-7-21 18:11:48
*@param quadToB 移动中B集
*@author gpy
*/
public void setQuadToB(List quadToB) {
this.mQuadToB = quadToB;
}
/**
*获得移动到终点坐标
*Created 2015-7-21 18:11:48
*@return 移动到终点坐标
*@author gpy
*/
public Point getLineTo() {
return mLineTo;
}
/**
*设置移动到终点坐标
*Created 2015-7-21 18:11:48
*@param lineTo 移动到终点坐标
*@author gpy
*/
public void setLineTo(Point lineTo) {
this.mLineTo = lineTo;
}
/**
*获得所在界面高距坐标
*Created 2015-7-21 18:11:48
*@return 所在界面高距坐标
*@author gpy
*/
public Point getOffset() {
return mOffset;
}
/**
*设置所在界面高距坐标
*Created 2015-7-21 18:11:48
*@param offset 所在界面高距坐标
*@author gpy
*/
public void setOffset(Point offset) {
this.mOffset = offset;
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/bean/DrawPoint.java
================================================
package com.github.guanpy.wblib.bean;
import com.github.guanpy.wblib.utils.BeanUtil;
public class DrawPoint {
/**绘画类型*/
private int mType;
/**画笔路径*/
private DrawPenPoint mDrawPen;
/**文字*/
private DrawTextPoint mDrawText;
/**画笔路径(字符形式)*/
private DrawPenStr mDrawPenStr;
/**
*获得画笔路径(字符形式)
*Created 2015-7-21 17:9:7
*@return 画笔路径(字符形式)
*@author gpy
*/
public DrawPenStr getDrawPenStr() {
return mDrawPenStr;
}
/**
*设置画笔路径(字符形式)
*Created 2015-7-21 17:9:7
*@param DrawPenStr 画笔路径(字符形式)
*@author gpy
*/
public void setDrawPenStr(DrawPenStr DrawPenStr) {
this.mDrawPenStr = DrawPenStr;
}
/**
*获得绘画类型
*Created 2015-7-13 10:42:14
*@return 绘画类型
*@author gpy
*/
public int getType() {
return mType;
}
/**
*设置绘画类型
*Created 2015-7-13 10:42:14
*@param type 绘画类型
*@author gpy
*/
public void setType(int type) {
this.mType = type;
}
/**
*获得画笔路径
*Created 2015-7-13 10:42:14
*@return 画笔路径
*@author gpy
*/
public DrawPenPoint getDrawPen() {
return mDrawPen;
}
/**
*设置画笔路径
*Created 2015-7-13 10:42:14
*@param drawPen 画笔路径
*@author gpy
*/
public void setDrawPen(DrawPenPoint drawPen) {
this.mDrawPen = drawPen;
}
/**
*获得文字
*Created 2015-7-13 10:42:14
*@return 文字
*@author gpy
*/
public DrawTextPoint getDrawText() {
return mDrawText;
// if(null==mDrawTexts||mDrawTexts.size()==0){
// return null;
// }
// return mDrawTexts.get(0);
}
/**
*设置文字
*Created 2015-7-13 10:42:14
*@param drawText 文字
*@author gpy
*/
public void setDrawText(DrawTextPoint drawText) {
mDrawText = drawText;
// if(null==drawText){
// return;
// }
// if(null==mDrawTexts){
// mDrawTexts = new ArrayList();
// }
// mDrawTexts.add(0,drawText);
}
/**
* 拷贝数据,防止引用传递
* 只在文字情况下使用
* Created 2015-8-10 16:55:49
*
* @author : gpy
*/
public static DrawPoint copyDrawPoint(DrawPoint drawPoint) {
DrawPoint dp = new DrawPoint();
try {
dp.setType(drawPoint.getType());
DrawTextPoint dtp = new DrawTextPoint();
dtp = (DrawTextPoint) BeanUtil.CopyBeanToBean(drawPoint.getDrawText(), dtp);
dp.setDrawText(dtp);
} catch (Exception e) {
e.printStackTrace();
}
return dp;
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/bean/DrawTextPoint.java
================================================
package com.github.guanpy.wblib.bean;
/**
* 绘画存储-文字
* Created 2015-7-13 10:36:1
*
* @author gpy
*/
public class DrawTextPoint {
/**
* 唯一性标识
*/
private long mId;
/**
* 文字x坐标
*/
private float mX;
/**
* 文字y坐标
*/
private float mY;
/**
* 文字
*/
private String mStr;
/**
* 是否有下划线
*/
private boolean mIsUnderline;
/**
* 是否斜体
*/
private boolean mIsItalics;
/**
* 是否粗体
*/
private boolean mIsBold;
/**
* 文字颜色
*/
private int mColor;
/**
* 当前文字状态
*/
private int mStatus;
/**
* 是否显示
*/
private boolean mIsVisible;
/**
* 获得唯一性标识
* Created 2015-7-13 10:42:14
*
* @return 唯一性标识
* @author gpy
*/
public long getId() {
return mId;
}
/**
* 设置唯一性标识
* Created 2015-7-13 10:42:14
*
* @param id 唯一性标识
* @author gpy
*/
public void setId(long id) {
this.mId = id;
}
/**
* 获得文字x坐标
* Created 2015-7-13 10:34:39
*
* @return 文字x坐标
* @author gpy
*/
public float getX() {
return mX;
}
/**
* 设置文字x坐标
* Created 2015-7-13 10:34:39
*
* @param x 文字x坐标
* @author gpy
*/
public void setX(float x) {
this.mX = x;
}
/**
* 获得文字y坐标
* Created 2015-7-13 10:34:39
*
* @return 文字y坐标
* @author gpy
*/
public float getY() {
return mY;
}
/**
* 设置文字y坐标
* Created 2015-7-13 10:34:39
*
* @param y 文字y坐标
* @author gpy
*/
public void setY(float y) {
this.mY = y;
}
/**
* 获得文字
* Created 2015-7-13 10:34:39
*
* @return 文字
* @author gpy
*/
public String getStr() {
return mStr;
}
/**
* 设置文字
* Created 2015-7-13 10:34:39
*
* @param str 文字
* @author gpy
*/
public void setStr(String str) {
this.mStr = str;
}
/**
* 获得是否有下划线
* Created 2015-7-17 14:57:13
*
* @return 是否有下划线
* @author gpy
*/
public boolean getIsUnderline() {
return mIsUnderline;
}
/**
* 设置是否有下划线
* Created 2015-7-17 14:57:13
*
* @param isUnderline 是否有下划线
* @author gpy
*/
public void setIsUnderline(boolean isUnderline) {
this.mIsUnderline = isUnderline;
}
/**
* 获得是否斜体
* Created 2015-7-17 14:57:13
*
* @return 是否斜体
* @author gpy
*/
public boolean getIsItalics() {
return mIsItalics;
}
/**
* 设置是否斜体
* Created 2015-7-17 14:57:13
*
* @param isItalics 是否斜体
* @author gpy
*/
public void setIsItalics(boolean isItalics) {
this.mIsItalics = isItalics;
}
/**
* 获得是否粗体
* Created 2015-7-17 14:57:13
*
* @return 是否粗体
* @author gpy
*/
public boolean getIsBold() {
return mIsBold;
}
/**
* 设置是否粗体
* Created 2015-7-17 14:57:13
*
* @param isBold 是否粗体
* @author gpy
*/
public void setIsBold(boolean isBold) {
this.mIsBold = isBold;
}
/**
* 获得文字颜色
* Created 2015-7-17 15:40:0
*
* @return 文字颜色
* @author gpy
*/
public int getColor() {
return mColor;
}
/**
* 设置文字颜色
* Created 2015-7-17 15:40:0
*
* @param color 文字颜色
* @author gpy
*/
public void setColor(int color) {
this.mColor = color;
}
/**
* 获得当前文字状态
* Created 2015-7-13 10:34:39
*
* @return 当前文字状态
* @author gpy
*/
public int getStatus() {
return mStatus;
}
/**
* 设置当前文字状态
* Created 2015-7-13 10:34:39
*
* @param status 当前文字状态
* @author gpy
*/
public void setStatus(int status) {
this.mStatus = status;
}
/**
* 获得是否显示
* Created 2015-7-13 11:31:52
*
* @return 是否显示
* @author gpy
*/
public boolean getIsVisible() {
return mIsVisible;
}
/**
* 设置是否显示
* Created 2015-7-13 11:31:52
*
* @param isVisible 是否显示
* @author gpy
*/
public void setIsVisible(boolean isVisible) {
this.mIsVisible = isVisible;
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/bean/Point.java
================================================
package com.github.guanpy.wblib.bean;
/**
* Created by gpy on 2015/8/21.
*/
public class Point {
/**
* X坐标
*/
private float mX;
/**
* Y坐标
*/
private float mY;
public Point(){
}
public Point(float x,float y){
mX = x;
mY = y;
}
/**
* 获得X坐标
* Created 2015-7-21 18:6:32
*
* @return X坐标
* @author gpy
*/
public float getX() {
return mX;
}
/**
* 设置X坐标
* Created 2015-7-21 18:6:32
*
* @param x X坐标
* @author gpy
*/
public void setX(float x) {
this.mX = x;
}
/**
* 获得Y坐标
* Created 2015-7-21 18:6:32
*
* @return Y坐标
* @author gpy
*/
public float getY() {
return mY;
}
/**
* 设置Y坐标
* Created 2015-7-21 18:6:32
*
* @param y Y坐标
* @author gpy
*/
public void setY(float y) {
this.mY = y;
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/bean/WhiteBoardPoint.java
================================================
package com.github.guanpy.wblib.bean;
import java.util.ArrayList;
import java.util.List;
/**
* 画板绘画路径存储
*
* @author gpy
*/
public class WhiteBoardPoint {
/**
* 画板id
*/
private int mId;
/**
* 保存路径
*/
private List mSavePoints;
/**
* 撤销路径
*/
private List mDeletePoints;
/**
* 获得画板id Created 2015-7-12 10:6:10
*
* @return 画板id
* @author gpy
*/
public int getId() {
return mId;
}
/**
* 设置画板id Created 2015-7-12 10:6:10
*
* @param id 画板id
* @author gpy
*/
public void setId(int id) {
this.mId = id;
}
/**
* 获得保存路径 Created 2015-7-12 10:6:10
*
* @return 保存路径
* @author gpy
*/
public List getSavePoints() {
if (mSavePoints == null) {
mSavePoints = new ArrayList();
}
return mSavePoints;
}
/**
* 获得撤销路径 Created 2015-7-12 10:6:10
*
* @return 撤销路径
* @author gpy
*/
public List getDeletePoints() {
if (mDeletePoints == null) {
mDeletePoints = new ArrayList();
}
return mDeletePoints;
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/bean/WhiteBoardPoints.java
================================================
package com.github.guanpy.wblib.bean;
import java.util.List;
/**
* 画板合集
* Created by gpy on 2015/8/21.
*/
public class WhiteBoardPoints {
/**唯一性id*/
private String mId;
/**画板合集*/
private List mWhiteBoardPoints;
/**
*获得唯一性id
*Created 2015-7-21 15:19:17
*@return 唯一性id
*@author gpy
*/
public String getId() {
return mId;
}
/**
*设置唯一性id
*Created 2015-7-21 15:19:17
*@param id 唯一性id
*@author gpy
*/
public void setId(String id) {
this.mId = id;
}
/**
*获得画板合集
*Created 2015-7-21 15:19:17
*@return 画板合集
*@author gpy
*/
public List getWhiteBoardPoints() {
return mWhiteBoardPoints;
}
/**
*设置画板合集
*Created 2015-7-21 15:19:17
*@param whiteBoardPoints 画板合集
*@author gpy
*/
public void setWhiteBoardPoints(List whiteBoardPoints) {
this.mWhiteBoardPoints = whiteBoardPoints;
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/utils/AppContextUtil.java
================================================
package com.github.guanpy.wblib.utils;
import android.content.Context;
/**
* AppContextUtil
*
* @author yangz
* @version 2014/11/4
*/
public class AppContextUtil {
private static Context sContext;
public static void init(Context ctx) {
sContext = ctx.getApplicationContext();
}
public static Context getContext() {
return sContext;
}
public static int getColor(int resId) {
if (sContext == null) {
return -1;
}
return sContext.getResources().getColor(resId);
}
public static String getString(int resId) {
if (sContext == null) {
return null;
}
return sContext.getResources().getString(resId);
}
public static String getString(int resId, Object... objs) {
if (sContext == null) {
return null;
}
return sContext.getResources().getString(resId, objs);
}
/**
* dip转px
*/
public static int dip2px(float dpValue) {
final float scale = AppContextUtil.getContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/utils/BeanUtil.java
================================================
package com.github.guanpy.wblib.utils;
import java.lang.reflect.Method;
/**
* Created by gpy on 2015/8/13.
*/
public class BeanUtil {
/**
* @return Object
*
* 用到反射机制
*
* 此方法将调用obj1的getter方法,将得到的值作为相应的参数传给obj2的setter方法
*
* 注意,obj1的getter方法和obj2方法必须是public类型
* @parameter Object obj1,Object obj2
*/
public static Object CopyBeanToBean(Object obj1, Object obj2) throws Exception {
Method[] method1 = obj1.getClass().getMethods();
Method[] method2 = obj2.getClass().getMethods();
String methodName1;
String methodFix1;
String methodName2;
String methodFix2;
for (int i = 0; i < method1.length; i++) {
methodName1 = method1[i].getName();
methodFix1 = methodName1.substring(3, methodName1.length());
if (methodName1.startsWith("get")) {
for (int j = 0; j < method2.length; j++) {
methodName2 = method2[j].getName();
methodFix2 = methodName2.substring(3, methodName2.length());
if (methodName2.startsWith("set")) {
if (methodFix2.equals(methodFix1)) {
Object[] objs1 = new Object[0];
Object[] objs2 = new Object[1];
objs2[0] = method1[i].invoke(obj1, objs1);//激活obj1的相应的get的方法,objs1数组存放调用该方法的参数,此例中没有参数,该数组的长度为0
method2[j].invoke(obj2, objs2);//激活obj2的相应的set的方法,objs2数组存放调用该方法的参数
continue;
}
}
}
}
}
return obj2;
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/utils/Events.java
================================================
package com.github.guanpy.wblib.utils;
/**
* @author gpy
* @version 2015/8/26.
*/
public class Events {
/**
* 白板相关
*/
public static final String WHITE_BOARD_UNDO_REDO = "undo_redo";
public static final String WHITE_BOARD_TEXT_EDIT = "text_edit";
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/utils/OperationUtils.java
================================================
package com.github.guanpy.wblib.utils;
import com.github.guanpy.wblib.bean.DrawPoint;
import com.github.guanpy.wblib.bean.WhiteBoardPoint;
import com.github.guanpy.wblib.bean.WhiteBoardPoints;
import java.util.ArrayList;
import java.util.List;
/**
* 白板操作公共类
*
* @author gpy
*/
public class OperationUtils {
/**
* 操作类型-画笔
*/
public static final int DRAW_PEN = 1;
/**
* 操作类型-文字
*/
public static final int DRAW_TEXT = 2;
/**
* 操作类型-橡皮擦
*/
public static final int DRAW_ERASER = 3;
/**
* 单例
*/
private static OperationUtils mOperationStack;
/**
* 当前是否禁止白板操作
*/
public boolean DISABLE = true;
/**
* 当前所在白板位置
*/
public int mCurrentIndex = 0;
/**
* 每次操作的唯一标识
*/
private long markId = 0;
/**
* 当前按钮点击
*/
public int mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_CLICK;
/**
* 当前按钮点击
*/
public int mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_NORMAL;
/**
* 当前按钮点击
*/
public int mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_NORMAL;
/**
* 当前按钮点击
*/
public int mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_NORMAL;
/**
* 当前绘画类型:笔或者文字等
*/
public int mCurrentDrawType = DRAW_PEN;
/**
* 当前颜色
*/
public int mCurrentColor = WhiteBoardVariable.Color.ORANGE;
/**
* 当前画笔大小
*/
public int mCurrentPenSize = WhiteBoardVariable.PenSize.MIDDLE;
/**
* 当前橡皮擦大小
*/
public int mCurrentEraserSize = WhiteBoardVariable.EraserSize.MIDDLE;
/**
* 白板操作集
*/
private WhiteBoardPoints mWhiteBoardPoints;
/**
* 单例
*/
public static OperationUtils getInstance() {
if (mOperationStack == null) {
mOperationStack = new OperationUtils();
}
return mOperationStack;
}
/**
* 私有实例化
*/
private OperationUtils() {
}
/**
* 初始化操作集
*/
public void init() {
DISABLE = true;
mCurrentIndex = 0;
markId = 0;
mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_NORMAL;
mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_NORMAL;
mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_NORMAL;
mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_NORMAL;
mCurrentDrawType = DRAW_PEN;
mCurrentColor = WhiteBoardVariable.Color.ORANGE;
mCurrentPenSize = WhiteBoardVariable.PenSize.MIDDLE;
mCurrentEraserSize = WhiteBoardVariable.EraserSize.MIDDLE;
OperationUtils.getInstance().initDrawPointList();
}
/**
* 返回指定白板的操作集
*/
public WhiteBoardPoint getDrawPointList(int i) {
if (null != mWhiteBoardPoints) {
if (mWhiteBoardPoints.getWhiteBoardPoints().size() <= i) {
WhiteBoardPoint drawPointList = new WhiteBoardPoint();
drawPointList.setId(i);
mWhiteBoardPoints.getWhiteBoardPoints().add(drawPointList);
return getDrawPointList(i);
} else {
return mWhiteBoardPoints.getWhiteBoardPoints().get(i);
}
} else {
mWhiteBoardPoints = new WhiteBoardPoints();
mWhiteBoardPoints.setWhiteBoardPoints(new ArrayList());
return getDrawPointList(i);
}
}
/**
* 返回指定白板的操作集大小
*/
public int getDrawPointSize() {
if (mWhiteBoardPoints != null && null != mWhiteBoardPoints.getWhiteBoardPoints()) {
return mWhiteBoardPoints.getWhiteBoardPoints().size();
} else {
getDrawPointList(mCurrentIndex);
return getDrawPointSize();
}
}
/**
* 返回指定白板的操作集
*/
public WhiteBoardPoints getWhiteBoardPoints() {
return mWhiteBoardPoints;
}
/**
* 返回指定白板的操作集
*/
public void setWhiteBoardPoints(WhiteBoardPoints whiteBoardPoints) {
mWhiteBoardPoints = whiteBoardPoints;
}
/**
* 初始化白板
*/
public void initDrawPointList() {
if (mWhiteBoardPoints != null && mWhiteBoardPoints.getWhiteBoardPoints() != null) {
mWhiteBoardPoints.getWhiteBoardPoints().clear();
} else {
getDrawPointList(mCurrentIndex);
}
}
/**
* 新建白板
*/
public void newPage() {
mCurrentIndex = getDrawPointSize();
getDrawPointList(mCurrentIndex);
}
/**
* 获取每次操作的唯一标识
*/
public long getNewMarkId() {
return markId++;
}
/**
* 获取当前白板操作集
*/
public List getSavePoints() {
return OperationUtils.getInstance().getDrawPointList(OperationUtils.getInstance().mCurrentIndex).getSavePoints();
}
/**
* 获取当前白板删除操作集
*/
public List getDeletePoints() {
return OperationUtils.getInstance().getDrawPointList(OperationUtils.getInstance().mCurrentIndex).getDeletePoints();
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/utils/WhiteBoardVariable.java
================================================
package com.github.guanpy.wblib.utils;
import com.github.guanpy.wblib.R;
/**
* 白板属性值汇总
* Created by gpy on 2015/8/17.
*/
public final class WhiteBoardVariable {
/**白板工具栏操作*/
public interface Operation{
/**画笔-正常*/
int PEN_NORMAL = 1 ;
/**画笔-点击*/
int PEN_CLICK = 2 ;
/**画笔-展开*/
int PEN_EXPAND = 3 ;
/**颜色-正常*/
int COLOR_NORMAL = 4 ;
/**颜色-点击*/
int COLOR_CLICK = 5 ;
/**颜色-展开*/
int COLOR_EXPAND = 6 ;
/**文字-正常*/
int TEXT_NORMAL = 7 ;
/**文字-点击*/
int TEXT_CLICK = 8 ;
/**文字-展开*/
int TEXT_EXPAND =9 ;
/**橡皮擦-正常*/
int ERASER_NORMAL = 10 ;
/**橡皮擦-点击*/
int ERASER_CLICK = 11 ;
/**橡皮擦-展开*/
int ERASER_EXPAND = 12 ;
/**点击外围*/
int OUTSIDE_CLICK = 13 ;
}
/**颜色*/
public interface Color{
/**黑色*/
int BLACK = AppContextUtil.getContext().getResources().getColor(R.color.grey_3e);
/**橙色*/
int ORANGE = AppContextUtil.getContext().getResources().getColor(R.color.orange);
/**粉色*/
int PINK = AppContextUtil.getContext().getResources().getColor(R.color.light_red);
/**紫色*/
int PURPLE = AppContextUtil.getContext().getResources().getColor(R.color.primary_purple);
/**绿色*/
int GREEN = AppContextUtil.getContext().getResources().getColor(R.color.green);
}
/**画笔大小*/
public interface PenSize{
/**大*/
int LARRGE = AppContextUtil.dip2px(9);
/**中*/
int MIDDLE = AppContextUtil.dip2px(6);
/**小*/
int MINI = AppContextUtil.dip2px(4);
}
/**橡皮擦大小*/
public interface EraserSize{
/**大*/
int LARRGE = AppContextUtil.dip2px(16);
/**中*/
int MIDDLE = AppContextUtil.dip2px(9);
/**小*/
int MINI = AppContextUtil.dip2px(4);
}
/**圆环宽度大小*/
public interface RingSize{
/**大*/
int LARRGE = AppContextUtil.dip2px(3);
/**小*/
int MINI = AppContextUtil.dip2px(1);
}
/**文字风格*/
public interface TextStyle{
/**设置下划线*/
int CHANGE_UNDERLINE = 1;
/**设置斜体*/
int CHANGE_ITALICS =2;
/**设置粗体*/
int CHANGE_BOLD = 3;
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/widget/DrawPenView.java
================================================
package com.github.guanpy.wblib.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.github.guanpy.library.EventBus;
import com.github.guanpy.wblib.R;
import com.github.guanpy.wblib.bean.DrawPenPoint;
import com.github.guanpy.wblib.bean.DrawPenStr;
import com.github.guanpy.wblib.bean.DrawPoint;
import com.github.guanpy.wblib.bean.Point;
import com.github.guanpy.wblib.utils.Events;
import com.github.guanpy.wblib.utils.OperationUtils;
import java.util.Iterator;
public class DrawPenView extends View {
/**
* 用于画线
*/
private Paint mPaint = null;
/**
* 用于画图
*/
private Paint mBitmapPaint = null;
/**
* 画图路径
*/
private Path mPath = null;
/**
* 步骤存储bean
*/
private DrawPoint mDrawPath = null;
/**
* 绘画存储-画笔路径(字符串格式,方便储存)
*/
private DrawPenStr mDrawPenStr = null;
/**
* 画图
*/
private Bitmap mBottomBitmap = null;
private int mBottomBitmapDrawHeight = 0;
float posX, posY;
private final float TOUCH_TOLERANCE = 4;
private Context mContext;
private Canvas mCanvas = null;
public DrawPenView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
initView(context);
}
public DrawPenView(Context context, AttributeSet attr) {
super(context, attr);
initView(context);
}
public DrawPenView(Context context) {
super(context);
initView(context);
}
private void initView(Context context) {
mContext = context;
initPaint();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
public void init(Paint paint) {
if (paint == null) {
initPaint();
} else {
mPaint = paint;
}
}
/**
* 初始化画笔
*/
private void initPaint() {
mPaint = new Paint();
mPaint.setAntiAlias(true);//是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢
mPaint.setDither(true);// 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
mPaint.setColor(OperationUtils.getInstance().mCurrentColor);//设置绘制的颜色
mPaint.setStyle(Paint.Style.STROKE);//设置画笔的样式
mPaint.setStrokeJoin(Paint.Join.ROUND);//设置绘制时各图形的结合方式,如平滑效果等
mPaint.setStrokeCap(Paint.Cap.ROUND);//当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式 Cap.ROUND,或方形样式Cap.SQUARE
mPaint.setStrokeWidth(2 * OperationUtils.getInstance().mCurrentPenSize);//当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
}
/**
* 初始化画笔
*/
public void changeEraser() {
mPaint.setColor(mContext.getResources().getColor(R.color.transparent));
mPaint.setStrokeWidth(2 * OperationUtils.getInstance().mCurrentEraserSize);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//擦除模式
postInvalidate();
}
/**
* 修改橡皮擦尺寸
*/
public void setEraserSize() {
mPaint.setStrokeWidth(2 * OperationUtils.getInstance().mCurrentEraserSize);//size为圆半径
postInvalidate();
}
/**
* 修改画笔尺寸
*/
public void setPenSize() {
mPaint.setStrokeWidth(2 * OperationUtils.getInstance().mCurrentPenSize);//size为圆半径
postInvalidate();
}
/**
* 修改画笔颜色
*/
public void setPenColor() {
mPaint.setColor(OperationUtils.getInstance().mCurrentColor);
postInvalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if(w>0&&h>0){
mBottomBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBottomBitmap);
}
}
@Override
public void onDraw(Canvas canvas) {
canvas.drawColor(mContext.getResources().getColor(R.color.transparent));
int nCanvasHeight = canvas.getHeight();
int nBitmapHeight = mBottomBitmap.getHeight();
mBottomBitmapDrawHeight = (nCanvasHeight - nBitmapHeight) / 2;
canvas.drawBitmap(mBottomBitmap, 0, mBottomBitmapDrawHeight, mBitmapPaint);
if (mPath != null) {
canvas.drawPath(mPath, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (OperationUtils.getInstance().DISABLE && (OperationUtils.getInstance().mCurrentDrawType == OperationUtils.DRAW_PEN || OperationUtils.getInstance().mCurrentDrawType == OperationUtils.DRAW_ERASER)) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath = new Path();
mDrawPath = new DrawPoint();
mPath.moveTo(x, y);
DrawPenPoint dpp = new DrawPenPoint();
dpp.setPaint(new Paint(mPaint));
dpp.setPath(mPath);
//绘画时存储字符形式
mDrawPenStr = new DrawPenStr();
mDrawPenStr.setColor(mPaint.getColor());
mDrawPenStr.setStrokeWidth(mPaint.getStrokeWidth());
mDrawPenStr.setMoveTo(new Point(x,y));
if(OperationUtils.getInstance().mCurrentDrawType == OperationUtils.DRAW_ERASER){
mDrawPenStr.setIsEraser(true);
}else{
mDrawPenStr.setIsEraser(false);
}
mDrawPath.setDrawPen(dpp);
mDrawPath.setType(OperationUtils.DRAW_PEN);
posX = x;
posY = y;
postInvalidate();
break;
case MotionEvent.ACTION_MOVE:
float dx = Math.abs(x - posX);
float dy = Math.abs(y - posY);
if (dx >= TOUCH_TOLERANCE || dy > TOUCH_TOLERANCE) {
mDrawPenStr.getQuadToA().add(new Point(posX,posY));
mDrawPenStr.getQuadToB().add(new Point((x + posX) / 2,(y + posY) / 2));
mPath.quadTo(posX, posY, (x + posX) / 2, (y + posY) / 2);
posX = x;
posY = y;
}
postInvalidate();
break;
case MotionEvent.ACTION_UP:
mDrawPenStr.setLineTo(new Point(posX, posY));
mPath.lineTo(posX, posY);
mDrawPenStr.setOffset(new Point(0, -mBottomBitmapDrawHeight));
mPath.offset(0, -mBottomBitmapDrawHeight);
mCanvas.drawPath(mPath, mPaint);
mDrawPath.setDrawPenStr(mDrawPenStr);
OperationUtils.getInstance().getSavePoints().add(mDrawPath);
OperationUtils.getInstance().getDeletePoints().clear();
EventBus.postEvent(Events.WHITE_BOARD_UNDO_REDO);
mPath = null;
postInvalidate();
break;
}
}
return true;
}
public void setPaint(Paint paint) {
if (paint == null) {
initPaint();
postInvalidate();
return;
}
mPaint = paint;
postInvalidate();
}
public void clearImage() {
OperationUtils.getInstance().getSavePoints().clear();
OperationUtils.getInstance().getDeletePoints().clear();
int width = mCanvas.getWidth();
int height = mCanvas.getHeight();
mBottomBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas.setBitmap(mBottomBitmap);
postInvalidate();
}
public void undo() {
showPoints();
}
public void redo() {
showPoints();
}
/**
* 重绘一遍路径
*/
public void showPoints() {
int width = mCanvas.getWidth();
int height = mCanvas.getHeight();
mBottomBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas.setBitmap(mBottomBitmap);
Iterator iter = OperationUtils.getInstance().getSavePoints().iterator();
DrawPoint temp;
while (iter.hasNext()) {
temp = iter.next();
if (temp.getType() == OperationUtils.DRAW_PEN) {
mCanvas.drawPath(temp.getDrawPen().getPath(), temp.getDrawPen().getPaint());
}
}
postInvalidate();
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/widget/DrawTextLayout.java
================================================
package com.github.guanpy.wblib.widget;
import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import com.github.guanpy.library.EventBus;
import com.github.guanpy.wblib.R;
import com.github.guanpy.wblib.bean.DrawPoint;
import com.github.guanpy.wblib.bean.DrawTextPoint;
import com.github.guanpy.wblib.utils.Events;
import com.github.guanpy.wblib.utils.OperationUtils;
import com.github.guanpy.wblib.utils.WhiteBoardVariable;
/**
* 白板--文字层
* @author gpy
*/
public class DrawTextLayout extends FrameLayout {
private Context mContext;
private static final int MARGIN_RIGHT = 100;
private static final int MARGIN_BOTTOM = 75;
public DrawTextLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public DrawTextLayout(Context context) {
super(context);
initView(context);
}
private void initView(Context context) {
mContext = context;
}
public void init(Activity activity) {
LayoutParams params = (LayoutParams) this.getLayoutParams();
if (activity.getWindowManager() != null) {
Display display = activity.getWindowManager().getDefaultDisplay();
params.width = display.getWidth();
params.height = display.getWidth();
}
this.setLayoutParams(params);
this.setBackgroundColor(getResources().getColor(R.color.transparent));
showPoints();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (OperationUtils.getInstance().mCurrentDrawType == OperationUtils.DRAW_TEXT&&OperationUtils.getInstance().DISABLE) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
float moveX = event.getX();
float moveY = event.getY();
if(getHeight()-moveY= 0; i--) {
DrawPoint temp = OperationUtils.getInstance().getSavePoints().get(i);
if (temp.getType()== OperationUtils.DRAW_TEXT&&temp.getDrawText().getId() == drawPoint.getDrawText().getId()) {//如果文字组件是之前已存在,则隐藏之前的
OperationUtils.getInstance().getSavePoints().get(i).getDrawText().setIsVisible(false);
break;
}
}
if(!TextUtils.isEmpty(drawPoint.getDrawText().getStr())){
OperationUtils.getInstance().getSavePoints().add(drawPoint);
EventBus.postEvent(Events.WHITE_BOARD_UNDO_REDO);
}
OperationUtils.getInstance().getDeletePoints().clear();
}
/**设置文字风格:下划线、粗体、斜体等*/
public void setTextStyle(int changeStyle){
int size = OperationUtils.getInstance().getSavePoints().size();
if(size==0){
return;
}
DrawPoint dp = OperationUtils.getInstance().getSavePoints().get(size - 1);
if(dp.getType()== OperationUtils.DRAW_TEXT){
DrawPoint temp = DrawPoint.copyDrawPoint(dp);
switch (changeStyle){
case WhiteBoardVariable.TextStyle.CHANGE_UNDERLINE:
temp.getDrawText().setIsUnderline(!temp.getDrawText().getIsUnderline());
break;
case WhiteBoardVariable.TextStyle.CHANGE_ITALICS:
temp.getDrawText().setIsItalics(!temp.getDrawText().getIsItalics());
break;
case WhiteBoardVariable.TextStyle.CHANGE_BOLD:
temp.getDrawText().setIsBold(!temp.getDrawText().getIsBold());
break;
}
updatePoint(temp);
showPoints();
}
}
/**设置文字颜色*/
public void setTextColor(){
int size = OperationUtils.getInstance().getSavePoints().size();
if(size==0){
return;
}
DrawPoint dp = OperationUtils.getInstance().getSavePoints().get(size-1);
if(dp.getType()== OperationUtils.DRAW_TEXT&&dp.getDrawText().getStatus()==DrawTextView.TEXT_DETAIL){
DrawPoint temp = DrawPoint.copyDrawPoint(dp);
temp.getDrawText().setColor(OperationUtils.getInstance().mCurrentColor);
updatePoint(temp);
showPoints();
}
}
/**撤销*/
public void undo(){
DrawPoint drawPoint = OperationUtils.getInstance().getDeletePoints().get(OperationUtils.getInstance().getDeletePoints().size()-1);
int size = OperationUtils.getInstance().getSavePoints().size();
if(size>0) {
for (int i = size - 1; i >= 0; i--) {
DrawPoint temp = OperationUtils.getInstance().getSavePoints().get(i);
if (temp.getType() == OperationUtils.DRAW_TEXT && temp.getDrawText().getId() == drawPoint.getDrawText().getId()) {//如果文字组件是之前已存在,则显示最近的
OperationUtils.getInstance().getSavePoints().get(i).getDrawText().setIsVisible(true);
break;
}
}
}
showPoints();
}
/**重做*/
public void redo(){
int size = OperationUtils.getInstance().getSavePoints().size();
DrawPoint drawPoint = OperationUtils.getInstance().getSavePoints().get(size - 1);
if(size>1) {
for (int i = size - 2; i >= 0; i--) {
DrawPoint temp = OperationUtils.getInstance().getSavePoints().get(i);
if (temp.getType() == OperationUtils.DRAW_TEXT && temp.getDrawText().getId() == drawPoint.getDrawText().getId()) {//如果文字组件是之前已存在,则隐藏之前的
OperationUtils.getInstance().getSavePoints().get(i).getDrawText().setIsVisible(false);
break;
}
}
}
showPoints();
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public int dip2px(float dpValue) {
final float scale = mContext.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
================================================
FILE: wblib/src/main/java/com/github/guanpy/wblib/widget/DrawTextView.java
================================================
package com.github.guanpy.wblib.widget;
import android.app.Activity;
import android.content.Context;
import android.graphics.Paint;
import android.text.Spannable;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.github.guanpy.library.EventBus;
import com.github.guanpy.wblib.R;
import com.github.guanpy.wblib.bean.DrawPoint;
import com.github.guanpy.wblib.utils.Events;
import com.github.guanpy.wblib.utils.OperationUtils;
public class DrawTextView extends RelativeLayout implements
View.OnClickListener {
/**
* 显示状态
*/
public static final int TEXT_VIEW = 1;
/**
* 编辑(文字编辑)状态
*/
public static final int TEXT_EDIT = 2;
/**
* 详情(显示删除、编辑按钮)状态
*/
public static final int TEXT_DETAIL = 3;
/**
* 被删除状态
*/
public static final int TEXT_DELETE = 4;
/** */
private View mVOutside;
/** */
private RelativeLayout mRlContent;
/** */
private RelativeLayout mRlText;
/** */
private EditText mEtTextEdit;
/** */
private TextView mTvTextEdit;
/** */
private Button mBtTextDelete;
/** */
private Button mBtTextEdit;
private Context mContext;
private CallBackListener mCallBackListener;
private DrawPoint mDrawPoint;
private int mWidth;
/**
* 特殊字符所需
*/
private Spannable mSpannable;
public DrawTextView(Context context
, DrawPoint drawPoint,
CallBackListener callBackListener) {
super(context);
init(context, drawPoint, callBackListener);
}
private void init(Context context
, DrawPoint drawPoint,
CallBackListener callBackListener) {
mContext = context;
mDrawPoint = DrawPoint.copyDrawPoint(drawPoint);
mCallBackListener = callBackListener;
Display display = ((Activity) mContext).getWindowManager()
.getDefaultDisplay();
mWidth = display.getWidth();
initUI();
initEvent();
switchView(mDrawPoint.getDrawText().getStatus());
}
/**
* 初始化界面控件
* Created 2015-8-10 16:55:49
*
* @author : gpy
*/
private void initUI() {
LayoutInflater.from(mContext).inflate(R.layout.draw_text, this, true);
mVOutside = (View) findViewById(R.id.v_outside);
mRlContent = (RelativeLayout) findViewById(R.id.rl_content);
mRlText = (RelativeLayout) findViewById(R.id.rl_text);
mEtTextEdit = (EditText) findViewById(R.id.et_text_edit);
mTvTextEdit = (TextView) findViewById(R.id.tv_text_edit);
mBtTextDelete = (Button) findViewById(R.id.bt_text_delete);
mBtTextEdit = (Button) findViewById(R.id.bt_text_edit);
if (null != mDrawPoint) {
setText(mDrawPoint.getDrawText().getStr());
}
setLayoutParams();
}
/**
* 初始化监听
* Created 2015-8-10 16:55:49
*
* @author : gpy
*/
private void initEvent() {
mVOutside.setOnClickListener(this);
mRlText.setOnClickListener(this);
mEtTextEdit.setOnClickListener(this);
mBtTextDelete.setOnClickListener(this);
mBtTextEdit.setOnClickListener(this);
mTvTextEdit.setOnClickListener(this);
mTvTextEdit.setOnTouchListener(new OnTouchListener() {
int lastX, lastY;
@Override
public boolean onTouch(View view, MotionEvent event) {
if (mDrawPoint.getDrawText().getStatus() == TEXT_DETAIL&& OperationUtils.getInstance().DISABLE) {
int ea = event.getAction();
switch (ea) {
case MotionEvent.ACTION_DOWN:
// 获取触摸事件触摸位置的原始X坐标
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
int left = mRlContent.getLeft() + dx;
int top = mRlContent.getTop() + dy;
int right = mRlContent.getRight() + dx;
int bottom = mRlContent.getBottom() + dy;
if (left < 0) {
left = 0;
right = left + mRlContent.getWidth();
}
if (right > getWidth()) {
right = getWidth();
left = right - mRlContent.getWidth();
}
if (top < 0) {
top = 0;
bottom = top + mRlContent.getHeight();
}
if (bottom > getHeight()) {
bottom = getHeight();
top = bottom - mRlContent.getHeight();
}
mDrawPoint.getDrawText().setX(left);
mDrawPoint.getDrawText().setY(top);
Log.e("移动", "-" + left + "," + top);
mRlContent.layout(left, top, right, bottom);
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
if (null != mCallBackListener) {
mCallBackListener.onUpdate(mDrawPoint);
}
break;
}
}
return false;
}
});
}
private void setText(String strText) {
if (!TextUtils.isEmpty(strText)) {
mEtTextEdit.setText(strText);
mTvTextEdit.setText(strText);
}
mEtTextEdit.setTextColor(mDrawPoint.getDrawText().getColor());
mTvTextEdit.setTextColor(mDrawPoint.getDrawText().getColor());
if (mDrawPoint.getDrawText().getIsUnderline()) {
mTvTextEdit.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);
mEtTextEdit.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);
}
if (mDrawPoint.getDrawText().getIsBold()) {
mTvTextEdit.getPaint().setFakeBoldText(true);
mEtTextEdit.getPaint().setFakeBoldText(true);
}
}
private void setLayoutParams() {
LayoutParams layParamsTxt = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
layParamsTxt.leftMargin = (int) mDrawPoint.getDrawText().getX();
layParamsTxt.topMargin = (int) mDrawPoint.getDrawText().getY();
mRlContent.setLayoutParams(layParamsTxt);
}
public void switchView(int currentStatus) {
switch (currentStatus) {
case TEXT_VIEW:
mVOutside.setVisibility(View.GONE);
mEtTextEdit.setVisibility(View.GONE);
mTvTextEdit.setVisibility(View.VISIBLE);
mRlText.setBackgroundResource(
R.color.transparent);
mBtTextEdit.setVisibility(View.GONE);
mBtTextDelete.setVisibility(View.GONE);
break;
case TEXT_EDIT:
mVOutside.setBackgroundResource(R.color.white);
mVOutside.setVisibility(View.VISIBLE);
mEtTextEdit.setVisibility(View.VISIBLE);
mTvTextEdit.setVisibility(View.GONE);
mRlText.setBackgroundResource(R.drawable.draw_text_border);
mBtTextEdit.setVisibility(View.GONE);
mEtTextEdit.setSelection(mEtTextEdit.getText().length());
mBtTextDelete.setVisibility(View.GONE);
EventBus.postEvent(Events.WHITE_BOARD_TEXT_EDIT);
showSoftKeyBoard(mEtTextEdit);
break;
case TEXT_DETAIL:
mVOutside.setBackgroundResource(R.color.transparent);
mVOutside.setVisibility(View.VISIBLE);
mEtTextEdit.setVisibility(View.GONE);
mTvTextEdit.setVisibility(View.VISIBLE);
mRlText.setBackgroundResource(R.drawable.draw_text_border);
mBtTextEdit.setVisibility(View.VISIBLE);
mBtTextDelete.setVisibility(View.VISIBLE);
break;
case TEXT_DELETE:
break;
default:
break;
}
Log.d("gpy","文字宽:"+mRlText.getHeight());
if (mDrawPoint.getDrawText().getStatus() != currentStatus) {
mDrawPoint.getDrawText().setStatus(currentStatus);
if (null != mCallBackListener && currentStatus != TEXT_EDIT) {
mCallBackListener.onUpdate(mDrawPoint);
}
}
}
/**
* 文字编辑完成
*
* @param isSave 是否保存
*/
public void afterEdit(boolean isSave) {
Log.d("gpy", "要保存的文字:" + mEtTextEdit.getText().toString());
if (isSave) {
mDrawPoint.getDrawText().setStr(mEtTextEdit.getText().toString());
}
switchView(TEXT_VIEW);
hideSoftInput();
}
@Override
public void onClick(View v) {
int vId = v.getId();
if (vId == R.id.v_outside) {
if (mDrawPoint.getDrawText().getStatus() == TEXT_DETAIL && OperationUtils.getInstance().DISABLE) {
switchView(TEXT_VIEW);
}
hideSoftInput();
} else if (vId == R.id.tv_text_edit) {
if (OperationUtils.getInstance().DISABLE) {
switchView(TEXT_DETAIL);
}
} else if (vId == R.id.bt_text_delete) {
if (OperationUtils.getInstance().DISABLE) {
switchView(TEXT_DELETE);
}
} else if (vId == R.id.bt_text_edit) {
if (OperationUtils.getInstance().DISABLE) {
switchView(TEXT_EDIT);
}
}
}
public interface CallBackListener {
/**
* 更新文字属性
*/
void onUpdate(DrawPoint drawPoint);
}
private void showSoftKeyBoard(final EditText et) {
et.requestFocus();
et.post(new Runnable() {
@Override
public void run() {
// 弹出输入法
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(et, InputMethodManager.RESULT_UNCHANGED_SHOWN);
}
});
}
private void hideSoftInput() {
if (this == null || mContext == null || mEtTextEdit == null) {
return;
}
// 隐藏输入法
((InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(mEtTextEdit.getWindowToken(), 0);
}
}
================================================
FILE: wblib/src/main/res/drawable/draw_text_border.xml
================================================
================================================
FILE: wblib/src/main/res/layout/draw_text.xml
================================================
================================================
FILE: wblib/src/main/res/values/colors.xml
================================================
#3F51B5
#303F9F
#FF4081
#ffffff
#00000000
#7f000000
#cc2c1670
#B2000000
#3e3e3e
#3e3e3e
#ff6a00
#f54983
#663fde
#24a8a3
#f7f7f7
================================================
FILE: wblib/src/main/res/values/strings.xml
================================================
wblib