- * Created Date: 16/5/31 - *
- * Copyright (C) 2016 GcsSloop. - *
- * GitHub: https://github.com/GcsSloop
- */
-public class SearchView extends View {
-
- // 画笔
- private Paint mPaint;
-
- // View 宽高
- private int mViewWidth;
- private int mViewHeight;
-
- // 这个视图拥有的状态
- public static enum State {
- NONE,
- STARTING,
- SEARCHING,
- ENDING
- }
-
- // 当前的状态(非常重要)
- private State mCurrentState = State.NONE;
-
- // 放大镜与外部圆环
- private Path path_srarch;
- private Path path_circle;
-
- // 测量Path 并截取部分的工具
- private PathMeasure mMeasure;
-
- // 默认的动效周期 2s
- private int defaultDuration = 2000;
-
- // 控制各个过程的动画
- private ValueAnimator mStartingAnimator;
- private ValueAnimator mSearchingAnimator;
- private ValueAnimator mEndingAnimator;
-
- // 动画数值(用于控制动画状态,因为同一时间内只允许有一种状态出现,具体数值处理取决于当前状态)
- private float mAnimatorValue = 0;
-
- // 动效过程监听器
- private ValueAnimator.AnimatorUpdateListener mUpdateListener;
- private Animator.AnimatorListener mAnimatorListener;
-
- // 用于控制动画状态转换
- private Handler mAnimatorHandler;
-
- // 判断是否已经搜索结束
- private boolean isOver = false;
-
- private int count = 0;
-
- public SearchView(Context context) {
- super(context);
-
- initPaint();
-
- initPath();
-
- initListener();
-
- initHandler();
-
- initAnimator();
-
- // 进入开始动画
- mCurrentState = State.STARTING;
- mStartingAnimator.start();
-
- }
-
- private void initPaint() {
- mPaint = new Paint();
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setColor(Color.WHITE);
- mPaint.setStrokeWidth(15);
- mPaint.setStrokeCap(Paint.Cap.ROUND);
- mPaint.setAntiAlias(true);
- }
-
- private void initPath() {
- path_srarch = new Path();
- path_circle = new Path();
-
- mMeasure = new PathMeasure();
-
- // 注意,不要到360度,否则内部会自动优化,测量不能取到需要的数值
- RectF oval1 = new RectF(-50, -50, 50, 50); // 放大镜圆环
- path_srarch.addArc(oval1, 45, 359.9f);
-
- RectF oval2 = new RectF(-100, -100, 100, 100); // 外部圆环
- path_circle.addArc(oval2, 45, -359.9f);
-
- float[] pos = new float[2];
-
- mMeasure.setPath(path_circle, false); // 放大镜把手的位置
- mMeasure.getPosTan(0, pos, null);
-
- path_srarch.lineTo(pos[0], pos[1]); // 放大镜把手
-
- Log.i("TAG", "pos=" + pos[0] + ":" + pos[1]);
- }
-
- private void initListener() {
- mUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mAnimatorValue = (float) animation.getAnimatedValue();
- invalidate();
- }
- };
-
- mAnimatorListener = new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
-
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- // getHandle发消息通知动画状态更新
- mAnimatorHandler.sendEmptyMessage(0);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
-
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
-
- }
- };
- }
-
- private void initHandler() {
- mAnimatorHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (mCurrentState) {
- case STARTING:
- // 从开始动画转换好搜索动画
- isOver = false;
- mCurrentState = State.SEARCHING;
- mStartingAnimator.removeAllListeners();
- mSearchingAnimator.start();
- break;
- case SEARCHING:
- if (!isOver) { // 如果搜索未结束 则继续执行搜索动画
- mSearchingAnimator.start();
- Log.e("Update", "RESTART");
-
- count++;
- if (count>2){ // count大于2则进入结束状态
- isOver = true;
- }
- } else { // 如果搜索已经结束 则进入结束动画
- mCurrentState = State.ENDING;
- mEndingAnimator.start();
- }
- break;
- case ENDING:
- // 从结束动画转变为无状态
- mCurrentState = State.NONE;
- break;
- }
- }
- };
- }
-
- private void initAnimator() {
- mStartingAnimator = ValueAnimator.ofFloat(0, 1).setDuration(defaultDuration);
- mSearchingAnimator = ValueAnimator.ofFloat(0, 1).setDuration(defaultDuration);
- mEndingAnimator = ValueAnimator.ofFloat(1, 0).setDuration(defaultDuration);
-
- mStartingAnimator.addUpdateListener(mUpdateListener);
- mSearchingAnimator.addUpdateListener(mUpdateListener);
- mEndingAnimator.addUpdateListener(mUpdateListener);
-
- mStartingAnimator.addListener(mAnimatorListener);
- mSearchingAnimator.addListener(mAnimatorListener);
- mEndingAnimator.addListener(mAnimatorListener);
- }
-
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mViewWidth = w;
- mViewHeight = h;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- drawSearch(canvas);
- }
-
- private void drawSearch(Canvas canvas) {
-
- mPaint.setColor(Color.WHITE);
-
-
- canvas.translate(mViewWidth / 2, mViewHeight / 2);
-
- canvas.drawColor(Color.parseColor("#0082D7"));
-
- switch (mCurrentState) {
- case NONE:
- canvas.drawPath(path_srarch, mPaint);
- break;
- case STARTING:
- mMeasure.setPath(path_srarch, false);
- Path dst = new Path();
- mMeasure.getSegment(mMeasure.getLength() * mAnimatorValue, mMeasure.getLength(), dst, true);
- canvas.drawPath(dst, mPaint);
- break;
- case SEARCHING:
- mMeasure.setPath(path_circle, false);
- Path dst2 = new Path();
- float stop = mMeasure.getLength() * mAnimatorValue;
- float start = (float) (stop - ((0.5 - Math.abs(mAnimatorValue - 0.5)) * 200f));
- mMeasure.getSegment(start, stop, dst2, true);
- canvas.drawPath(dst2, mPaint);
- break;
- case ENDING:
- mMeasure.setPath(path_srarch, false);
- Path dst3 = new Path();
- mMeasure.getSegment(mMeasure.getLength() * mAnimatorValue, mMeasure.getLength(), dst3, true);
- canvas.drawPath(dst3, mPaint);
- break;
- }
- }
-}
-
-```
diff --git a/CustomView/Advance/Res/Checkmark.png b/CustomView/Advance/Res/Checkmark.png
deleted file mode 100755
index b8b881ce..00000000
Binary files a/CustomView/Advance/Res/Checkmark.png and /dev/null differ
diff --git a/CustomView/Advance/[1]CustomViewProcess.md b/CustomView/Advance/[1]CustomViewProcess.md
deleted file mode 100644
index dcbbc99b..00000000
--- a/CustomView/Advance/[1]CustomViewProcess.md
+++ /dev/null
@@ -1,245 +0,0 @@
-# 自定义View分类与流程
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-经历过前面三篇啰啰嗦嗦的基础篇之后,终于到了进阶篇,正式进入解析自定义View的阶段。
-
-## 前言
-**本章节为什么要叫进阶篇?(虽然讲的是基础内容),因为从本篇开始,将会逐渐揭开自定义View的神秘面纱,每一篇都将比上一篇内容更加深入,利用所学的知识能够制作更加炫酷自定义View,就像在台阶上一样,每一篇都更上一层,~~帮助大家一步步走向人生巅峰,出任CEO,迎娶白富美。~~ 误,是帮助大家更加了解那些炫酷的自定义View是如何制作的,达到举一反三的效果。**
-
-
-## 一.自定义View分类
-
-**我将自定义View分为了两类(sloop个人分类法,非官方):**
-
-### 1.自定义ViewGroup
-
- **自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或各种Layout,包含有子View。**
-
-> 例如:应用底部导航条中的条目,一般都是上面图标(ImageView),下面文字(TextView),那么这两个就可以用自定义ViewGroup组合成为一个Veiw,提供两个属性分别用来设置文字和图片,使用起来会更加方便。
-
-### 2.自定义View
-
- **在没有现成的View,需要自己实现的时候,就使用自定义View,一般继承自View,SurfaceView或其他的View,不包含子View。**
-
-> 例如:制作一个支持自动加载网络图片的ImageView,制作图表等。
-
-**PS: 自定义View在大多数情况下都有替代方案,利用图片或者组合动画来实现,但是使用后者可能会面临内存耗费过大,制作麻烦更诸多问题。**
-
-*******
-
-## 二.几个重要的函数
-
-### 1.构造函数
-
-构造函数是View的入口,可以用于**初始化一些的内容,和获取自定义属性**。
-
-View的构造函数有四种重载分别如下:
-``` java
- public void SloopView(Context context) {}
- public void SloopView(Context context, AttributeSet attrs) {}
- public void SloopView(Context context, AttributeSet attrs, int defStyleAttr) {}
- public void SloopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {}
-```
- 可以看出,关于View构造函数的参数有多有少,先排除几个不常用的,留下常用的再研究。
-
- **有四个参数的构造函数在API21的时候才添加上,暂不考虑。**
-
-有三个参数的构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style,且只有在明确调用的时候才会生效,以系统中的ImageButton为例说明:
-``` java
- public ImageButton(Context context, AttributeSet attrs) {
- //调用了三个参数的构造函数,明确指定第三个参数
- this(context, attrs, com.android.internal.R.attr.imageButtonStyle);
- }
-
- public ImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
- //此处调了四个参数的构造函数,无视即可
- this(context, attrs, defStyleAttr, 0);
- }
-```
-**注意:即使你在View中使用了Style这个属性也不会调用三个参数的构造函数,所调用的依旧是两个参数的构造函数。**
-
-**由于三个参数的构造函数第三个参数一般不用,暂不考虑,第三个参数的具体用法会在以后用到的时候详细介绍。**
-
-排除了两个之后,只剩下一个参数和两个参数的构造函数,他们的详情如下:
-``` java
- //一般在直接New一个View的时候调用。
- public void SloopView(Context context) {}
-
- //一般在layout文件中使用的时候会调用,关于它的所有属性(包括自定义属性)都会包含在attrs中传递进来。
- public void SloopView(Context context, AttributeSet attrs) {}
-```
-**以下方法调用的是一个参数的构造函数:**
-``` java
- //在Avtivity中
- SloopView view = new SloopView(this);
-```
-**以下方法调用的是两个参数的构造函数:**
-``` xml
- //在layout文件中 - 格式为: 包名.View名
- 如果之后返回当前Activity则接着调用
-
-
-## 参考资料:
-[View](http://developer.android.com/reference/android/view/View.html)
-[ViewGroup](http://developer.android.com/reference/android/view/ViewGroup.html)
-[View.MeasureSpec](http://developer.android.com/reference/android/view/View.MeasureSpec.html)
-[onMeasure,MeasureSpec源码 流程 思路详解](http://blog.csdn.net/a396901990/article/details/36475213)
-
-[Android中自定义样式与View的构造函数中的第三个参数defStyle的意义](http://www.cnblogs.com/angeldevil/p/3479431.html)
-[android view构造函数研究](http://blog.csdn.net/z103594643/article/details/6755017)
-[Android View构造方法第三参数使用方法详解](http://blog.csdn.net/mybeta/article/details/39993449)
-
-[Android 自定义View onMeasure方法的实现](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1102/1891.html)
-[Android API指南(二)自定义控件02之 onMeasure](http://wangkuiwu.github.io/2014/06/20/View-OnMeasure/)
-[Android中View的绘制过程 onMeasure方法简述](http://www.cnblogs.com/mengdd/p/3332882.html)
-
-
-
diff --git a/CustomView/Advance/[2]Canvas_BasicGraphics.md b/CustomView/Advance/[2]Canvas_BasicGraphics.md
deleted file mode 100644
index 0eacbedf..00000000
--- a/CustomView/Advance/[2]Canvas_BasicGraphics.md
+++ /dev/null
@@ -1,541 +0,0 @@
-# Canvas之绘制基本形状
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-在上一篇[自定义View分类与流程](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B1%5DCustomViewProcess.md)中我们了解自定义View相关的基本知识,不过,这些东西依旧还是理论,并不能**拿来(zhuang)用(B)**, 这一次我们就了解一些**能(zhaung)用(B)**的东西。
-
-在本篇文章中,我们先了解Canvas的基本用法,最后用一个小示例来结束本次教程。
-
-## 一.Canvas简介
-
-Canvas我们可以称之为画布,能够在上面绘制各种东西,是安卓平台2D图形绘制的基础,非常强大。
-
-**一般来说,比较基础的东西有两大特点:
- 1.可操作性强:由于这些是构成上层的基础,所以可操作性必然十分强大。
- 2.比较难用:各种方法太过基础,想要完美的将这些操作组合起来有一定难度。**
-
-不过不必担心,本系列文章不仅会介绍到Canvas的操作方法,还会简单介绍一些设计思路和技巧。
-
-## 二.Canvas的常用操作速查表
-
-操作类型 | 相关API | 备注
---- | --- | ---
-绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布
-绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧
-绘制图片 | drawBitmap, drawPicture | 绘制位图和图片
-绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字
-绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用到该函数
-顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用
-画布剪裁 | clipPath, clipRect | 设置画布的显示区域
-画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数
-画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、倾斜
-Matrix(矩阵) | getMatrix, setMatrix, concat | 实际画布的位移,缩放等操作的都是图像矩阵Matrix,只不过Matrix比较难以理解和使用,故封装了一些常用的方法。
-
-> PS: Canvas常用方法在上面表格中已经全部列出了,当然还存在一些其他的方法未列出,具体可以参考官方文档 [Canvas](http://developer.android.com/reference/android/graphics/Canvas.html)
-
-******
-
-## 三.Canvas详解
-
-本篇内容主要讲解如何利用Canvas绘制基本图形。
-
-
-### 绘制颜色:
-
-绘制颜色是填充整个画布,常用于绘制底色。
-``` java
- canvas.drawColor(Color.BLUE); //绘制蓝色
-```
-
-
-
-> 关于颜色的更多资料请参考[基础篇_颜色](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView%2FBase%2F%5B3%5DColor.md)
-
-******
-
-### 创建画笔:
-要想绘制内容,首先需要先创建一个画笔,如下:
-``` java
- // 1.创建一个画笔
- private Paint mPaint = new Paint();
-
- // 2.初始化画笔
- private void initPaint() {
- mPaint.setColor(Color.BLACK); //设置画笔颜色
- mPaint.setStyle(Paint.Style.FILL); //设置画笔模式为填充
- mPaint.setStrokeWidth(10f); //设置画笔宽度为10px
- }
-
- // 3.在构造函数中初始化
- public SloopView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initPaint();
- }
-```
-在创建完画笔之后,就可以在Canvas中绘制各种内容了。
-
-******
-
-### 绘制点:
-
-可以绘制一个点,也可以绘制一组点,如下:
-``` java
- canvas.drawPoint(200, 200, mPaint); //在坐标(200,200)位置绘制一个点
- canvas.drawPoints(new float[]{ //绘制一组点,坐标位置由float数组指定
- 500,500,
- 500,600,
- 500,700
- },mPaint);
-```
-关于坐标原点默认在左上角,水平向右为x轴增大方向,竖直向下为y轴增大方向。
-
-> 更多参考这里 [基础篇_坐标系](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView%2FBase%2F%5B1%5DCoordinateSystem.md)
-
-
-
-
-******
-
-### 绘制直线:
-绘制直线需要两个点,初始点和结束点,同样绘制直线也可以绘制一条或者绘制一组:
-``` java
- canvas.drawLine(300,300,500,600,mPaint); // 在坐标(300,300)(500,600)之间绘制一条直线
- canvas.drawLines(new float[]{ // 绘制一组线 每四数字(两个点的坐标)确定一条线
- 100,200,200,200,
- 100,300,200,300
- },mPaint);
-```
-
-
-
-
-******
-
-### 绘制矩形:
-确定确定一个矩形最少需要四个数据,就是**对角线的两个点**的坐标值,这里一般采用**左上角和右下角**的两个点的坐标。
-
-关于绘制矩形,Canvas提供了三种重载方法,第一种就是提供**四个数值(矩形左上角和右下角两个点的坐标)来确定一个矩形**进行绘制。
-其余两种是先将矩形封装为**Rect或RectF**(实际上仍然是用两个坐标点来确定的矩形),然后传递给Canvas绘制,如下:
-
-``` java
- // 第一种
- canvas.drawRect(100,100,800,400,mPaint);
-
- // 第二种
- Rect rect = new Rect(100,100,800,400);
- canvas.drawRect(rect,mPaint);
-
- // 第三种
- RectF rectF = new RectF(100,100,800,400);
- canvas.drawRect(rectF,mPaint);
-```
-以上三种方法所绘制出来的结果是完全一样的。
-
-
-
-看到这里,相信很多观众会产生一个疑问,为什么会有Rect和RectF两种?两者有什么区别吗?
-
-答案当然是存在区别的,**两者最大的区别就是精度不同,Rect是int(整形)的,而RectF是float(单精度浮点型)的**。除了精度不同,两种提供的方法也稍微存在差别,在这里我们暂时无需关注,想了解更多参见官方文档 [Rect](http://developer.android.com/reference/android/graphics/Rect.html) 和 [RectF](http://developer.android.com/reference/android/graphics/RectF.html)
-
-******
-
-### 绘制圆角矩形:
-绘制圆角矩形也提供了两种重载方式,如下:
-``` java
- // 第一种
- RectF rectF = new RectF(100,100,800,400);
- canvas.drawRoundRect(rectF,30,30,mPaint);
-
- // 第二种
- canvas.drawRoundRect(100,100,800,400,30,30,mPaint);
-```
-上面两种方法绘制效果也是一样的,但鉴于第二种方法在API21的时候才添加上,所以我们一般使用的都是第一种。
-
-
-
-下面简单解析一下圆角矩形的几个必要的参数的意思。
-
-很明显可以看出,第二种方法前四个参数和第一种方法的RectF作用是一样的,都是为了确定一个矩形,最后一个参数Paint是画笔,无需多说,**与矩形相比,圆角矩形多出来了两个参数rx 和 ry**,这两个参数是干什么的呢?
-
-稍微分析一下,既然是圆角矩形,他的角肯定是圆弧(圆形的一部分),**我们一般用什么确定一个圆形呢?**
-
-答案是**圆心 和 半径,其中圆心用于确定位置,而半径用于确定大小**。
-
-由于矩形位置已经确定,所以其边角位置也是确定的,那么确定位置的参数就可以省略,只需要用半径就能描述一个圆弧了。
-
-但是,**半径只需要一个参数,但这里怎么会有两个呢?**
-
-好吧,让你发现了,**这里圆角矩形的角实际上不是一个正圆的圆弧,而是椭圆的圆弧,这里的两个参数实际上是椭圆的两个半径**,他们看起来个如下图:
-
-
-
-**红线标注的 rx 与 ry 就是两个半径,也就是相比绘制矩形多出来的那两个参数。**
-
-我们了解到原理后,就可以为所欲为了,通过计算可知我们上次绘制的矩形宽度为700,高度为300,当你让 rx大于350(宽度的一半), ry大于150(高度的一半) 时奇迹就出现了, 你会发现圆角矩形变成了一个椭圆, 他们画出来是这样的 ( 为了方便确认我更改了画笔颜色, 同时绘制出了矩形和圆角矩形 ):
-
-``` java
- // 矩形
- RectF rectF = new RectF(100,100,800,400);
-
- // 绘制背景矩形
- mPaint.setColor(Color.GRAY);
- canvas.drawRect(rectF,mPaint);
-
- // 绘制圆角矩形
- mPaint.setColor(Color.BLUE);
- canvas.drawRoundRect(rectF,700,400,mPaint);
-```
-
-
-
-其中灰色部分是我们所选定的矩形,而里面的圆角矩形则变成了一个椭圆,实际上在rx为宽度的一半,ry为高度的一半时,刚好是一个椭圆,通过上面我们分析的原理推算一下就能得到,而当rx大于宽度的一半,ry大于高度的一半时,实际上是无法计算出圆弧的,所以drawRoundRect对大于该数值的参数进行了限制(修正),凡是大于一半的参数均按照一半来处理。
-
-
-******
-
-### 绘制椭圆:
-相对于绘制圆角矩形,绘制椭圆就简单的多了,因为他只需要一个矩形矩形作为参数:
-
-``` java
- // 第一种
- RectF rectF = new RectF(100,100,800,400);
- canvas.drawOval(rectF,mPaint);
-
- // 第二种
- canvas.drawOval(100,100,800,400,mPaint);
-```
-同样,以上两种方法效果完全一样,但一般使用第一种。
-
-
-
-绘制椭圆实际上就是绘制一个矩形的内切图形,原理如下,就不多说了:
-
-
-
-PS: 如果你传递进来的是一个长宽相等的矩形(即正方形),那么绘制出来的实际上就是一个圆。
-
-******
-### 绘制圆:
-
-绘制圆形也比较简单, 如下:
-
-```
- canvas.drawCircle(500,500,400,mPaint); // 绘制一个圆心坐标在(500,500),半径为400 的圆。
-```
-绘制圆形有四个参数,前两个是圆心坐标,第三个是半径,最后一个是画笔。
-
-
-
-******
-### 绘制圆弧:
-
-绘制圆弧就比较神奇一点了,为了理解这个比较神奇的东西,我们先看一下它需要的几个参数:
-
-``` java
-// 第一种
-public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}
-
-// 第二种
-public void drawArc(float left, float top, float right, float bottom, float startAngle,
- float sweepAngle, boolean useCenter, @NonNull Paint paint) {}
-```
-
-从上面可以看出,相比于绘制椭圆,绘制圆弧还多了三个参数:
-
-``` java
-startAngle // 开始角度
-sweepAngle // 扫过角度
-useCenter // 是否使用中心
-```
-
-通过字面意思我们基本能猜测出来前两个参数(startAngle, sweepAngel)的作用,就是确定角度的起始位置和扫过角度, 不过第三个参数是干嘛的?试一下就知道了,上代码:
-
-```
- RectF rectF = new RectF(100,100,800,400);
- // 绘制背景矩形
- mPaint.setColor(Color.GRAY);
- canvas.drawRect(rectF,mPaint);
-
- // 绘制圆弧
- mPaint.setColor(Color.BLUE);
- canvas.drawArc(rectF,0,90,false,mPaint);
-
- //-------------------------------------
-
- RectF rectF2 = new RectF(100,600,800,900);
- // 绘制背景矩形
- mPaint.setColor(Color.GRAY);
- canvas.drawRect(rectF2,mPaint);
-
- // 绘制圆弧
- mPaint.setColor(Color.BLUE);
- canvas.drawArc(rectF2,0,90,true,mPaint);
-```
-
-上述代码实际上是绘制了一个起始角度为0度,扫过90度的圆弧,两者的区别就是是否使用了中心点,结果如下:
-
-
-
-可以发现使用了中心点之后绘制出来类似于一个扇形,而不使用中心点则是圆弧起始点和结束点之间的连线加上圆弧围成的图形。这样中心点这个参数的作用就很明显了,不必多说想必大家试一下就明白了。 另外可以关于角度可以参考一下这篇文章: [角度与弧度](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView%2FBase%2F%5B2%5DAngleAndRadian.md)
-
-相比于使用椭圆,我们还是使用正圆比较多的,使用正圆展示一下效果:
-
-```
- RectF rectF = new RectF(100,100,800,400);
- // 绘制背景矩形
- mPaint.setColor(Color.GRAY);
- canvas.drawRect(rectF,mPaint);
-
- // 绘制圆弧
- mPaint.setColor(Color.BLUE);
- canvas.drawArc(rectF,0,90,false,mPaint);
-
- //-------------------------------------
-
- RectF rectF2 = new RectF(100,600,800,900);
- // 绘制背景矩形
- mPaint.setColor(Color.GRAY);
- canvas.drawRect(rectF2,mPaint);
-
- // 绘制圆弧
- mPaint.setColor(Color.BLUE);
- canvas.drawArc(rectF2,0,90,true,mPaint);
-```
-
-
-******
-### 简要介绍Paint
-
-看了上面这么多,相信有一部分人会产生一个疑问,如果我想绘制一个圆,只要边不要里面的颜色怎么办?
-
-很简单,绘制的**基本形状由Canvas确定**,但绘制出来的**颜色,具体效果则由Paint确定**。
-
-如果你注意到了的话,在一开始我们设置画笔样式的时候是这样的:
-
-``` java
- mPaint.setStyle(Paint.Style.FILL); //设置画笔模式为填充
-```
-
-为了展示方便,容易看出效果,之前使用的模式一直为填充模式,实际上画笔有三种模式,如下:
-
-``` java
-STROKE //描边
-FILL //填充
-FILL_AND_STROKE //描边加填充
-```
-
-为了区分三者效果我们做如下实验:
-
-```
- Paint paint = new Paint();
- paint.setColor(Color.BLUE);
- paint.setStrokeWidth(40); //为了实验效果明显,特地设置描边宽度非常大
-
- // 描边
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawCircle(200,200,100,paint);
-
- // 填充
- paint.setStyle(Paint.Style.FILL);
- canvas.drawCircle(200,500,100,paint);
-
- // 描边加填充
- paint.setStyle(Paint.Style.FILL_AND_STROKE);
- canvas.drawCircle(200, 800, 100, paint);
-```
-
-
-
-一图胜千言,通过以上实验我们可以比较明显的看出三种模式的区别,如果只需要边缘不需要填充内容的话只需要设置模式为描边(STROKE)即可。
-
-其实关于Paint的内容也是有不少的,这些只是冰山一角,在后续内容中会详细的讲解Paint。
-
-******
-## 小示例
-
-### 简要介绍画布的操作:
-
-> 画布操作详细内容会在下一篇文章中讲解, 不是本文重点,但以下示例中可能会用到,所以此处简要介绍一下。
-
-相关操作 | 简要介绍
-----------|------------------------
-save | 保存当前画布状态
-restore | 回滚到上一次保存的状态
-translate | 相对于当前位置位移
-rotate | 旋转
-
-### 制作一个饼状图
-
-在展示百分比数据的时候经常会用到饼状图,像这样:
-
-
-
-### 简单分析
-
-其实根据我们上面的知识已经能自己制作一个饼状图了。不过制作东西最重要的不是制作结果,而是制作思路。
-相信我贴上代码大家一看就立刻明白了,非常简单的东西。不过嘛,咱们还是想了解一下制作思路:
-
-先分析饼状图的构成,非常明显,饼状图就是一个又一个的扇形构成的,每个扇形都有不同的颜色,对应的有名字,数据和百分比。
-
-经以上信息可以得出饼状图的最基本数据应包括:名字 数据值 百分比 对应的角度 颜色。
-
-
-用户关心的数据 : 名字 数据值 百分比
-需要程序计算的数据: 百分比 对应的角度
-其中颜色这一项可以用户指定也可以用程序指定(我们这里采用程序指定)。
-
-
-### 封装数据:
-``` java
-public class PieData {
- // 用户关心数据
- private String name; // 名字
- private float value; // 数值
- private float percentage; // 百分比
-
- // 非用户关心数据
- private int color = 0; // 颜色
- private float angle = 0; // 角度
-
- public PieData(@NonNull String name, @NonNull float value) {
- this.name = name;
- this.value = value;
- }
-}
-```
-PS: 以上省略了get set方法
-
-### 自定义View:
-先按照自定义View流程梳理一遍(确定各个步骤应该做的事情):
-
-步骤 | 关键字 | 作用
-:---:|-------------- | -----------------------
- 1 | 构造函数 | 初始化(初始化画笔Paint)
- 2 | onMeasure | 测量View的大小(暂时不用关心)
- 3 | onSizeChanged | 确定View大小(记录当前View的宽高)
- 4 | onLayout | 确定子View布局(无子View,不关心)
- 5 | onDraw | 实际绘制内容(绘制饼状图)
- 6 | 提供接口 | 提供接口(提供设置数据的接口)
-
-代码如下:
-
-``` java
-public class PieView extends View {
- // 颜色表
- private int[] mColors = {0xFFCCFF00, 0xFF6495ED, 0xFFE32636, 0xFF800000, 0xFF808000, 0xFFFF8C69, 0xFF808080,
- 0xFFE6B800, 0xFF7CFC00};
- // 饼状图初始绘制角度
- private float mStartAngle = 0;
- // 数据
- private ArrayList
-
-> **PS: 这个饼状图并没有添加百分比等数据,仅作为示例使用。**
-
-## 总结:
-
- 其实自定义View只要按照流程一步步的走,也是比较容易的。不过里面也有不少坑,这些坑还是自己踩过印象比较深,建议大家不要直接copy源码,自己手打体验一下。
-
-## About Me
-### 作者微博: @GcsSloop
-
-
-
-## 参考资料:
-
-[View](http://developer.android.com/reference/android/view/View.html)
-[Canvas](http://developer.android.com/reference/android/graphics/Canvas.html)
-[Android Canvas绘图详解](http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html)
-
-
diff --git a/CustomView/Advance/[3]Canvas_Convert.md b/CustomView/Advance/[3]Canvas_Convert.md
deleted file mode 100644
index 5d47a6a9..00000000
--- a/CustomView/Advance/[3]Canvas_Convert.md
+++ /dev/null
@@ -1,448 +0,0 @@
-# Canvas之画布操作
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-上一篇[Canvas之绘制基本形状](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B2%5DCanvas_BasicGraphics.md)中我们了解了如何使用Canvas绘制基本图形,本次了解一些基本的画布操作。
-
-本来想把画布操作放到后面部分的,但是发现很多图形绘制都离不开画布操作,于是先讲解一下画布的基本操作方法。
-
-## 一.Canvas的常用操作速查表
-
-操作类型 | 相关API | 备注
---- | --- | ---
-绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布
-绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧
-绘制图片 | drawBitmap, drawPicture | 绘制位图和图片
-绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字
-绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用到该函数
-顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用
-画布剪裁 | clipPath, clipRect | 设置画布的显示区域
-画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数
-画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、倾斜
-Matrix(矩阵) | getMatrix, setMatrix, concat | 实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。
-
-******
-## 二.Canvas基本操作
-
-### 1.画布操作
-#### 为什么要有画布操作?
-
-画布操作可以帮助我们用更加容易理解的方式制作图形。
-
-例如: 从坐标原点为起点,绘制一个长度为20dp,与水平线夹角为30度的线段怎么做?
-
-按照我们通常的想法(*被常年训练出来的数学思维*),就是先使用三角函数计算出线段结束点的坐标,然后调用drawLine即可。
-
-然而这是否是被固有思维禁锢了?
-
-假设我们先绘制一个长度为20dp的水平线,然后将这条水平线旋转30度,则最终看起来效果是相同的,而且不用进行三角函数计算,这样是否更加简单了一点呢?
-
-**合理的使用画布操作可以帮助你用更容易理解的方式创作你想要的效果,这也是画布操作存在的原因。**
-
-**PS: 所有的画布操作都只影响后续的绘制,对之前已经绘制过的内容没有影响。**
-
-*****
-#### ⑴位移(translate)
-
- translate是坐标系的移动,可以为图形绘制选择一个合适的坐标系。
- **请注意,位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动**,如下:
-``` java
- // 省略了创建画笔的代码
-
- // 在坐标原点绘制一个黑色圆形
- mPaint.setColor(Color.BLACK);
- canvas.translate(200,200);
- canvas.drawCircle(0,0,100,mPaint);
-
- // 在坐标原点绘制一个蓝色圆形
- mPaint.setColor(Color.BLUE);
- canvas.translate(200,200);
- canvas.drawCircle(0,0,100,mPaint);
-```
-
-
-
-我们首先将坐标系移动一段距离绘制一个圆形,之后再移动一段距离绘制一个圆形,两次移动是可叠加的。
-
-*****
-#### ⑵缩放(scale)
-缩放提供了两个方法,如下:
-``` java
- public void scale (float sx, float sy)
-
- public final void scale (float sx, float sy, float px, float py)
-```
-这两个方法中前两个参数是相同的分别为x轴和y轴的缩放比例。而第二种方法比前一种多了两个参数,用来控制缩放中心位置的。
-
-缩放比例(sx,sy)取值范围详解:
-
-取值范围(n)| 说明
---------- | ------
-[-∞, -1) | 先根据缩放中心放大n倍,再根据中心轴进行翻转
--1 | 根据缩放中心轴进行翻转
-(-1, 0) | 先根据缩放中心缩小到n,再根据中心轴进行翻转
-0 | 不会显示,若sx为0,则宽度为0,不会显示,sy同理
-(0, 1) | 根据缩放中心缩小到n
-1 | 没有变化
-(1, +∞) | 根据缩放中心放大n倍
-
-如果在缩放时稍微注意一下就会发现缩放的中心默认为坐标原点,而缩放中心轴就是坐标轴,如下:
-
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- RectF rect = new RectF(0,-400,400,0); // 矩形区域
-
- mPaint.setColor(Color.BLACK); // 绘制黑色矩形
- canvas.drawRect(rect,mPaint);
-
- canvas.scale(0.5f,0.5f); // 画布缩放
-
- mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
- canvas.drawRect(rect,mPaint);
-```
-(为了更加直观,我添加了一个坐标系,可以比较明显的看出,缩放中心就是坐标原点)
-
-
-
-接下来我们使用第二种方法让缩放中心位置稍微改变一下,如下:
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- RectF rect = new RectF(0,-400,400,0); // 矩形区域
-
- mPaint.setColor(Color.BLACK); // 绘制黑色矩形
- canvas.drawRect(rect,mPaint);
-
- canvas.scale(0.5f,0.5f,200,0); // 画布缩放 <-- 缩放中心向右偏移了200个单位
-
- mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
- canvas.drawRect(rect,mPaint);
-```
-(图中用箭头指示的就是缩放中心。)
-
-
-
-前面两个示例缩放的数值都是正数,按照表格中的说明,**当缩放比例为负数的时候会根据缩放中心轴进行翻转**,下面我们就来实验一下:
-
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- RectF rect = new RectF(0,-400,400,0); // 矩形区域
-
- mPaint.setColor(Color.BLACK); // 绘制黑色矩形
- canvas.drawRect(rect,mPaint);
-
-
- canvas.scale(-0.5f,-0.5f); // 画布缩放
-
- mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
- canvas.drawRect(rect,mPaint);
-```
-
-
-> 为了效果明显,这次我不仅添加了坐标系而且对矩形中几个重要的点进行了标注,具有相同字母标注的点是一一对应的。
-
-由于本次未对缩放中心进行偏移,所有默认的缩放中心就是坐标原点,中心轴就是x轴和y轴。
-
-本次缩放可以看做是先根据缩放中心(坐标原点)缩放到原来的0.5倍,然后分别按照x轴和y轴进行翻转。
-
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- RectF rect = new RectF(0,-400,400,0); // 矩形区域
-
- mPaint.setColor(Color.BLACK); // 绘制黑色矩形
- canvas.drawRect(rect,mPaint);
-
-
- canvas.scale(-0.5f,-0.5f,200,0); // 画布缩放 <-- 缩放中心向右偏移了200个单位
-
- mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
- canvas.drawRect(rect,mPaint);
-```
-
-
-> 添加了这么多的辅助内容,希望大家能够看懂。
-
-本次对缩放中心点y轴坐标进行了偏移,故中心轴也向右偏移了。
-
-
-PS:和位移(translate)一样,缩放也是可以叠加的。
-``` java
- canvas.scale(0.5f,0.5f);
- canvas.scale(0.5f,0.1f);
-```
-调用两次缩放则 x轴实际缩放为0.5x0.5=0.25 y轴实际缩放为0.5x0.1=0.05
-
-下面我们利用这一特性制作一个有趣的图形。
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- RectF rect = new RectF(-400,-400,400,400); // 矩形区域
-
- for (int i=0; i<=20; i++)
- {
- canvas.scale(0.9f,0.9f);
- canvas.drawRect(rect,mPaint);
- }
-```
-
-
-
-*****
-#### ⑶旋转(rotate)
-旋转提供了两种方法:
-``` java
- public void rotate (float degrees)
-
- public final void rotate (float degrees, float px, float py)
-```
-和缩放一样,第二种方法多出来的两个参数依旧是控制旋转中心点的。
-
-默认的旋转中心依旧是坐标原点:
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- RectF rect = new RectF(0,-400,400,0); // 矩形区域
-
- mPaint.setColor(Color.BLACK); // 绘制黑色矩形
- canvas.drawRect(rect,mPaint);
-
- canvas.rotate(180); // 旋转180度 <-- 默认旋转中心为原点
-
- mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
- canvas.drawRect(rect,mPaint);
-```
-
-
-
-改变旋转中心位置:
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- RectF rect = new RectF(0,-400,400,0); // 矩形区域
-
- mPaint.setColor(Color.BLACK); // 绘制黑色矩形
- canvas.drawRect(rect,mPaint);
-
- canvas.rotate(180,200,0); // 旋转180度 <-- 旋转中心向右偏移200个单位
-
- mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
- canvas.drawRect(rect,mPaint);
-```
-
-
-
-好吧,旋转也是可叠加的
-``` java
- canvas.rotate(180);
- canvas.rotate(20);
-```
-调用两次旋转,则实际的旋转角度为180+20=200度。
-
-为了演示这一个效果,我做了一个不明觉厉的东西:
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- canvas.drawCircle(0,0,400,mPaint); // 绘制两个圆形
- canvas.drawCircle(0,0,380,mPaint);
-
- for (int i=0; i<=360; i+=10){ // 绘制圆形之间的连接线
- canvas.drawLine(0,380,0,400,mPaint);
- canvas.rotate(10);
- }
-```
-
-
-*****
-#### ⑷倾斜(skew)
-
-skew这里翻译为倾斜,有的地方也叫错切。
-
-倾斜只提供了一种方法:
-``` java
- public void skew (float sx, float sy)
-```
-参数含义:
-float sx:将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,
-float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值.
-
-示例:
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- RectF rect = new RectF(0,0,200,200); // 矩形区域
-
- mPaint.setColor(Color.BLACK); // 绘制黑色矩形
- canvas.drawRect(rect,mPaint);
-
- canvas.skew(1,0); // 在x轴倾斜45度 <-- tan45 = 1
-
- mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
- canvas.drawRect(rect,mPaint);
-```
-
-
-如你所想,倾斜也是可叠加的,不过请注意,调用次序不同绘制结果也会不同
-``` java
- // 将坐标系原点移动到画布正中心
- canvas.translate(mWidth / 2, mHeight / 2);
-
- RectF rect = new RectF(0,0,200,200); // 矩形区域
-
- mPaint.setColor(Color.BLACK); // 绘制黑色矩形
- canvas.drawRect(rect,mPaint);
-
- canvas.skew(1,0); // 在x轴倾斜45度 <-- tan45 = 1
- canvas.skew(0,1); // 在y轴倾斜45度 <-- tan45 = 1
-
- mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
- canvas.drawRect(rect,mPaint);
-```
-
-
-
-*****
-#### ⑸快照(save)和回滚(restore)
-
-
-Q: 为什存在快照与回滚
-A:画布的操作是不可逆的,而且很多画布操作会影响后续的步骤,例如第一个例子,两个圆形都是在坐标原点绘制的,而因为坐标系的移动绘制出来的实际位置不同。所以会对画布的一些状态进行保存和回滚。
-
-
-与之相关的API:
-
-相关API | 简介
---- | ---
-save | 把当前的画布的状态进行保存,然后放入特定的栈中
-saveLayerXxx | 新建一个图层,并放入特定的栈中
-restore | 把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布
-restoreToCount| 弹出指定位置及其以上所有的状态,并按照指定位置的状态进行恢复
-getSaveCount | 获取栈中内容的数量(即保存次数)
-
-下面对其中的一些概念和方法进行分析:
-
-##### 状态栈:
-其实这个栈我也不知道叫什么名字,暂时叫做状态栈吧,它看起来像下面这样:
-
-
-
-这个栈可以存储画布状态和图层状态。
-
-Q:什么是画布和图层?
-A:实际上我们看到的画布是由多个图层构成的,如下图(图片来自网络):
-
-
-
-实际上我们之前讲解的绘制操作和画布操作都是在默认图层上进行的。
-在通常情况下,使用默认图层就可满足需求,但是如果需要绘制比较复杂的内容,如地图(地图可以有多个地图层叠加而成,比如:政区层,道路层,兴趣点层)等,则分图层绘制比较好一些。
-你可以把这些图层看做是一层一层的玻璃板,你在每层的玻璃板上绘制内容,然后把这些玻璃板叠在一起看就是最终效果。
-
-
-##### SaveFlags
-
-数据类型 | 名称 | 简介
---- | --- | ---
-int | ALL_SAVE_FLAG | 默认,保存全部状态
-int | CLIP_SAVE_FLAG | 保存剪辑区
-int | CLIP_TO_LAYER_SAVE_FLAG | 剪裁区作为图层保存
-int | FULL_COLOR_LAYER_SAVE_FLAG | 保存图层的全部色彩通道
-int | HAS_ALPHA_LAYER_SAVE_FLAG | 保存图层的alpha(不透明度)通道
-int | MATRIX_SAVE_FLAG | 保存Matrix信息(translate, rotate, scale, skew)
-
-##### save
-save 有两种方法:
-``` java
- // 保存全部状态
- public int save ()
-
- // 根据saveFlags参数保存一部分状态
- public int save (int saveFlags)
-```
-可以看到第二种方法比第一种多了一个saveFlags参数,使用这个参数可以只保存一部分状态,更加灵活,这个saveFlags参数具体可参考上面表格中的内容。
-
-每调用一次save方法,都会在栈顶添加一条状态信息,以上面状态栈图片为例,再调用一次save则会在第5次上面载添加一条状态。
-
-#### saveLayerXxx
-saveLayerXxx有比较多的方法:
-``` java
-// 无图层alpha(不透明度)通道
-public int saveLayer (RectF bounds, Paint paint)
-public int saveLayer (RectF bounds, Paint paint, int saveFlags)
-public int saveLayer (float left, float top, float right, float bottom, Paint paint)
-public int saveLayer (float left, float top, float right, float bottom, Paint paint, int saveFlags)
-
-// 有图层alpha(不透明度)通道
-public int saveLayerAlpha (RectF bounds, int alpha)
-public int saveLayerAlpha (RectF bounds, int alpha, int saveFlags)
-public int saveLayerAlpha (float left, float top, float right, float bottom, int alpha)
-public int saveLayerAlpha (float left, float top, float right, float bottom, int alpha, int saveFlags)
-```
-注意:saveLayerXxx方法会让你花费更多的时间去渲染图像(图层多了相互之间叠加会导致计算量成倍增长),使用前请谨慎,如果可能,尽量避免使用。
-
-使用saveLayerXxx方法,也会将图层状态也放入状态栈中,同样使用restore方法进行恢复。
-
-这个暂时不过多讲述,如果以后用到详细讲解。(因为这里面东西也有不少啊QAQ)
-
-##### restore
-状态回滚,就是从栈顶取出一个状态然后根据内容进行恢复。
-
-同样以上面状态栈图片为例,调用一次restore方法则将状态栈中第5次取出,根据里面保存的状态进行状态恢复。
-
-##### restoreToCount
-弹出指定位置以及以上所有状态,并根据指定位置状态进行恢复。
-
-以上面状态栈图片为例,如果调用restoreToCount(2) 则会弹出 2 3 4 5 的状态,并根据第2次保存的状态进行恢复。
-
-##### getSaveCount
-获取保存的次数,即状态栈中保存状态的数量,以上面状态栈图片为例,使用该函数的返回值为5。
-
-不过请注意,该函数的最小返回值为1,即使弹出了所有的状态,返回值依旧为1,代表默认状态。
-
-##### 常用格式
-虽然关于状态的保存和回滚啰嗦了不少,不过大多数情况下只需要记住下面的步骤就可以了:
-``` java
- save(); //保存状态
- ... //具体操作
- restore(); //回滚到之前的状态
-```
-这种方式也是最简单和最容易理解的使用方法。
-
-
-
-******
-## 三.总结
-
-如本文一开始所说,合理的使用画布操作可以帮助你用更容易理解的方式创作你想要的效果。
-
-(,,• ₃ •,,)
-
-PS: 由于本人英文水平有限,某些地方可能存在误解或词语翻译不准确,如果你对此有疑问可以提交Issues进行反馈。
-
-## About Me
-### 作者微博: @GcsSloop
-
-
-
-******
-## 四.参考资料
-
-[Canvas](http://developer.android.com/reference/android/graphics/Canvas.html)
-[canvas变换与操作](http://blog.csdn.net/harvic880925/article/details/39080931)
-[Canvas之translate、scale、rotate、skew方法讲解](http://blog.csdn.net/tianjian4592/article/details/45234419)
-[Canvas的save(),saveLayer()和restore()浅谈](http://www.cnblogs.com/liangstudyhome/p/4143498.html)
-[Graphics->Layers](http://www.programgo.com/article/72302404062/;jsessionid=8E62016408BFFB21D46F9C878A49D8EE)
-[]()
-[]()
-
diff --git a/CustomView/Advance/[4]Canvas_PictureText.md b/CustomView/Advance/[4]Canvas_PictureText.md
deleted file mode 100644
index 401d21a4..00000000
--- a/CustomView/Advance/[4]Canvas_PictureText.md
+++ /dev/null
@@ -1,506 +0,0 @@
-# Canvas之图片文字
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-在上一篇文章[Canvas之画布操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B3%5DCanvas_Convert.md)中我们了解了画布的一些基本操作方法,本次了解一些绘制图片文字相关的内容。如果你对前几篇文章讲述的内容熟练掌握的话,那么恭喜你,本篇结束之后,大部分的自定义View已经难不倒你了,当然了,这并不是终点,接下来还会有更加炫酷的技能。
-
-## 一.Canvas的常用操作速查表
-
-操作类型 | 相关API | 备注
----------|---------|-----------
-绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布
-绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧
-绘制图片 | drawBitmap, drawPicture | 绘制位图和图片
-绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字
-绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用到该函数
-顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用
-画布剪裁 | clipPath, clipRect | 设置画布的显示区域
-画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数
-画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、倾斜
-Matrix(矩阵) | getMatrix, setMatrix, concat | 实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。
-
-******
-# 二.Canvas基本操作详解
-
-## 1.绘制图片
-
-绘制有两种方法,drawPicture(矢量图) 和 drawBitmap(位图),接下来我们一一了解。
-
-### (1)drawPicture
-
-**使用Picture前请关闭硬件加速,以免引起不必要的问题!
使用Picture前请关闭硬件加速,以免引起不必要的问题!
使用Picture前请关闭硬件加速,以免引起不必要的问题!**
-
-**在AndroidMenifest文件中application节点下添上 android:hardwareAccelerated="false"以关闭整个应用的硬件加速。
更多请参考这里:[Android的硬件加速及可能导致的问题](https://github.com/GcsSloop/AndroidNote/issues/7)**
-
-关于drawPicture一开始还是挺让人费解的,不过嘛,我们接下来慢慢研究一下它的用途。
-
-既然是drawPicture就要了解一下什么是Picture。 顾名思义,Picture的意思是图片。
-
-不过嘛,我觉得这么用图片这个名词解释Picture是不合适的,为何这么说?请看其官方文档对[Picture](http://developer.android.com/reference/android/graphics/Picture.html)的解释:
-
-
-A Picture records drawing calls (via the canvas returned by beginRecording) and can then play them back into Canvas (via draw(Canvas) or drawPicture(Picture)).For most content (e.g. text, lines, rectangles), drawing a sequence from a picture can be faster than the equivalent API calls, since the picture performs its playback without incurring any method-call overhead.
-
-
-好吧,我知道很多人对这段鸟语是看不懂的,至于为什么要放在这里,仅仅是为了显得更加专业(偷笑)。
-
-**下面我就对这段不明觉厉的鸟语用通俗的话翻译一下:**
-
-某一天小萌想在朋友面前显摆一下,于是在单杠上来了一个后空翻,动作姿势请参照下图:
-
-
-
-朋友都说 恩,很不错。 想再看一遍 (〃ω〃)。ヽ(〃∀〃)ノ。⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄
-
-于是小萌又来了一遍,如是几次之后,小萌累的吐血三升。
-
-于是小萌机智的想,我何不能用手机将我是飒爽英姿录下来呢,直接保存成为**后空翻.avi** 下次想显摆的时候直接拿出手机,点一下播放就行了,省时省力。
-
-小萌被自己的机智深深的折服了,然后Picture就诞生啦。(╯‵□′)╯︵┻━┻掀桌,坑爹呢,这剧情跳跃也忒大了吧。
-
-
-**好吧,言归正传,这次我们了解的Picture和上文中的录像功能是类似的,只不过我们Picture录的是Canvas中绘制的内容。**
-
-我们把Canvas绘制点,线,矩形等诸多操作用Picture录制下来,下次需要的时候拿来就能用,使用Picture相比于再次调用绘图API,开销是比较小的,也就是说对于重复的操作可以更加省时省力。
-
-**PS:你可以把Picture看作是一个录制Canvas操作的录像机。**
-
-了解了Picture的概念之后,我们再了解一下Picture的相关方法。
-
-相关方法 | 简介
-------------------------------------------------------------|--------------------
-public int getWidth () | 获取宽度
-public int getHeight () | 获取高度
-public Canvas beginRecording (int width, int height) | 开始录制 (返回一个Canvas,在Canvas中所有的绘制都会存储在Picture中)
-public void endRecording () | 结束录制
-public void draw (Canvas canvas) | 将Picture中内容绘制到Canvas中
-public static Picture createFromStream (InputStream stream) | (已废弃)通过输入流创建一个Picture
-public void writeToStream (OutputStream stream) | (已废弃)将Picture中内容写出到输出流中
-
-上面表格中基本上已经列出了Picture的所有方法,其中getWidth和getHeight没什么好说的,最后两个已经废弃也自然就不用关注了,排除了这些方法之后,只剩三个方法了,接下来我们就比较详细的了解一下:
-
-**很明显,beginRecording 和 endRecording 是成对使用的,一个开始录制,一个是结束录制,两者之间的操作将会存储在Picture中。**
-
-#### 使用示例:
-
-**准备工作:**
-
-录制内容,即将一些Canvas操作用Picture存储起来,录制的内容是不会直接显示在屏幕上的,只是存储起来了而已。
-
-``` java
- // 1.创建Picture
- private Picture mPicture = new Picture();
-
----------------------------------------------------------------
-
- // 2.录制内容方法
- private void recording() {
- // 开始录制 (接收返回值Canvas)
- Canvas canvas = mPicture.beginRecording(500, 500);
- // 创建一个画笔
- Paint paint = new Paint();
- paint.setColor(Color.BLUE);
- paint.setStyle(Paint.Style.FILL);
-
- // 在Canvas中具体操作
- // 位移
- canvas.translate(250,250);
- // 绘制一个圆
- canvas.drawCircle(0,0,100,paint);
-
- mPicture.endRecording();
- }
-
----------------------------------------------------------------
-
- // 3.在使用前调用(我在构造函数中调用了)
- public Canvas3(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- recording(); // 调用录制
- }
-
-```
-
-**具体使用:**
-
-Picture虽然方法就那么几个,但是具体使用起来还是分很多情况的,由于录制的内容不会直接显示,就像存储的视频不点击播放不会自动播放一样,同样,想要将Picture中的内容显示出来就需要手动调用播放(绘制),将Picture中的内容绘制出来可以有以下几种方法:
-
-序号 | 简介
------|-----------
- 1 | 使用Picture提供的draw方法绘制。
- 2 | 使用Canvas提供的drawPicture方法绘制。
- 3 | 将Picture包装成为PictureDrawable,使用PictureDrawable的draw方法绘制。
-
-
-以上几种方法主要区别:
-
-主要区别 | 分类 | 简介
--------------------|-----------------------------------|------------------
-是否对Canvas有影响 | 1有影响
2,3不影响 | 此处指绘制完成后是否会影响Canvas的状态(Matrix clip等)
-可操作性强弱 | 1可操作性较弱
2,3可操作性较强 | 此处的可操作性可以简单理解为对绘制结果可控程度。
-
-几种方法简介和主要区别基本就这么多了,接下来对于各种使用方法一一详细介绍:
-
-**1.使用Picture提供的draw方法绘制:**
-``` java
- // 将Picture中的内容绘制在Canvas上
- mPicture.draw(canvas);
-```
-
-
-
-**PS:这种方法在比较低版本的系统上绘制后可能会影响Canvas状态,所以这种方法一般不会使用。**
-
-**2.使用Canvas提供的drawPicture方法绘制**
-
-drawPicture有三种方法:
-``` java
-public void drawPicture (Picture picture)
-
-public void drawPicture (Picture picture, Rect dst)
-
-public void drawPicture (Picture picture, RectF dst)
-```
-和使用Picture的draw方法不同,Canvas的drawPicture不会影响Canvas状态。
-
-**简单示例:**
-``` java
- canvas.drawPicture(mPicture,new RectF(0,0,mPicture.getWidth(),200));
-```
-
-
-
- **PS:对照上一张图片,可以比较明显的看出,绘制的内容根据选区进行了缩放。 **
-
-**3.将Picture包装成为PictureDrawable,使用PictureDrawable的draw方法绘制。**
-```
- // 包装成为Drawable
- PictureDrawable drawable = new PictureDrawable(mPicture);
- // 设置绘制区域 -- 注意此处所绘制的实际内容不会缩放
- drawable.setBounds(0,0,250,mPicture.getHeight());
- // 绘制
- drawable.draw(canvas);
-```
-
-
-
-**PS:此处setBounds是设置在画布上的绘制区域,并非根据该区域进行缩放,也不是剪裁Picture,每次都从Picture的左上角开始绘制。**
-
-> **注意:在使用Picture之前请关闭硬件加速,以免引起不必要的问题,如何关闭请参考这里: [Android的硬件加速及可能导致的问题](https://github.com/GcsSloop/AndroidNote/issues/7)**
-
-### (2)drawBitmap
-
- > 其实一开始知道要讲Bitmap我是拒绝的,为什么呢?因为Bitmap就是很多问题的根源啊有木有,Bitmap可能导致内存不足,内存泄露,ListView中的复用混乱等诸多问题。想完美的掌控Bitmap还真不是一件容易的事情。限于篇幅**本文对于Bitmap不会过多的展开,只讲解一些常用的功能**,关于Bitmap详细内容,以后开专题讲解QAQ。
-
- 既然要绘制Bitmap,就要先获取一个Bitmap,那么如何获取呢?
-
- **获取Bitmap方式:**
-
- 序号 | 获取方式 | 备注
- -----|---------------------------|-----------------------------------------
- 1 | 通过Bitmap创建 | 复制一个已有的Bitmap(_新Bitmap状态和原有的一致_) 或者 创建一个空白的Bitmap(_内容可改变_)
- 2 | 通过BitmapDrawable获取 | 从资源文件 内存卡 网络等地方获取一张图片并转换为内容不可变的Bitmap
- 3 | 通过BitmapFactory获取 | 从资源文件 内存卡 网络等地方获取一张图片并转换为内容不可变的Bitmap
-
-**通常来说,我们绘制Bitmap都是读取已有的图片转换为Bitmap绘制到Canvas上。**
-很明显,第1种方式不能满足我们的要求,暂时排除。
-第2种方式虽然也可满足我们的要求,但是我不推荐使用这种方式,至于为什么在后续详细讲解Drawable的时候会说明,暂时排除。
-第3种方法我们会比较详细的说明一下如何从各个位置获取图片。
-
-#### 通过BitmapFactory从不同位置获取Bitmap:
-
-**资源文件(drawable/mipmap/raw):**
-``` java
- Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),R.raw.bitmap);
-```
-**资源文件(assets):**
-``` java
- Bitmap bitmap=null;
- try {
- InputStream is = mContext.getAssets().open("bitmap.png");
- bitmap = BitmapFactory.decodeStream(is);
- is.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
-```
-
-**内存卡文件:**
-``` java
- Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/bitmap.png");
-```
-
-**网络文件:**
-``` java
- // 此处省略了获取网络输入流的代码
- Bitmap bitmap = BitmapFactory.decodeStream(is);
- is.close();
-```
-
-既然已经获得到了Bitmap,那么就开始本文的重点了,将Bitmap绘制到画布上。
-
-#### 绘制Bitmap:
-
-依照惯例先预览一下drawBitmap的常用方法:
-``` java
- // 第一种
- public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)
-
- // 第二种
- public void drawBitmap (Bitmap bitmap, float left, float top, Paint paint)
-
- // 第三种
- public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
- public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
-```
-
-第一种方法中后两个参数(matrix, paint)是在绘制的时候对图片进行一些改变,如果只是需要将图片内容绘制出来只需要如下操作就可以了:
-
-PS:图片左上角位置默认为坐标原点。
-
-``` java
- canvas.drawBitmap(bitmap,new Matrix(),new Paint());
-```
-
-> 关于Matrix和Paint暂时略过吧,一展开又是啰啰嗦嗦一大段,反正挖坑已经是常态了,大家应该也习惯了(PAP).
-
-
-
-第二种方法就是在绘制时指定了图片左上角的坐标(距离坐标原点的距离):
-
-> **注意:此处指定的是与坐标原点的距离,并非是与屏幕顶部和左侧的距离, 虽然默认状态下两者是重合的,但是也请注意分别两者的不同。**
-
-``` java
- canvas.drawBitmap(bitmap,200,500,new Paint());
-```
-
-
-
-第三种方法比较有意思,上面多了两个矩形区域(src,dst),这两个矩形选区是干什么用的?
-
-名称 | 作用
---------------------------|---------------------
-Rect src | 指定绘制图片的区域
-Rect dst 或RectF dst | 指定图片在屏幕上显示(绘制)的区域
-
-示例:
-``` java
- // 将画布坐标系移动到画布中央
- canvas.translate(mWidth/2,mHeight/2);
-
- // 指定图片绘制区域(左上角的四分之一)
- Rect src = new Rect(0,0,bitmap.getWidth()/2,bitmap.getHeight()/2);
-
- // 指定图片在屏幕上显示的区域
- Rect dst = new Rect(0,0,200,400);
-
- // 绘制图片
- canvas.drawBitmap(bitmap,src,dst,null);
-```
-
-
-**详解:**
-
-上面是以绘制该图为例,用src指定了图片绘制部分的区域,即下图中红色方框标注的区域。
-
-
-
-然后用dst指定了绘制在屏幕上的绘制,即下图中蓝色方框标注的区域,图片宽高会根据指定的区域自动进行缩放。
-
-
-
-从上面可知,第三种方法可以绘制图片的一部分到画布上,这有什么用呢?
-
-如果你看过某些游戏的资源文件,你可能会看到如下的图片(图片来自网络):
-
-
-
-用一张图片包含了大量的素材,在绘制的时候每次只截取一部分进行绘制,这样可以大大的减少素材数量,而且素材管理起来也很方便。
-
-然而这和我们有什么关系呢?我们又不做游戏开发。
-
-确实,我们不做游戏开发,但是在某些时候我们需要制作一些炫酷的效果,这些效果因为太复杂了用代码很难实现或者渲染效率不高。这时候很多人就会想起帧动画,将动画分解成一张一张的图片然后使用帧动画制作出来,这种实现方式的确比较简单,但是一个动画效果的图片有十几到几十张,一个应用里面来几个这样炫酷的动画效果就会导致资源文件出现一大堆,想找其中的某一张资源图片简直就是灾难啊有木有。但是把同一个动画效果的所有资源图片整理到一张图片上,会大大的**减少资源文件数量,方便管理**,妈妈再也不怕我找不到资源文件了,**同时也节省了图片文件头、文件结束块以及调色板等占用的空间。**
-
-**下面是利用drawBitmap第三种方法制作的一个简单示例:**
-
-资源文件如下:
-
-
-
-最终效果如下:
-
-
-
-源码如下:
-
-> PS:由于是示例代码,做的很粗糙,仅作为学习示例,不建议在任何实际项目中使用。
-
-[_点击此处查看源码_](https://github.com/GcsSloop/AndroidNote/issues/10)
-
-## 2.绘制文字
-依旧预览一下相关常用方法:
-``` java
- // 第一类
- public void drawText (String text, float x, float y, Paint paint)
- public void drawText (String text, int start, int end, float x, float y, Paint paint)
- public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)
- public void drawText (char[] text, int index, int count, float x, float y, Paint paint)
-
- // 第二类
- public void drawPosText (String text, float[] pos, Paint paint)
- public void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)
-
- // 第三类
- public void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
- public void drawTextOnPath (char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)
-```
-> PS 其中的CharSequence和String的区别可以到这里看看. [->戳这里<-](https://github.com/GcsSloop/AndroidNote/issues/16)
-
-绘制文字部分大致可以分为三类:
-
-第一类只能指定文本基线位置位置(基线x默认在字符串左侧,基线y默认在字符串下方)。
-第二类可以分别指定每个文字的位置。
-第三类是指定一个路径,根据路径绘制文字。
-
-通过上面常用方法的参数也可看出,绘制文字也是需要画笔的,而且文字的大小,颜色,字体,对齐方式都是由画笔控制的。
-
-不过嘛这里仅简单介绍几种常用方法(反正挖坑多了也不怕),具体在讲解Paint时再详细讲解。
-
-**Paint文本相关常用方法表**
-
-标题 | 相关方法 | 备注
------|---------------------------|----------------------
-色彩 | setColor setARGB setAlpha | 设置颜色,透明度
-大小 | setTextSize | 设置文本字体大小
-字体 | setTypeface | 设置或清除字体样式
-样式 | setStyle | 填充(FILL),描边(STROKE),填充加描边(FILL_AND_STROKE)
-对齐 | setTextAlign | 左对齐(LEFT),居中对齐(CENTER),右对齐(RIGHT)
-测量 | measureText | 测量文本大小(注意,请在设置完文本各项参数后调用)
-
-为了绘制文本,我们先创建一个文本画笔:
-``` java
- Paint textPaint = new Paint(); // 创建画笔
- textPaint.setColor(Color.BLACK); // 设置颜色
- textPaint.setStyle(Paint.Style.FILL); // 设置样式
- textPaint.setTextSize(50); // 设置字体大小
-```
-
-### 第一类(drawText)
-第一类可以指定文本开始的位置,可以截取文本中部分内容进行绘制。
-
-其中x,y两个参数是指定文本绘制两个基线,示例:
-``` java
-
- // 文本(要绘制的内容)
- String str = "ABCDEFGHIJK";
-
- // 参数分别为 (文本 基线x 基线y 画笔)
- canvas.drawText(str,200,500,textPaint);
-```
-
-
-> PS: 图中字符串下方的红线是基线y,基线x未在图中画出。
-
-当然啦,除了能指定绘制文本的起始位置,还能只取出文本中的一部分内容进行绘制。
-
-截取文本中的一部分,对于String和CharSequence来说只指定字符串下标start和end位置(**注意:0<= start < end < str.length()**)
-
-以上一个例子使用的字符串为例,它的下标是这样的(wait,我为啥要说这个,算了,不管了,就这样吧(๑•́ ₃ •̀๑)):
-
-字符 | A | B | C | D | E | F | G | H | I | J | K
- ---|---|---|---|---|---|---|---|---|---|---|---
-下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
-
-假设我我们指定star为1,end为3,那么最终截取的字符串就是"BC"。
-
-一般来说,**使用start和end指定的区间是前闭后开的,即包含start指定的下标,而不包含end指定的下标**,故[1,3)最后获取到的下标只有 下标1 和 下标2 的字符,就是"BC".
-
-示例:
-``` java
- // 文本(要绘制的内容)
- String str = "ABCDEFGHIJK";
- // 参数分别为 (字符串 开始截取位置 结束截取位置 基线x 基线y 画笔)
- canvas.drawText(str,1,3,200,500,textPaint);
-```
-
-
-另外,对于字符数组char[]我们截取字符串使用起始位置(index)和长度(count)来确定。
-
-同样,我们指定index为1,count为3,那么最终截取到的字符串是"BCD".
-
-其实就是从下标位置为1处向后数3位就是截取到的字符串,示例:
-``` java
- // 字符数组(要绘制的内容)
- char[] chars = "ABCDEFGHIJK".toCharArray();
-
- // 参数为 (字符数组 起始坐标 截取长度 基线x 基线y 画笔)
- canvas.drawText(chars,1,3,200,500,textPaint);
-```
-
-
-### 第二类(drawPosText)
-
-通过和第一类比较,我们可以发现,第二类中没有指定x,y坐标的参数,而是出现了这样一个参数**float[] pos**。
-
-好吧,这个名为pos的浮点型数组就是指定坐标的,至于为啥要用数组嘛,因为这家伙野心比较大,想给每个字符都指定一个位置。
-
-示例:
-``` java
- String str = "SLOOP";
-
- canvas.drawPosText(str,new float[]{
- 100,100, // 第一个字符位置
- 200,200, // 第二个字符位置
- 300,300, // ...
- 400,400,
- 500,500
- },textPaint);
-```
-
-
-
-不过嘛,虽然虽然这个方法也比较容易理解,但是关于这个方法我个人是不推荐使用的,因为坑比较的,主要有一下几点:
-
-序号 | 反对理由
------|----------------------
- 1 | 必须指定所有字符位置,否则直接crash掉,反人类设计
- 2 | 性能不佳,在大量使用的时候可能导致卡顿
- 3 | 不支持emoji等特殊字符,不支持字形组合与分解
-
-关于第二类的第二种方法:
-
-``` java
-public void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)
-```
-
-和上面一样,就是从字符数组中切出来一段进行绘制,相信以诸位看官的聪明才智一眼就看出来了,我这里就不多说了,真的不是我偷懒啊(ˉ▽ ̄~) ~~
-
-### 第三类(drawTextOnPath)
-
-第三类要用到path这个大杀器,作为一个厉害角色怎么能这么轻易露脸呢,先保持一下神秘感,也就是说,下回再和大家见面喽。
-
-# 三.总结
-
-学会了图片和文字绘制,对于大部分自定义View都能制作了,可以去看看这位大神制作的作品,尝试模仿一下[一个绚丽的loading动效分析与实现!](http://blog.csdn.net/tianjian4592/article/details/44538605)
-
-
-
-(,,• ₃ •,,)
-
-PS: 由于本人英文水平有限,某些地方可能存在误解或词语翻译不准确,如果你对此有疑问可以提交Issues进行反馈。
-
-## About Me
-
-### 作者微博: @GcsSloop
-
-
-
-## 参考资料
-
-[Canvas](http://developer.android.com/reference/android/graphics/Canvas.html)
-[Bitmap](http://developer.android.com/reference/android/graphics/Bitmap.html)
-[Paint](http://developer.android.com/reference/android/graphics/Paint.html)
-[Android ApiDemo 笔记(一)Content与Graphics](http://blog.csdn.net/wufenglong/article/details/5596402)
-
diff --git a/CustomView/Advance/[5]Path_Basic.md b/CustomView/Advance/[5]Path_Basic.md
deleted file mode 100644
index acd7df0c..00000000
--- a/CustomView/Advance/[5]Path_Basic.md
+++ /dev/null
@@ -1,581 +0,0 @@
-# Path之基本操作
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-在上一篇[Canvas之图片文字](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B4%5DCanvas_PictureText.md)中我们了解了如何使用Canvas中绘制图片文字,结合前几篇文章,Canvas的基本操作已经差不多完结了,然而Canvas不仅仅具有这些基本的操作,还可以更加炫酷,本次会了解到path(路径)这个Canvas中的神器,有了这个神器,就能创造出更多**炫(zhuang)酷(B)**的东东了。
-
-******
-
-# 一.Path常用方法表
-> 为了兼容性(_偷懒_) 本表格中去除了部分API21(即安卓版本5.0)以上才添加的方法。
-
-作用 | 相关方法 | 备注
-----------------|-----------------|------------------------------------------
-移动起点 | moveTo | 移动下一次操作的起点位置
-设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同
-连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path
-闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域
-添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别)
-是否为空 | isEmpty | 判断Path是否为空
-是否为矩形 | isRect | 判断path是否是一个矩形
-替换路径 | set | 用新的路径替换到当前路径所有内容
-偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作)
-贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法
-rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)**
-填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式
-提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)**
-布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作)
-计算边界 | computeBounds | 计算Path的边界
-重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType**
-矩阵操作 | transform | 矩阵变换
-
-
-# 二.Path详解
-
-**请关闭硬件加速,以免引起不必要的问题!
请关闭硬件加速,以免引起不必要的问题!
请关闭硬件加速,以免引起不必要的问题!**
-
-**在AndroidMenifest文件中application节点下添上 android:hardwareAccelerated="false"以关闭整个应用的硬件加速。
更多请参考这里:[Android的硬件加速及可能导致的问题](https://github.com/GcsSloop/AndroidNote/issues/7)**
-
-## Path作用
-本次特地开了一篇详细讲解Path,为什么要单独摘出来呢,这是因为Path在2D绘图中是一个很重要的东西。
-
-在前面我们讲解的所有绘制都是简单图形(如 矩形 圆 圆弧等),而对于那些复杂一点的图形则没法去绘制(如绘制一个心形 正多边形 五角星等),而**使用Path不仅能够绘制简单图形,也可以绘制这些比较复杂的图形。另外,根据路径绘制文本和剪裁画布都会用到Path。**
-
-关于Path的作用先简单地说这么多,具体的我们接下来慢慢研究。
-
-## Path含义
-
-**官方介绍:**
-
-_The Path class encapsulates compound (multiple contour) geometric paths consisting of straight line segments, quadratic curves, and cubic curves. It can be drawn with canvas.drawPath(path, paint), either filled or stroked (based on the paint's Style), or it can be used for clipping or to draw text on a path._
-
-> 嗯,没错依旧是拿来装逼的,如果你看不懂的话,不用担心,其实并没有什么卵用。
-
-**通俗解释(sloop个人版):**
-
-**Path是封装了由直线和曲线(二次,三次贝塞尔曲线)构成的几何路径。你能用Canvas中的drawPath来把这条路径画出来(同样支持Paint的不同绘制模式),也可以用于剪裁画布和根据路径绘制文字。我们有时会用Path来描述一个图像的轮廓,所以也会称为轮廓线(轮廓线仅是Path的一种使用方法,两者并不等价)**
-
-
-另外路径有开放和封闭的区别。
-
-图像 | 名称 | 备注
- --- | --- | ---
-  | 封闭路径 | 首尾相接形成了一个封闭区域
-  | 开放路径 | 没有首位相接形成封闭区域
-
-> 这个是我随便画的,仅为展示一下区别,请无视我灵魂画师一般的绘图水准。
-
-**与Path相关的还有一些比较神奇的概念,不过暂且不说,等接下来需要用到的时候再详细说明。**
-
-## Path使用方法详解
-
-前面扯了一大堆概念性的东西。接下来就开始实战了,请诸位看官准备好瓜子、花生、爆米花,坐下来慢慢观看。
-
-
-
-### 第1组: moveTo、 setLastPoint、 lineTo 和 close
-
-由于Path的有些知识点无法单独来讲,所以本次采取了一次讲一组方法。
-
-按照惯例,先创建画笔:
-
-``` java
- Paint mPaint = new Paint(); // 创建画笔
- mPaint.setColor(Color.BLACK); // 画笔颜色 - 黑色
- mPaint.setStyle(Paint.Style.STROKE); // 填充模式 - 描边
- mPaint.setStrokeWidth(10); // 边框宽度 - 10
-```
-
-#### lineTo:
-方法预览:
-```
-public void lineTo (float x, float y)
-```
-
- 首先讲解的的LineTo,为啥先讲解这个呢?
-
- 是因为moveTo、 setLastPoint、 close都无法直接看到效果,借助有具现化效果的lineTo才能让这些方法现出原形。
-
-
-
-lineTo很简单,只有一个方法,作用也很容易理解,line嘛,顾名思义就是一条线。
-
-俗话(数学书上)说,两点确定一条直线,但是看参数明显只给了一个点的坐标吧(这不按常理出牌啊)。
-
-再仔细一看,这个lineTo除了line外还有一个to呢,to翻译过来就是“至”,到某个地方的意思,**lineTo难道是指从某个点到参数坐标点之间连一条线?**
-
-没错,你猜对了,但是这某个点又是哪里呢?
-
-前面我们提到过Path可以用来描述一个图像的轮廓,图像的轮廓通常都是用一条线构成的,所以这里的某个点就是上次操作结束的点,如果没有进行过操作则默认点为坐标原点。
-
-那么我们就来试一下:
-
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心(宽高数据在onSizeChanged中获取)
-
- Path path = new Path(); // 创建Path
-
- path.lineTo(200, 200); // lineTo
- path.lineTo(200,0);
-
- canvas.drawPath(path, mPaint); // 绘制Path
-```
-
-
-
-
-在示例中我们调用了两次lineTo,**第一次由于之前没有过操作,所以默认点就是坐标原点O,结果就是坐标原点O到A(200,200)之间连直线(用蓝色圈1标注)。**
-
-**第二次lineTo的时候,由于上次的结束位置是A(200,200),所以就是A(200,200)到B(200,0)之间的连线(用蓝色圈2标注)。**
-
-#### moveTo 和 setLastPoint:
-
-方法预览:
-``` java
- // moveTo
- public void moveTo (float x, float y)
-
- // setLastPoint
- public void setLastPoint (float dx, float dy)
-```
-
-这两个方法虽然在作用上有相似之处,但实际上却是完全不同的两个东东,具体参照下表:
-
-方法名 | 简介 | 是否影响之前的操作 | 是否影响之后操作
---- | --- | --- | ---
-moveTo | 移动下一次操作的起点位置 | 否 | 是
-setLastPoint | 设置之前操作的最后一个点位置 | 是 | 是
-
-废话不多说,直接上代码:
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
-
- Path path = new Path(); // 创建Path
-
- path.lineTo(200, 200); // lineTo
-
- path.moveTo(200,100); // moveTo
-
- path.lineTo(200,0); // lineTo
-
- canvas.drawPath(path, mPaint); // 绘制Path
-```
-
-
-这个和上面演示lineTo的方法类似,只不过在两个lineTo之间添加了一个moveTo。
-
-**moveTo只改变下次操作的起点,在执行完第一次LineTo的时候,本来的默认点位置是A(200,200),但是moveTo将其改变成为了C(200,100),所以在第二次调用lineTo的时候就是连接C(200,100) 到 B(200,0) 之间的直线(用蓝色圈2标注)。**
-
-下面是setLastPoint的示例:
-
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
-
- Path path = new Path(); // 创建Path
-
- path.lineTo(200, 200); // lineTo
-
- path.setLastPoint(200,100); // setLastPoint
-
- path.lineTo(200,0); // lineTo
-
- canvas.drawPath(path, mPaint); // 绘制Path
-```
-
-
-**setLastPoint是重置上一次操作的最后一个点,在执行完第一次的lineTo的时候,最后一个点是A(200,200),而setLastPoint更改最后一个点为C(200,100),所以在实际执行的时候,第一次的lineTo就不是从原点O到A(200,200)的连线了,而变成了从原点O到C(200,100)之间的连线了。**
-
-**在执行完第一次lineTo和setLastPoint后,最后一个点的位置是C(200,100),所以在第二次调用lineTo的时候就是C(200,100) 到 B(200,0) 之间的连线(用蓝色圈2标注)。**
-
-#### close
-
-方法预览:
-``` java
- public void close ()
-```
-
-close方法用于连接当前最后一个点和最初的一个点(如果两个点不重合的话),最终形成一个封闭的图形。
-
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
-
- Path path = new Path(); // 创建Path
-
- path.lineTo(200, 200); // lineTo
-
- path.lineTo(200,0); // lineTo
-
- path.close(); // close
-
- canvas.drawPath(path, mPaint); // 绘制Path
-```
-
-
-很明显,两个lineTo分别代表第1和第2条线,而close在此处的作用就算连接了B(200,0)点和圆的O之间的第3条线,使之形成一个封闭的图形。
-
-**注意:close的作用是封闭路径,与当前最后一个点和第一个点并不等价。如果连接了最后一个点和第一个点仍然无法形成封闭图形,则close什么 也不做。**
-
-### 第2组: addXxx与arcTo
-
-这次内容主要是在Path中添加基本图形,重点区分addArc与arcTo。
-
-#### 第一类(基本形状)
-方法预览:
-``` java
-// 第一类(基本形状)
- // 圆形
- public void addCircle (float x, float y, float radius, Path.Direction dir)
- // 椭圆
- public void addOval (RectF oval, Path.Direction dir)
- // 矩形
- public void addRect (float left, float top, float right, float bottom, Path.Direction dir)
- public void addRect (RectF rect, Path.Direction dir)
- // 圆角矩形
- public void addRoundRect (RectF rect, float[] radii, Path.Direction dir)
- public void addRoundRect (RectF rect, float rx, float ry, Path.Direction dir)
-```
-
-**这一类就是在path中添加一个基本形状,基本形状部分和前面所讲的绘制基本形状并无太大差别,详情参考[Canvas(1)颜色与基本形状](https://github.com/GcsSloop/AndroidNote/blob/master/%E9%97%AE%E9%A2%98/Canvas/Canvas(1).md), 本次只将其中不同的部分摘出来详细讲解一下。**
-
-**仔细观察一下第一类是方法,无一例外,在最后都有一个_Path.Direction_,这是一个什么神奇的东东?**
-
-Direction的意思是 方向,趋势。 点进去看一下会发现Direction是一个枚举(Enum)类型,里面只有两个枚举常量,如下:
-
-类型 | 解释 | 翻译
------|-------------------|-------
-CW | clockwise | 顺时针
-CCW | counter-clockwise | 逆时针
-
-> **瞬间懵逼,我只是想添加一个基本的形状啊,搞什么顺时针和逆时针, (╯‵□′)╯︵┻━┻**
-
-**稍安勿躁,┬─┬ ノ( ' - 'ノ) {摆好摆好) 既然存在肯定是有用的,先偷偷剧透一下这个顺时针和逆时针的作用。**
-
-序号 | 作用
------|---------------------------------------------------
- 1 | 在添加图形时确定闭合顺序(各个点的记录顺序)
- 2 | 对图形的渲染结果有影响(是判断图形渲染的重要条件)
-
-这个先剧透这么多,至于对闭合顺序有啥影响,自相交图形的渲染等问题等请慢慢看下去
-
-咱们先研究确定闭合顺序的问题,添加一个矩形试试看:
-
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
-
- Path path = new Path();
-
- path.addRect(-200,-200,200,200, Path.Direction.CW);
-
- canvas.drawPath(path,mPaint);
-```
-
-
-**将上面代码的CW改为CCW再运行一次。接下来就是见证奇迹的时刻,两次运行结果一模一样,有木有很神奇!**
-
-> **(╯°Д°)╯︵ ┻━┻(再TM掀一次)
-坑人也不带这样的啊,一毛一样要它干嘛。**
-
-**其实啊,这个东东是自带隐身技能的,想要让它现出原形,就要用到咱们刚刚学到的setLastPoint(重置当前最后一个点的位置)。**
-
-```
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
-
- Path path = new Path();
-
- path.addRect(-200,-200,200,200, Path.Direction.CW);
-
- path.setLastPoint(-300,300); // <-- 重置最后一个点的位置
-
- canvas.drawPath(path,mPaint);
-```
-
-
-
-可以明显看到,图形发生了奇怪的变化。为何会如此呢?
-
-我们先分析一下,绘制一个矩形(仅绘制边线),实际上只需要进行四次lineTo操作就行了,也就是说,只需要知道4个点的坐标,然后使用moveTo到第一个点,之后依次lineTo就行了(从上面的测试可以看出,在实际绘制中也确实是这么干的)。
-
-可是为什么要这么做呢?确定一个矩形最少需要两个点(对角线的两个点),根据这两个点的坐标直接算出四条边然后画出来不就行了,干嘛还要先计算出四个点坐标,之后再连直线呢?
-
-这个就要涉及一些path的存储问题了,前面在path中的定义中说过,Path是封装了由直线和曲线(二次,三次贝塞尔曲线)构成的几何路径。其中曲线部分用的是贝塞尔曲线,稍后再讲。 然而除了曲线部分就只剩下直线了,对于直线的存储最简单的就是记录坐标点,然后直接连接各个点就行了。虽然记录矩形只需要两个点,但是如果只用两个点来记录一个矩形的话,就要额外增加一个标志位来记录这是一个矩形,显然对于存储和解析都是很不划算的事情,将矩形转换为直线,为的就是存储记录方便。
-
-**扯了这么多,该回归正题了,就是我们的顺时针和逆时针在这里是干啥的?**
-
-图形在实际记录中就是记录各个的点,对于一个图形来说肯定有多个点,既然有这么多的点,肯定就需要一个先后顺序,这里顺时针和逆时针就是用来确定记录这些点的顺序的。
-
-对于上面这个矩形来说,我们采用的是顺时针(CW),所以记录的点的顺序就是 A -> B -> C -> D. 最后一个点就是D,我们这里使用setLastPoint改变最后一个点的位置实际上是改变了D的位置。
-
-理解了上面的原理之后,设想如果我们将顺时针改为逆时针(CCW),则记录点的顺序应该就是 A -> D -> C -> B, 再使用setLastPoint则改变的是B的位置,我们试试看结果和我们的猜想是否一致:
-
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
-
- Path path = new Path();
-
- path.addRect(-200,-200,200,200, Path.Direction.CCW);
-
- path.setLastPoint(-300,300); // <-- 重置最后一个点的位置
-
- canvas.drawPath(path,mPaint);
-```
-
-
-
-通过验证发现,发现结果和我们猜想的一样,但是还有一个潜藏的问题不晓得大家可否注意到。**我们用两个点的坐标确定了一个矩形,矩形起始点(A)就是我们指定的第一个点的坐标。**
-
-**需要注意的是,交换坐标点的顺序可能就会影响到某些绘制内容哦,例如上面的例子,你可以尝试交换两个坐标点,或者指定另外两个点来作为参数,虽然指定的是同一个矩形,但实际绘制出来是不同的哦。**
-
-**参数中点的顺序很重要!
参数中点的顺序很重要!
参数中点的顺序很重要!
**
-
-重要的话说三遍,本次是用矩形作为例子的,其他的几个图形基本上都包含了曲线,详情参见后续的贝塞尔曲线部分。
-
-**关于顺时针和逆时针对图形填充结果的影响请等待后续文章,虽然只讲了一个Path,但也是内容颇多,放进一篇中就太长了,请见谅。**
-
-#### 第二类(Path)
-方法预览:
-``` java
-// 第二类(Path)
- // path
- public void addPath (Path src)
- public void addPath (Path src, float dx, float dy)
- public void addPath (Path src, Matrix matrix)
-```
-
-
-这个相对比较简单,也很容易理解,就是将两个Path合并成为一个。
-
-第三个方法是将src添加到当前path之前先使用Matrix进行变换。
-
-第二个方法比第一个方法多出来的两个参数是将src进行了位移之后再添加进当前path中。
-
-示例:
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
- canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
-
- Path path = new Path();
- Path src = new Path();
-
- path.addRect(-200,-200,200,200, Path.Direction.CW);
- src.addCircle(0,0,100, Path.Direction.CW);
-
- path.addPath(src,0,200);
-
- mPaint.setColor(Color.BLACK); // 绘制合并后的路径
- canvas.drawPath(path,mPaint);
-```
-
-
-
-首先我们新建地方两个Path(矩形和圆形)中心都是坐标原点,我们在将包含圆形的path添加到包含矩形的path之前将其进行移动了一段距离,最终绘制出来的效果就如上面所示。
-
-#### 第三类(addArc与arcTo)
-方法预览:
-``` java
-// 第三类(addArc与arcTo)
- // addArc
- public void addArc (RectF oval, float startAngle, float sweepAngle)
- // arcTo
- public void arcTo (RectF oval, float startAngle, float sweepAngle)
- public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
-```
-
-从名字就可以看出,这两个方法都是与圆弧相关的,作用都是添加一个圆弧到path中,但既然存在两个方法,两者之间肯定是有区别的:
-
-名称 | 作用 | 区别
- --- | --- | ---
- addArc | 添加一个圆弧到path | 直接添加一个圆弧到path中
- arcTo | 添加一个圆弧到path | 添加一个圆弧到path,如果圆弧的起点和上次最后一个坐标点不相同,就连接两个点
-
-可以看到addArc有1个方法(_实际上是两个的,但另一个重载方法是API21添加的_), 而arcTo有2个方法,其中一个最后多了一个布尔类型的变量forceMoveTo。
-
-**forceMoveTo是什么作用呢?**
-
-这个变量意思为“是否强制使用moveTo”,也就是说,是否使用moveTo将变量移动到圆弧的起点位移,也就意味着:
-
-forceMoveTo | 含义 | 等价方法
- --- | --- | ---
- true | 将最后一个点移动到圆弧起点,即不连接最后一个点与圆弧起点 | public void addArc (RectF oval, float startAngle, float sweepAngle)
- false | 不移动,而是连接最后一个点与圆弧起点 | public void arcTo (RectF oval, float startAngle, float sweepAngle)
-
-**示例(addArc):**
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
- canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
-
- Path path = new Path();
- path.lineTo(100,100);
-
- RectF oval = new RectF(0,0,300,300);
-
- path.addArc(oval,0,270);
- // path.arcTo(oval,0,270,true); // <-- 和上面一句作用等价
-
- canvas.drawPath(path,mPaint);
-```
-
-
-
-**示例(arcTo):**
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
- canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
-
- Path path = new Path();
- path.lineTo(100,100);
-
- RectF oval = new RectF(0,0,300,300);
-
- path.arcTo(oval,0,270);
- // path.arcTo(oval,0,270,false); // <-- 和上面一句作用等价
-
- canvas.drawPath(path,mPaint);
-```
-
-
-
-从上面两张运行效果图可以清晰的看出来两者的区别,我就不再废话了。
-
-### 第3组:isEmpty、 isRect、isConvex、 set 和 offset
-
-这一组比较简单,稍微说一下就可以了。
-
-#### isEmpty
-方法预览:
-``` java
- public boolean isEmpty ()
-```
-
-判断path中是否包含内容。
-
-``` java
- Path path = new Path();
- Log.e("1",path.isEmpty()+"");
-
- path.lineTo(100,100);
- Log.e("2",path.isEmpty()+"");
-```
-
-log输出结果:
-
-```
-03-02 14:22:54.770 12379-12379/com.sloop.canvas E/1: true
-03-02 14:22:54.770 12379-12379/com.sloop.canvas E/2: false
-```
-
-#### isRect
-方法预览:
-``` java
-public boolean isRect (RectF rect)
-```
-
-判断path是否是一个矩形,如果是一个矩形的话,会将矩形的信息存放进参数rect中。
-
-``` java
- path.lineTo(0,400);
- path.lineTo(400,400);
- path.lineTo(400,0);
- path.lineTo(0,0);
-
- RectF rect = new RectF();
- boolean b = path.isRect(rect);
- Log.e("Rect","isRect:"+b+"| left:"+rect.left+"| top:"+rect.top+"| right:"+rect.right+"| bottom:"+rect.bottom);
-```
-
-log 输出结果:
-```
-03-02 16:48:39.669 24179-24179/com.sloop.canvas E/Rect: isRect:true| left:0.0| top:0.0| right:400.0| bottom:400.0
-```
-
-#### set
-方法预览:
-``` java
- public void set (Path src)
-```
-
-将新的path赋值到现有path。
-
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
- canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
-
- Path path = new Path(); // path添加一个矩形
- path.addRect(-200,-200,200,200, Path.Direction.CW);
-
- Path src = new Path(); // src添加一个圆
- src.addCircle(0,0,100, Path.Direction.CW);
-
- path.set(src); // 大致相当于 path = src;
-
- canvas.drawPath(path,mPaint);
-```
-
-
-#### offset
-方法预览:
-```java
- public void offset (float dx, float dy)
- public void offset (float dx, float dy, Path dst)
-```
-
-这个的作用也很简单,就是对path进行一段平移,它和Canvas中的translate作用很像,但Canvas作用于整个画布,而path的offset只作用于当前path。
-
-**但是第二个方法最后怎么会有一个path作为参数?**
-
-其实第二个方法中最后的参数das是存储平移后的path的。
-
-dst状态 | 效果
- --------------|---------------------------------
- dst不为空 | 将当前path平移后的状态存入dst中,不会影响当前path
- dat为空(null) | 平移将作用于当前path,相当于第一种方法
-
-示例:
-``` java
- canvas.translate(mWidth / 2, mHeight / 2); // 移动坐标系到屏幕中心
- canvas.scale(1,-1); // <-- 注意 翻转y坐标轴
-
- Path path = new Path(); // path中添加一个圆形(圆心在坐标原点)
- path.addCircle(0,0,100, Path.Direction.CW);
-
- Path dst = new Path(); // dst中添加一个矩形
- dst.addRect(-200,-200,200,200, Path.Direction.CW);
-
- path.offset(300,0,dst); // 平移
-
- canvas.drawPath(path,mPaint); // 绘制path
-
- mPaint.setColor(Color.BLUE); // 更改画笔颜色
-
- canvas.drawPath(dst,mPaint); // 绘制dst
-```
-
-
-从运行效果图可以看出,虽然我们在dst中添加了一个矩形,但是并没有表现出来,所以,当dst中存在内容时,dst中原有的内容会被清空,而存放平移后的path。
-
-# 三.总结
-
-本想一篇把path写完,但是万万没想到居然扯了这么多。本篇中讲解的是直线部分和一些常用方法,下一篇将着重讲解贝塞尔曲线和自相交图形渲染等相关问题,敬请期待哦。
-
-学完本篇之后又解锁了新的境界,可以看看这位大神的文章[ Android雷达图(蜘蛛网图)绘制](http://blog.csdn.net/crazy__chen/article/details/50163693)
-
-
-
-这个精小干练,非常适合新手练习使用,帮助大家更好的熟悉path的使用。
-
-(,,• ₃ •,,)
-
-PS: 由于本人水平有限,某些地方可能存在误解或不准确,如果你对此有疑问可以提交Issues进行反馈。
-
-## About Me
-
-### 作者微博: @GcsSloop
-
-
-
-## 参考资料
-
-[Path](http://developer.android.com/reference/android/graphics/Path.html)
-[Canvas](http://developer.android.com/reference/android/graphics/Canvas.html)
-[android绘图之Path总结](http://ghui.me/post/2015/10/android-graphics-path/)
diff --git a/CustomView/Advance/[6]Path_Bezier.md b/CustomView/Advance/[6]Path_Bezier.md
deleted file mode 100644
index cade573c..00000000
--- a/CustomView/Advance/[6]Path_Bezier.md
+++ /dev/null
@@ -1,591 +0,0 @@
-# Path之贝塞尔曲线
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-在上一篇文章[Path之基本图形](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_BasicGraphics.md)中我们了解了Path的基本使用方法,本次了解Path中非常非常非常重要的内容-贝塞尔曲线。
-
-
-******
-
-## 一.Path常用方法表
-> 为了兼容性(_偷懒_) 本表格中去除了在API21(即安卓版本5.0)以上才添加的方法。忍不住吐槽一下,为啥看起来有些顺手就能写的重载方法要等到API21才添加上啊。宝宝此刻内心也是崩溃的。
-
-作用 | 相关方法 | 备注
-----------------|-----------------|------------------------------------------
-移动起点 | moveTo | 移动下一次操作的起点位置
-设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同
-连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path
-闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域
-添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别)
-是否为空 | isEmpty | 判断Path是否为空
-是否为矩形 | isRect | 判断path是否是一个矩形
-替换路径 | set | 用新的路径替换到当前路径所有内容
-偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作)
-贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法
-rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)**
-填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式
-提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)**
-布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作)
-计算边界 | computeBounds | 计算Path的边界
-重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType**
-矩阵操作 | transform | 矩阵变换
-
-## 二.Path详解
-
-上一次除了一些常用函数之外,讲解的基本上都是直线,本次需要了解其中的曲线部分,说到曲线,就不得不提大名鼎鼎的贝塞尔曲线。它的发明者是下面这个人(法国数学家PierreBézier)。
-
-
-
-### 贝塞尔曲线能干什么?
-
-贝塞尔曲线的运用是十分广泛的,可以说**贝塞尔曲线奠定了计算机绘图的基础(_因为它可以将任何复杂的图形用精确的数学语言进行描述_)**,在你不经意间就已经使用过它了。
-
-你会使用Photoshop的话,你可能会注意到里面有一个**钢笔工具**,这个钢笔工具核心就是贝塞尔曲线。
-
-你说你不会PS? 没关系,你如果看过前面的文章或者用过2D绘图,肯定绘制过圆,圆弧,圆角矩形等这些东西。这里面的圆弧部分全部都是贝塞尔曲线的运用。
-
-#### 贝塞尔曲线作用十分广泛,简单举几个的栗子:
-> * QQ小红点拖拽效果
-* 一些炫酷的下拉刷新控件
-* 阅读软件的翻书效果
-* 一些平滑的折线图的制作
-* 很多炫酷的动画效果
-
-
-### 如何轻松入门贝塞尔曲线?
-
-虽然贝塞尔曲线用途非常广泛,然而目前貌似并没有适合的中文教程,能够搜索出来Android关于贝塞尔曲线的中文文章基本可以分为以下几种:
-* 科普型(只是让人了解贝塞尔,并没有实质性的内容)
-* 装逼型(摆出来一大堆公式,引用一堆英文原文)
-* 基础型(仅仅是讲解贝塞尔曲线的两个函数用法)
-* 实战型(根据实例讲解其中贝塞尔曲线的运用)
-
-以上几种类型中比较有用的就是基础型和实战型,但两者各有不足,本文会综合两者内容,从零开始学习贝塞尔曲线。
-
-### 第一步.理解贝塞尔曲线的原理
-
-此处理解贝塞尔曲线并非是学会公式的推导过程(不是推倒(ノ*・ω・)ノ),而是要了解贝塞尔曲线是如何生成的。
-贝塞尔曲线是用一系列点来控制曲线状态的,我将这些点简单分为两类:
-
- 类型 | 作用
--------|------
-数据点 | 确定曲线的起始和结束位置
-控制点 | 确定曲线的弯曲程度
-
-> 此处暂时仅作了解概念,接下来就会讲解其中详细的含义。
-
-**一阶曲线原理:**
-
-一阶曲线是没有控制点的,仅有两个数据点(A 和 B),最终效果一个线段。
-
-
-
-> **上图表示的是一阶曲线生成过程中的某一个阶段,动态过程可以参照下图(本文中贝塞尔曲线相关的动态演示图片来自维基百科)。**
-
-
-
-> **PS:一阶曲线其实就是前面讲解过的lineTo。**
-
-**二阶曲线原理:**
-
-二阶曲线由两个数据点(A 和 C),一个控制点(B)来描述曲线状态,大致如下:
-
-
-
-上图中红色曲线部分就是传说中的二阶贝塞尔曲线,那么这条红色曲线是如何生成的呢?接下来我们就以其中的一个状态分析一下:
-
-
-
-连接AB BC,并在AB上取点D,BC上取点E,使其满足条件:
-
-
-
-
-连接DE,取点F,使得:
-
-
-这样获取到的点F就是贝塞尔曲线上的一个点,动态过程如下:
-
-
-
-> **PS: 二阶曲线对应的方法是quadTo**
-
-**三阶曲线原理:**
-
-三阶曲线由两个数据点(A 和 D),两个控制点(B 和 C)来描述曲线状态,如下:
-
-
-
-三阶曲线计算过程与二阶类似,具体可以见下图动态效果:
-
-
-
-> **PS: 三阶曲线对应的方法是cubicTo**
-
-#### [贝塞尔曲线速查表](https://github.com/GcsSloop/AndroidNote/blob/master/QuickChart/Bessel.md)
-
-#### 强烈推荐[点击这里](http://bezier.method.ac/)练习贝塞尔曲线,可以加深对贝塞尔曲线的理解程度。
-
-### 第二步.了解贝塞尔曲线相关函数使用方法
-
-#### 一阶曲线:
-
-一阶曲线是一条线段,非常简单,可以参见上一篇文章[Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md),此处就不详细讲解了。
-
-#### 二阶曲线:
-
-通过上面对二阶曲线的简单了解,我们知道二阶曲线是由两个数据点,一个控制点构成,接下来我们就用一个实例来演示二阶曲线是如何运用的。
-
-首先,两个数据点是控制贝塞尔曲线开始和结束的位置,比较容易理解,而控制点则是控制贝塞尔的弯曲状态,相对来说比较难以理解,所以本示例重点在于理解贝塞尔曲线弯曲状态与控制点的关系,废话不多说,先上效果图:
-
-
-
-> 为了更加容易看出控制点与曲线弯曲程度的关系,上图中绘制出了辅助点和辅助线,从上面的动态图可以看出,贝塞尔曲线在动态变化过程中有类似于橡皮筋一样的弹性效果,因此在制作一些弹性效果的时候很常用。
-
-主要代码如下:
-
-``` java
-public class Bezier extends View {
-
- private Paint mPaint;
- private int centerX, centerY;
-
- private PointF start, end, control;
-
- public Bessel1(Context context) {
- super(context);
- mPaint = new Paint();
- mPaint.setColor(Color.BLACK);
- mPaint.setStrokeWidth(8);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setTextSize(60);
-
- start = new PointF(0,0);
- end = new PointF(0,0);
- control = new PointF(0,0);
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- centerX = w/2;
- centerY = h/2;
-
- // 初始化数据点和控制点的位置
- start.x = centerX-200;
- start.y = centerY;
- end.x = centerX+200;
- end.y = centerY;
- control.x = centerX;
- control.y = centerY-100;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // 根据触摸位置更新控制点,并提示重绘
- control.x = event.getX();
- control.y = event.getY();
- invalidate();
- return true;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- // 绘制数据点和控制点
- mPaint.setColor(Color.GRAY);
- mPaint.setStrokeWidth(20);
- canvas.drawPoint(start.x,start.y,mPaint);
- canvas.drawPoint(end.x,end.y,mPaint);
- canvas.drawPoint(control.x,control.y,mPaint);
-
- // 绘制辅助线
- mPaint.setStrokeWidth(4);
- canvas.drawLine(start.x,start.y,control.x,control.y,mPaint);
- canvas.drawLine(end.x,end.y,control.x,control.y,mPaint);
-
- // 绘制贝塞尔曲线
- mPaint.setColor(Color.RED);
- mPaint.setStrokeWidth(8);
-
- Path path = new Path();
-
- path.moveTo(start.x,start.y);
- path.quadTo(control.x,control.y,end.x,end.y);
-
- canvas.drawPath(path, mPaint);
- }
-}
-
-```
-
-#### 三阶曲线:
-三阶曲线由两个数据点和两个控制点来控制曲线状态。
-
-
-
-代码:
-
-``` java
-public class Bezier2 extends View {
-
- private Paint mPaint;
- private int centerX, centerY;
-
- private PointF start, end, control1, control2;
- private boolean mode = true;
-
- public Bezier2(Context context) {
- this(context, null);
-
- }
-
- public Bezier2(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mPaint = new Paint();
- mPaint.setColor(Color.BLACK);
- mPaint.setStrokeWidth(8);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setTextSize(60);
-
- start = new PointF(0, 0);
- end = new PointF(0, 0);
- control1 = new PointF(0, 0);
- control2 = new PointF(0, 0);
- }
-
- public void setMode(boolean mode) {
- this.mode = mode;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- centerX = w / 2;
- centerY = h / 2;
-
- // 初始化数据点和控制点的位置
- start.x = centerX - 200;
- start.y = centerY;
- end.x = centerX + 200;
- end.y = centerY;
- control1.x = centerX;
- control1.y = centerY - 100;
- control2.x = centerX;
- control2.y = centerY - 100;
-
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // 根据触摸位置更新控制点,并提示重绘
- if (mode) {
- control1.x = event.getX();
- control1.y = event.getY();
- } else {
- control2.x = event.getX();
- control2.y = event.getY();
- }
- invalidate();
- return true;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- //drawCoordinateSystem(canvas);
-
- // 绘制数据点和控制点
- mPaint.setColor(Color.GRAY);
- mPaint.setStrokeWidth(20);
- canvas.drawPoint(start.x, start.y, mPaint);
- canvas.drawPoint(end.x, end.y, mPaint);
- canvas.drawPoint(control1.x, control1.y, mPaint);
- canvas.drawPoint(control2.x, control2.y, mPaint);
-
- // 绘制辅助线
- mPaint.setStrokeWidth(4);
- canvas.drawLine(start.x, start.y, control1.x, control1.y, mPaint);
- canvas.drawLine(control1.x, control1.y,control2.x, control2.y, mPaint);
- canvas.drawLine(control2.x, control2.y,end.x, end.y, mPaint);
-
- // 绘制贝塞尔曲线
- mPaint.setColor(Color.RED);
- mPaint.setStrokeWidth(8);
-
- Path path = new Path();
-
- path.moveTo(start.x, start.y);
- path.cubicTo(control1.x, control1.y, control2.x,control2.y, end.x, end.y);
-
- canvas.drawPath(path, mPaint);
- }
-}
-
-```
-
-> 三阶曲线相比于二阶曲线可以制作更加复杂的形状,但是对于高阶的曲线,用低阶的曲线组合也可达到相同的效果,就是传说中的**降阶**。因此我们对贝塞尔曲线的封装方法一般最高只到三阶曲线。
-
-#### 降阶与升阶
-
-类型 | 释义 | 变化
------|---|---
-降阶 | 在保持曲线形状与方向不变的情况下,减少控制点数量,即降低曲线阶数 | 方法变得简单,数据点变多,控制点可能减少,灵活性变弱
-升阶 | 在保持曲线形状与方向不变的情况下,增加控制点数量,即升高曲线阶数 | 方法更加复杂,数据点不变,控制点增加,灵活性变强
-
-### 第三步.贝塞尔曲线使用实例
-
-**在制作这个实例之前,首先要明确一个内容,就是在什么情况下需要使用贝塞尔曲线?**
-
-> 需要绘制不规则图形时? 当然不是!目前来说,我觉得使用贝塞尔曲线主要有以下几个方面(仅个人拙见,可能存在错误,欢迎指正)
-
-序号 | 内容 | 用例
------|-----------------------------------------------|---------
- 1 | 事先不知道曲线状态,需要实时计算时 | 天气预报气温变化的平滑折线图
- 2 | 显示状态会根据用户操作改变时 | QQ小红点,仿真翻书效果
- 3 | 一些比较复杂的运动状态(配合PathMeasure使用) | 复杂运动状态的动画效果
-
-至于只需要一个静态的曲线图形的情况,用图片岂不是更好,大量的计算会很不划算。
-
-如果是显示SVG矢量图的话,已经有相关的解析工具了(内部依旧运用的有贝塞尔曲线),不需要手动计算。
-
-**贝塞尔曲线的主要优点是可以实时控制曲线状态,并可以通过改变控制点的状态实时让曲线进行平滑的状态变化。**
-
-### 接下来我们就用一个简单的示例让一个圆渐变成为心形:
-
-#### 效果图:
-
-
-
-#### 思路分析:
-
-我们最终的需要的效果是将一个圆转变成一个心形,通过分析可知,圆可以由四段三阶贝塞尔曲线组合而成,如下:
-
-
-
-心形也可以由四段的三阶的贝塞尔曲线组成,如下:
-
-
-
-两者的差别仅仅在于数据点和控制点位置不同,因此只需要调整数据点和控制点的位置,就能将圆形变为心形。
-
-#### 核心难点:
-
-##### 1.如何得到数据点和控制点的位置?
-
- 关于使用绘制圆形的数据点与控制点早就已经有人详细的计算好了,可以参考stackoverflow的一个回答[How to create circle with Bézier curves?](http://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves)其中的数据只需要拿来用即可。
-
- 而对于心形的数据点和控制点,可以由圆形的部分数据点和控制点平移后得到,具体参数可以自己慢慢调整到一个满意的效果。
-
-##### 2.如何达到渐变效果?
-
- 渐变其实就是每次对数据点和控制点稍微移动一点,然后重绘界面,在短时间多次的调整数据点与控制点,使其逐渐接近目标值,通过不断的重绘界面达到一种渐变的效果。过程可以参照下图动态效果:
-
- 
-
-#### 代码:
-
-``` java
-public class Bezier3 extends View {
- private static final float C = 0.551915024494f; // 一个常量,用来计算绘制圆形贝塞尔曲线控制点的位置
-
- private Paint mPaint;
- private int mCenterX, mCenterY;
-
- private PointF mCenter = new PointF(0,0);
- private float mCircleRadius = 200; // 圆的半径
- private float mDifference = mCircleRadius*C; // 圆形的控制点与数据点的差值
-
- private float[] mData = new float[8]; // 顺时针记录绘制圆形的四个数据点
- private float[] mCtrl = new float[16]; // 顺时针记录绘制圆形的八个控制点
-
- private float mDuration = 1000; // 变化总时长
- private float mCurrent = 0; // 当前已进行时长
- private float mCount = 100; // 将时长总共划分多少份
- private float mPiece = mDuration/mCount; // 每一份的时长
-
-
- public Bezier3(Context context) {
- this(context, null);
-
- }
-
- public Bezier3(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mPaint = new Paint();
- mPaint.setColor(Color.BLACK);
- mPaint.setStrokeWidth(8);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setTextSize(60);
-
-
- // 初始化数据点
-
- mData[0] = 0;
- mData[1] = mCircleRadius;
-
- mData[2] = mCircleRadius;
- mData[3] = 0;
-
- mData[4] = 0;
- mData[5] = -mCircleRadius;
-
- mData[6] = -mCircleRadius;
- mData[7] = 0;
-
- // 初始化控制点
-
- mCtrl[0] = mData[0]+mDifference;
- mCtrl[1] = mData[1];
-
- mCtrl[2] = mData[2];
- mCtrl[3] = mData[3]+mDifference;
-
- mCtrl[4] = mData[2];
- mCtrl[5] = mData[3]-mDifference;
-
- mCtrl[6] = mData[4]+mDifference;
- mCtrl[7] = mData[5];
-
- mCtrl[8] = mData[4]-mDifference;
- mCtrl[9] = mData[5];
-
- mCtrl[10] = mData[6];
- mCtrl[11] = mData[7]-mDifference;
-
- mCtrl[12] = mData[6];
- mCtrl[13] = mData[7]+mDifference;
-
- mCtrl[14] = mData[0]-mDifference;
- mCtrl[15] = mData[1];
- }
-
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mCenterX = w / 2;
- mCenterY = h / 2;
- }
-
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- drawCoordinateSystem(canvas); // 绘制坐标系
-
- canvas.translate(mCenterX, mCenterY); // 将坐标系移动到画布中央
- canvas.scale(1,-1); // 翻转Y轴
-
- drawAuxiliaryLine(canvas);
-
-
- // 绘制贝塞尔曲线
- mPaint.setColor(Color.RED);
- mPaint.setStrokeWidth(8);
-
- Path path = new Path();
- path.moveTo(mData[0],mData[1]);
-
- path.cubicTo(mCtrl[0], mCtrl[1], mCtrl[2], mCtrl[3], mData[2], mData[3]);
- path.cubicTo(mCtrl[4], mCtrl[5], mCtrl[6], mCtrl[7], mData[4], mData[5]);
- path.cubicTo(mCtrl[8], mCtrl[9], mCtrl[10], mCtrl[11], mData[6], mData[7]);
- path.cubicTo(mCtrl[12], mCtrl[13], mCtrl[14], mCtrl[15], mData[0], mData[1]);
-
- canvas.drawPath(path, mPaint);
-
- mCurrent += mPiece;
- if (mCurrent < mDuration){
-
- mData[1] -= 120/mCount;
- mCtrl[7] += 80/mCount;
- mCtrl[9] += 80/mCount;
-
- mCtrl[4] -= 20/mCount;
- mCtrl[10] += 20/mCount;
-
- postInvalidateDelayed((long) mPiece);
- }
- }
-
- // 绘制辅助线
- private void drawAuxiliaryLine(Canvas canvas) {
- // 绘制数据点和控制点
- mPaint.setColor(Color.GRAY);
- mPaint.setStrokeWidth(20);
-
- for (int i=0; i<8; i+=2){
- canvas.drawPoint(mData[i],mData[i+1], mPaint);
- }
-
- for (int i=0; i<16; i+=2){
- canvas.drawPoint(mCtrl[i], mCtrl[i+1], mPaint);
- }
-
-
- // 绘制辅助线
- mPaint.setStrokeWidth(4);
-
- for (int i=2, j=2; i<8; i+=2, j+=4){
- canvas.drawLine(mData[i],mData[i+1],mCtrl[j],mCtrl[j+1],mPaint);
- canvas.drawLine(mData[i],mData[i+1],mCtrl[j+2],mCtrl[j+3],mPaint);
- }
- canvas.drawLine(mData[0],mData[1],mCtrl[0],mCtrl[1],mPaint);
- canvas.drawLine(mData[0],mData[1],mCtrl[14],mCtrl[15],mPaint);
- }
-
- // 绘制坐标系
- private void drawCoordinateSystem(Canvas canvas) {
- canvas.save(); // 绘制做坐标系
-
- canvas.translate(mCenterX, mCenterY); // 将坐标系移动到画布中央
- canvas.scale(1,-1); // 翻转Y轴
-
- Paint fuzhuPaint = new Paint();
- fuzhuPaint.setColor(Color.RED);
- fuzhuPaint.setStrokeWidth(5);
- fuzhuPaint.setStyle(Paint.Style.STROKE);
-
- canvas.drawLine(0, -2000, 0, 2000, fuzhuPaint);
- canvas.drawLine(-2000, 0, 2000, 0, fuzhuPaint);
-
- canvas.restore();
- }
-}
-
-```
-
-## 三.总结
-
-其实关于贝塞尔曲线最重要的是核心理解贝塞尔曲线的生成方式,只有理解了贝塞尔曲线的生成方式,才能更好的运用贝塞尔曲线。在上一篇末尾说本篇要涉及一点自相交图形渲染问题,不幸的是,本篇没有了,请期待下一篇(可能会在下一篇中出现o(* ̄︶ ̄*)o),下一篇依旧Path相关内容,教给大家一些更好玩的东西。
-
-解锁新的境界之[【绘制一个弹性的圆】](http://www.jianshu.com/p/791d3a791ec2):
-
-
-
-(,,• ₃ •,,)
-#### PS: 由于本人水平有限,某些地方可能存在误解或不准确,如果你对此有疑问可以提交Issues进行反馈。
-
-## About Me
-
-### 作者微博: @GcsSloop
-
-
-
-## 参考资料
-[Path](http://developer.android.com/reference/android/graphics/Path.html)
-[Canvas](http://developer.android.com/reference/android/graphics/Canvas.html)
-[贝塞尔曲线扫盲](http://www.html-js.com/article/1628)
-[贝塞尔曲线-维基百科](https://zh.wikipedia.org/wiki/%E8%B2%9D%E8%8C%B2%E6%9B%B2%E7%B7%9A)
-[How to create circle with Bézier curves?](http://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves)
-[三次贝塞尔曲线练习之弹性的圆](http://www.jianshu.com/p/791d3a791ec2)
-
-
-
-
-
-
diff --git a/CustomView/Advance/[7]Path_Over.md b/CustomView/Advance/[7]Path_Over.md
deleted file mode 100644
index 88cbd1b7..00000000
--- a/CustomView/Advance/[7]Path_Over.md
+++ /dev/null
@@ -1,412 +0,0 @@
-# Path之完结篇(伪)
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-经历过前两篇 [Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md) 和 [Path之贝塞尔曲线](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B6%5DPath_Bezier.md) 的讲解,本篇终于进入Path的收尾篇,本篇结束后Path的大部分相关方法都已经讲解完了,但Path还有一些更有意思的玩法,应该会在后续的文章中出现吧,嗯,应该会的ˊ_>ˋ
-
-******
-
-## 一.Path常用方法表
-> 为了兼容性(_偷懒_) 本表格中去除了在API21(即安卓版本5.0)以上才添加的方法。忍不住吐槽一下,为啥看起来有些顺手就能写的重载方法要等到API21才添加上啊。宝宝此刻内心也是崩溃的。
-
-作用 | 相关方法 | 备注
-----------------|-----------------|------------------------------------------
-移动起点 | moveTo | 移动下一次操作的起点位置
-设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同
-连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path
-闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域
-添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别)
-是否为空 | isEmpty | 判断Path是否为空
-是否为矩形 | isRect | 判断path是否是一个矩形
-替换路径 | set | 用新的路径替换到当前路径所有内容
-偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作)
-贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法
-rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)**
-填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式
-提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)**
-布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作)
-计算边界 | computeBounds | 计算Path的边界
-重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType**
-矩阵操作 | transform | 矩阵变换
-
-
-## 二、Path方法详解
-
-### rXxx方法
-
-此类方法可以看到和前面的一些方法看起来很像,只是在前面多了一个r,那么这个rXxx和前面的一些方法有什么区别呢?
-
-> **rXxx方法的坐标使用的是相对位置(基于当前点的位移),而之前方法的坐标是绝对位置(基于当前坐标系的坐标)。**
-
-**举个例子:**
-
-``` java
- Path path = new Path();
-
- path.moveTo(100,100);
- path.lineTo(100,200);
-
- canvas.drawPath(path,mDeafultPaint);
-```
-
-
-在这个例子中,先移动点到坐标(100,100)处,之后再连接 _点(100,100)_ 到 _(100,200)_ 之间点直线,非常简单,画出来就是一条竖直的线,那接下来看下一个例子:
-
-``` java
- Path path = new Path();
-
- path.moveTo(100,100);
- path.rLineTo(100,200);
-
- canvas.drawPath(path,mDeafultPaint);
-```
-
-
-这个例子中,将 lineTo 换成了 rLineTo 可以看到在屏幕上原本是竖直的线变成了倾斜的线。这是因为最终我们连接的是 _(100,100)_ 和 _(200, 300)_ 之间的线段。
-
-在使用rLineTo之前,当前点的位置在 (100,100) , 使用了 rLineTo(100,200) 之后,下一个点的位置是在当前点的基础上加上偏移量得到的,即 (100+100, 100+200) 这个位置,故最终结果如上所示。
-
-**PS: 此处仅以 rLineTo 为例,只要理解 “绝对坐标” 和 “相对坐标” 的区别,其他方法类比即可。**
-
-### 填充模式
-
-我们在之前的文章中了解到,Paint有三种样式,“描边” “填充” 以及 “描边加填充”,我们这里所了解到就是在Paint设置为后两种样式时**不同的填充模式对图形渲染效果的影响**。
-
-**我们要给一个图形内部填充颜色,首先需要分清哪一部分是外部,哪一部分是内部,机器不像我们人那么聪明,机器是如何判断内外呢?**
-
-机器判断图形内外,一般有以下两种方法:
-
-> PS:此处所有的图形均为封闭图形,不包括图形不封闭这种情况。
-
-方法 | 判定条件 | 解释
----------------|-----------------------------------------------|----------------
-奇偶规则 | 奇数表示在图形内,偶数表示在图形外 | 从任意位置p作一条射线, 若与该射线相交的图形边的数目为奇数,则p是图形内部点,否则是外部点。
-非零环绕数规则 | 若环绕数为0表示在图形外,非零表示在图形内 | 首先使图形的边变为矢量。将环绕数初始化为零。再从任意位置p作一条射线。当从p点沿射线方向移动时,对在每个方向上穿过射线的边计数,每当图形的边从右到左穿过射线时,环绕数加1,从左到右时,环绕数减1。处理完图形的所有相关边之后,若环绕数为非零,则p为内部点,否则,p是外部点。
-
-接下来我们先了解一下两种判断方法是如何工作的。
-
-#### 奇偶规则(Even-Odd Rule)
-
-这一个比较简单,也容易理解,直接用一个简单示例来说明。
-
-
-
-在上图中有一个四边形,我们选取了三个点来判断这些点是否在图形内部。
-
->
-P1: 从P1发出一条射线,发现图形与该射线相交边数为0,偶数,故P1点在图形外部。
-P2: 从P2发出一条射线,发现图形与该射线相交边数为1,奇数,故P2点在图形内部。
-P3: 从P3发出一条射线,发现图形与该射线相交边数为2,偶数,故P3点在图形外部。
-
-
-#### 非零环绕数规则(Non-Zero Winding Number Rule)
-
-非零环绕数规则相对来说比较难以理解一点。
-
-我们在之前的文章 [Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md) 中我们了解到,在给Path中添加图形时需要指定图形的添加方式,是用顺时针还是逆时针,另外我们不论是使用lineTo,quadTo,cubicTo还是其他连接线的方法,都是从一个点连接到另一个点,换言之,**Path中任何线段都是有方向性的**,这也是使用非零环绕数规则的基础。
-
-我们依旧用一个简单的例子来说明非零环绕数规则的用法:
-
-> **PS: 注意图形中线段的方向性!**
-
-
-
->
-P1: 从P1点发出一条射线,沿射线防线移动,并没有与边相交点部分,环绕数为0,故P1在图形外边。
-P2: 从P2点发出一条射线,沿射线方向移动,与图形点左侧边相交,该边从左到右穿过穿过射线,环绕数-1,最终环绕数为-1,故P2在图形内部。
-P3: 从P3点发出一条射线,沿射线方向移动,在第一个交点处,底边从右到左穿过射线,环绕数+1,在第二个交点处,右侧边从左到右穿过射线,环绕数-1,最终环绕数为0,故P3在图形外部。
-
-通常,这两种方法的判断结果是相同的,但也存在两种方法判断结果不同的情况,如下面这种情况:
-
-> 注意图形线段的方向,就不详细解释了,用上面的方法进行判断即可。
-
-
-
-#### 自相交图形
-
-**自相交图形定义:多边形在平面内除顶点外还有其他公共点。**
-
-简单的提一下自相交图形,了解概念即可,下图就是一个简单的自相交图形:
-
-
-
-#### Android中的填充模式
-
-Android中的填充模式有四种,是封装在Path中的一个枚举。
-
-模式 | 简介
------------------|-----------------------
-EVEN_ODD | 奇偶规则
-INVERSE_EVEN_ODD | 反奇偶规则
-WINDING | 非零环绕数规则
-INVERSE_WINDING | 反非零环绕数规则
-
-我们可以看到上面有四种模式,分成两对,例如 "奇偶规则" 与 "反奇偶规则" 是一对,它们之间有什么关系呢?
-
-Inverse 和含义是“相反,对立”,说明反奇偶规则刚好与奇偶规则相反,例如对于一个矩形而言,使用奇偶规则会填充矩形内部,而使用反奇偶规则会填充矩形外部,这个会在后面示例中代码展示两者对区别。
-
-#### Android与填充模式相关的方法
-
-> 这些都是Path中的方法。
-
-方法 | 作用
-------------------------|----------------------------
-setFillType | 设置填充规则
-getFillType | 获取当前填充规则
-isInverseFillType | 判断是否是反向(INVERSE)规则
-toggleInverseFillType | 切换填充规则(即原有规则与反向规则之间相互切换)
-
-#### 示例演示:
-
-本演示着重于帮助理解填充模式中的一些难点和易混淆的问题,对于一些比较简单的问题,读者可自行验证,本文中不会过多赘述。
-
-##### 奇偶规则与反奇偶规则
-
-``` java
- mDeafultPaint.setStyle(Paint.Style.FILL); // 设置画布模式为填充
-
- canvas.translate(mViewWidth / 2, mViewHeight / 2); // 移动画布(坐标系)
-
- Path path = new Path(); // 创建Path
-
- //path.setFillType(Path.FillType.EVEN_ODD); // 设置Path填充模式为 奇偶规则
- path.setFillType(Path.FillType.INVERSE_EVEN_ODD); // 反奇偶规则
-
- path.addRect(-200,-200,200,200, Path.Direction.CW); // 给Path中添加一个矩形
-```
-
-下面两张图片分别是在奇偶规则于反奇偶规则的情况下绘制的结果,可以看出其填充的区域刚好相反:
-
-> PS: 白色为背景色,黑色为填充色。
-
-
-
-
-##### 图形边的方向对非零奇偶环绕数规则填充结果的影响
-
-我们之前讨论过给Path添加图形时顺时针与逆时针的作用,除了上次讲述的方便记录外,就是本文所涉及的另外一个重要作用了: **"作为非零环绕数规则的判断依据。"**
-
-通过前面我们已经大致了解了在图形边的方向会如何影响到填充效果,我们这里验证一下:
-
-``` java
- mDeafultPaint.setStyle(Paint.Style.FILL); // 设置画笔模式为填充
-
- canvas.translate(mViewWidth / 2, mViewHeight / 2); // 移动画布(坐系)
-
- Path path = new Path(); // 创建Path
-
- // 添加小正方形 (通过这两行代码来控制小正方形边的方向,从而演示不同的效果)
- // path.addRect(-200, -200, 200, 200, Path.Direction.CW);
- path.addRect(-200, -200, 200, 200, Path.Direction.CCW);
-
- // 添加大正方形
- path.addRect(-400, -400, 400, 400, Path.Direction.CCW);
-
- path.setFillType(Path.FillType.WINDING); // 设置Path填充模式为非零环绕规则
-
- canvas.drawPath(path, mDeafultPaint); // 绘制Path
-```
-
-
-
-
-
-### 布尔操作(API19)
-
-布尔操作与我们中学所学的集合操作非常像,只要知道集合操作中等交集,并集,差集等操作,那么理解布尔操作也是很容易的。
-
-**布尔操作是两个Path之间的运算,主要作用是用一些简单的图形通过一些规则合成一些相对比较复杂,或难以直接得到的图形**。
-
-如太极中的阴阳鱼,如果用贝塞尔曲线制作的话,可能需要六段贝塞尔曲线才行,而在这里我们可以用四个Path通过布尔运算得到,而且会相对来说更容易理解一点。
-
-
-
-``` java
- canvas.translate(mViewWidth / 2, mViewHeight / 2);
-
- Path path1 = new Path();
- Path path2 = new Path();
- Path path3 = new Path();
- Path path4 = new Path();
-
- path1.addCircle(0, 0, 200, Path.Direction.CW);
- path2.addRect(0, -200, 200, 200, Path.Direction.CW);
- path3.addCircle(0, -100, 100, Path.Direction.CW);
- path4.addCircle(0, 100, 100, Path.Direction.CCW);
-
-
- path1.op(path2, Path.Op.DIFFERENCE);
- path1.op(path3, Path.Op.UNION);
- path1.op(path4, Path.Op.DIFFERENCE);
-
- canvas.drawPath(path1, mDeafultPaint);
-```
-
-前面演示了布尔运算的作用,接下来我们了解一下布尔运算的核心:布尔逻辑。
-
-Path的布尔运算有五种逻辑,如下:
-
-逻辑名称 | 类比 | 说明 | 示意图
--------------------|------|----------------------------------------|-------------------------
-DIFFERENCE | 差集 | Path1中减去Path2后剩下的部分 | 
-REVERSE_DIFFERENCE | 差集 | Path2中减去Path1后剩下的部分 | 
-INTERSECT | 交集 | Path1与Path2相交的部分 | 
-UNION | 并集 | 包含全部Path1和Path2 | 
-XOR | 异或 | 包含Path1与Path2但不包括两者相交的部分 | 
-
-#### 布尔运算方法
-
-通过前面到理论知识铺垫,相信大家对布尔运算已经有了基本的认识和理解,下面我们用代码演示一下布尔运算:
-
-在Path中的布尔运算有两个方法
-
-``` java
- boolean op (Path path, Path.Op op)
- boolean op (Path path1, Path path2, Path.Op op)
-```
-
-两个方法中的返回值用于判断布尔运算是否成功,它们使用方法如下:
-
-``` `java
- // 对 path1 和 path2 执行布尔运算,运算方式由第二个参数指定,运算结果存入到path1中。
- path1.op(path2, Path.Op.DIFFERENCE);
-
- // 对 path1 和 path2 执行布尔运算,运算方式由第三个参数指定,运算结果存入到path3中。
- path3.op(path1, path2, Path.Op.DIFFERENCE)
-```
-
-#### 布尔运算示例
-
-
-
-代码:
-
-``` java
- int x = 80;
- int r = 100;
-
- canvas.translate(250,0);
-
- Path path1 = new Path();
- Path path2 = new Path();
- Path pathOpResult = new Path();
-
- path1.addCircle(-x, 0, r, Path.Direction.CW);
- path2.addCircle(x, 0, r, Path.Direction.CW);
-
- pathOpResult.op(path1,path2, Path.Op.DIFFERENCE);
- canvas.translate(0, 200);
- canvas.drawText("DIFFERENCE", 240,0,mDeafultPaint);
- canvas.drawPath(pathOpResult,mDeafultPaint);
-
- pathOpResult.op(path1,path2, Path.Op.REVERSE_DIFFERENCE);
- canvas.translate(0, 300);
- canvas.drawText("REVERSE_DIFFERENCE", 240,0,mDeafultPaint);
- canvas.drawPath(pathOpResult,mDeafultPaint);
-
- pathOpResult.op(path1,path2, Path.Op.INTERSECT);
- canvas.translate(0, 300);
- canvas.drawText("INTERSECT", 240,0,mDeafultPaint);
- canvas.drawPath(pathOpResult,mDeafultPaint);
-
- pathOpResult.op(path1,path2, Path.Op.UNION);
- canvas.translate(0, 300);
- canvas.drawText("UNION", 240,0,mDeafultPaint);
- canvas.drawPath(pathOpResult,mDeafultPaint);
-
- pathOpResult.op(path1,path2, Path.Op.XOR);
- canvas.translate(0, 300);
- canvas.drawText("XOR", 240,0,mDeafultPaint);
- canvas.drawPath(pathOpResult,mDeafultPaint);
-```
-
-### 计算边界
-
-这个方法主要作用是计算Path所占用的空间以及所在位置,方法如下:
-
-``` java
- void computeBounds (RectF bounds, boolean exact)
-```
-
-它有两个参数:
-
-参数 | 作用
--------|--------
-bounds | 测量结果会放入这个矩形
-exact | 是否精确测量,目前这一个参数作用已经废弃,一般写true即可。
-
-关于exact如有疑问可参见Google官方的提交记录[Path.computeBounds()](https://code.google.com/p/android/issues/detail?id=4070)
-
-#### 计算边界示例
-
-计算path边界的一个简单示例.
-
-
-
-代码:
-
-``` java
- // 移动canvas,mViewWidth与mViewHeight在 onSizeChanged 方法中获得
- canvas.translate(mViewWidth/2,mViewHeight/2);
-
- RectF rect1 = new RectF(); // 存放测量结果的矩形
-
- Path path = new Path(); // 创建Path并添加一些内容
- path.lineTo(100,-50);
- path.lineTo(100,50);
- path.close();
- path.addCircle(-100,0,100, Path.Direction.CW);
-
- path.computeBounds(rect1,true); // 测量Path
-
- canvas.drawPath(path,mDeafultPaint); // 绘制Path
-
- mDeafultPaint.setStyle(Paint.Style.STROKE);
- mDeafultPaint.setColor(Color.RED);
- canvas.drawRect(rect1,mDeafultPaint); // 绘制边界
-```
-
-### 重置路径
-
-重置Path有两个方法,分别是reset和rewind,两者区别主要有一下两点:
-
-方法 | 是否保留FillType设置 | 是否保留原有数据结构
--------|:--------------------:|:--------------------:
-reset | 是 | 否
-rewind | 否 | 是
-
-**这个两个方法应该何时选择呢?**
-
-选择权重: FillType > 数据结构
-
-_因为“FillType”影响的是显示效果,而“数据结构”影响的是重建速度。_
-
-
-## 总结
-
-Path中常用的方法到此已经结束,希望能够帮助大家加深对Path对理解运用,让大家能够用Path愉快的玩耍。( ̄▽ ̄)
-
-(,,• ₃ •,,)
-#### PS: 由于本人水平有限,某些地方可能存在误解或不准确,如果你对此有疑问可以提交Issues进行反馈。
-
-## About Me
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-
-
-
-## 参考资料
-[Path](https://developer.android.com/reference/android/graphics/Path.html)
-[维基百科-Nonzero-rule](https://en.wikipedia.org/wiki/Nonzero-rule)
-[android绘图之Path总结](http://ghui.me/post/2015/10/android-graphics-path/)
-[布尔逻辑](https://zh.wikipedia.org/wiki/%E5%B8%83%E5%B0%94%E9%80%BB%E8%BE%91)
-[GoogleCode-Path.computeBounds()](https://code.google.com/p/android/issues/detail?id=4070)
-[Path.reset vs Path.rewind](http://stackoverflow.com/questions/11505617/path-reset-vs-path-rewind)
-[]()
-[]()
-
-
-
-
-
diff --git a/CustomView/Advance/[8]Path_Play.md b/CustomView/Advance/[8]Path_Play.md
deleted file mode 100644
index eeca557b..00000000
--- a/CustomView/Advance/[8]Path_Play.md
+++ /dev/null
@@ -1,552 +0,0 @@
-# Path之玩出花样(PathMeasure)
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-
-可以看到,在经过
-[Path之基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md)
-[Path之贝塞尔曲线](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B6%5DPath_Bezier.md) 和
-[Path之完结篇(伪)](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B7%5DPath_Over.md) 后, Path中各类方法基本上都讲完了,表格中还没有讲解到到方法就是矩阵变换了,难道本篇终于要讲矩阵了?
-非也,矩阵这一部分仍在后面单独讲解,本篇主要讲解 PathMeasure 这个类与 Path 的一些使用技巧。
-
-> PS:不要问我为什么不讲 PathEffect,因为这个方法在后面的Paint系列中。
-
-先放一个图镇楼,省的下面无聊的内容把你们都吓跑了Σ( ̄。 ̄ノ)ノ
-
-
-
-******
-
-## Path & PathMeasure
-
-顾名思义,PathMeasure是一个用来测量Path的类,主要有以下方法:
-
-### 构造方法
-
-方法名 | 释义
----|---
-PathMeasure() | 创建一个空的PathMeasure
-PathMeasure(Path path, boolean forceClosed) | 创建 PathMeasure 并关联一个指定的Path(Path需要已经创建完成)。
-
-### 公共方法
-
-返回值 | 方法名 | 释义
---------|--------------------------------------------------------------------------|-------------------
-void | setPath(Path path, boolean forceClosed) | 关联一个Path
-boolean | isClosed() | 是否闭合
-float | getLength() | 获取Path的长度
-boolean | nextContour() | 跳转到下一个轮廓
-boolean | getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) | 截取片段
-boolean | getPosTan(float distance, float[] pos, float[] tan) | 获取指定长度的位置坐标及该点切线值
-boolean | getMatrix(float distance, Matrix matrix, int flags) | 获取指定长度的位置坐标及该点Matrix
-
-PathMeasure的方法也不多,接下来我们就逐一的讲解一下。
-
-******
-
-
-### 1.构造函数
-
-构造函数有两个。
-
-**无参构造函数:**
-
-``` java
- PathMeasure ()
-```
-
-用这个构造函数可创建一个空的 PathMeasure,但是使用之前需要先调用 setPath 方法来与 Path 进行关联。被关联的 Path 必须是已经创建好的,如果关联之后 Path 内容进行了更改,则需要使用 setPath 方法重新关联。
-
-**有参构造函数:**
-
-``` java
- PathMeasure (Path path, boolean forceClosed)
-```
-
-用这个构造函数是创建一个 PathMeasure 并关联一个 Path, 其实和创建一个空的 PathMeasure 后调用 setPath 进行关联效果是一样的,同样,被关联的 Path 也必须是已经创建好的,如果关联之后 Path 内容进行了更改,则需要使用 setPath 方法重新关联。
-
-该方法有两个参数,第一个参数自然就是被关联的 Path 了,第二个参数是用来确保 Path 闭合,如果设置为 true, 则不论之前Path是否闭合,都会自动闭合该 Path(如果Path可以闭合的话)。
-
-**在这里有两点需要明确:**
-
->
-* 1. 不论 forceClosed 设置为何种状态(true 或者 false), 都不会影响原有Path的状态,**即 Path 与 PathMeasure 关联之后,之前的的 Path 不会有任何改变。**
-* 2. forceClosed 的设置状态可能会影响测量结果,**如果 Path 未闭合但在与 PathMeasure 关联的时候设置 forceClosed 为 true 时,测量结果可能会比 Path 实际长度稍长一点,获取到到是该 Path 闭合时的状态。**
-
-下面我们用一个例子来验证一下:
-
-```
- canvas.translate(mViewWidth/2,mViewHeight/2);
-
- Path path = new Path();
-
- path.lineTo(0,200);
- path.lineTo(200,200);
- path.lineTo(200,0);
-
- PathMeasure measure1 = new PathMeasure(path,false);
- PathMeasure measure2 = new PathMeasure(path,true);
-
- Log.e("TAG", "forceClosed=false---->"+measure1.getLength());
- Log.e("TAG", "forceClosed=true----->"+measure2.getLength());
-
- canvas.drawPath(path,mDeafultPaint);
-```
-
-log如下:
-```
- 25521-25521/com.gcssloop.canvas E/TAG: forceClosed=false---->600.0
- 25521-25521/com.gcssloop.canvas E/TAG: forceClosed=true----->800.0
-```
-
-绘制在界面上的效果如下:
-
-
-
-我们所创建的 Path 实际上是一个边长为 200 的正方形的三条边,通过上面的示例就能验证以上两个问题。
-
->
-* 1.我们将 Path 与两个的 PathMeasure 进行关联,并给 forceClosed 设置了不同的状态,之后绘制再绘制出来的 Path 没有任何变化,所以与 Path 与 PathMeasure进行关联并不会影响 Path 状态。
-* 2.我们可以看到,设置 forceClosed 为 true 的方法比设置为 false 的方法测量出来的长度要长一点,这是由于 Path 没有闭合的缘故,多出来的距离正是 Path 最后一个点与最开始一个点之间点距离。**forceClosed 为 false 测量的是当前 Path 状态的长度, forceClosed 为 true,则不论Path是否闭合测量的都是 Path 的闭合长度。**
-
-
-
-
-
-### 2.setPath、 isClosed 和 getLength
-
-这三个方法都如字面意思一样,非常简单,这里就简单是叙述一下,不再过多讲解。
-
-setPath 是 PathMeasure 与 Path 关联的重要方法,效果和 构造函数 中两个参数的作用是一样的。
-
-isClosed 用于判断 Path 是否闭合,但是如果你在关联 Path 的时候设置 forceClosed 为 true 的话,这个方法的返回值则一定为true。
-
-getLength 用于获取 Path 的总长度,在之前的测试中已经用过了。
-
-
-
-
-
-### 3.getSegment
-
-getSegment 用于获取Path的一个片段,方法如下:
-
-``` java
- boolean getSegment (float startD, float stopD, Path dst, boolean startWithMoveTo)
-```
-
-方法各个参数释义:
-
-参数 | 作用 | 备注
-----------------|----------------------------------|--------------------------------------------
-返回值(boolean) | 判断截取是否成功 | true 表示截取成功,结果存入dst中,false 截取失败,不会改变dst中内容
-startD | 开始截取位置距离 Path 起点的长度 | 取值范围: 0 <= startD < stopD <= Path总长度
-stopD | 结束截取位置距离 Path 起点的长度 | 取值范围: 0 <= startD < stopD <= Path总长度
-dst | 截取的 Path 将会添加到 dst 中 | 注意: 是添加,而不是替换
-startWithMoveTo | 起始点是否使用 moveTo | 用于保证截取的 Path 第一个点位置不变
-
->
-* 如果 startD、stopD 的数值不在取值范围 [0, getLength] 内,或者 startD == stopD 则返回值为 false,不会改变 dst 内容。
-* 如果在安卓4.4或者之前的版本,在默认开启硬件加速的情况下,更改 dst 的内容后可能绘制会出现问题,请关闭硬件加速或者给 dst 添加一个单个操作,例如: dst.rLineTo(0, 0)
-
-我们先看看这个方法如何使用:
-
-我们创建了一个 Path, 并在其中添加了一个矩形,现在我们想截取矩形中的一部分,就是下图中红色的部分。
-
-> 矩形边长400dp,起始点在左上角,顺时针
-
-
-
-代码:
-
-``` java
- canvas.translate(mViewWidth / 2, mViewHeight / 2); // 平移坐标系
-
- Path path = new Path(); // 创建Path并添加了一个矩形
- path.addRect(-200, -200, 200, 200, Path.Direction.CW);
-
- Path dst = new Path(); // 创建用于存储截取后内容的 Path
-
- PathMeasure measure = new PathMeasure(path, false); // 将 Path 与 PathMeasure 关联
-
- // 截取一部分存入dst中,并使用 moveTo 保持截取得到的 Path 第一个点的位置不变
- measure.getSegment(200, 600, dst, true);
-
- canvas.drawPath(dst, mDeafultPaint); // 绘制 dst
-```
-
-结果如下:
-
-
-
-从上图可以看到我们成功到将需要到片段截取了出来,然而当 dst 中有内容时会怎样呢?
-
-``` java
- canvas.translate(mViewWidth / 2, mViewHeight / 2); // 平移坐标系
-
- Path path = new Path(); // 创建Path并添加了一个矩形
- path.addRect(-200, -200, 200, 200, Path.Direction.CW);
-
- Path dst = new Path(); // 创建用于存储截取后内容的 Path
- dst.lineTo(-300, -300); // <--- 在 dst 中添加一条线段
-
- PathMeasure measure = new PathMeasure(path, false); // 将 Path 与 PathMeasure 关联
-
- measure.getSegment(200, 600, dst, true); // 截取一部分 并使用 moveTo 保持截取得到的 Path 第一个点的位置不变
-
- canvas.drawPath(dst, mDeafultPaint); // 绘制 Path
-```
-
-结果如下:
-
-
-
-从上面的示例可以看到 dst 中的线段保留了下来,可以得到结论:**被截取的 Path 片段会添加到 dst 中,而不是替换 dst 中到内容。**
-
-前面两个例子中 startWithMoveTo 均为 true, 如果设置为false会怎样呢?
-
-``` java
- canvas.translate(mViewWidth / 2, mViewHeight / 2); // 平移坐标系
-
- Path path = new Path(); // 创建Path并添加了一个矩形
- path.addRect(-200, -200, 200, 200, Path.Direction.CW);
-
- Path dst = new Path(); // 创建用于存储截取后内容的 Path
- dst.lineTo(-300, -300); // 在 dst 中添加一条线段
-
- PathMeasure measure = new PathMeasure(path, false); // 将 Path 与 PathMeasure 关联
-
- measure.getSegment(200, 600, dst, false); // <--- 截取一部分 不使用 startMoveTo, 保持 dst 的连续性
-
- canvas.drawPath(dst, mDeafultPaint); // 绘制 Path
-```
-
-结果如下:
-
-
-
-从该示例我们又可以得到一条结论:**如果 startWithMoveTo 为 true, 则被截取出来到Path片段保持原状,如果 startWithMoveTo 为 false,则会将截取出来的 Path 片段的起始点移动到 dst 的最后一个点,以保证 dst 的连续性。**
-
-从而我们可以用以下规则来判断 startWithMoveTo 的取值:
-
-取值 | 主要功用
-------|------------------
-true | 保证截取得到的 Path 片段不会发生形变
-false | 保证存储截取片段的 Path(dst) 的连续性
-
-
-
-
-
-### 4.nextContour
-
-我们知道 Path 可以由多条曲线构成,但不论是 getLength , getgetSegment 或者是其它方法,都只会在其中第一条线段上运行,而这个 `nextContour` 就是用于跳转到下一条曲线到方法,_如果跳转成功,则返回 true, 如果跳转失败,则返回 false。_
-
-如下,我们创建了一个 Path 并使其中包含了两个闭合的曲线,内部的边长是200,外面的边长是400,现在我们使用 PathMeasure 分别测量两条曲线的总长度。
-
-
-
-代码:
-
-``` java
- canvas.translate(mViewWidth / 2, mViewHeight / 2); // 平移坐标系
-
- Path path = new Path();
-
- path.addRect(-100, -100, 100, 100, Path.Direction.CW); // 添加小矩形
- path.addRect(-200, -200, 200, 200, Path.Direction.CW); // 添加大矩形
-
- canvas.drawPath(path,mDeafultPaint); // 绘制 Path
-
- PathMeasure measure = new PathMeasure(path, false); // 将Path与PathMeasure关联
-
- float len1 = measure.getLength(); // 获得第一条路径的长度
-
- measure.nextContour(); // 跳转到下一条路径
-
- float len2 = measure.getLength(); // 获得第二条路径的长度
-
- Log.i("LEN","len1="+len1); // 输出两条路径的长度
- Log.i("LEN","len2="+len2);
-```
-
-log输出结果:
-```
-05-30 02:00:33.899 19879-19879/com.gcssloop.canvas I/LEN: len1=800.0
-05-30 02:00:33.899 19879-19879/com.gcssloop.canvas I/LEN: len2=1600.0
-```
-
-通过测试,我们可以得到以下内容:
-
-* 1.曲线的顺序与 Path 中添加的顺序有关。
-* 2.getLength 获取到到是当前一条曲线分长度,而不是整个 Path 的长度。
-* 3.getLength 等方法是针对当前的曲线(其它方法请自行验证)。
-
-
-
-
-
-#### 5.getPosTan
-
-这个方法是用于得到路径上某一长度的位置以及该位置的正切值:
-``` java
- boolean getPosTan (float distance, float[] pos, float[] tan)
-```
-
-方法各个参数释义:
-
-参数 | 作用 | 备注
-----------------|----------------------------------|--------------------------------------------
-返回值(boolean) | 判断获取是否成功 | true表示成功,数据会存入 pos 和 tan 中,
false 表示失败,pos 和 tan 不会改变
-distance | 距离 Path 起点的长度 | 取值范围: 0 <= distance <= getLength
-pos | 该点的坐标值 | 坐标值: (x==[0], y==[1])
-tan | 该点的正切值 | 正切值: (x==[0], y==[1])
-
-这个方法也不难理解,除了其中 `tan` 这个东东,这个东西是干什么的呢?
-
-`tan` 是用来判断 Path 的趋势的,即在这个位置上曲线的走向,请看下图示例,注意箭头的方向:
-
-
-
-**[点击这里下载箭头图片](http://ww1.sinaimg.cn/large/005Xtdi2jw1f4gam21ktoj3069069jre.jpg)**
-
-可以看到 上图中箭头在沿着 Path 运动时,方向始终与 Path 走向保持一致,下面我们来看看代码是如何实现的:
-
-首先我们需要定义几个必要的变量:
-
-``` java
- private float currentValue = 0; // 用于纪录当前的位置,取值范围[0,1]映射Path的整个长度
-
- private float[] pos; // 当前点的实际位置
- private float[] tan; // 当前点的tangent值,用于计算图片所需旋转的角度
- private Bitmap mBitmap; // 箭头图片
- private Matrix mMatrix; // 矩阵,用于对图片进行一些操作
-```
-
-初始化这些变量(在构造函数中调用这个方法):
-
-``` java
- private void init(Context context) {
- pos = new float[2];
- tan = new float[2];
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inSampleSize = 2; // 缩放图片
- mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.arrow, options);
- mMatrix = new Matrix();
- }
-```
-
-具体绘制:
-
-``` java
-
- canvas.translate(mViewWidth / 2, mViewHeight / 2); // 平移坐标系
-
- Path path = new Path(); // 创建 Path
-
- path.addCircle(0, 0, 200, Path.Direction.CW); // 添加一个圆形
-
- PathMeasure measure = new PathMeasure(path, false); // 创建 PathMeasure
-
- currentValue += 0.005; // 计算当前的位置在总长度上的比例[0,1]
- if (currentValue >= 1) {
- currentValue = 0;
- }
-
- measure.getPosTan(measure.getLength() * currentValue, pos, tan); // 获取当前位置的坐标以及趋势
-
- mMatrix.reset(); // 重置Matrix
- float degrees = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI); // 计算图片旋转角度
-
- mMatrix.postRotate(degrees, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2); // 旋转图片
- mMatrix.postTranslate(pos[0] - mBitmap.getWidth() / 2, pos[1] - mBitmap.getHeight() / 2); // 将图片绘制中心调整到与当前点重合
-
- canvas.drawPath(path, mDeafultPaint); // 绘制 Path
- canvas.drawBitmap(mBitmap, mMatrix, mDeafultPaint); // 绘制箭头
-
- invalidate(); // 重绘页面
-```
-
-**核心要点:**
-
->
-* 1.**通过 `tan` 得值计算出图片旋转的角度**,tan 是 tangent 的缩写,即中学中常见的正切, 其中tan[0](x)是邻边边长,tan[1](y)是对边边长,而Math中 `atan2` 方法是根据正切是数值计算出该角度的大小,得到的单位是弧度,所以上面又将弧度转为了角度。
-* 2.**通过 `Matrix` 来设置图片对旋转角度和位移**,这里使用的方法与前面讲解过对 canvas操作 有些类似,对于 `Matrix` 会在后面专一进行讲解,敬请期待。
-* 3.**页面刷新**,页面刷新此处是在 onDraw 里面调用了 invalidate 方法来保持界面不断刷新,但并不提倡这么做,正确对做法应该是使用 线程 或者 ValueAnimator 来控制界面的刷新,关于控制页面刷新这一部分会在后续的 动画部分 详细讲解,同样敬请期待。
-
-
-
-
-### 6.getMatrix
-
-这个方法是用于得到路径上某一长度的位置以及该位置的正切值的矩阵:
-``` java
-boolean getMatrix (float distance, Matrix matrix, int flags)
-```
-
-方法各个参数释义:
-
-参数 | 作用 | 备注
-----------------|----------------------------------|--------------------------------------------
-返回值(boolean) | 判断获取是否成功 | true表示成功,数据会存入matrix中,false 失败,matrix内容不会改变
-distance | 距离 Path 起点的长度 | 取值范围: 0 <= distance <= getLength
-matrix | 根据 falgs 封装好的matrix | 会根据 flags 的设置而存入不同的内容
-flags | 规定哪些内容会存入到matrix中 | 可选择
POSITION_MATRIX_FLAG(位置)
ANGENT_MATRIX_FLAG(正切)
-
-其实这个方法就相当于我们在前一个例子中封装 `matrix` 的过程由 `getMatrix` 替我们做了,我们可以直接得到一个封装好到 `matrix`,岂不快哉。
-
-但是我们看到最后到 `flags` 选项可以选择 `位置` 或者 `正切` ,如果我们两个选项都想选择怎么办?
-
-如果两个选项都想选择,可以将两个选项之间用 `|` 连接起来,如下:
-```
-measure.getMatrix(distance, matrix, PathMeasure.TANGENT_MATRIX_FLAG | PathMeasure.POSITION_MATRIX_FLAG);
-```
-
-我们可以将上面都例子中 `getPosTan` 替换为 `getMatrix`, 看看是不是会显得简单很多:
-
-具体绘制:
-
-``` java
- Path path = new Path(); // 创建 Path
-
- path.addCircle(0, 0, 200, Path.Direction.CW); // 添加一个圆形
-
- PathMeasure measure = new PathMeasure(path, false); // 创建 PathMeasure
-
- currentValue += 0.005; // 计算当前的位置在总长度上的比例[0,1]
- if (currentValue >= 1) {
- currentValue = 0;
- }
-
- // 获取当前位置的坐标以及趋势的矩阵
- measure.getMatrix(measure.getLength() * currentValue, mMatrix, PathMeasure.TANGENT_MATRIX_FLAG | PathMeasure.POSITION_MATRIX_FLAG);
-
- mMatrix.preTranslate(-mBitmap.getWidth() / 2, -mBitmap.getHeight() / 2); // <-- 将图片绘制中心调整到与当前点重合(注意:此处是前乘pre)
-
- canvas.drawPath(path, mDeafultPaint); // 绘制 Path
- canvas.drawBitmap(mBitmap, mMatrix, mDeafultPaint); // 绘制箭头
-
- invalidate(); // 重绘页面
-```
-
-> 由于此处代码运行结果与上面一样,便不再贴图片了,请参照上面一个示例的效果图。
-
-可以看到使用 getMatrix 方法的确可以节省一些代码,不过这里依旧需要注意一些内容:
-
->
-* 1.对 `matrix` 的操作必须要在 `getMatrix` 之后进行,否则会被 `getMatrix` 重置而导致无效。
-* 2.矩阵对旋转角度默认为图片的左上角,我们此处需要使用 `preTranslate` 调整为图片中心。
-* 3.pre(矩阵前乘) 与 post(矩阵后乘) 的区别,此处请等待后续的文章或者自行搜索。
-
-*****
-
-
-## Path & SVG
-
-我们知道,用Path可以创建出各种个样的图形,但如果图形过于复杂时,用代码写就不现实了,不仅麻烦,而且容易出错,所以在绘制复杂的图形时我们一般是将 SVG 图像转换为 Path。
-
-**你说什么是 SVG?**
-
-SVG 是一种矢量图,内部用的是 xml 格式化存储方式存储这操作和数据,你完全可以将 SVG 看作是 Path 的各项操作简化书写后的存储格式。
-
-Path 和 SVG 结合通常能诞生出一些奇妙的东西,如下:
-
-
-
-
->
-**该图片来自这个开源库 ->[PathView](https://github.com/geftimov/android-pathview)**
-**SVG 转 Path 的解析可以用这个库 -> [AndroidSVG](https://bigbadaboom.github.io/androidsvg/)**
-
-限于篇幅以及本人精力,这一部分就暂不详解了,感兴趣的可以直接看源码,或者搜索一些相关的解析文章。
-
-*****
-
-## Path使用技巧
-
-**话说本篇文章的名字不是叫 玩出花样么?怎么只见前面啰啰嗦嗦的扯了一大堆不明所以的东西,花样在哪里?**
-
->
-**前面的内容虽然啰嗦繁杂,但却是重中之重的基础,如果在修仙界,这叫根基,而下面讲述的内容的是招式,有了根基才能演化出千变万化的招式,而没有根基只学招式则是徒有其表,只能学一样会一样,很难适应千变万化的需求。**
-
-先放一个效果图,然后分析一下实现过程:
-
-
-
-这是一个搜索的动效图,通过分析可以得到它应该有四种状态,分别如下:
-
-状态 |概述
----------|--------------------------------------------------
-初始状态 | 初始状态,没有任何动效,只显示一个搜索标志 :mag:
-准备搜索 | 放大镜图标逐渐变化为一个点
-正在搜索 | 围绕这一个圆环运动,并且线段长度会周期性变化
-准备结束 | 从一个点逐渐变化成为放大镜图标
-
-这些状态是有序转换的,转换流程以及转换条件如下:
-
-> 其中 `正在搜索` 这个状态持续时间长度是不确定的,在没有搜索完成前,应该一直处于搜索状态。
-
-
-
-简单的分析了其大致的流程之后,就到了制作的重点:对细节对把握。
-
-### Path 划分
-
-为了制作对方便,此处整个动效用了两个 Path, 一个是中间对放大镜, 另一个则是外侧的圆环,将两者全部画出来是这样子的。
-
-
-
-其中 Path 的走向要把握好,如下(只是一个放大镜,并不是♂):
-
-
-
-其中圆形上面的点可以用 PathMeasure 测量,无需计算。
-
-### 动画状态与时间关联
-
-此处使用的是 ValueAnimator,它可以将一段时间映射到一段数值上,随着时间变化不断的更新数值,并且可以使用插值器开控制数值变化规律(此处使用的是默认插值器)。
-
-> PS: 本来不想提前暴露这个的,准备偷偷留到动画部分(。-_-。) 但实在是没有优雅的替代方案了。
-
-### 具体绘制
-
-绘制部分是根据 当前状态以及从 ValueAnimator 获得的数值来截取 Path 中合适的部分绘制出来。
-
-### 最终效果
-
-
-
-### 源码
-
-上面的内容是为了帮助大家从把控全局流程以及理解某些细节的设计思路,而更多的内容都藏在代码中,代码总体也不算长,感兴趣的可以自己敲一遍。
-
-#### [戳这里查看源码](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/Code/SearchView.md)
-
-> PS: 本代码仅作为示例使用,还有诸多不足,如 自定义属性,视图大小, 点击事件, 监听回调 等,并不适合直接使用,有需要的可以自行补足相关内容。
-
-
-## 总结
-
-**本文中虽然后面的内容看起来比较高大上一点,但前面"啰嗦"的废话才是真正的干货,把前面的东西学会了,后面的各种效果都能信手拈来,如果只研究后面的东西,则是取其形,而难以会其意。**
-
-#### PS: 由于本人水平有限,某些地方可能存在误解或不准确,如果你对此有疑问可以提交Issues进行反馈。
-
-## About Me
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-
-
-
-## 参考资料
-[PathMeasure](https://developer.android.com/reference/android/graphics/PathMeasure.html)
-[AndroidSVG](https://bigbadaboom.github.io/androidsvg/)
-[android-pathview](https://github.com/geftimov/android-pathview)
-[android Path 和 PathMeasure 进阶](http://blog.csdn.net/cquwentao/article/details/51436852)
-[]()
-
-
-
-
-
-
diff --git a/CustomView/Advance/[99]DrawText.md b/CustomView/Advance/[99]DrawText.md
deleted file mode 100644
index fe9982a1..00000000
--- a/CustomView/Advance/[99]DrawText.md
+++ /dev/null
@@ -1,279 +0,0 @@
-# drawText之坐标、居中、绘制多行
-
-本文用于讲解Canvas中关于DrawText相关的一些常见问题,如坐标,居中,和绘制多行。
-
-之前由于个人的疏忽以及对问题的想当然,没有进行验证,在 [【安卓自定义View进阶 - 图片文字】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B4%5DCanvas_PictureText.md) 这篇文章中出现了一个错误,有不少眼睛雪亮的网友都发现了该错误并给予了反馈,非常感谢这些网友的帮助。
-
-
-
-## 错误原因
-
-这个错误是drawText方法中坐标的一个问题,就一般的绘图而言,坐标一般都是指定左上角,然而drawText默认并不是左上角,甚至不是大家测试后认为的左下角,而是一个**由Paint中Align决定的对齐基准线**,该API注释原文如下:
-
-> Draw the text, with origin at (x,y), using the specified paint. **The origin is interpreted based on the Align setting in the paint.**
-
-在默认情况下基线如下图所示:
-
-> PS:基线(BaseLine)有两条,是用户指定的坐标确定的,在默认情况下,基线X在字符串左侧,基线y在字符串下方(但并不是最低的部分)。
-
-
-
-## 分析这样设计的原因
-
-**Q: 为何基线y要放到文字下面,而不是上面?**
-
-> A : 既然采用这种对齐方式,必然有其缘由,至少不是为了坑我这种小白。据本人猜测可能有以下原因:
-* 1.符合人类书写习惯,不论是汉字还是英文或是其他语言,我们在书写对齐的时候都是以下面为基准线的,而不是上面,(**我们默认的基准线类似于四线格中的第三条线**)。
-
-* 2.字的特点,字的显示不仅有有中文汉字,还有一些特殊字符,并且大部分是根据下面对齐的,如果把对齐的基线放到上面并使其显示整齐,设计太麻烦,如下:
-
-* 3.字体的特点,我们都知道,字有很多的字体风格,不同字体风格的大小是不同的,如果以以上面为基准线而让其底部对齐,这设计难度简直不敢想象:
-
-**综上所述,基线y放到下面不仅符合人的书写习惯,而且更加便于设计。**
-
-## drawText从入门到懵逼
-
-虽然之前在 [图片文字](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B4%5DCanvas_PictureText.md) 这篇文章中已经简单的了解部分关于文字的方法,但Paint中关于文字的方法还有很多,本文会了解一些我们比较关心的一些内容,例如绘制居中的文本,多行文本等,在此之前我们先了解一下Paint中与文本相关的内部类或者枚举:
-
-名称 | 类型 | 主要作用
----------------|:------:|------------------------------------------------------
-Align | 枚举 | 指定基准线与文本的相对关系(包含 左对齐 右对齐 居中)
-Style | 枚举 | 设置样式,但不仅仅是为文本服务(包含 描边 填充 描边加填充)
-FontMetrics | 内部类 | 描述给定的文本大小,字体,间距等各种度量值(度量结果类型为float)
-FontMetricsInt | 内部类 | 作用同上,但度量结果返回值是int型的
-
-### Align
-
-Align中文意思是对齐,其作用正式如此,我们使用过 Word 的人都知道文本有 *左对齐、居中、右对齐、两端对齐、分散对齐* 五种模式,Align作用就是设置文本的对齐模式,但是并没有这么多,仅有 **左对齐、居中、右对齐** 三种模式,如下:
-
-> 吐槽:就因为没有两端对齐和分散对齐,导致长文本,尤其是中英混合的长文本在手机上显示效果奇差,相信做阅读类软件的程序员深有体会,最终还要自定义View解决。
-
-枚举类型 | 作用
----------|-------------------------------------------------------------
-LEFT | 左对齐 基线X在文本左侧,基线y在文本下方,文本出现在给定坐标的右侧,是默认的对齐方式
-RIGHT | 右对齐 基线x在文本右侧,基线y在文本下方,文本出现在给定坐标的左侧
-CENTER | 居中对齐 基线x在文本中间,基线y在文本下方,文本出现在给定坐标的两侧
-
-Align对应的方法如下:
-
-``` java
- public Paint.Align getTextAlign () // 获取对齐方式
-
- public void setTextAlign (Paint.Align align) // 设置对齐方式
-```
-
-在实际运用中基线与模式之间的关系则如下图所示:
-
-
-
-> PS 该图片是截屏加工所得,其中红色的先是各自的基准线。注意汉字有一部分是在基准线下面的。
-
-其核心代码如下:
-
-``` java
- // 平移画布 - 如有疑问请参考画布操作这篇文章
- canvas.translate(mCenterX,0); // mCenterX 是屏幕宽度的一半,在onSizeChanged中获取
-
- // 设置字体颜色
- mPaint.setColor(Color.rgb(0x06,0xaf,0xcd));
-
- // 在不同模式下绘制文字
- mPaint.setTextAlign(Paint.Align.LEFT);
- canvas.drawText("左对齐", 0, 200, mPaint);
-
- mPaint.setTextAlign(Paint.Align.CENTER);
- canvas.drawText("居中对齐", 0, 400, mPaint);
-
- mPaint.setTextAlign(Paint.Align.RIGHT);
- canvas.drawText("右对齐", 0, 600, mPaint);
-```
-
-### Style
-
-Style的意思是样式,这个在 [Canvas之绘制基本形状](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B2%5DCanvas_BasicGraphics.md) 这篇文章中讲过,它有三种状态:
-
-枚举类型 | 作用
-----------------|----------------
-FILL | 填充
-STROKE | 描边
-FILL_AND_STROKE | 填充加描边
-
-Style 对应的方法如下:
-
-``` java
-public Paint.Style getStyle () // 获取当然样式
-
-public void setStyle (Paint.Style style) // 设置样式
-```
-
-效果如下:
-
-
-
-核心代码:
-
-``` java
- // 平移画布 - 如有疑问请参考画布操作这篇文章
- canvas.translate(mCenterX,0); // mCenterX 是屏幕宽度的一半,在onSizeChanged中获取
-
- mPaint.setTextAlign(Paint.Align.CENTER);
- mPaint.setColor(Color.rgb(0x06,0xaf,0xcd));
-
- // 设置不同的样式
-
- // 填充
- mPaint.setStyle(Paint.Style.FILL);
- canvas.drawText("GcsSloop 中文", 0, 200, mPaint);
-
- // 描边
- mPaint.setStyle(Paint.Style.STROKE);
- canvas.drawText("GcsSloop 中文", 0, 400, mPaint);
-
- // 描边加填充
- mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
- canvas.drawText("GcsSloop 中文", 0, 600, mPaint);
-```
-
-### FontMetrics
-
-FontMetrics 是 Paint 的一个内部类,根据名字我们可以大致知道这是一个描述**字体规格**相关的类,关于这个类的描述原文是这样的:
-
-> Class that describes the various metrics for a font at a given text size. Remember, Y values increase going down, so those values will be positive, and values that measure distances going up will be negative. This class is returned by getFontMetrics().
-
-翻译一下:
-
-> 简单来说,FontMetrics包含了当前文本相关的各项参数,你可以通过 Paint中 _getFontMetrics()_ 这个方法来获取到这个类。
-(另外,原文中还特地强调了一下关于坐标正负的问题。)
-
-##### FontMetrics包含了以下几个数值:
-
-> 如果没有特殊说明,一下文章中“基线”默认代表“基线Y”。
-
-名称 | 正负| 释义
---------|:---:|--------------------------------------------------------
-top | - | 在指定字形和大小的情况下,字符最高点与基线之间的距离
-ascent | - | 单个字符的最高点与基线距离的推荐值(不包括字母上面的符号)
-descent | + | 单个字符的最低点与基线距离的推荐值
-bottom | + | 在指定字形和大小的情况下,字符最低点与基线之间的距离
-leading | + | 行间距,当前行bottom与下一行top之间的距离的推荐值 (通常为0,因为top与ascent,bottom与leading之间的距离足够作为行间距了)
-
-
-
-看了上面啰啰嗦嗦讲了一堆,你可能会产生一些疑问,这里我简单解释一下:
-
-0、 FontMetrics到底有什么用?
-
-> FontMetrics 是字体规格,比较精确的测量出文字相关的各种数据,在很多地方都是用得到的,比较常见的就是我们的音乐播放器中的歌词显示,需要实时的变字体位置,这里就需要比较精确是数值来进行计算以确保不会出现两行文字重叠等问题。
-
-1、为什么表格中最高点距离基线的值是负值,而最低点反而是正值?
-
-> 这是因为手机屏幕坐标系的特殊性,在数学中常见的坐标系y轴是向上的,而对于手机而言,y轴默认是向下的,所以数值越小越靠近屏幕顶端,即最高点的数值比基线小,最高点减去基线结果自然为负数。 更多参考 [坐标系](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B1%5DCoordinateSystem.md) 这篇文章。
-
-2、为什么表格中很多都是推荐值?
-
-> 这是因为字的规格不仅受字大小的影响,而且受字体风格的影响,不同的字体风格差别很大,其结果可能会有偏差,故大部分都是推荐值。
-
-3、 具体绘制的文本不同会影响 FontMetrics 中的数值吗?
-
-> 不会, **FontMetrics中的数值受字体大小(FontSize) 和 字体风格(Typeface) 影响**, 而不会因为具体绘制的内容不同而改变,给Paint设置完字体大小和字体风格后就能获取到正确的FontMetrics。
-
-**获取FontMetrics的方法**
-``` java
- Paint.FontMetrics mMetrics = mPaint.getFontMetrics();
-
- Log.e("TAG", "top=" + mMetrics.top);
- Log.e("TAG", "ascent=" + mMetrics.ascent);
- Log.e("TAG", "descent=" + mMetrics.descent);
- Log.e("TAG", "bottom=" + mMetrics.bottom);
- Log.e("TAG", "leading=" + mMetrics.leading);
-```
-结果:
-```
-05-15 21:18:13.315 13112-13112/com.gcssloop.canvas E/TAG: top=-152.98828
-05-15 21:18:13.315 13112-13112/com.gcssloop.canvas E/TAG: ascent=-129.88281
-05-15 21:18:13.315 13112-13112/com.gcssloop.canvas E/TAG: descent=34.179688
-05-15 21:18:13.315 13112-13112/com.gcssloop.canvas E/TAG: bottom=37.939453
-05-15 21:18:13.315 13112-13112/com.gcssloop.canvas E/TAG: leading=0.0
-```
-
-**由于FontMetrics中的 ascent 与 descent 比较常用,所以可以直接通过Paint获取:**
-``` java
- Log.e("TAG", "P.ascent=" + mPaint.ascent());
- Log.e("TAG", "P.descent=" + mPaint.descent());
-```
-结果,可以看到与通过FontMetrics获得的结果相同。
-```
-05-15 21:24:18.950 13112-13112/com.gcssloop.canvas E/TAG: P.ascent=-129.88281
-05-15 21:24:18.955 13112-13112/com.gcssloop.canvas E/TAG: P.descent=34.179688
-```
-
-
-## 文字居中
-
-对于绘制居中的文本来说,我们可以封装一个方法用中心点作为绘制坐标,在绘制的时候转换为实际坐标。
-
-根据前面的知识可知,想让文字水平居中很容易,只需要设置 TextAlign 为 CENTER,那么基线X(BaseLineX)自然就是这个字符串的中心了。
-
-而让文字垂直居中则有些麻烦了,因为基线Y(BaseLineY)既不是顶部,底部,也不是中心,所以文本居中最难的内容就是计算BaseLineY的位置。
-
-我们已知:
-
-> 1. 中心位置坐标,centerX, centerY
-2. 文本高度:height = descent-ascent
-3. descent的坐标:descentY = centerY + 1/2height
-4. baseLineY坐标:baseLineY = descentY-descent
-
-通过上面内容可以推算出如下公式:
-
-> baseLineY = centerY - 1/2(ascent + descent)
-
-**根据公式我们可以封装一个方法:**
-
-``` java
- /**
- * 居中绘制文本
- *
- * @param text
- * @param canvas
- * @param paint
- */
- public void drawTextByCenter(String text, float x, float y, Canvas canvas, Paint paint) {
- Paint tempPaint = new Paint(paint); // 创建一个临时画笔,防止影响原来画笔的状态
- tempPaint.setTextAlign(Paint.Align.CENTER); // 设置文本对齐方式为居中
-
- // 通过y计算出baseline的位置
- float baseline = y - (tempPaint.descent() + tempPaint.ascent()) / 2;
-
- canvas.drawText(text, x, baseline, tempPaint); //绘制文本
- }
-```
-
-**测试方法是否正确**
-
-``` java
- canvas.translate(mCenterX, mCenterY);
-
- String text = "ASSA";
- mPaint.setColor(Color.BLACK);
-
- drawTextByCenter(text, 0, 0, canvas, mPaint);
-```
-
-结果:
-
-
-
-## 绘制多行
-
-前面讲的所有绘制文本都是绘制单行文本,而对于长文本就束手无策了,但是我们偶尔也需要绘制一些长文本,例如绘制一段文本,这样前面的就无法满足需求了。
-
-我们先思考一下如何才能绘制一段长文本让其可以自动换行,如自动测量文本长度,然后根据测量的内容截开成n行,然后一行一行的绘制。
-
-
-
-
-
-
-
-
-
diff --git a/CustomView/Advance/[9]Matrix_Basic.md b/CustomView/Advance/[9]Matrix_Basic.md
deleted file mode 100644
index 8aa48f65..00000000
--- a/CustomView/Advance/[9]Matrix_Basic.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Matrix基础
-
-前面讲了四篇 Path 相关的内容,本次终于要到了大家期盼已久的黑客帝国!
-
-
-
-如题,本篇的主角是 Matrix(并不是黑客帝国)。
-
-它在我们在之前的很多文章中都提及过,但并没有仔细的介绍过,从本篇开始终于要正式介绍它了,这个在2D绘图中十分重要的角色 -- Matrix。
-
->
-#### Matrix 的翻译过来是矩阵,模型。和其释义相同,Matrix是一个矩阵,其作用则是一个模型,一个控制视图状态的模型。
-
-也就是说, 我们进行界面视图等转换都是需要依靠 Matrix 的帮助的,例如我们之前在 [Canvas之画布操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B3%5DCanvas_Convert.md) 中讲解过的画布操作,这些操作的核心就是改变 Matrix 的数值。
-
-## Matrix方法表
-
-Matrix 有很多常用和不常用的方法,在本篇中重点不在于这些方法的讲解,而是帮助大家理解 Matrix 的一些基本概念。
-
-方法类别 | 相关API | 摘要
------------|---------------------------------------------------------|------------------------
-基本方法 | equals hashCode toString toShortString | 比较、 获取哈希值、 转换为字符串
-数值操作 | set reset setValues getValues | 设置、 重置、 设置数值、 获取数值
-设置(set) | setConcat setRotate setScale setSkew setTranslate | 设置变换
-前乘(pre) | preConcat preRotate preScale preSkew preTranslate | 前乘变换
-后乘(post) | postConcat postRotate postScale postSkew postTranslate | 后乘变换
-数值计算 | mapPoints mapRadius mapRect mapVectors | 计算变换后的数值
-特殊方法 | setPolyToPoly setRectToRect rectStaysRect setSinCos | 一些特殊操作
-矩阵相关 | invert isAffine isIdentity | 求逆矩阵、 是否为仿射矩阵、 是否为单位矩阵 ...
-
-
-## Matrix原理
-
-Matrix 本质是一个 3x3 的矩阵,里面有9个数值,分别用于控制视图状态的不同内容,我们对视图的操作最终都是改变Matrix里面的数值。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/CustomView/Base/[1]CoordinateSystem.md b/CustomView/Base/[1]CoordinateSystem.md
deleted file mode 100644
index 2e90e234..00000000
--- a/CustomView/Base/[1]CoordinateSystem.md
+++ /dev/null
@@ -1,67 +0,0 @@
-# 安卓中的坐标系
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-
-## 一.屏幕坐标系和数学坐标系的区别
-由于移动设备一般定义屏幕左上角为坐标原点,向右为x轴增大方向,向下为y轴增大方向,
-所以在手机屏幕上的坐标系与数学中常见的坐标系是稍微有点差别的,详情如下:
-
-(**PS:其中的∠a 是对应的,注意y轴方向!**)
-
-
-
-
-**实际屏幕上的默认坐标系如下:**
-
-> PS: 假设其中棕色部分为手机屏幕
-
-
-
-## 二.View的坐标系
-
-**注意:View的坐标系统是相对于父控件而言的.**
-
-``` java
- getTop(); //获取子View左上角距父View顶部的距离
- getLeft(); //获取子View左上角距父View左侧的距离
- getBottom(); //获取子View右下角距父View顶部的距离
- getRight(); //获取子View右下角距父View左侧的距离
-```
-**如下图所示:**
-
-
-
-## 三.MotionEvent中 get 和 getRaw 的区别
-```
- event.getX(); //触摸点相对于其所在组件坐标系的坐标
- event.getY();
-
- event.getRawX(); //触摸点相对于屏幕默认坐标系的坐标
- event.getRawY();
-
-```
-**如下图所示:**
-
-> PS:其中相同颜色的内容是对应的,其中为了显示方便,蓝色箭头向左稍微偏移了一点.
-
-
-
-## 四.核心要点
-
-序号 | 要点
-:---:|----
- 1 | 在数学中常见的坐标系与屏幕默认坐标系的差别
- 2 | View的坐标系是相对于父控件而言的
- 3 | MotionEvent中get和getRaw的区别
-
-## 五.参考文章:
-[Android 屏幕(View)坐标系统](http://blog.csdn.net/wangjinyu501/article/details/21827341)
-
-## About Me
-
-### 作者微博: @GcsSloop
-
-
-
diff --git a/CustomView/Base/[2]AngleAndRadian.md b/CustomView/Base/[2]AngleAndRadian.md
deleted file mode 100644
index 295b006c..00000000
--- a/CustomView/Base/[2]AngleAndRadian.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# 角度与弧度
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-安卓中角度(angle)与弧度(radian)的有关问题。
-
-## 一.前言
-
-### 1.为什么讲这个?
-
- 在我们自定义View,尤其是制作一些复杂炫酷的效果的时候,实际上是将一些简单的东西通过数学上精密的计算组合到一起形成的效果。
-
-这其中可能会涉及到画布的相关操作(旋转),以及一些正余弦函数的计算等,这些内容就会用到一些角度、弧度相关的知识。
-
-### 2.为什么对角的描述存在角度与弧度两种单位?
-
-简单来说就是为了方便,为了精确描述一个角的大小引入了角度与弧度的概念。
-
-由于两者进制是不同的(**角度是60进制,弧度是10进制**),在合适的地方使用合适的单位来描述会更加方便。
-
-> **例如:**
-角度是60进位制,遇到30°6′这样的角,应该转化为10进制的30.1°。但弧度就不需要,因为弧度本身就是十进制的实数。
-
-
-## 二.角度与弧度的定义
-
-角度和弧度一样都是描述角的一种度量单位,下面是它们的定义:
-
-名称 | 定义
-:---:| ---
-角度 | 两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。**当这段弧长正好等于圆周长的360分之一时,两条射线的夹角的大小为1度.**
-弧度 | 两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。**当这段弧长正好等于圆的半径时,两条射线的夹角大小为1弧度.**
-
-**如图:**
-
-
-
-
-
-## 三.角度和弧度的换算关系
-根据角度和弧度的的定义和圆的相关知识非常容易就能得出两者的换算公式:
-
-先设圆的周长为C. 半径为r
-
-C = 2πr;
-
-一周对应的角度为360度(角度),对应的弧度为2π弧度。
-
-故: **180度 = π弧度.**
-
-可得:
-
-**弧度 = 角度xπ/180**
-
-**角度 = 弧度x180/π**
-
-
-## 四.一些细节问题
-由于默认屏幕坐标系和常见数学坐标系的小差别([坐标系问题点这里](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B1%5DCoordinateSystem.md)),所以在角上必然也会存在一些区别,例如:
-
-**在常见的数学坐标系中角度增大方向为逆时针,**
-
-**在默认的屏幕坐标系中角度增大方向为顺时针。**
-
-
-
-## About Me
-### 作者微博: @GcsSloop
-
-
-
-
-
diff --git a/CustomView/Base/[3]Color.md b/CustomView/Base/[3]Color.md
deleted file mode 100644
index d27d00f4..00000000
--- a/CustomView/Base/[3]Color.md
+++ /dev/null
@@ -1,159 +0,0 @@
-# 颜色
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-### [【本系列相关文章】](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
-简要介绍安卓中的颜色相关内容,包括颜色的定义,创建颜色的几种方式,以及颜色的混合模式等。
-
-## 一.简单介绍颜色
-
-安卓支持的颜色模式:
-
-颜色模式 | 备注
-:--- | ---
-ARGB8888 | 四通道高精度(32位)
-ARGB4444 | 四通道低精度(16位)
-RGB565 | **屏幕默认模式**(16位)
-Alpha8 | 仅有透明通道(8位)
-
-*PS:其中字母表示通道类型,数值表示该类型用多少位二进制来描述。如ARGB8888则表示有四个通道(ARGB),每个对应的通道均用8位来描述。*
-
-*注意:我们常用的是ARGB8888和ARGB4444,而在所有的安卓设备屏幕上默认的模式都是RGB565,请留意这一点。*
-
-**以ARGB8888为例介绍颜色定义:**
-
-类型 | 解释 | 0(0x00) | 255(0xff)
-:-------- |:------ | :------ | :--------
-A(Alpha) | 透明度 | 透明 | 不透明
-R(Red) | 红色 | 无色 | 红色
-G(Green) | 绿色 | 无色 | 绿色
-B(Blue) | 蓝色 | 无色 | 蓝色
-
-*其中 A R G B 的取值范围均为0~255(即16进制的0x00~0xff)*
-
-A 从ox00到oxff表示从透明到不透明。
-
-RGB 从0x00到0xff表示颜色从浅到深。
-
-**当RGB全取最小值(0或0x000000)时颜色为黑色,全取最大值(255或0xffffff)时颜色为白色**
-
-## 二.几种创建或使用颜色的方式
-### 1.java中定义颜色
-``` java
- int color = Color.GRAY; //灰色
-```
- 由于Color类提供的颜色仅为有限的几个,通常还是用ARGB值进行表示。
-``` java
- int color = Color.argb(127, 255, 0, 0); //半透明红色
-
- int color = 0xaaff0000; //带有透明度的红色
-```
-### 2.在xml文件中定义颜色
-在/res/values/color.xml 文件中如下定义:
-``` xml
-
-
-
-
diff --git a/CustomView/README.md b/CustomView/README.md
deleted file mode 100644
index 485bd509..00000000
--- a/CustomView/README.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# 自定义View系列
-
-从零起步,从入门到懵逼的自定义View教程。
-
-## 基础篇
-
-
-
-*******
-
-## 进阶篇
-
-
-*******
-
-
-
-*******
-
-
-
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-
-
diff --git a/FINDME.md b/FINDME.md
new file mode 100644
index 00000000..83b7a72d
--- /dev/null
+++ b/FINDME.md
@@ -0,0 +1,30 @@
+## GcsSloop
+
+## 个人简介
+
+一名生活在 2.5 次元的魔法师。
+
+座右铭: Just Do IT later !
+
+## 联系我
+你可以通过以下几种方式联系到我。
+
+* [微博私信](http://weibo.com/GcsSloop)
+* [提交Issues](https://github.com/GcsSloop/AndroidNote/issues)
+* 发邮件到: GcsSloop@gmail.com
+
+
+
+
+## 我活动的平台
+
+
+| [微博](http://weibo.com/GcsSloop)
+| [掘金](http://gold.xitu.io/#/user/56dd579a75c4cd4365aca918)
+| [GitHub](https://github.com/GcsSloop)
+| [简书](http://www.jianshu.com/users/bc2fa21dbd1e/latest_articles)
+| [知乎](https://www.zhihu.com/people/li-yu-long-38)
+| [CSDN](http://blog.csdn.net/u013831257?viewmode=list)
+|
+
+
diff --git a/GankDevelopmentNote/chapter_1.md b/GankDevelopmentNote/chapter_1.md
deleted file mode 100644
index f68e6726..00000000
--- a/GankDevelopmentNote/chapter_1.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# Gank开发日志 - 整体规划
-
-## 前言
-
- 一直想找一个免费好用的网络接口做一个完完整整的客户端,然而一直没有找到合适的,直到某天看到代码家干货集中营的开放API,感觉很符合本人口味,于是决定做一个Gank的客户端。
-
- 然而定睛一看,Gank已经有这么多客户端了,而且大部分都做的还不错,让我也是压力山大啊,个人觉得,既然要做,就肯定要做一个和别人不一样的,有特色的,这才有意思嘛,然而带收藏的,纯妹子的,日报型的都有了,思来想去,也没有找到和别人不同的突破点,于是就暂时搁置了,突然某天灵光乍现,作品要体现自己的特色,**自己的特色不就是懒么?所以就做一个最偷工减料的客户端吧**。
-
-### 先预览完成效果,大家猜一下最终用了多少行代码:bangbang:
-
-
-
-
-**嘻嘻,这个大家先慢慢猜,稍后再告诉大家结果,下面开始本篇正文,对项目进行整体规划。**
-
-## 一.需求分析
-
- 在做项目之前,肯定要首先分析一下都需要哪些功能,以免花费大量精力结果实现了一些并没有什么卵用的功能。
-
-### 基本功能
-
-序号 | 功能
-:---:|--------------
- 1 | 展示最新的干货信息
- 2 | **看妹子,看妹子,看妹子!**
- 3 | **保存妹子图片,保存妹子图片,保存妹子图片!**
- 4 | 查看文章详情
- 5 | 可以方便的分享收藏文章
-
-
-### 可以砍掉功能
-
-
-
-我们百万大哥曾说过,**要么砍需求,要么砍需求方**,由于本次需求是我自己提出来了,砍自己容易被当成精神病,所以我决定砍需求。
-
-> **接下来请欣赏我如何为自己的偷懒找理由。**
-
-序号 | 需求 | 理由
-:---:|-----------------------|----------------
- 1 | 展示最新干货信息 | (必备功能,保留)
- 2 | ~~看妹子~~ | (看妹子还要新建显示图片的界面,太麻烦,砍了) 喂喂喂,话说这才是核心功能吧:joy:怎能说砍就砍。(那就交给浏览器干吧)
- 3 | ~~保存妹子~~ | (既然看妹子都交给浏览器干了,那保存妹子自然也是浏览器的活)
- 4 | ~~查看文章详情~~ |(什么?你说要做一个内置的浏览器(WebView)用来看文章?,话说一旦做了内置浏览器,就需要提供分享功能,提供查看保存妹子功能等等......这么繁重的活怎么能自己干,果断抛出去,拜拜啦,万恶的内置浏览器。)
- 5 | ~~方便的分享保存文章~~ | (话说这活不是已经交给其他浏览器干了么?)
-
-**砍需求成功,最终只剩一个需求了,哇哈哈哈哈哈哈~~~~~~~~**
-
-话说这样砍需求会不会影响体验效果?接下来分析一下使用外置浏览器的好处。
-
-序号 | 优点
-:---:|---------
- 1 | 手机默认都有浏览器,所以满足基本需求应该不成问题。
- 2 | 防止内置浏览器(WebView)因兼容性问题导致阅读效果不佳。
- 3 | 如果使用Chrome浏览器,360浏览器等并登陆账号,可以方便将手机收藏同步到电脑,毕竟大部分技术文章在手机端查看效果并不是很好。个人推荐使用Chrome,用Google账号登陆,在文末会提供科学上网软件。
- 4 | 作为本应用和核心功能,看妹子,保存妹子,浏览器都可以很好的完成,甚至你可以在浏览器中搜索图片出处,高清大图以及类似图片(首先,你要有一个Chrome和科学上网软件) 效果见下:point_down:
-
-
-
-
-
-
-
-
-
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 8f71f43f..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright {yyyy} {name of copyright owner}
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
diff --git a/MagicElements/SpiritForest.png b/MagicElements/SpiritForest.png
new file mode 100644
index 00000000..311f8004
Binary files /dev/null and b/MagicElements/SpiritForest.png differ
diff --git a/QuickChart/Bezier.md b/QuickChart/Bezier.md
deleted file mode 100644
index e4adf995..00000000
--- a/QuickChart/Bezier.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# 贝塞尔曲线常用操作速查表
-
-> ### 贝塞尔曲线的操作方法均包含在Path中,详情可参考[Path之贝塞尔曲线](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B6%5DPath_Bessel.md)
-
-> **表格中演示动画均来自维基百科**
-
-贝塞尔曲线 | 对应的方法 | 演示动画
-:-----------------------:|------------|------------------------------------------------------------------------------
- 一阶曲线
(线性曲线) | lineTo | 
- 二阶曲线 | quadTo | 
-三阶曲线 | cubicTo | 
-四阶曲线 | 无 | 
diff --git a/QuickChart/Canvas.md b/QuickChart/Canvas.md
deleted file mode 100644
index 709e5b96..00000000
--- a/QuickChart/Canvas.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# Canvas常用操作速查表
-
-操作分类 | 相关API | 备注
----------|---------|--------------
-绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布
**相关链接:**
[【基础-颜色】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B3%5DColor.md)
[【Canvas-颜色与基本形状】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B2%5DCanvas_BasicGraphics.md)
-绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧
**相关链接 :**
[【Canvas-颜色与基本形状】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B2%5DCanvas_BasicGraphics.md)
-绘制图片 | drawBitmap, drawPicture | 绘制位图和图片
**相关链接:**
[【Canvas-图片文字】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B4%5DCanvas_PictureText.md)
-绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字
**相关链接:**
[【Canvas-图片文字】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B4%5DCanvas_PictureText.md)
-绘制路径 | drawPath | 绘制路径,绘制贝塞尔曲线时也需要用到该函数
**相关链接:**
[【Path-基本操作】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md)
[【Path-贝塞尔曲线】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B6%5DPath_Bezier.md)
[【Path-完结篇(伪)】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B7%5DPath_Over.md)
-顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用
-画布剪裁 | clipPath, clipRect | 设置画布的显示区域
-画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 会滚到指定状态、 获取保存次数
**相关链接:**
[【Canvas-画布操作】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B3%5DCanvas_Convert.md)
-画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、倾斜
**相关链接:**
[【基础-坐标系】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B1%5DCoordinateSystem.md)
[【基础-角度弧度】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B2%5DAngleAndRadian.md)
[【Canvas-画布操作】](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B3%5DCanvas_Convert.md)
-Matrix(矩阵) | getMatrix, setMatrix, concat | 实际画布的位移,缩放等操作的都是图像矩阵Matrix,只不过Matrix比较难以理解和使用,故封装了一些常用的方法。
diff --git a/QuickChart/Matrix.md b/QuickChart/Matrix.md
deleted file mode 100644
index 01bf7cb8..00000000
--- a/QuickChart/Matrix.md
+++ /dev/null
@@ -1 +0,0 @@
-# Matrix常用操作速查表
diff --git a/QuickChart/Path.md b/QuickChart/Path.md
deleted file mode 100644
index 6ed41739..00000000
--- a/QuickChart/Path.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Path常用操作速查表
-
-> 为了兼容性(_偷懒_) 本表格中去除了在API21(即安卓版本5.0)以上才添加的方法。忍不住吐槽一下,为啥看起来有些顺手就能写的重载方法要等到API21才添加上啊。宝宝此刻内心也是崩溃的。
-
-作用 | 相关方法 | 备注
-----------------|-----------------|------------------------------------------
-移动起点 | moveTo | 移动下一次操作的起点位置
-设置终点 | setLastPoint | 重置当前path中最后一个点位置,如果在绘制之前调用,效果和moveTo相同
-连接直线 | lineTo | 添加上一个点到当前点之间的直线到Path
-闭合路径 | close | 连接第一个点连接到最后一个点,形成一个闭合区域
-添加内容 | addRect, addRoundRect, addOval, addCircle, addPath, addArc, arcTo | 添加(矩形, 圆角矩形, 椭圆, 圆, 路径, 圆弧) 到当前Path (注意addArc和arcTo的区别)
-是否为空 | isEmpty | 判断Path是否为空
-是否为矩形 | isRect | 判断path是否是一个矩形
-替换路径 | set | 用新的路径替换到当前路径所有内容
-偏移路径 | offset | 对当前路径之前的操作进行偏移(不会影响之后的操作)
-贝塞尔曲线 | quadTo, cubicTo | 分别为二次和三次贝塞尔曲线的方法
-rXxx方法 | rMoveTo, rLineTo, rQuadTo, rCubicTo | **不带r的方法是基于原点的坐标系(偏移量), rXxx方法是基于当前点坐标系(偏移量)**
-填充模式 | setFillType, getFillType, isInverseFillType, toggleInverseFillType | 设置,获取,判断和切换填充模式
-提示方法 | incReserve | 提示Path还有多少个点等待加入**(这个方法貌似会让Path优化存储结构)**
-布尔操作(API19) | op | 对两个Path进行布尔运算(即取交集、并集等操作)
-计算边界 | computeBounds | 计算Path的边界
-重置路径 | reset, rewind | 清除Path中的内容
**reset不保留内部数据结构,但会保留FillType.**
**rewind会保留内部的数据结构,但不保留FillType**
-矩阵操作 | transform | 矩阵变换
-
-## 相关文章
-
-* [Path基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md)
-* [贝塞尔曲线](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B6%5DPath_Bezier.md)
-* [Path完结篇(伪)](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B7%5DPath_Over.md)
-* [Path玩出花样](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B8%5DPath_Play.md)
-
diff --git a/QuickChart/README.md b/QuickChart/README.md
deleted file mode 100644
index 77d6afb4..00000000
--- a/QuickChart/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# 速查表
-
-序号 | 内容
-:---:|---------------
- 01 | [Canvas常用操作速查表](https://github.com/GcsSloop/AndroidNote/blob/master/QuickChart/Canvas.md)
- 02 | [Path常用操作速查表](https://github.com/GcsSloop/AndroidNote/blob/master/QuickChart/Path.md)
- 03 | [贝塞尔曲线常用操作速查表](https://github.com/GcsSloop/AndroidNote/blob/master/QuickChart/Bezier.md)
diff --git a/README.md b/README.md
index 4c354d0d..15ee79b3 100644
--- a/README.md
+++ b/README.md
@@ -1,59 +1,22 @@
-# AndroidNote
-### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-
-我的安卓学习笔记,记录学习过程中遇到的问题,以及我发布的安卓相关文章。
-
-如果出现链接失效等情况可以提交Issues提醒我修改相关内容。
-
-> #### PS:点击分类标题可以查看该分类的详细信息。
-
-## [自定义View系列](https://github.com/GcsSloop/AndroidNote/tree/master/CustomView)
-
- 序号 | 内容
-:----:|---------
- 01 | [安卓自定义View基础 - 坐标系](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B1%5DCoordinateSystem.md)
- 02 | [安卓自定义View基础 - 角度弧度](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B2%5DAngleAndRadian.md)
- 03 | [安卓自定义View基础 - 颜色](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Base/%5B3%5DColor.md)
- 04 | [安卓自定义View进阶 - 分类和流程](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B1%5DCustomViewProcess.md)
- 05 | [安卓自定义View进阶 - 绘制基本图形](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B2%5DCanvas_BasicGraphics.md)
- 06 | [安卓自定义View进阶 - 画布操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B3%5DCanvas_Convert.md)
- 07 | [安卓自定义View进阶 - 图片文字](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B4%5DCanvas_PictureText.md)
- 08 | [安卓自定义View进阶 - Path基本操作](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B5%5DPath_Basic.md)
- 09 | [安卓自定义View进阶 - 贝塞尔曲线](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B6%5DPath_Bezier.md)
- 10 | [安卓自定义View进阶 - Path完结篇(伪)](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B7%5DPath_Over.md)
- 11 | [安卓自定义View进阶 - Path玩出花样](https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B8%5DPath_Play.md)
-
-
-******
+# 魔法世界
-## [教程类](https://github.com/GcsSloop/AndroidNote/tree/master/Course)
+
-序号 | 内容
-:---:|--------
- 01 | [在AndroidStudio中使用PlantUML](https://github.com/GcsSloop/AndroidNote/blob/master/Course/HowToUsePlantUMLInAS.md)
- 02 | [优雅的发布Android开源库(论JitPack的优越性)](https://github.com/GcsSloop/AndroidNote/blob/master/Course/ReleaseLibraryByJitPack.md)
+欢迎突破重重阻隔来到这里,来到这个与由混沌和魔法构成的神奇世界,在这里,你可以通过与自然的交流来感受这个世界的奥秘。
-******
-
-## [速查表](https://github.com/GcsSloop/AndroidNote/tree/master/QuickChart)
+## 传送门
-序号 | 内容
-:---:|---------------
- 01 | [Canvas常用操作速查表](https://github.com/GcsSloop/AndroidNote/blob/master/QuickChart/Canvas.md)
- 02 | [Path常用操作速查表](https://github.com/GcsSloop/AndroidNote/blob/master/QuickChart/Path.md)
- 03 | [贝塞尔曲线常用操作速查表](https://github.com/GcsSloop/AndroidNote/blob/master/QuickChart/Bezier.md)
+通往现界的传送门,请谨慎使用。
-## [混沌水晶](https://github.com/GcsSloop/AndroidNote/tree/master/ChaosCrystal)
+[](https://github.com/GcsSloop/AndroidNote/tree/master)
-序号 | 内容
-:---:|---------------
- 01 | [在线查看Android API源码](https://github.com/GcsSloop/AndroidNote/blob/master/ChaosCrystal/HowToViewAPISourceOnline.md)
+## 关于我
-## About Me
+一个生活在 2.5 次元的魔法师
### 作者微博: [@GcsSloop](http://weibo.com/GcsSloop)
-
+
diff --git a/WorldRule/Activity/ActivityDestroy.md b/WorldRule/Activity/ActivityDestroy.md
new file mode 100644
index 00000000..0cf064dd
--- /dev/null
+++ b/WorldRule/Activity/ActivityDestroy.md
@@ -0,0 +1,45 @@
+# Activity结束情况
+
+## 1.正常结束
+
+应用程序退出或者调用`finish()`方法正常结束的Activity。
+
+## 2.系统配置改变导致Activity被销毁并重建
+
+如手机旋转屏幕,弹出键盘等导致Activity销毁并重建。
+
+如果想避免这种情况,可以在`AndroidManifest.xml`文件中为Activity进行配置,如下:
+
+```
+
+
+
+******
+
+## Tip
+
+#### 1.不要在`onPause()`中执行耗时操作,耗时操作尽量放在`onStop()`中执行。
+
+#### 2.异常终止会在`onStop()`之前调用`onSaveInstanceState()`方法,用于保存Activity数据,数据存储在Bundle对象中。
+
+#### 3.异常终止的Activity重新启动后会调用`onRestoreInstanceState()`方法来获取存储在Bundle对象中的数据(你也可以在`onCreate()`中获取到这个Bundle对象)。
+
+#### 4.View也有对应的`onSaveInstanceState()`和`onRestoreInstanceState()`来保存和回复View状态,和Activity类似。
+
+#### 5.异常状态下Activity重建流程
+
+
+
+
+
+
+
+ 方法 描述 允许被杀死? 接下来的方法
+
+
+ onCreate()
当Activity第一次被创建时调用.
+ 在这里进行初始化工作: 创建view, 为list绑定数据 等。
+
+ 如果Activity被杀死后重新初始化,你可以在savedInstanceState中得到被杀死之前 的某些状态信息。不允许
+
+ onStart()
+
+
+
+ onRestart()
当Activity切换到后台再切换回来时会被调用。
+ 不允许
+
+ onStart()
+
+
+ onStart()
当Activity对用户可见时调用。
+ 如果Activity进入前台则接下来调用
+ onResume()
如果Activity被隐藏则接下来调用onStop()
不允许
+
+ onResume()
或者
onStop()
+
+
+
+ onResume()
当Activity可以与用户交互时调用.此时当前Activity处于Activity栈的顶端。
+ 不允许
+
+ onPause()
+
+
+ onPause()
当启动一个新的界面时调用,表示当前Activity正在停止。
+ 可以在这个方法中保存一些数据,停止动画和一些其他操作,可能会占用大量CPU。不能在这个方法中执行耗时操作,因为只有这个方法执行后才会执行新Activity的
+ onResume()
。
如果快速返回当前Activity则会执行onResume()
,如果新Activity启动完成则接着执行onStop()
+ HONEYCOMB
之前
+ onResume()
或者
+ onStop()
+
+
+ onStop()
当Activity对用户不可见时调用,此时新的Activity已经启动完成并遮挡了该界面。
+
+ onRestart()
, 或者被销毁调用onDestroy()
。允许
+
+ onRestart()
或者
+ onDestroy()
+
+
+ onDestroy()
Activity被销毁时调用的最后一个函数. 可能是因为
+ finish()
方法被调用,或者是系统回收资源释放空间。你可以用 isFinishing()
方法用于区分是哪种情况。
可以在这个方法中进行最后的回收工作与资源释放。允许
+ 无
+
\ No newline at end of file
diff --git a/WorldRule/Activity/elements/abnormal_destory_and_restart.png b/WorldRule/Activity/elements/abnormal_destory_and_restart.png
new file mode 100644
index 00000000..8c768516
Binary files /dev/null and b/WorldRule/Activity/elements/abnormal_destory_and_restart.png differ
diff --git a/WorldRule/Activity/elements/activity_lifecycle.mdj b/WorldRule/Activity/elements/activity_lifecycle.mdj
new file mode 100644
index 00000000..5147a5af
--- /dev/null
+++ b/WorldRule/Activity/elements/activity_lifecycle.mdj
@@ -0,0 +1,3067 @@
+{
+ "_type": "Project",
+ "_id": "AAAAAAFF+h6SjaM2Hec=",
+ "name": "Activity生命周期",
+ "ownedElements": [
+ {
+ "_type": "FCFlowchart",
+ "_id": "AAAAAAFWaS4V4OkFxiQ=",
+ "_parent": {
+ "$ref": "AAAAAAFF+h6SjaM2Hec="
+ },
+ "name": "RestartActivity",
+ "ownedElements": [
+ {
+ "_type": "FCFlowchartDiagram",
+ "_id": "AAAAAAFWaS4V4OkGQRw=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkFxiQ="
+ },
+ "name": "abnormal_destory_and_restart",
+ "visible": true,
+ "defaultDiagram": false,
+ "ownedViews": [
+ {
+ "_type": "FCTerminatorView",
+ "_id": "AAAAAAFWaS9BCukR+LA=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaS9BCukP5N8="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFWaS9BCukSQZQ=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS9BCukR+LA="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#7fff00",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 178,
+ "top": 122,
+ "width": 77,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "Activity",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#7fff00",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 168,
+ "top": 112,
+ "width": 97,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFWaS9BCukSQZQ="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCTerminatorView",
+ "_id": "AAAAAAFWaS+50+konVs=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaS+50ukmrAI="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFWaS+50+kpINU=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS+50+konVs="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#7fff00",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 562,
+ "top": 122,
+ "width": 77,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "Activity",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#7fff00",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 552,
+ "top": 112,
+ "width": 97,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFWaS+50+kpINU="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFWaTAKVekzfPA=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTAKVOkxi/0="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFWaTAKVek0A6E=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTAKVekzfPA="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 146,
+ "top": 202,
+ "width": 141,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onSaveInstanceState()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 136,
+ "top": 192,
+ "width": 161,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTAKVek0A6E="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFWaTBu0ek+Ogo=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTBu0ek8izs="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFWaTBu0ek/0ug=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTBu0ek+Ogo="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 570,
+ "top": 202,
+ "width": 60,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onCreate()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 560,
+ "top": 192,
+ "width": 80,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTBu0ek/0ug="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFWaTC0LelHCDA=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTC0LOlFOek="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFWaTC0LelInBM=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTC0LelHCDA="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 178,
+ "top": 282,
+ "width": 77,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onDestroy()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 168,
+ "top": 272,
+ "width": 97,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTC0LelInBM="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCDataView",
+ "_id": "AAAAAAFWaTHfEOlRG8E=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTHfEOlPtls="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFWaTHfEelSLC4=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTHfEOlRG8E="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#cc9900",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 412,
+ "top": 202,
+ "width": 25,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "Bundle",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#cc9900",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 392,
+ "top": 192,
+ "width": 65,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTHfEelSLC4="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFWaTLyrOlrtA4=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTLyrOlpxc4="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFWaTLyrOlsMfc=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTLyrOlrtA4="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 530,
+ "top": 282,
+ "width": 148,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onRestoreInstanceState()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 520,
+ "top": 272,
+ "width": 168,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTLyrOlsMfc="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFWaTTRUemIaaI=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTTRUOmGvJY="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFWaTTRUumJCMk=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTTRUemIaaI="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTTRUOmGvJY="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 223,
+ "top": 161,
+ "width": 52,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.601089660872696,
+ "distance": 33.015148038438355,
+ "hostEdge": {
+ "$ref": "AAAAAAFWaTTRUemIaaI="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "异常情况",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFWaTAKVekzfPA="
+ },
+ "tail": {
+ "$ref": "AAAAAAFWaS9BCukR+LA="
+ },
+ "lineStyle": 2,
+ "points": "216:144;216:192",
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTTRUumJCMk="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFWaTYTfumk4XI=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTYTfemiqpA="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFWaTYTf+mlREw=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTYTfumk4XI="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTYTfemiqpA="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 614,
+ "top": 241,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFWaTYTfumk4XI="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFWaTLyrOlrtA4="
+ },
+ "tail": {
+ "$ref": "AAAAAAFWaTBu0ek+Ogo="
+ },
+ "lineStyle": 2,
+ "points": "600:224;600:272",
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTYTf+mlREw="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFWaTZiAemv/Ac=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTZiAOmtDjs="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFWaTZiAemwpcI=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTZiAemv/Ac="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTZiAOmtDjs="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 614,
+ "top": 161,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFWaTZiAemv/Ac="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFWaTBu0ek+Ogo="
+ },
+ "tail": {
+ "$ref": "AAAAAAFWaS+50+konVs="
+ },
+ "lineStyle": 2,
+ "points": "600:144;600:192",
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTZiAemwpcI="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFWaTeyeOnI2Pk=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTeyd+nG4gY="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFWaTeyeenJabg=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTeyeOnI2Pk="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTeyd+nG4gY="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 305,
+ "top": 187,
+ "width": 78,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFWaTeyeOnI2Pk="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "存储状态信息",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFWaTHfEOlRG8E="
+ },
+ "tail": {
+ "$ref": "AAAAAAFWaTAKVekzfPA="
+ },
+ "lineStyle": 2,
+ "points": "296:208;392:208",
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTeyeenJabg="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFWaTf61unTVm4=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTf61unRsUI="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFWaTf61unUZOI=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTf61unTVm4="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTf61unRsUI="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 463,
+ "top": 186,
+ "width": 78,
+ "height": 13,
+ "autoResize": false,
+ "alpha": -4.331883177985101,
+ "distance": 16.15549442140351,
+ "hostEdge": {
+ "$ref": "AAAAAAFWaTf61unTVm4="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "获取状态信息",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFWaTBu0ek+Ogo="
+ },
+ "tail": {
+ "$ref": "AAAAAAFWaTHfEOlRG8E="
+ },
+ "lineStyle": 2,
+ "points": "456:208;560:208",
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTf61unUZOI="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFWaTiJjenkbaQ=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTiJjOniQnc="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFWaTiJjenlIPY=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTiJjenkbaQ="
+ },
+ "model": {
+ "$ref": "AAAAAAFWaTiJjOniQnc="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 230,
+ "top": 241,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFWaTiJjenkbaQ="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFWaTC0LelHCDA="
+ },
+ "tail": {
+ "$ref": "AAAAAAFWaTAKVekzfPA="
+ },
+ "lineStyle": 2,
+ "points": "216:224;216:272",
+ "nameLabel": {
+ "$ref": "AAAAAAFWaTiJjenlIPY="
+ }
+ },
+ {
+ "_type": "UMLNoteLinkView",
+ "_id": "AAAAAAFWaTjmLensuB0=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFWaTBu0ek+Ogo="
+ },
+ "tail": {
+ "$ref": "AAAAAAFWaTAKVekzfPA="
+ },
+ "lineStyle": 1,
+ "points": "233:225;248:240;584:240;591:225"
+ },
+ {
+ "_type": "UMLTextView",
+ "_id": "AAAAAAFWaTmhDun2KP4=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkGQRw="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 392,
+ "top": 248,
+ "width": 62,
+ "height": 25,
+ "autoResize": false,
+ "text": "重新创建",
+ "wordWrap": true
+ }
+ ]
+ },
+ {
+ "_type": "FCTerminator",
+ "_id": "AAAAAAFWaS9BCukP5N8=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkFxiQ="
+ },
+ "name": "Activity",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFWaTTRUOmGvJY=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS9BCukP5N8="
+ },
+ "name": "异常情况",
+ "source": {
+ "$ref": "AAAAAAFWaS9BCukP5N8="
+ },
+ "target": {
+ "$ref": "AAAAAAFWaTAKVOkxi/0="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCTerminator",
+ "_id": "AAAAAAFWaS+50ukmrAI=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkFxiQ="
+ },
+ "name": "Activity",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFWaTZiAOmtDjs=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS+50ukmrAI="
+ },
+ "source": {
+ "$ref": "AAAAAAFWaS+50ukmrAI="
+ },
+ "target": {
+ "$ref": "AAAAAAFWaTBu0ek8izs="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFWaTAKVOkxi/0=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkFxiQ="
+ },
+ "name": "onSaveInstanceState()",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFWaTeyd+nG4gY=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTAKVOkxi/0="
+ },
+ "name": "存储状态信息",
+ "source": {
+ "$ref": "AAAAAAFWaTAKVOkxi/0="
+ },
+ "target": {
+ "$ref": "AAAAAAFWaTHfEOlPtls="
+ }
+ },
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFWaTiJjOniQnc=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTAKVOkxi/0="
+ },
+ "source": {
+ "$ref": "AAAAAAFWaTAKVOkxi/0="
+ },
+ "target": {
+ "$ref": "AAAAAAFWaTC0LOlFOek="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFWaTBu0ek8izs=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkFxiQ="
+ },
+ "name": "onCreate()",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFWaTYTfemiqpA=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTBu0ek8izs="
+ },
+ "source": {
+ "$ref": "AAAAAAFWaTBu0ek8izs="
+ },
+ "target": {
+ "$ref": "AAAAAAFWaTLyrOlpxc4="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFWaTC0LOlFOek=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkFxiQ="
+ },
+ "name": "onDestroy()"
+ },
+ {
+ "_type": "FCData",
+ "_id": "AAAAAAFWaTHfEOlPtls=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkFxiQ="
+ },
+ "name": "Bundle",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFWaTf61unRsUI=",
+ "_parent": {
+ "$ref": "AAAAAAFWaTHfEOlPtls="
+ },
+ "name": "获取状态信息",
+ "source": {
+ "$ref": "AAAAAAFWaTHfEOlPtls="
+ },
+ "target": {
+ "$ref": "AAAAAAFWaTBu0ek8izs="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFWaTLyrOlpxc4=",
+ "_parent": {
+ "$ref": "AAAAAAFWaS4V4OkFxiQ="
+ },
+ "name": "onRestoreInstanceState()"
+ }
+ ]
+ },
+ {
+ "_type": "FCFlowchart",
+ "_id": "AAAAAAFV/v9xvvL0FXk=",
+ "_parent": {
+ "$ref": "AAAAAAFF+h6SjaM2Hec="
+ },
+ "name": "Lifecycle",
+ "ownedElements": [
+ {
+ "_type": "FCFlowchartDiagram",
+ "_id": "AAAAAAFV/v9xv/L17pM=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "activity_lifecycle",
+ "visible": true,
+ "defaultDiagram": false,
+ "ownedViews": [
+ {
+ "_type": "FCTerminatorView",
+ "_id": "AAAAAAFV/wEVAPMUVu0=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/wEVAPMSpYw="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/wEVAPMV29g=",
+ "_parent": {
+ "$ref": "AAAAAAFV/wEVAPMUVu0="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#95c3fa",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 378,
+ "top": 74,
+ "width": 77,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "Activity启动",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#95c3fa",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 368,
+ "top": 64,
+ "width": 97,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/wEVAPMV29g="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFV/whfb/MwBjE=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/whfb/MuyM0="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/whfb/MxNaU=",
+ "_parent": {
+ "$ref": "AAAAAAFV/whfb/MwBjE="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 370,
+ "top": 146,
+ "width": 93,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onCreate()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 360,
+ "top": 136,
+ "width": 113,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/whfb/MxNaU="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFV/wjBG/M84eE=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/wjBGvM6PhI="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/wjBG/M9Muk=",
+ "_parent": {
+ "$ref": "AAAAAAFV/wjBG/M84eE="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 370,
+ "top": 218,
+ "width": 93,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onStart()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 360,
+ "top": 208,
+ "width": 113,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/wjBG/M9Muk="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFV/wkag/NGWlQ=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/wkag/NEqWQ="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/wkag/NHya4=",
+ "_parent": {
+ "$ref": "AAAAAAFV/wkag/NGWlQ="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 370,
+ "top": 362,
+ "width": 93,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onResume()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 360,
+ "top": 352,
+ "width": 113,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/wkag/NHya4="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCDecisionView",
+ "_id": "AAAAAAFV/wylhfNQ+sk=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/wylhfNODho="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/wylhfNR90U=",
+ "_parent": {
+ "$ref": "AAAAAAFV/wylhfNQ+sk="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#a3ffd1",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 388.25,
+ "top": 287.5,
+ "width": 56.5,
+ "height": 15,
+ "autoResize": false,
+ "underline": false,
+ "text": "进入前台",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#a3ffd1",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 360,
+ "top": 280,
+ "width": 113,
+ "height": 30,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/wylhfNR90U="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xFSXvNz50w=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xFSXfNxjlM="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xFSX/N0xIw=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xFSXvNz50w="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xFSXfNxjlM="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 427,
+ "top": 109,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xFSXvNz50w="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/whfb/MwBjE="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/wEVAPMUVu0="
+ },
+ "lineStyle": 2,
+ "points": "413:96;413:136",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xFSX/N0xIw="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xFpY/N8M74=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xFpYfN6Xco="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xFpZPN9gHY=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xFpY/N8M74="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xFpYfN6Xco="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 430,
+ "top": 181,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xFpY/N8M74="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/wjBG/M84eE="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/whfb/MwBjE="
+ },
+ "lineStyle": 2,
+ "points": "416:168;416:208",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xFpZPN9gHY="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xF3ifOFA3c=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xF3iPODvko="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xF3ifOGifs=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xF3ifOFA3c="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xF3iPODvko="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 429,
+ "top": 253,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xF3ifOFA3c="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/wylhfNQ+sk="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/wjBG/M84eE="
+ },
+ "lineStyle": 2,
+ "points": "415:240;415:280",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xF3ifOGifs="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xGKWfOOKJw=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xGKWPOMvNM="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xGKWfOPvwI=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xGKWfOOKJw="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xGKWPOMvNM="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 424,
+ "top": 323,
+ "width": 13,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xGKWfOOKJw="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "是",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/wkag/NGWlQ="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/wylhfNQ+sk="
+ },
+ "lineStyle": 2,
+ "points": "416:309;416:352",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xGKWfOPvwI="
+ }
+ },
+ {
+ "_type": "FCTerminatorView",
+ "_id": "AAAAAAFV/xKSkfOi2Rc=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xKSkfOg2kY="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/xKSkvOjsYU=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xKSkfOi2Rc="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#bdda66",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 378,
+ "top": 434,
+ "width": 77,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "Activity运行",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#bdda66",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 368,
+ "top": 424,
+ "width": 97,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xKSkvOjsYU="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xPczvOvRm0=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xPczfOt+zM="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xPczvOwExU=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xPczvOvRm0="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xPczfOt+zM="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 430,
+ "top": 397,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xPczvOvRm0="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/xKSkfOi2Rc="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/wkag/NGWlQ="
+ },
+ "lineStyle": 2,
+ "points": "416:384;416:424",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xPczvOwExU="
+ }
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFV/xWnRfPFd2c=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xWnRfPDRk8="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/xWnRvPGABQ=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xWnRfPFd2c="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 370,
+ "top": 522,
+ "width": 93,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onPause()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 360,
+ "top": 512,
+ "width": 113,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xWnRvPGABQ="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xX+VPPQMmw=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xX+U/POMMc="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xX+VPPRQ4k=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xX+VPPQMmw="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xX+U/POMMc="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#a43333",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 376,
+ "top": 475,
+ "width": 83,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 2.8198386825294843,
+ "distance": 3.1622776601683795,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xX+VPPQMmw="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "新Activity启动",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/xWnRfPFd2c="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/xKSkfOi2Rc="
+ },
+ "lineStyle": 2,
+ "points": "416:456;416:512",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xX+VPPRQ4k="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xfWpfPmlIs=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xfWpPPk2g4="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xfWpfPn/rA=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xfWpfPmlIs="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xfWpPPk2g4="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 472,
+ "top": 488,
+ "width": 109,
+ "height": 13,
+ "autoResize": false,
+ "alpha": -3.185043193111301,
+ "distance": 46.04345773288535,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xfWpfPmlIs="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "用户返回原Activity",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/wkag/NGWlQ="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/xWnRfPFd2c="
+ },
+ "lineStyle": 2,
+ "points": "472:528;528:528;528:368;472:368",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xfWpfPn/rA="
+ }
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFV/xjyNPP5ulo=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xjyNPP3rY8="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/xjyNfP6wfo=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xjyNPP5ulo="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 370,
+ "top": 610,
+ "width": 93,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onStop()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 360,
+ "top": 600,
+ "width": 113,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xjyNfP6wfo="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xlDJPQFmD8=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xlDI/QDGmE="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xlDJPQGLSk=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xlDJPQFmD8="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xlDI/QDGmE="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 376,
+ "top": 564,
+ "width": 83,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 2.6779406279303206,
+ "distance": 2.23606797749979,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xlDJPQFmD8="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "Activity不可见",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/xjyNPP5ulo="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/xWnRfPFd2c="
+ },
+ "lineStyle": 2,
+ "points": "416:544;416:600",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xlDJPQGLSk="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xrwjPQSqgY=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xrwjPQQqP4="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xrwjfQTRjQ=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xrwjPQSqgY="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xrwjPQQqP4="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 488,
+ "top": 271,
+ "width": 13,
+ "height": 13,
+ "autoResize": false,
+ "alpha": -2.6261896112278977,
+ "distance": 198.82907232092595,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xrwjPQSqgY="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "否",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/xjyNPP5ulo="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/wylhfNQ+sk="
+ },
+ "lineStyle": 2,
+ "points": "472:294;592:294;592:608;472:608",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xrwjfQTRjQ="
+ }
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFV/xw6GvQjUcs=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xw6GfQhmjc="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/xw6GvQkfb8=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xw6GvQjUcs="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 594,
+ "top": 218,
+ "width": 93,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onRestart()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 584,
+ "top": 208,
+ "width": 113,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xw6GvQkfb8="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/xz3QfQw+8E=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xz3PvQuya0="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/xz3QvQxF4k=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xz3QfQw+8E="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/xz3PvQuya0="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 600,
+ "top": 592,
+ "width": 109,
+ "height": 13,
+ "autoResize": false,
+ "alpha": -0.4939416393068934,
+ "distance": 29.5296461204668,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/xz3QfQw+8E="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "用户返回原Activity",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/xw6GvQjUcs="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/xjyNPP5ulo="
+ },
+ "lineStyle": 2,
+ "points": "472:624;640:624;640:240",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/xz3QvQxF4k="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/x2fIvRAXSo=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/x2fIfQ+0EI="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/x2fIvRBCN0=",
+ "_parent": {
+ "$ref": "AAAAAAFV/x2fIvRAXSo="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/x2fIfQ+0EI="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 527,
+ "top": 233,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/x2fIvRAXSo="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/wjBG/M84eE="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/xw6GvQjUcs="
+ },
+ "lineStyle": 2,
+ "points": "584:224;472:224",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/x2fIvRBCN0="
+ }
+ },
+ {
+ "_type": "FCProcessView",
+ "_id": "AAAAAAFV/x32VvRJTnk=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/x32VvRH25Y="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/x32VvRKh2w=",
+ "_parent": {
+ "$ref": "AAAAAAFV/x32VvRJTnk="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 370,
+ "top": 698,
+ "width": 93,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "onDestory()",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 360,
+ "top": 688,
+ "width": 113,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/x32VvRKh2w="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/x6dUPRX3lk=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/x6dT/RV9Ok="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/x6dUPRYHHc=",
+ "_parent": {
+ "$ref": "AAAAAAFV/x6dUPRX3lk="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/x6dT/RV9Ok="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 319,
+ "top": 652,
+ "width": 186,
+ "height": 13,
+ "autoResize": false,
+ "alpha": -1.8157758906584387,
+ "distance": 4.123105625617661,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/x6dUPRX3lk="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "Activity 正在停止 或 即将被销毁",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/x32VvRJTnk="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/xjyNPP5ulo="
+ },
+ "lineStyle": 2,
+ "points": "416:632;416:688",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/x6dUPRYHHc="
+ }
+ },
+ {
+ "_type": "FCTerminatorView",
+ "_id": "AAAAAAFV/x9Z8/RjHgw=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/x9Z8/RhJts="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/x9Z8/Rk4V8=",
+ "_parent": {
+ "$ref": "AAAAAAFV/x9Z8/RjHgw="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffa874",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 378,
+ "top": 770,
+ "width": 77,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "Activity销毁",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffa874",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 368,
+ "top": 760,
+ "width": 97,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/x9Z8/Rk4V8="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/yBC1vRv6WU=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/yBC1fRtKU8="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/yBC1vRwoLE=",
+ "_parent": {
+ "$ref": "AAAAAAFV/yBC1vRv6WU="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/yBC1fRtKU8="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 430,
+ "top": 733,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/yBC1vRv6WU="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/x9Z8/RjHgw="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/x32VvRJTnk="
+ },
+ "lineStyle": 2,
+ "points": "416:720;416:760",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/yBC1vRwoLE="
+ }
+ },
+ {
+ "_type": "FCTerminatorView",
+ "_id": "AAAAAAFV/yDnHvR4DQ0=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/yDnHfR2MMU="
+ },
+ "subViews": [
+ {
+ "_type": "LabelView",
+ "_id": "AAAAAAFV/yDnHvR5pXM=",
+ "_parent": {
+ "$ref": "AAAAAAFV/yDnHvR4DQ0="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffa874",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 202,
+ "top": 426,
+ "width": 77,
+ "height": 13,
+ "autoResize": false,
+ "underline": false,
+ "text": "应用被杀死",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffa874",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 192,
+ "top": 416,
+ "width": 97,
+ "height": 33,
+ "autoResize": false,
+ "nameLabel": {
+ "$ref": "AAAAAAFV/yDnHvR5pXM="
+ },
+ "wordWrap": true
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/yGJjvSEDqM=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/yGJjfSCCDo="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/yGJj/SF3HY=",
+ "_parent": {
+ "$ref": "AAAAAAFV/yGJjvSEDqM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/yGJjfSCCDo="
+ },
+ "visible": false,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 225,
+ "top": 601,
+ "width": 0,
+ "height": 13,
+ "autoResize": false,
+ "alpha": 1.5707963267948966,
+ "distance": 15,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/yGJjvSEDqM="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/yDnHvR4DQ0="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/xjyNPP5ulo="
+ },
+ "lineStyle": 2,
+ "points": "360:608;240:608;240:448",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/yGJj/SF3HY="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/yGylvSPTYQ=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/yGylfSNGiY="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/yGylvSQH2U=",
+ "_parent": {
+ "$ref": "AAAAAAFV/yGylvSPTYQ="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/yGylfSNGiY="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 175,
+ "top": 496,
+ "width": 130,
+ "height": 13,
+ "autoResize": false,
+ "alpha": -1.7628205140063358e-7,
+ "distance": 26,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/yGylvSPTYQ="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "高优先级应用需要内存",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/yDnHvR4DQ0="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/xWnRfPFd2c="
+ },
+ "lineStyle": 2,
+ "points": "360:528;240:528;240:448",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/yGylvSQH2U="
+ }
+ },
+ {
+ "_type": "FCFlowView",
+ "_id": "AAAAAAFV/yJm2fSdBSE=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xv/L17pM="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/yJm2PSbHa0="
+ },
+ "subViews": [
+ {
+ "_type": "EdgeLabelView",
+ "_id": "AAAAAAFV/yJm2vSeOnI=",
+ "_parent": {
+ "$ref": "AAAAAAFV/yJm2fSdBSE="
+ },
+ "model": {
+ "$ref": "AAAAAAFV/yJm2PSbHa0="
+ },
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "left": 186,
+ "top": 279,
+ "width": 109,
+ "height": 13,
+ "autoResize": false,
+ "alpha": -1.570796252168031,
+ "distance": 134,
+ "hostEdge": {
+ "$ref": "AAAAAAFV/yJm2fSdBSE="
+ },
+ "edgePosition": 1,
+ "underline": false,
+ "text": "用户返回原Activity",
+ "horizontalAlignment": 2,
+ "verticalAlignment": 5
+ }
+ ],
+ "visible": true,
+ "enabled": true,
+ "lineColor": "#000000",
+ "fillColor": "#ffffff",
+ "fontColor": "#000000",
+ "font": "Arial;13;0",
+ "showShadow": true,
+ "containerChangeable": false,
+ "containerExtending": false,
+ "head": {
+ "$ref": "AAAAAAFV/whfb/MwBjE="
+ },
+ "tail": {
+ "$ref": "AAAAAAFV/yDnHvR4DQ0="
+ },
+ "lineStyle": 2,
+ "points": "240:416;240:152;360:152",
+ "nameLabel": {
+ "$ref": "AAAAAAFV/yJm2vSeOnI="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCTerminator",
+ "_id": "AAAAAAFV/wEVAPMSpYw=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "Activity启动",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xFSXfNxjlM=",
+ "_parent": {
+ "$ref": "AAAAAAFV/wEVAPMSpYw="
+ },
+ "source": {
+ "$ref": "AAAAAAFV/wEVAPMSpYw="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/whfb/MuyM0="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFV/whfb/MuyM0=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "onCreate()",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xFpYfN6Xco=",
+ "_parent": {
+ "$ref": "AAAAAAFV/whfb/MuyM0="
+ },
+ "source": {
+ "$ref": "AAAAAAFV/whfb/MuyM0="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/wjBGvM6PhI="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFV/wjBGvM6PhI=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "onStart()",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xF3iPODvko=",
+ "_parent": {
+ "$ref": "AAAAAAFV/wjBGvM6PhI="
+ },
+ "source": {
+ "$ref": "AAAAAAFV/wjBGvM6PhI="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/wylhfNODho="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFV/wkag/NEqWQ=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "onResume()",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xPczfOt+zM=",
+ "_parent": {
+ "$ref": "AAAAAAFV/wkag/NEqWQ="
+ },
+ "source": {
+ "$ref": "AAAAAAFV/wkag/NEqWQ="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/xKSkfOg2kY="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCDecision",
+ "_id": "AAAAAAFV/wylhfNODho=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "进入前台",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xGKWPOMvNM=",
+ "_parent": {
+ "$ref": "AAAAAAFV/wylhfNODho="
+ },
+ "name": "是",
+ "source": {
+ "$ref": "AAAAAAFV/wylhfNODho="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/wkag/NEqWQ="
+ }
+ },
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xrwjPQQqP4=",
+ "_parent": {
+ "$ref": "AAAAAAFV/wylhfNODho="
+ },
+ "name": "否",
+ "source": {
+ "$ref": "AAAAAAFV/wylhfNODho="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/xjyNPP3rY8="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCTerminator",
+ "_id": "AAAAAAFV/xKSkfOg2kY=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "Activity运行",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xX+U/POMMc=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xKSkfOg2kY="
+ },
+ "name": "新Activity启动",
+ "source": {
+ "$ref": "AAAAAAFV/xKSkfOg2kY="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/xWnRfPDRk8="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFV/xWnRfPDRk8=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "onPause()",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xfWpPPk2g4=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xWnRfPDRk8="
+ },
+ "name": "用户返回原Activity",
+ "source": {
+ "$ref": "AAAAAAFV/xWnRfPDRk8="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/wkag/NEqWQ="
+ }
+ },
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xlDI/QDGmE=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xWnRfPDRk8="
+ },
+ "name": "Activity不可见",
+ "source": {
+ "$ref": "AAAAAAFV/xWnRfPDRk8="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/xjyNPP3rY8="
+ }
+ },
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/yGylfSNGiY=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xWnRfPDRk8="
+ },
+ "name": "高优先级应用需要内存",
+ "source": {
+ "$ref": "AAAAAAFV/xWnRfPDRk8="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/yDnHfR2MMU="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFV/xjyNPP3rY8=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "onStop()",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/xz3PvQuya0=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xjyNPP3rY8="
+ },
+ "name": "用户返回原Activity",
+ "source": {
+ "$ref": "AAAAAAFV/xjyNPP3rY8="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/xw6GfQhmjc="
+ }
+ },
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/x6dT/RV9Ok=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xjyNPP3rY8="
+ },
+ "name": "Activity 正在停止 或 即将被销毁",
+ "source": {
+ "$ref": "AAAAAAFV/xjyNPP3rY8="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/x32VvRH25Y="
+ }
+ },
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/yGJjfSCCDo=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xjyNPP3rY8="
+ },
+ "source": {
+ "$ref": "AAAAAAFV/xjyNPP3rY8="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/yDnHfR2MMU="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFV/xw6GfQhmjc=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "onRestart()",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/x2fIfQ+0EI=",
+ "_parent": {
+ "$ref": "AAAAAAFV/xw6GfQhmjc="
+ },
+ "source": {
+ "$ref": "AAAAAAFV/xw6GfQhmjc="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/wjBGvM6PhI="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCProcess",
+ "_id": "AAAAAAFV/x32VvRH25Y=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "onDestory()",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/yBC1fRtKU8=",
+ "_parent": {
+ "$ref": "AAAAAAFV/x32VvRH25Y="
+ },
+ "source": {
+ "$ref": "AAAAAAFV/x32VvRH25Y="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/x9Z8/RhJts="
+ }
+ }
+ ]
+ },
+ {
+ "_type": "FCTerminator",
+ "_id": "AAAAAAFV/x9Z8/RhJts=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "Activity销毁"
+ },
+ {
+ "_type": "FCTerminator",
+ "_id": "AAAAAAFV/yDnHfR2MMU=",
+ "_parent": {
+ "$ref": "AAAAAAFV/v9xvvL0FXk="
+ },
+ "name": "应用被杀死",
+ "ownedElements": [
+ {
+ "_type": "FCFlow",
+ "_id": "AAAAAAFV/yJm2PSbHa0=",
+ "_parent": {
+ "$ref": "AAAAAAFV/yDnHfR2MMU="
+ },
+ "name": "用户返回原Activity",
+ "source": {
+ "$ref": "AAAAAAFV/yDnHfR2MMU="
+ },
+ "target": {
+ "$ref": "AAAAAAFV/whfb/MuyM0="
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/WorldRule/Activity/elements/activity_lifecycle.png b/WorldRule/Activity/elements/activity_lifecycle.png
new file mode 100644
index 00000000..1358098a
Binary files /dev/null and b/WorldRule/Activity/elements/activity_lifecycle.png differ
diff --git a/WorldRule/OpenGL/README.md b/WorldRule/OpenGL/README.md
new file mode 100644
index 00000000..3798a254
--- /dev/null
+++ b/WorldRule/OpenGL/README.md
@@ -0,0 +1 @@
+# OpenGL
diff --git a/WorldRule/README.md b/WorldRule/README.md
new file mode 100644
index 00000000..fe023818
--- /dev/null
+++ b/WorldRule/README.md
@@ -0,0 +1,3 @@
+# 基本法则
+
+这里记载着世界运转的法则,不过是不完整的,也许你可以帮助我来完善这些法则,帮助我收集法则碎片,也许有一天我们可以集齐所有的法则,那时我们便可以用法则的力量创造全新的世界了,或者让这个世界变得更加美好。