├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── markdown-navigator
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── lee
│ │ └── drawlayoutsample
│ │ └── ExampleInstrumentedTest.java
│ ├── assets
│ ├── View coordinates.png
│ ├── all_black.svg
│ ├── all_green.svg
│ ├── all_red.svg
│ ├── hot_black.svg
│ ├── hot_green.svg
│ ├── hot_red.svg
│ ├── jewelry_black.svg
│ ├── jewelry_green.svg
│ ├── jewelry_red.svg
│ ├── line_black.svg
│ ├── line_green.svg
│ ├── line_red.svg
│ ├── smile_black.svg
│ ├── smile_green.svg
│ └── smile_red.svg
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── lee
│ │ │ └── drawlayoutsample
│ │ │ ├── App.java
│ │ │ ├── EditTextInfo.java
│ │ │ ├── ElementMemento.java
│ │ │ ├── IElementMemento.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MementoCreataker.java
│ │ │ ├── MementoOriginator.java
│ │ │ ├── ViewInfo.java
│ │ │ └── utils
│ │ │ ├── BaseUtils.java
│ │ │ └── LogUtils.java
│ └── res
│ │ ├── drawable-hdpi
│ │ ├── actionbar_ic_cancel.png
│ │ ├── actionbar_ic_copy.png
│ │ ├── actionbar_ic_delete.png
│ │ ├── actionbar_ic_done.png
│ │ ├── all_normal.png
│ │ ├── all_selected.png
│ │ ├── back.png
│ │ ├── forward.png
│ │ ├── gallery_toolbar_chinabrush_press.png
│ │ ├── hot_normal.png
│ │ ├── hot_selected.png
│ │ ├── ic_menu_rotate_light_n.png
│ │ ├── jewelry_normal.png
│ │ ├── jewelry_selected.png
│ │ ├── line.png
│ │ ├── line_nomal.png
│ │ ├── line_selected.png
│ │ ├── smile_normal.png
│ │ ├── smile_selected.png
│ │ ├── text_normal.png
│ │ ├── text_select.png
│ │ └── wangge.jpg
│ │ ├── drawable
│ │ ├── border_shape.xml
│ │ ├── border_shape_blue.xml
│ │ ├── border_shape_focus.xml
│ │ ├── border_shape_green.xml
│ │ ├── border_shape_white.xml
│ │ ├── draw_selector_bg.xml
│ │ ├── ic_all_black.xml
│ │ ├── ic_all_green.xml
│ │ ├── ic_all_red.xml
│ │ ├── ic_hot_black.xml
│ │ ├── ic_hot_green.xml
│ │ ├── ic_hot_red.xml
│ │ ├── ic_jewelry_black.xml
│ │ ├── ic_jewelry_green.xml
│ │ ├── ic_jewelry_red.xml
│ │ ├── ic_smile_black.xml
│ │ ├── ic_smile_green.xml
│ │ └── ic_smile_red.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── draw_navigation_bar_layout.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── lee
│ └── drawlayoutsample
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | 1.8
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DrawLayoutSample
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 | defaultConfig {
7 | applicationId "com.lee.drawlayoutsample"
8 | minSdkVersion 15
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.3.1'
28 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
29 | testCompile 'junit:junit:4.12'
30 | }
31 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Android_Develop\Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/lee/drawlayoutsample/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.lee.drawlayoutsample", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/assets/View coordinates.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/assets/View coordinates.png
--------------------------------------------------------------------------------
/app/src/assets/all_black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/all_green.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/all_red.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/hot_black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/hot_green.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/hot_red.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/jewelry_black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/jewelry_green.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/jewelry_red.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/line_black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/line_green.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/line_red.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/smile_black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/smile_green.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/assets/smile_red.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/App.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 | import android.app.Application;
4 |
5 | import com.lee.drawlayoutsample.utils.BaseUtils;
6 |
7 | /**
8 | * Created by Lee on 2017/7/24.
9 | */
10 |
11 | public class App extends Application {
12 |
13 | @Override
14 | public void onCreate() {
15 | super.onCreate();
16 | BaseUtils.initialize(this);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/EditTextInfo.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 | import android.os.Parcel;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * Created by Lee on 2016/11/4.
9 | */
10 |
11 | public class EditTextInfo extends ViewInfo implements Serializable {
12 |
13 | public EditTextInfo(int id, float degree) {
14 | super(id, degree);
15 | }
16 |
17 | public String text;
18 |
19 | @Override
20 | public int describeContents() {
21 | return 0;
22 | }
23 |
24 | @Override
25 | public void writeToParcel(Parcel dest, int flags) {
26 | super.writeToParcel(dest, flags);
27 | dest.writeString(this.text);
28 | }
29 |
30 | protected EditTextInfo(Parcel in) {
31 | super(in);
32 | this.text = in.readString();
33 | }
34 |
35 | public static final Creator CREATOR = new Creator() {
36 | @Override
37 | public EditTextInfo createFromParcel(Parcel source) {
38 | return new EditTextInfo(source);
39 | }
40 |
41 | @Override
42 | public EditTextInfo[] newArray(int size) {
43 | return new EditTextInfo[size];
44 | }
45 | };
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/ElementMemento.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by Lee on 2017/1/18.
7 | */
8 |
9 | public class ElementMemento implements IElementMemento {
10 |
11 | private List mInfos;
12 |
13 | public ElementMemento(List mementos) {
14 | mInfos = mementos;
15 | }
16 |
17 | public List getInfos() {
18 | return mInfos;
19 | }
20 |
21 | @Override
22 | public String toString() {
23 | return "ElementMemento{" +
24 | "mInfos=" + mInfos +
25 | '}';
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/IElementMemento.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 | /**
4 | * Created by Lee on 2017/1/18.
5 | */
6 |
7 | public interface IElementMemento {
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.graphics.Bitmap;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.Paint;
11 | import android.graphics.Rect;
12 | import android.graphics.drawable.VectorDrawable;
13 | import android.os.Build;
14 | import android.os.Bundle;
15 | import android.support.v4.app.FragmentActivity;
16 | import android.text.TextUtils;
17 | import android.util.DisplayMetrics;
18 | import android.util.Log;
19 | import android.view.MotionEvent;
20 | import android.view.ScaleGestureDetector;
21 | import android.view.View;
22 | import android.view.Window;
23 | import android.view.animation.Animation;
24 | import android.view.animation.TranslateAnimation;
25 | import android.widget.EditText;
26 | import android.widget.FrameLayout;
27 | import android.widget.ImageView;
28 | import android.widget.RadioGroup;
29 |
30 | import com.lee.drawlayoutsample.utils.LogUtils;
31 |
32 | import java.io.FileNotFoundException;
33 | import java.io.FileOutputStream;
34 | import java.lang.reflect.Field;
35 | import java.util.ArrayList;
36 | import java.util.HashSet;
37 | import java.util.List;
38 | import java.util.Set;
39 |
40 |
41 | public class MainActivity extends FragmentActivity implements View.OnClickListener, RadioGroup.OnCheckedChangeListener {
42 | private static final String TAG = "MainActivity";
43 | private final int DEGREE_0 = 0;
44 | private final int DEGREE_90 = 90;
45 | private final int DEGREE_180 = 180;
46 | private final int DEGREE_270 = 270;
47 | private ScaleGestureDetector mScaleGestureDetector;
48 | private ScaleGestureListener mScaleGestureListener = new ScaleGestureListener();
49 |
50 | private Set mViewList = new HashSet();
51 | private Set mFocusViewList = new HashSet();
52 | private long downTime = 0;
53 | private float downX = 0f;
54 | private float downY = 0f;
55 | private float downImageX = 0f;
56 | private float downImageY = 0f;
57 |
58 | private float fdownX = 0f;
59 | private float fdownY = 0f;
60 |
61 | private int imageW = 0;
62 | private int imageH = 0;
63 |
64 | private float locationX = 0f;
65 | private float locationY = 0f;
66 | private DisplayMetrics mDisplayMetrics;
67 | private int mStatusBarHeight = 0;
68 | private FrameLayout mRootView;
69 | private ImageView mCurrentImageView;
70 |
71 | private Bitmap mLineBitmap;
72 | private Bitmap mLineBitmapBlack;
73 | private Bitmap mLineBitmapGreen;
74 | private Bitmap mLineBitmapRed;
75 |
76 |
77 | private List mInfoList = new ArrayList();
78 | private FrameLayout mContent;
79 | private List mRectList;
80 | private float mCurrentScale = 1f;
81 | private float mContentDownX = 0f;
82 | private float mContentDownY = 0f;
83 | private boolean mMoved = false;
84 | private boolean mSelectTextTools;
85 | private ImageView mTextTools;
86 | private List mLefts = new ArrayList();
87 | private List mTops = new ArrayList();
88 | private List mRights = new ArrayList();
89 | private List mBottoms = new ArrayList();
90 | private List mLines = new ArrayList();
91 | private static final int LIMIT = 50;
92 | private static final int OFFSET = 100;
93 | private static final int PADDING = 20;
94 |
95 | private int mCurrentColor; // 0--黑色,1--绿色,2--红色
96 | private MementoCreataker mCreataker;
97 | private MementoOriginator mOriginator;
98 | private int mCurrentIndex = -1;
99 | private FrameLayout.LayoutParams mDefaultEditTextParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
100 | private FrameLayout.LayoutParams mContentLayoutParams;
101 | private int mRealInfoId = 5000;
102 | private float mStartX;
103 | private float mStartY;
104 | private static final int STROKE_WIDTH = 5;
105 |
106 |
107 | @Override
108 | protected void onCreate(Bundle savedInstanceState) {
109 | super.onCreate(savedInstanceState);
110 | requestWindowFeature(Window.FEATURE_NO_TITLE);
111 | setContentView(R.layout.activity_main);
112 | mOriginator = new MementoOriginator();
113 | mCreataker = new MementoCreataker();
114 |
115 |
116 | mDisplayMetrics = new DisplayMetrics();
117 | getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
118 | mStatusBarHeight = getStatusBarHeight(this);
119 | mRootView = (FrameLayout) findViewById(R.id.root);
120 | mContent = (FrameLayout) findViewById(R.id.content);
121 |
122 | RadioGroup radioGroup = (RadioGroup) findViewById(R.id.radiogroup);
123 | radioGroup.setOnCheckedChangeListener(this);
124 | mContentLayoutParams = (FrameLayout.LayoutParams) mContent.getLayoutParams();
125 | mContentLayoutParams.width = mDisplayMetrics.widthPixels - 312;
126 | mContentLayoutParams.height = mDisplayMetrics.heightPixels - mStatusBarHeight - 107;
127 |
128 | mContent.setOnTouchListener(new View.OnTouchListener() {
129 | @Override
130 | public boolean onTouch(View v, MotionEvent event) {
131 | mScaleGestureDetector.onTouchEvent(event);
132 | int action = event.getAction();
133 | switch (action) {
134 | case MotionEvent.ACTION_DOWN:
135 | mContentDownX = event.getX();
136 | mContentDownY = event.getY();
137 | for (View view : mViewList) {
138 | if (((ViewInfo) view.getTag()).id == R.id.rectIcon) {
139 | Log.d(TAG, "rectIcon onDown...");
140 | view.setBackgroundResource(R.drawable.border_shape);
141 | } else {
142 | Log.i(TAG, "not rectIcon onDown...");
143 | view.setBackgroundColor(Color.TRANSPARENT);
144 | }
145 | if (((ViewInfo) view.getTag()).id == R.id.rectIcon) {
146 | view.setOnTouchListener(new MyTouchListener((ImageView) view));
147 | int[] location = new int[2];
148 | view.getLocationOnScreen(location);
149 | Rect rect = new Rect();
150 | rect.left = location[0];
151 | rect.right = location[0] + view.getWidth();
152 | rect.top = location[1];
153 | rect.bottom = location[1] + view.getHeight();
154 | if (rect.contains((int) event.getX(), (int) event.getY())) {
155 | view.setBackgroundResource(R.drawable.border_shape_blue);
156 | }
157 | }
158 | }
159 | mFocusViewList.clear();
160 | mMoved = true;
161 | return true;
162 | case MotionEvent.ACTION_MOVE:
163 | int w = mContent.getWidth();
164 | int h = mContent.getHeight();
165 | float maxW = (w * (mCurrentScale - 1f)) / 2;
166 | float maxH = (h * (mCurrentScale - 1f)) / 2;
167 | if (event.getPointerCount() <= 1 && mCurrentScale > 1f && mMoved) {
168 | Log.e(TAG, "move");
169 | mMoved = true;
170 | float disX = mContentDownX - event.getX();
171 | float disY = mContentDownY - event.getY();
172 | if (((int) disY + mContent.getScrollY()) >= -maxH
173 | && ((int) disY + mContent.getScrollY()) <= maxH
174 | && ((int) disX + mContent.getScrollX()) >= -maxW
175 | && ((int) disX + mContent.getScrollX()) <= maxW) {
176 | mContent.scrollBy((int) disX, (int) disY);
177 | }
178 | mContentDownX = event.getX();
179 | mContentDownY = event.getY();
180 | return true;
181 | } else {
182 | Log.e(TAG, "not move");
183 | mMoved = false;
184 | }
185 | return false;
186 | case MotionEvent.ACTION_UP:
187 |
188 | mMoved = false;
189 |
190 | if (mSelectTextTools) {
191 |
192 | float x = event.getRawX();
193 | float y = event.getRawY();
194 | Log.i(TAG, "x: " + x + "### y:" + y);
195 |
196 | if (x <= 312 || x >= 1920 || y <= 106 || y >= 1200) {
197 | Log.d(TAG, "不在画布区域内 x: " + x + "### y:" + y);
198 | return true;
199 | } else {
200 | EditText editText = new EditText(MainActivity.this);
201 | editText.requestFocus();
202 | editText.setX(x - 312);
203 | editText.setY(y - 106);
204 | editText.setId(mViewList.size() + 1);
205 | ViewInfo viewInfo = new EditTextInfo(editText.getId(), 0);
206 | viewInfo.realId = ++mRealInfoId;
207 | viewInfo.type = ViewInfo.TYPE_EDITTEXT;
208 | viewInfo.x = editText.getX();
209 | viewInfo.y = editText.getY();
210 | editText.setTag(viewInfo);
211 |
212 | Log.d(TAG, "editTextId : " + editText.getId());
213 | mViewList.add(editText);
214 | editText.setBackgroundResource(R.drawable.border_shape_focus);
215 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
216 | mContent.addView(editText, layoutParams);
217 | createMemento(editText, false, true);
218 |
219 | }
220 |
221 | }
222 | return false;
223 | default:
224 | break;
225 | }
226 | return false;
227 | }
228 | });
229 |
230 | mScaleGestureDetector = new ScaleGestureDetector(this, mScaleGestureListener);
231 | ImageView allImageView = (ImageView) findViewById(R.id.allIcon);
232 | allImageView.setOnTouchListener(mTouchListener);
233 | allImageView.setOnLongClickListener(mLongClickListener);
234 | ImageView smileImageView = (ImageView) findViewById(R.id.smileIcon);
235 | smileImageView.setOnTouchListener(mTouchListener);
236 | smileImageView.setOnLongClickListener(mLongClickListener);
237 | ImageView jewelryImageView = (ImageView) findViewById(R.id.jewelryIcon);
238 | jewelryImageView.setOnTouchListener(mTouchListener);
239 | jewelryImageView.setOnLongClickListener(mLongClickListener);
240 | ImageView hotImageView = (ImageView) findViewById(R.id.hotIcon);
241 | hotImageView.setOnTouchListener(mTouchListener);
242 | hotImageView.setOnLongClickListener(mLongClickListener);
243 |
244 | ImageView lineImageView = (ImageView) findViewById(R.id.lineIcon);
245 | lineImageView.setOnTouchListener(mTouchListener);
246 | lineImageView.setOnLongClickListener(mLongClickListener);
247 | ImageView rect = (ImageView) findViewById(R.id.rectIcon);
248 | rect.setOnTouchListener(mTouchListener);
249 | rect.setOnLongClickListener(mLongClickListener);
250 |
251 |
252 | findViewById(R.id.clear).setOnClickListener(this);
253 | findViewById(R.id.rotate).setOnClickListener(this);
254 | findViewById(R.id.delete).setOnClickListener(this);
255 | findViewById(R.id.copy).setOnClickListener(this);
256 | findViewById(R.id.cancel).setOnClickListener(this);
257 | findViewById(R.id.done).setOnClickListener(this);
258 | findViewById(R.id.back).setOnClickListener(this);
259 | findViewById(R.id.forward).setOnClickListener(this);
260 | mTextTools = (ImageView) findViewById(R.id.text);
261 | mTextTools.setOnClickListener(this);
262 | mViewList.clear();
263 |
264 | layoutViews();
265 | }
266 |
267 | private void layoutViews() {
268 |
269 | mViewList.clear();
270 | mContent.removeAllViews();
271 |
272 | if (mInfoList != null) {
273 | LogUtils.v("mInfoList : " + mInfoList.toString());
274 | for (ViewInfo viewInfo : mInfoList) {
275 |
276 | ViewInfo newViewInfo;
277 |
278 | if (viewInfo.type == ViewInfo.TYPE_EDITTEXT) {
279 | newViewInfo = new EditTextInfo(viewInfo.id, viewInfo.degree);
280 |
281 | newViewInfo.type = ViewInfo.TYPE_EDITTEXT;
282 | String text = ((EditTextInfo) viewInfo).text;
283 | ((EditTextInfo) newViewInfo).text = text;
284 | EditText editText = new EditText(MainActivity.this);
285 | editText.setTag(newViewInfo);
286 | editText.setX(viewInfo.x);
287 | editText.setY(viewInfo.y);
288 | editText.setText(text);
289 |
290 | mViewList.add(editText);
291 | mContent.addView(editText, mDefaultEditTextParams);
292 |
293 | } else {
294 | newViewInfo = new ViewInfo(viewInfo.id, viewInfo.degree);
295 | newViewInfo.color = viewInfo.color;
296 |
297 | mContentLayoutParams = new FrameLayout.LayoutParams(viewInfo.width, viewInfo.height);
298 |
299 | ImageView imageView = new ImageView(MainActivity.this);
300 | imageView.setScaleType(ImageView.ScaleType.FIT_XY);
301 | imageView.setOnTouchListener(new MyTouchListener(imageView));
302 | imageView.setTag(newViewInfo);
303 | imageView.setX(viewInfo.x);
304 | imageView.setY(viewInfo.y);
305 | setImageResource(imageView, false);
306 | if (newViewInfo.degree != 0) {
307 | imageView.setRotation(viewInfo.degree);
308 | }
309 | mViewList.add(imageView);
310 | mContent.addView(imageView, mContentLayoutParams);
311 | }
312 | newViewInfo.height = viewInfo.height;
313 | newViewInfo.width = viewInfo.width;
314 | newViewInfo.x = viewInfo.x;
315 | newViewInfo.y = viewInfo.y;
316 | newViewInfo.realId = viewInfo.realId;
317 | }
318 | }
319 | }
320 |
321 |
322 | @Override
323 | public void onDestroy() {
324 | super.onDestroy();
325 | mRootView.removeAllViews();
326 |
327 | recycle(mLineBitmap, mLineBitmapBlack, mLineBitmapGreen, mLineBitmapRed);
328 | }
329 |
330 | private void recycle(Bitmap... bitmaps) {
331 | if (bitmaps != null && bitmaps.length > 0) {
332 | for (Bitmap bitmap : bitmaps) {
333 | if (bitmap != null) bitmap.recycle();
334 | }
335 | }
336 | }
337 |
338 | public void setImageResource(ImageView v, boolean focus) {
339 | ViewInfo viewInfo = (ViewInfo) v.getTag();
340 | switch (viewInfo.id) {
341 | case R.id.allIcon:
342 | realSetImageResource(v, viewInfo, focus, R.drawable.all_selected, R.drawable.ic_all_black, R.drawable.ic_all_green, R.drawable.ic_all_red);
343 | break;
344 | case R.id.smileIcon:
345 | realSetImageResource(v, viewInfo, focus, R.drawable.smile_selected, R.drawable.ic_smile_black, R.drawable.ic_smile_green, R.drawable.ic_smile_red);
346 | break;
347 | case R.id.jewelryIcon:
348 | realSetImageResource(v, viewInfo, focus, R.drawable.jewelry_selected, R.drawable.ic_jewelry_black, R.drawable.ic_jewelry_green, R.drawable.ic_jewelry_red);
349 | break;
350 | case R.id.hotIcon:
351 | realSetImageResource(v, viewInfo, focus, R.drawable.hot_selected, R.drawable.ic_hot_black, R.drawable.ic_hot_green, R.drawable.ic_hot_red);
352 | break;
353 |
354 | case R.id.lineIcon:
355 |
356 | if (mLineBitmap == null) {
357 |
358 | mLineBitmapBlack = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
359 | mLineBitmapGreen = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
360 | mLineBitmapRed = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
361 |
362 | Paint paint = new Paint();
363 | paint.setColor(Color.BLACK);
364 | paint.setStrokeWidth(STROKE_WIDTH);
365 |
366 | Canvas canvas = new Canvas(mLineBitmapBlack);
367 | canvas.drawLine(0, 50, 100, 50, paint);
368 |
369 | paint.setColor(Color.RED);
370 | canvas = new Canvas(mLineBitmapRed);
371 | canvas.drawLine(0, 50, 100, 50, paint);
372 |
373 | paint.setColor(Color.GREEN);
374 | canvas = new Canvas(mLineBitmapGreen);
375 | canvas.drawLine(0, 50, 100, 50, paint);
376 |
377 | mLineBitmap = mLineBitmapBlack;
378 |
379 | if (viewInfo.color == 2) {
380 | mLineBitmap = mLineBitmapRed;
381 | } else if (mCurrentColor == 1) {
382 | mLineBitmap = mLineBitmapGreen;
383 | }
384 | }
385 | if (focus) {
386 | v.setImageResource(R.drawable.line_selected);
387 | } else {
388 | v.setImageBitmap(mLineBitmap);
389 | }
390 | break;
391 |
392 | case R.id.rectIcon:
393 | if (focus) {
394 | v.setBackgroundResource(R.drawable.border_shape_focus);
395 | } else {
396 | v.setBackgroundResource(R.drawable.border_shape);
397 | }
398 | break;
399 | default:
400 | break;
401 | }
402 | }
403 |
404 |
405 | private void realSetImageResource(ImageView v, ViewInfo viewInfo, boolean focus, int focusId, int blackId, int greenId, int redId) {
406 | if (focus) {
407 | v.setImageResource(focusId);
408 | } else {
409 | if (viewInfo.color == 2) {
410 | v.setImageResource(redId);
411 | } else if (viewInfo.color == 1) {
412 | v.setImageResource(greenId);
413 | } else {
414 | v.setImageResource(blackId);
415 | }
416 | }
417 | }
418 |
419 |
420 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
421 | private Bitmap getBitmap(VectorDrawable vectorDrawable) {
422 | Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
423 | vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
424 | Canvas canvas = new Canvas(bitmap);
425 | vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
426 | vectorDrawable.draw(canvas);
427 | return bitmap;
428 | }
429 |
430 | @Override
431 | public void onClick(View v) {
432 | switch (v.getId()) {
433 | case R.id.rotate:
434 | for (View view : mFocusViewList) {
435 | LogUtils.d("start x: " + view.getX() + ", y :" + view.getY());
436 | ViewInfo viewInfo = (ViewInfo) view.getTag();
437 | if (viewInfo.id == R.id.lineIcon || viewInfo.id == R.id.xuxianIcon || viewInfo.id == R.id.rectIcon) {
438 | FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
439 | params.width = view.getHeight();
440 | params.height = view.getWidth();
441 | view.requestLayout();
442 | }
443 | float degree = view.getRotation() + 90f;
444 | LogUtils.d("degree: " + degree);
445 | if (degree >= 360) {
446 | degree = 0;
447 | }
448 | view.setRotation(degree);
449 | LogUtils.d("end x: " + view.getX() + ", y :" + view.getY());
450 | createMemento(view, false, false);
451 |
452 | }
453 | break;
454 | case R.id.clear:
455 | for (View view : mViewList) {
456 | mContent.removeView(view);
457 | }
458 | mViewList.clear();
459 | mContent.requestLayout();
460 | break;
461 | case R.id.delete:
462 | for (View view : new ArrayList(mFocusViewList)) {
463 | removeViews(view);
464 | createMemento(view, true, false);
465 | }
466 | mContent.requestLayout();
467 | break;
468 | case R.id.copy:
469 | LogUtils.i("mFocusViewList size: " + mFocusViewList.size());
470 | for (View view : mFocusViewList) {
471 | copyView(view);
472 | if (((ViewInfo) view.getTag()).id == R.id.rectIcon) {
473 | int[] location = new int[2];
474 | view.getLocationOnScreen(location);
475 | int x = location[0];
476 | int y = location[1];
477 | Rect srcRect = new Rect();
478 | srcRect.left = x;
479 | srcRect.right = x + view.getWidth();
480 | srcRect.top = y;
481 | srcRect.bottom = y + view.getHeight();
482 | List rectList = getNeedMoveView(srcRect, (ImageView) view);
483 | for (View view1 : rectList) {
484 | copyView(view1);
485 | }
486 | }
487 | }
488 | break;
489 | case R.id.cancel:
490 | setResult(Activity.RESULT_CANCELED);
491 | finish();
492 | break;
493 | case R.id.done:
494 |
495 |
496 | Bitmap bitmap = captureScreen();
497 | FileOutputStream outputStream = null;
498 | if (bitmap != null) {
499 | try {
500 | outputStream = new FileOutputStream(getExternalCacheDir() + "/draw.jpg");
501 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
502 | } catch (FileNotFoundException e) {
503 | e.printStackTrace();
504 | } finally {
505 | try {
506 | if (outputStream != null) {
507 | outputStream.close();
508 | }
509 | } catch (Exception e) {
510 | Log.e(TAG, e.getMessage(), e);
511 | }
512 |
513 | }
514 | }
515 |
516 |
517 | mContent.setScaleX(1f);
518 | mContent.setScaleY(1f);
519 | mInfoList.clear();
520 | for (View view : mViewList) {
521 |
522 | ViewInfo viewInfo = (ViewInfo) view.getTag();
523 | ViewInfo newViewInfo;
524 |
525 | if (viewInfo.type == ViewInfo.TYPE_EDITTEXT) {
526 | String string = ((EditText) view).getText().toString();
527 | if (TextUtils.isEmpty(string)) {
528 | continue;
529 | }
530 | newViewInfo = new EditTextInfo(viewInfo.id, viewInfo.degree);
531 | ((EditTextInfo) newViewInfo).text = ((EditText) view).getText().toString();
532 | newViewInfo.type = ViewInfo.TYPE_EDITTEXT;
533 | } else {
534 | newViewInfo = new ViewInfo(viewInfo.id, viewInfo.degree);
535 | }
536 | newViewInfo.color = viewInfo.color;
537 | newViewInfo.width = view.getWidth();
538 | newViewInfo.height = view.getHeight();
539 | int[] location = new int[2];
540 | view.getLocationOnScreen(location);
541 | newViewInfo.x = location[0];
542 | newViewInfo.y = location[1];
543 |
544 | mInfoList.add(newViewInfo);
545 | }
546 | Log.d(TAG, "end mInfoList : " + mInfoList.toString());
547 |
548 | finish();
549 | break;
550 | case R.id.text:
551 | mSelectTextTools = !mSelectTextTools;
552 | if (mSelectTextTools) {
553 | mTextTools.setImageResource(R.drawable.text_select);
554 | } else {
555 | mTextTools.setImageResource(R.drawable.text_normal);
556 | if (mViewList != null && !mViewList.isEmpty()) {
557 | ArrayList removeViews = new ArrayList<>();
558 | for (View view : mViewList) {
559 | if (view instanceof EditText) {
560 | String string = ((EditText) view).getText().toString();
561 | if (TextUtils.isEmpty(string)) {
562 | removeViews.add(view);
563 | mContent.removeView(view);
564 | LogUtils.d("移除未输入内容的EditText...");
565 | }
566 | }
567 | }
568 | if (!removeViews.isEmpty()) {
569 | mViewList.removeAll(removeViews);
570 | }
571 | }
572 | }
573 | break;
574 | case R.id.back:
575 | --mCurrentIndex;
576 | ElementMemento memento = mCreataker.restoreMemento(mCurrentIndex);
577 | if (memento == null) {
578 | ++mCurrentIndex;
579 | } else {
580 | mInfoList.clear();
581 | mInfoList.addAll(mOriginator.restoreMemento(memento));
582 | mOriginator.printMementos();
583 | layoutViews();
584 | }
585 | LogUtils.d("back mCurrentIndex: " + mCurrentIndex);
586 | break;
587 | case R.id.forward:
588 | ++mCurrentIndex;
589 | memento = mCreataker.restoreMemento(mCurrentIndex);
590 | if (memento == null) {
591 | --mCurrentIndex;
592 | } else {
593 | mInfoList.clear();
594 | mInfoList.addAll(mOriginator.restoreMemento(memento));
595 | layoutViews();
596 | }
597 | LogUtils.d("forward mCurrentIndex: " + mCurrentIndex);
598 | break;
599 |
600 | default:
601 | break;
602 | }
603 | }
604 |
605 | private void removeViews(View view) {
606 | mContent.removeView(view);
607 | mViewList.remove(view);
608 | mFocusViewList.remove(view);
609 | }
610 |
611 |
612 | @Override
613 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
614 | super.onActivityResult(requestCode, resultCode, data);
615 | }
616 |
617 | public static int getStatusBarHeight(Context context) {
618 | Class> c = null;
619 | Object obj = null;
620 | Field field = null;
621 | int x = 0, statusBarHeight = 0;
622 | try {
623 | c = Class.forName("com.android.internal.R$dimen");
624 | obj = c.newInstance();
625 | field = c.getField("status_bar_height");
626 | x = Integer.parseInt(field.get(obj).toString());
627 | statusBarHeight = context.getResources().getDimensionPixelSize(x);
628 | } catch (Exception e1) {
629 | e1.printStackTrace();
630 | }
631 | return statusBarHeight;
632 | }
633 |
634 | private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
635 | @Override
636 | public boolean onTouch(View v, final MotionEvent event) {
637 | int action = event.getAction();
638 | if (mCurrentImageView == null && MotionEvent.ACTION_DOWN != action) {
639 | return false;
640 | }
641 |
642 | switch (action) {
643 | case MotionEvent.ACTION_DOWN:
644 | fdownX = event.getX();
645 | fdownY = event.getY();
646 | LogUtils.d("fdownX: " + fdownX + " ###fdownY: " + fdownY);
647 | getLineCoordinate();
648 | break;
649 | case MotionEvent.ACTION_MOVE:
650 | float disX = event.getX() - fdownX - OFFSET;
651 | float disY = event.getY() - fdownY - OFFSET;
652 | LogUtils.d("disX: " + disX + " ### disY: " + disY + " ### getX: " + event.getX() + " ### getY: " + event.getY());
653 | mCurrentImageView.setX(mCurrentImageView.getX() + disX);
654 | mCurrentImageView.setY(mCurrentImageView.getY() + disY);
655 | LogUtils.i("mCurrentImageView.getX(): " + mCurrentImageView.getX() + " ### mCurrentImageView.getY(): " + mCurrentImageView.getY());
656 | fdownX = event.getX() - OFFSET;
657 | fdownY = event.getY() - OFFSET;
658 | LogUtils.v("fdownX: " + fdownX + " ### fdownY: " + fdownY);
659 |
660 | imageW = mCurrentImageView.getWidth();
661 | imageH = mCurrentImageView.getHeight();
662 |
663 | mCurrentImageView.setBackgroundResource(android.R.color.transparent);
664 | setImageResource(mCurrentImageView, true);
665 |
666 | return true;
667 | case MotionEvent.ACTION_UP:
668 | float x = mCurrentImageView.getX();
669 | float y = mCurrentImageView.getY();
670 | if (x <= 212) {
671 | cancelMoveView(x, y);
672 | return true;
673 | } else {
674 | if (x > 212 && x < 312) {
675 | x = 312;
676 | } else if (x > (mDisplayMetrics.widthPixels - 100)) {
677 | x = mDisplayMetrics.widthPixels - 100;
678 | }
679 |
680 | if (y <= 106) {
681 | y = 106;
682 | } else if (y > mDisplayMetrics.heightPixels - 100 - mStatusBarHeight) {
683 | y = mDisplayMetrics.heightPixels - 100 - mStatusBarHeight;
684 | }
685 | mCurrentImageView.setX(x - 312);
686 | mCurrentImageView.setY(y - 107);
687 | setImageResource(mCurrentImageView, false);
688 | mRootView.removeView(mCurrentImageView);
689 | mContent.addView(mCurrentImageView);
690 |
691 | createMemento(mCurrentImageView, false, true);
692 |
693 | if (((ViewInfo) mCurrentImageView.getTag()).id == R.id.rectIcon) {
694 | mCurrentImageView.setBackgroundResource(R.drawable.border_shape);
695 | } else {
696 | mCurrentImageView.setBackgroundResource(android.R.color.transparent);
697 | }
698 | }
699 | mCurrentImageView = null;
700 | break;
701 | case MotionEvent.ACTION_CANCEL:
702 | float x1 = mCurrentImageView.getX();
703 | float y1 = mCurrentImageView.getY();
704 | cancelMoveView(x1, y1);
705 | break;
706 | }
707 | return false;
708 | }
709 | };
710 |
711 |
712 | private void createMemento(View view, boolean isDelete, boolean isNewElement) {
713 |
714 | if (mInfoList == null) {
715 | mInfoList = new ArrayList<>();
716 | }
717 | mCurrentIndex++;
718 |
719 | // LogUtils.d("add mCurrentIndex: " + mCurrentIndex);
720 |
721 | ViewInfo viewInfo = (ViewInfo) view.getTag();
722 | // LogUtils.d("viewInfo: " + viewInfo);
723 | if (isNewElement) { //刚刚从侧边栏拖拽出来的元素
724 | // LogUtils.d("新增元素");
725 | viewInfo.width = viewInfo.width == 0 ? view.getWidth() : viewInfo.width;
726 | viewInfo.height = viewInfo.height == 0 ? view.getHeight() : viewInfo.height;
727 | viewInfo.x = viewInfo.x == 0 ? (int) view.getX() : viewInfo.x;
728 | viewInfo.y = viewInfo.y == 0 ? (int) view.getY() : viewInfo.y;
729 | mInfoList.add(viewInfo);
730 | } else { //改变现有元素
731 | // LogUtils.d("改变现有元素");
732 | if (isDelete) {
733 | // LogUtils.i("删除元素");
734 | for (int i = mInfoList.size() - 1; i >= 0; i--) {
735 | ViewInfo info = mInfoList.get(i);
736 | if (info.id == viewInfo.id && info.realId == viewInfo.realId) {
737 | // LogUtils.i("删除重复元素: " + info);
738 | mInfoList.remove(info);
739 | }
740 | }
741 | } else {
742 | ViewInfo newViewInfo = new ViewInfo(viewInfo.id, view.getRotation());
743 | newViewInfo.realId = ++mRealInfoId;
744 | newViewInfo.width = view.getWidth();
745 | newViewInfo.height = view.getHeight();
746 | newViewInfo.x = view.getX();
747 | newViewInfo.y = view.getY();
748 | newViewInfo.type = viewInfo.type;
749 | newViewInfo.color = mCurrentColor;
750 |
751 | for (int i = mInfoList.size() - 1; i >= 0; i--) {
752 | ViewInfo info = mInfoList.get(i);
753 | if (info.id == viewInfo.id && info.realId == viewInfo.realId) {
754 | // LogUtils.i("删除重复元素: " + info);
755 | mInfoList.remove(info);
756 | view.setTag(newViewInfo);
757 | }
758 | }
759 | mInfoList.add(newViewInfo);
760 | }
761 | }
762 |
763 | List infos = new ArrayList<>();
764 |
765 | infos.addAll(mInfoList);
766 | mOriginator.setInfos(infos);
767 | mCreataker.createMemento(mOriginator.createMemento(), mCurrentIndex);
768 |
769 | }
770 |
771 | private void cancelMoveView(float x, float y) {
772 | TranslateAnimation translateAnimation = new TranslateAnimation(0, locationX - x, 0, locationY - y);
773 | translateAnimation.setDuration(200);
774 | translateAnimation.setAnimationListener(new Animation.AnimationListener() {
775 | @Override
776 | public void onAnimationStart(Animation animation) {
777 | }
778 |
779 | @Override
780 | public void onAnimationEnd(Animation animation) {
781 | mRootView.removeView(mCurrentImageView);
782 | }
783 |
784 | @Override
785 | public void onAnimationRepeat(Animation animation) {
786 |
787 | }
788 | });
789 | mCurrentImageView.startAnimation(translateAnimation);
790 | }
791 |
792 | private View.OnLongClickListener mLongClickListener = new View.OnLongClickListener() {
793 | @Override
794 | public boolean onLongClick(View v) {
795 | final ImageView imageView = new ImageView(MainActivity.this);
796 | mCurrentImageView = imageView;
797 | ViewInfo viewInfo = new ViewInfo(v.getId(), 0);
798 | viewInfo.type = ViewInfo.TYPE_IMAGEVIEW;
799 | viewInfo.color = mCurrentColor;
800 | viewInfo.realId = ++mRealInfoId;
801 | imageView.setTag(viewInfo);
802 | imageView.setScaleType(ImageView.ScaleType.FIT_XY);
803 | setImageResource(imageView, true);
804 | int[] location = new int[2];
805 | v.getLocationOnScreen(location);
806 | locationX = location[0];
807 | locationY = location[1];
808 | imageView.setX(locationX + 5);
809 | imageView.setY(locationY + 5);
810 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(v.getWidth(), v.getHeight());
811 | mRootView.addView(imageView, params);
812 | mViewList.add(imageView);
813 | imageView.setOnTouchListener(new MyTouchListener(imageView));
814 | return true;
815 | }
816 | };
817 |
818 |
819 | @Override
820 | public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
821 |
822 | switch (checkedId) {
823 | case R.id.rb_black:
824 | mCurrentColor = 0;
825 | mLineBitmap = mLineBitmapBlack;
826 |
827 | break;
828 | case R.id.rb_green:
829 | mCurrentColor = 1;
830 | mLineBitmap = mLineBitmapGreen;
831 |
832 | break;
833 | case R.id.rb_red:
834 | mCurrentColor = 2;
835 | mLineBitmap = mLineBitmapRed;
836 |
837 | break;
838 | default:
839 | LogUtils.e("default checkedId: " + checkedId, new IllegalArgumentException());
840 | break;
841 | }
842 | for (View view : mFocusViewList) {
843 | if (view instanceof ImageView) {
844 | createMemento(view, false, false);
845 | setImageResource((ImageView) view, false);
846 | }
847 | }
848 | }
849 |
850 |
851 | private class MyTouchListener implements View.OnTouchListener {
852 | private ImageView imageView;
853 |
854 | MyTouchListener(ImageView imageView) {
855 | this.imageView = imageView;
856 | }
857 |
858 | @Override
859 | public boolean onTouch(View v, MotionEvent event) {
860 | int action = event.getAction();
861 | ViewInfo viewInfo = (ViewInfo) v.getTag();
862 |
863 | float targetX = 0;
864 | float targetY = 0;
865 | float targetRight = 0;
866 | float targetBottom = 0;
867 |
868 | switch (action) {
869 | case MotionEvent.ACTION_DOWN:
870 | mStartX = imageView.getX();
871 | mStartY = imageView.getY();
872 | downX = event.getX();
873 | downY = event.getY();
874 | if (v.getRotation() == DEGREE_90) {
875 | LogUtils.d("90 ");
876 | downX = v.getHeight() - event.getY();
877 | downY = v.getWidth() - (v.getWidth() - event.getX());
878 | } else if (v.getRotation() == DEGREE_180) {
879 | LogUtils.d("180 ");
880 | downX = v.getWidth() - event.getX();
881 | downY = v.getHeight() - event.getY();
882 | } else if (v.getRotation() == DEGREE_270) {
883 | LogUtils.d("270 ");
884 | downX = event.getY();
885 | downY = v.getWidth() - event.getX();
886 | }
887 | LogUtils.d("downX: " + downX + " , downY: " + downY);
888 | downTime = System.currentTimeMillis();
889 |
890 | imageW = imageView.getWidth();
891 | imageH = imageView.getHeight();
892 |
893 | int[] location0 = new int[2];
894 | imageView.getLocationOnScreen(location0);
895 | int x0 = location0[0];
896 | int y0 = location0[1];
897 | Rect srcRect = new Rect();
898 | srcRect.left = x0;
899 | srcRect.right = x0 + imageView.getWidth();
900 | srcRect.top = y0;
901 | srcRect.bottom = y0 + imageView.getHeight();
902 |
903 | getLineCoordinate();
904 |
905 | if (viewInfo.id == R.id.rectIcon) {
906 | mRectList = getNeedMoveView(srcRect, imageView);
907 | }
908 | return true;
909 | case MotionEvent.ACTION_MOVE:
910 | float x1 = event.getX();
911 | float y1 = event.getY();
912 |
913 | if (v.getRotation() == DEGREE_90) {
914 | x1 = v.getHeight() - event.getY();
915 | y1 = v.getWidth() - (v.getWidth() - event.getX());
916 | } else if (v.getRotation() == DEGREE_180) {
917 | x1 = v.getWidth() - event.getX();
918 | y1 = v.getHeight() - event.getY();
919 | } else if (v.getRotation() == DEGREE_270) {
920 | x1 = event.getY();
921 | y1 = v.getWidth() - event.getX();
922 | }
923 |
924 | float disX = x1 - downX;
925 | float disY = y1 - downY;
926 |
927 | LogUtils.i("disX : " + (int) disX + ", disY : " + (int) disY);
928 |
929 | if ((viewInfo.id == R.id.lineIcon || viewInfo.id == R.id.xuxianIcon) && mFocusViewList.contains(imageView)) {
930 | FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) imageView.getLayoutParams();
931 | params.width = imageW + (int) disX;
932 | params.height = imageH + (int) disY;
933 | imageView.requestLayout();
934 | } else if (viewInfo.id == R.id.rectIcon && mFocusViewList.contains(imageView)) {
935 | FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) imageView.getLayoutParams();
936 | params.width = imageW + (int) disX;
937 | if (params.width < 5) {
938 | params.width = 5;
939 | }
940 | params.height = imageH + (int) disY;
941 | if (params.height < 5) {
942 | params.height = 5;
943 | }
944 | imageView.requestLayout();
945 | } else {
946 | if (viewInfo.id == R.id.rectIcon) {
947 | imageView.setX(imageView.getX() + disX);
948 | imageView.setY(imageView.getY() + disY);
949 | if (mRectList != null) {
950 | for (View view : mRectList) {
951 | view.setX(view.getX() + disX);
952 | view.setY(view.getY() + disY);
953 | }
954 | }
955 | } else {
956 | if (mFocusViewList.contains(imageView)) {
957 | FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) imageView.getLayoutParams();
958 | params.width = imageW + (int) disX;
959 | params.height = imageH + (int) disY;
960 | imageView.requestLayout();
961 | } else { //处理图标拖动
962 |
963 | imageView.setX(imageView.getX() + disX - OFFSET);
964 | imageView.setY(imageView.getY() + disY - OFFSET);
965 | imageView.setBackgroundResource(android.R.color.transparent);
966 |
967 | targetX = imageView.getX();
968 | targetY = imageView.getY();
969 | targetRight = targetX + imageW;
970 | targetBottom = targetY + imageH;
971 | // LogUtils.d("ACTION_MOVE " + (int) targetX + "," + (int) targetY + "," + (int) targetRight + "," + (int) targetBottom);
972 |
973 | for (int i = 0; i < mTops.size(); i++) {
974 | float consultTop = mTops.get(i);
975 | View line = mLines.get(i);
976 | ViewInfo lineInfo = (ViewInfo) line.getTag();
977 | if ((lineInfo.degree == 90 || lineInfo.degree == 270) && Math.abs(consultTop - targetBottom) <= LIMIT) { //在竖线上面
978 | int lineMiddleX = (2 * mRights.get(i) - line.getHeight()) / 2;//获取到线条的y/2
979 | if (disX >= 0) { //从左往右
980 | if (Math.abs(mLefts.get(i) - targetRight) <= OFFSET) {
981 | imageView.setX(lineMiddleX - imageW / 2);
982 | imageView.setY(consultTop - imageH + PADDING);
983 | imageView.setBackgroundResource(R.drawable.border_shape_green);
984 | Log.d(TAG, "竖线上边匹配成功 从左往右 targetBottom : " + targetBottom + ", consultTop: " + consultTop);
985 | }
986 | } else {
987 | if (Math.abs(targetX - mRights.get(i)) <= OFFSET) {
988 | imageView.setX(lineMiddleX - imageW / 2);
989 | imageView.setY(consultTop - imageH + PADDING);
990 | imageView.setBackgroundResource(R.drawable.border_shape_green);
991 | Log.d(TAG, "竖线上边匹配成功 从右往左 targetBottom : " + targetBottom + ", consultTop: " + consultTop);
992 | }
993 | }
994 | }
995 | }
996 |
997 | for (int i = 0; i < mBottoms.size(); i++) {
998 | float consultBottom = mBottoms.get(i);
999 | View line = mLines.get(i);
1000 | ViewInfo lineInfo = (ViewInfo) line.getTag();
1001 | if ((lineInfo.degree == 90 || lineInfo.degree == 270) && Math.abs(targetY - consultBottom) <= LIMIT) {
1002 | int lineMiddleX = (2 * mRights.get(i) - line.getHeight()) / 2;//获取到线条的y/2
1003 | if (disX >= 0) { //从左往右
1004 | if (Math.abs(mLefts.get(i) - targetRight) <= OFFSET) {
1005 | imageView.setX(lineMiddleX - imageW / 2);
1006 | imageView.setY(consultBottom - PADDING);
1007 | imageView.setBackgroundResource(R.drawable.border_shape_green);
1008 | Log.i(TAG, "竖线下边匹配成功 从左往右 targetY : " + targetY + ", consultBottom : " + consultBottom);
1009 | }
1010 | } else {
1011 | if (Math.abs(targetX - mRights.get(i)) <= OFFSET) {
1012 | imageView.setX(lineMiddleX - imageW / 2);
1013 | imageView.setY(consultBottom - PADDING);
1014 | imageView.setBackgroundResource(R.drawable.border_shape_green);
1015 | Log.i(TAG, "竖线下边匹配成功 从右往左 targetY : " + targetY + ", consultBottom : " + consultBottom);
1016 | }
1017 | }
1018 | }
1019 | }
1020 |
1021 | for (int i = 0; i < mLefts.size(); i++) {
1022 | float consultLeft = mLefts.get(i);
1023 | View line = mLines.get(i);
1024 | ViewInfo lineInfo = (ViewInfo) line.getTag();
1025 | if ((lineInfo.degree == 0 || lineInfo.degree == 180) && Math.abs(consultLeft - targetRight) <= LIMIT) {
1026 | int lineMiddleY = (2 * mBottoms.get(i) - line.getHeight()) / 2;//获取到线条的y/2
1027 | int newY = lineMiddleY - imageH / 2;
1028 | if (disY >= 0) { //从上到下
1029 | if (Math.abs(mTops.get(i) - targetBottom) <= OFFSET) {
1030 | imageView.setX(consultLeft - imageW + PADDING);
1031 | imageView.setY(newY);
1032 | imageView.setBackgroundResource(R.drawable.border_shape_green);
1033 | Log.d(TAG, "横线左边匹配成功 从上往下 targetRight : " + targetRight + " , consultLeft: " + consultLeft);
1034 | }
1035 | } else {
1036 | if (Math.abs(targetY - mBottoms.get(i)) <= OFFSET) {
1037 | imageView.setX(consultLeft - imageW + PADDING);
1038 | imageView.setY(newY);
1039 | imageView.setBackgroundResource(R.drawable.border_shape_green);
1040 | Log.d(TAG, "横线左边匹配成功 从下往上 targetRight : " + targetRight + " , consultLeft: " + consultLeft);
1041 | }
1042 | }
1043 | }
1044 | }
1045 |
1046 | for (int i = 0; i < mRights.size(); i++) {
1047 | float consultRight = mRights.get(i);
1048 | View line = mLines.get(i);
1049 | ViewInfo lineInfo = (ViewInfo) line.getTag();
1050 | if ((lineInfo.degree == 0 || lineInfo.degree == 180) && Math.abs(targetX - consultRight) <= LIMIT) {
1051 | int lineMiddleY = (2 * mBottoms.get(i) - line.getHeight()) / 2;//获取到线条的y/2
1052 | int newY = lineMiddleY - imageH / 2;
1053 | Log.d(TAG, "lineMiddleY : " + lineMiddleY + ", newY: " + newY);
1054 | if (disY >= 0) { //从上往下 1.如果targetBottom - con
1055 | if (Math.abs(mTops.get(i) - targetBottom) <= OFFSET) {
1056 | imageView.setX(consultRight - PADDING);
1057 | imageView.setY(newY);
1058 | imageView.setBackgroundResource(R.drawable.border_shape_green);
1059 | Log.d(TAG, "横线右边匹配成功 从上往下 targetX : " + targetX + " , consultRight: " + consultRight);
1060 | }
1061 | } else {
1062 | if (Math.abs(targetY - mBottoms.get(i)) <= OFFSET) {
1063 | imageView.setX(consultRight - PADDING);
1064 | imageView.setY(newY);
1065 | imageView.setBackgroundResource(R.drawable.border_shape_green);
1066 | Log.d(TAG, "横线右边匹配成功 从下往上 targetX : " + targetX + " , consultRight: " + consultRight);
1067 | }
1068 | }
1069 |
1070 | }
1071 | }
1072 |
1073 | }
1074 | }
1075 | }
1076 | return true;
1077 | case MotionEvent.ACTION_UP:
1078 | float x = imageView.getX();
1079 | float y = imageView.getY();
1080 |
1081 | if (System.currentTimeMillis() - downTime > 1500) {
1082 | //it's long click
1083 | } else {
1084 | if (viewInfo.id == R.id.rectIcon && mRectList != null && !mRectList.isEmpty()) {
1085 | boolean hasFocusOtherView = false;
1086 | for (View view : mRectList) {
1087 | int[] location = new int[2];
1088 | view.getLocationOnScreen(location);
1089 | Rect rect = new Rect();
1090 | rect.left = location[0];
1091 | rect.right = location[0] + view.getWidth();
1092 | rect.top = location[1];
1093 | rect.bottom = location[1] + view.getHeight();
1094 |
1095 | imageView.getLocationOnScreen(location);
1096 | int pX = location[0] + (int) event.getX();
1097 | int pY = location[1] + (int) event.getY();
1098 | if (rect.contains(pX, pY)) {
1099 | hasFocusOtherView = true;
1100 | mFocusViewList.add(view);
1101 | view.setBackgroundResource(R.drawable.border_shape_blue);
1102 | imageView.setBackgroundResource(R.drawable.border_shape);
1103 | mFocusViewList.remove(imageView);
1104 | imageView.setOnTouchListener(null);
1105 | break;
1106 | }
1107 | }
1108 |
1109 | if (!hasFocusOtherView) {
1110 | imageView.setOnTouchListener(new MyTouchListener(imageView));
1111 | mFocusViewList.add(imageView);
1112 | imageView.setBackgroundResource(R.drawable.border_shape_blue);
1113 | if (mRectList != null) {
1114 | for (View view : mRectList) {
1115 | view.setBackgroundColor(Color.TRANSPARENT);
1116 | mFocusViewList.remove(view);
1117 | }
1118 | }
1119 | imageView.requestLayout();
1120 | }
1121 | // removeViews(v);
1122 | } else {
1123 | mFocusViewList.add(imageView);
1124 | if (Math.abs(x - downImageX) <= 5 && Math.abs(y - downImageY) <= 5) {
1125 | imageView.setBackgroundResource(R.drawable.border_shape_blue);
1126 | }
1127 | }
1128 | }
1129 | if (x < 0) {
1130 | x = 0;
1131 | imageView.setX(x);
1132 | } else if (x > (mDisplayMetrics.widthPixels - 312 - 100)) {
1133 | x = mDisplayMetrics.widthPixels - 100 - 312;
1134 | imageView.setX(x);
1135 | }
1136 |
1137 | if (y <= 0) {
1138 | y = 0;
1139 | imageView.setY(y);
1140 | } else if (y > mDisplayMetrics.heightPixels - 100 - mStatusBarHeight - 107) {
1141 | y = mDisplayMetrics.heightPixels - 100 - mStatusBarHeight - 107;
1142 | imageView.setY(y);
1143 | }
1144 |
1145 | if (Math.abs(mStartX - x) >= 3 || Math.abs(mStartY - y) >= 3) {
1146 | createMemento(imageView, false, false);
1147 | }
1148 |
1149 | if (mRectList != null) {
1150 | mRectList.clear();
1151 | }
1152 | return true;
1153 | }
1154 | return false;
1155 | }
1156 | }
1157 |
1158 |
1159 | private void getLineCoordinate() {
1160 | mLefts.clear();
1161 | mTops.clear();
1162 | mRights.clear();
1163 | mBottoms.clear();
1164 | mLines.clear();
1165 | for (View view : mViewList) {
1166 | ViewInfo viewInfo = (ViewInfo) view.getTag();
1167 | if (R.id.lineIcon == viewInfo.id || R.id.xuxianIcon == viewInfo.id) {
1168 | mLines.add(view);
1169 |
1170 | int x = (int) view.getX();
1171 | int y = (int) view.getY();
1172 | int bottom = y + view.getHeight();
1173 | int right = x + view.getWidth();
1174 |
1175 | mLefts.add(x);
1176 | mTops.add(y);
1177 | mRights.add(right);
1178 | mBottoms.add(bottom);
1179 | }
1180 | }
1181 |
1182 | Log.d(TAG, "mLefts : " + mLefts.toString());
1183 | Log.i(TAG, "mTops : " + mTops.toString());
1184 | Log.d(TAG, "mRights : " + mRights.toString());
1185 | Log.i(TAG, "mBottoms : " + mBottoms.toString());
1186 |
1187 | }
1188 |
1189 | public Bitmap captureScreen() {
1190 | // 允许当前窗口保存缓存信息
1191 | for (int i = 0; i < mContent.getChildCount(); i++) {
1192 | View view = mContent.getChildAt(i);
1193 | if (view instanceof EditText) {
1194 | ((EditText) view).setCursorVisible(false);
1195 | }
1196 | view.clearFocus();
1197 | view.setBackgroundResource(android.R.color.transparent);
1198 | }
1199 | mContent.setBackgroundResource(android.R.color.white);
1200 | mContent.setDrawingCacheEnabled(true);
1201 | mContent.measure(View.MeasureSpec.makeMeasureSpec((int) (mContent.getWidth() * 1), View.MeasureSpec.EXACTLY),
1202 | View.MeasureSpec.makeMeasureSpec((int) (mContent.getHeight() * 1), View.MeasureSpec.EXACTLY));
1203 | mContent.layout(0, 0, mContent.getWidth(), mContent.getHeight());
1204 | mContent.buildDrawingCache();
1205 |
1206 | // 去掉状态栏
1207 | Bitmap cacheBmp = mContent.getDrawingCache();
1208 | Bitmap resultBmp = null;
1209 | if (null != cacheBmp) {
1210 | int width = mContent.getWidth();
1211 | int height = mContent.getHeight();
1212 | resultBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
1213 | Canvas canvas = new Canvas(resultBmp);
1214 | Rect srcRect = new Rect();
1215 | srcRect.left = 0;
1216 | srcRect.top = 0;
1217 | srcRect.right = cacheBmp.getWidth();
1218 | srcRect.bottom = cacheBmp.getHeight();
1219 |
1220 | Rect dstRect = new Rect();
1221 | dstRect.left = 0;
1222 | dstRect.top = 0;
1223 | dstRect.right = width;
1224 | dstRect.bottom = height;
1225 | canvas.drawBitmap(cacheBmp, srcRect, dstRect, new Paint());
1226 | cacheBmp.recycle();
1227 | }
1228 |
1229 | // 销毁缓存信息
1230 | mContent.setDrawingCacheEnabled(false);
1231 | mContent.destroyDrawingCache();
1232 | return resultBmp;
1233 | }
1234 |
1235 |
1236 | private boolean inRange(Rect srcRect, Rect checkRect) {
1237 | return srcRect.contains(checkRect);
1238 | }
1239 |
1240 | private List getNeedMoveView(Rect srcRect, ImageView imageView) {
1241 | List list = new ArrayList();
1242 | for (View view : mViewList) {
1243 | if (view == imageView) {
1244 | continue;
1245 | }
1246 | int[] location = new int[2];
1247 | view.getLocationOnScreen(location);
1248 | int x = location[0];
1249 | int y = location[1];
1250 | Rect checkRect = new Rect();
1251 | checkRect.left = x + 25;
1252 | checkRect.right = x + view.getWidth() - 25;
1253 | checkRect.top = y + 25;
1254 | checkRect.bottom = y + view.getHeight() - 25;
1255 | if (inRange(srcRect, checkRect)) {
1256 | list.add(view);
1257 | }
1258 | }
1259 |
1260 | return list;
1261 | }
1262 |
1263 | private void copyView(View view) {
1264 |
1265 | final ImageView imageView = new ImageView(MainActivity.this);
1266 | ViewInfo tag = (ViewInfo) view.getTag();
1267 |
1268 | ViewInfo viewInfo = new ViewInfo(tag.id, tag.degree);
1269 | viewInfo.type = tag.type;
1270 | viewInfo.color = tag.color;
1271 | viewInfo.realId = ++mRealInfoId;
1272 | viewInfo.width = tag.width;
1273 | viewInfo.height = tag.height;
1274 |
1275 | imageView.setTag(viewInfo);
1276 |
1277 | imageView.setScaleType(ImageView.ScaleType.FIT_XY);
1278 | setImageResource(imageView, false);
1279 | int[] location = new int[2];
1280 | view.getLocationOnScreen(location);
1281 | locationX = location[0];
1282 | locationY = location[1];
1283 | imageView.setX(locationX + 5);
1284 | imageView.setY(locationY + 5);
1285 | imageView.setOnTouchListener(new MyTouchListener(imageView));
1286 | if (viewInfo.degree != 0) {
1287 | imageView.setRotation(viewInfo.degree);
1288 | }
1289 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(view.getWidth(), view.getHeight());
1290 | mContent.addView(imageView, params);
1291 | mViewList.add(imageView);
1292 |
1293 | createMemento(imageView, false, true);
1294 | }
1295 |
1296 | public class ScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {
1297 | @Override
1298 | public boolean onScale(ScaleGestureDetector detector) {
1299 | float dSpan = detector.getCurrentSpan() - detector.getPreviousSpan();
1300 | float dScale = (dSpan * 0.1f) / 100f;
1301 | float scale = mCurrentScale + dScale;
1302 | if (scale > 4.0f) {
1303 | scale = 4.0f;
1304 | } else if (scale < 0.5f) {
1305 | scale = 0.5f;
1306 | }
1307 | mContent.setScaleX(scale);
1308 | mContent.setScaleY(scale);
1309 | mCurrentScale = scale;
1310 | return true;
1311 | }
1312 |
1313 | @Override
1314 | public boolean onScaleBegin(ScaleGestureDetector detector) {
1315 | mMoved = false;
1316 | return true;
1317 | }
1318 |
1319 | @Override
1320 | public void onScaleEnd(ScaleGestureDetector detector) {
1321 |
1322 | }
1323 | }
1324 | }
1325 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/MementoCreataker.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 | import android.widget.Toast;
4 |
5 | import com.lee.drawlayoutsample.utils.BaseUtils;
6 | import com.lee.drawlayoutsample.utils.LogUtils;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * Created by Lee on 2017/1/18.
13 | */
14 |
15 | public class MementoCreataker {
16 |
17 | // private MementoOriginator mOriginator;
18 | private List mMementos = new ArrayList<>();
19 | private List mBackups = new ArrayList<>();
20 |
21 | public void createMemento(ElementMemento memento) {
22 | // ElementMemento memento = mOriginator.createMemento();
23 | mMementos.add(memento);
24 | }
25 |
26 | public void createMemento(ElementMemento memento, int index) {
27 |
28 | int lastIndex = mMementos.size() - 1;
29 | LogUtils.i("lastIndex: " + lastIndex);
30 | LogUtils.d("start createMemento ,mMementos size:" + mMementos.size()+"\n #####"+mMementos.toString());
31 | if (index > lastIndex) {//直接加在最后一个节点位置
32 | LogUtils.d("插入到最后一个位置:" + index);
33 | createMemento(memento);
34 | } else if (index >= 0 && index <= lastIndex) {
35 | LogUtils.d("插入到指定位置:" + index);
36 | for (int i = mMementos.size() - 1; i >= index; i--) {
37 | mMementos.remove(i);
38 | }
39 | createMemento(memento);
40 | } else {
41 | throw new IndexOutOfBoundsException();
42 | }
43 | LogUtils.i("end createMemento ,mMementos size:" + mMementos.size()+"\n #####"+mMementos.toString());
44 | }
45 |
46 | public ElementMemento restoreMemento(int index) {
47 | if (index < 0 || index >= mMementos.size()) {
48 | if (index < 0) {
49 | Toast.makeText(BaseUtils.getContext(), "没有上一步了", Toast.LENGTH_SHORT).show();
50 | } else {
51 | Toast.makeText(BaseUtils.getContext(), "没有下一步了", Toast.LENGTH_SHORT).show();
52 | }
53 | return null;
54 | }
55 | // ElementMemento elementMemento = mMementos.get(index);
56 | // mOriginator.restoreMemento(elementMemento);
57 | return mMementos.get(index);
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/MementoOriginator.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 |
4 | import com.lee.drawlayoutsample.utils.LogUtils;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /**
10 | * Created by Lee on 2017/1/18.
11 | */
12 |
13 | public class MementoOriginator {
14 |
15 | private List mInfos;
16 |
17 | public MementoOriginator() {
18 | mInfos = new ArrayList<>();
19 | }
20 |
21 | public List restoreMemento(ElementMemento memento) {
22 | mInfos = memento.getInfos();
23 | return mInfos;
24 | }
25 |
26 | public ElementMemento createMemento() {
27 | return new ElementMemento(mInfos);
28 | }
29 |
30 | public void setInfos(List infos) {
31 | mInfos = infos;
32 | }
33 |
34 | public void printMementos() {
35 | LogUtils.d("mInfos size: " + mInfos.size() + " $$$ mInfos: " + mInfos.toString());
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/ViewInfo.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * Created by Lee on 2016/11/4.
10 | */
11 |
12 | public class ViewInfo implements Serializable, Parcelable {
13 |
14 | public ViewInfo(int id, float degree) {
15 | this.id = id;
16 | this.degree = degree;
17 | }
18 |
19 |
20 | public static final int TYPE_IMAGEVIEW = 0;
21 | public static final int TYPE_EDITTEXT = 1;
22 |
23 | public int id;
24 | public float degree;
25 | public int width;
26 | public int height;
27 | public float x;
28 | public float y;
29 | //0 imageView 1 EditText
30 | public int type;
31 | public int color;
32 | public int realId;
33 |
34 | // @Override
35 | // public boolean equals(Object o) {
36 | // if (o == null) {
37 | // return false;
38 | // }
39 | // if (o instanceof ViewInfo) {
40 | // ViewInfo info = (ViewInfo) o;
41 | // if (info.id == id && info.degree == degree && info.width == width && info.height == height
42 | // && info.x == x && info.y == y && info.type == type && info.color == color) {
43 | // return true;
44 | // }
45 | // }
46 | // return false;
47 | // }
48 |
49 | // @Override
50 | // public int hashCode() {
51 | // return Objects.hash(id, degree, width, height, x, y, type, color);
52 | // }
53 |
54 | public static final Creator CREATOR = new Creator() {
55 | @Override
56 | public ViewInfo createFromParcel(Parcel in) {
57 | return new ViewInfo(in);
58 | }
59 |
60 | @Override
61 | public ViewInfo[] newArray(int size) {
62 | return new ViewInfo[size];
63 | }
64 | };
65 |
66 | @Override
67 | public String toString() {
68 | return "ViewInfo{" +
69 | "id=" + id +
70 | ", degree=" + degree +
71 | ", width=" + width +
72 | ", height=" + height +
73 | ", x=" + x +
74 | ", y=" + y +
75 | ", type=" + type +
76 | ", color=" + color +
77 | ", realId=" + realId +
78 | '}';
79 | }
80 |
81 | @Override
82 | public int describeContents() {
83 | return 0;
84 | }
85 |
86 | @Override
87 | public void writeToParcel(Parcel dest, int flags) {
88 | dest.writeInt(this.id);
89 | dest.writeFloat(this.degree);
90 | dest.writeInt(this.width);
91 | dest.writeInt(this.height);
92 | dest.writeFloat(this.x);
93 | dest.writeFloat(this.y);
94 | dest.writeInt(this.type);
95 | dest.writeInt(this.color);
96 | }
97 |
98 | protected ViewInfo(Parcel in) {
99 | this.id = in.readInt();
100 | this.degree = in.readFloat();
101 | this.width = in.readInt();
102 | this.height = in.readInt();
103 | this.x = in.readFloat();
104 | this.y = in.readFloat();
105 | this.type = in.readInt();
106 | this.color = in.readInt();
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/utils/BaseUtils.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample.utils;
2 |
3 | import android.content.Context;
4 | import android.content.res.AssetManager;
5 | import android.content.res.Configuration;
6 | import android.content.res.Resources;
7 | import android.support.annotation.NonNull;
8 | import android.util.DisplayMetrics;
9 |
10 | public class BaseUtils {
11 |
12 | private static Context context;
13 |
14 | public static void initialize(@NonNull Context context) {
15 | BaseUtils.context = context;
16 | }
17 |
18 | public static Context getContext() {
19 | synchronized (BaseUtils.class) {
20 | if (BaseUtils.context == null)
21 | throw new NullPointerException("Call BaseUtils.initialize(context) within your Application onCreate() method.");
22 |
23 | return BaseUtils.context.getApplicationContext();
24 | }
25 | }
26 |
27 | public static Resources getResources() {
28 | return BaseUtils.getContext().getResources();
29 | }
30 |
31 | public static Resources.Theme getTheme() {
32 | return BaseUtils.getContext().getTheme();
33 | }
34 |
35 | public static AssetManager getAssets() {
36 | return BaseUtils.getContext().getAssets();
37 | }
38 |
39 | public static Configuration getConfiguration() {
40 | return BaseUtils.getResources().getConfiguration();
41 | }
42 |
43 | public static DisplayMetrics getDisplayMetrics() {
44 | return BaseUtils.getResources().getDisplayMetrics();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lee/drawlayoutsample/utils/LogUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013. wyouflf (wyouflf@gmail.com)
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.lee.drawlayoutsample.utils;
17 |
18 | import android.text.TextUtils;
19 | import android.util.Log;
20 |
21 | /**
22 | * Log工具,类似android.util.Log。
23 | * tag自动产生,格式: customTagPrefix:className.methodName(L:lineNumber),
24 | * customTagPrefix为空时只输出:className.methodName(L:lineNumber)。
25 | */
26 | public class LogUtils {
27 |
28 | public static String customTagPrefix = "";
29 |
30 | private LogUtils() {
31 | }
32 |
33 | private static boolean allowLog = true;
34 |
35 | private static boolean allowD = true;
36 |
37 | private static boolean allowE = true;
38 |
39 | private static boolean allowI = true;
40 |
41 | private static boolean allowV = true;
42 |
43 | private static boolean allowW = true;
44 |
45 | private static boolean allowWtf = true;
46 |
47 | private static String generateTag(StackTraceElement caller) {
48 | String tag = "%s.%s(L:%d)";
49 | String callerClazzName = caller.getClassName();
50 | callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
51 | tag = String.format(tag, callerClazzName, caller.getMethodName(), caller.getLineNumber());
52 | tag = TextUtils.isEmpty(customTagPrefix) ? tag : customTagPrefix + ":" + tag;
53 | return tag;
54 | }
55 |
56 | public static CustomLogger customLogger;
57 |
58 | public interface CustomLogger {
59 | void d(String tag, String content);
60 |
61 | void d(String tag, String content, Throwable tr);
62 |
63 | void e(String tag, String content);
64 |
65 | void e(String tag, String content, Throwable tr);
66 |
67 | void i(String tag, String content);
68 |
69 | void i(String tag, String content, Throwable tr);
70 |
71 | void v(String tag, String content);
72 |
73 | void v(String tag, String content, Throwable tr);
74 |
75 | void w(String tag, String content);
76 |
77 | void w(String tag, String content, Throwable tr);
78 |
79 | void w(String tag, Throwable tr);
80 |
81 | void wtf(String tag, String content);
82 |
83 | void wtf(String tag, String content, Throwable tr);
84 |
85 | void wtf(String tag, Throwable tr);
86 | }
87 |
88 | public static void d(String content) {
89 | if (!allowLog || !allowD)
90 | return;
91 | StackTraceElement caller = getCallerStackTraceElement();
92 | String tag = generateTag(caller);
93 |
94 | if (customLogger != null) {
95 | customLogger.d(tag, "" + content);
96 | } else {
97 | Log.d(tag, "" + content);
98 | }
99 | }
100 |
101 | public static void d(String content, Throwable tr) {
102 | if (!allowLog || !allowD)
103 | return;
104 | StackTraceElement caller = getCallerStackTraceElement();
105 | String tag = generateTag(caller);
106 |
107 | if (customLogger != null) {
108 | customLogger.d(tag, "" + content, tr);
109 | } else {
110 | Log.d(tag, "" + content, tr);
111 | }
112 | }
113 |
114 | public static void e(String content) {
115 | if (!allowE)
116 | return;
117 | StackTraceElement caller = getCallerStackTraceElement();
118 | String tag = generateTag(caller);
119 |
120 | if (customLogger != null) {
121 | customLogger.e(tag, "" + content);
122 | } else {
123 | Log.e(tag, "" + content);
124 | }
125 | }
126 |
127 | public static void e(String content, Throwable tr) {
128 | if (!allowE)
129 | return;
130 | StackTraceElement caller = getCallerStackTraceElement();
131 | String tag = generateTag(caller);
132 |
133 | if (customLogger != null) {
134 | customLogger.e(tag, "" + content, tr);
135 | } else {
136 | Log.e(tag, "" + content, tr);
137 | }
138 | }
139 |
140 | public static void i(String content) {
141 | if (!allowLog || !allowI)
142 | return;
143 | StackTraceElement caller = getCallerStackTraceElement();
144 | String tag = generateTag(caller);
145 |
146 | if (customLogger != null) {
147 | customLogger.i(tag, "" + content);
148 | } else {
149 | Log.i(tag, "" + content);
150 | }
151 | }
152 |
153 | public static void i(String content, Throwable tr) {
154 | if (!allowLog || !allowI)
155 | return;
156 | StackTraceElement caller = getCallerStackTraceElement();
157 | String tag = generateTag(caller);
158 |
159 | if (customLogger != null) {
160 | customLogger.i(tag, "" + content, tr);
161 | } else {
162 | Log.i(tag, "" + content, tr);
163 | }
164 | }
165 |
166 | public static void v(String content) {
167 | if (!allowLog || !allowV)
168 | return;
169 | StackTraceElement caller = getCallerStackTraceElement();
170 | String tag = generateTag(caller);
171 |
172 | if (customLogger != null) {
173 | customLogger.v(tag, "" + content);
174 | } else {
175 | Log.v(tag, "" + content);
176 | }
177 | }
178 |
179 | public static void v(String content, Throwable tr) {
180 | if (!allowLog || !allowV)
181 | return;
182 | StackTraceElement caller = getCallerStackTraceElement();
183 | String tag = generateTag(caller);
184 |
185 | if (customLogger != null) {
186 | customLogger.v(tag, "" + content, tr);
187 | } else {
188 | Log.v(tag, "" + content, tr);
189 | }
190 | }
191 |
192 | public static void w(String content) {
193 | if (!allowLog || !allowW)
194 | return;
195 | StackTraceElement caller = getCallerStackTraceElement();
196 | String tag = generateTag(caller);
197 |
198 | if (customLogger != null) {
199 | customLogger.w(tag, "" + content);
200 | } else {
201 | Log.w(tag, "" + content);
202 | }
203 | }
204 |
205 | public static void w(String content, Throwable tr) {
206 | if (!allowLog || !allowW)
207 | return;
208 | StackTraceElement caller = getCallerStackTraceElement();
209 | String tag = generateTag(caller);
210 |
211 | if (customLogger != null) {
212 | customLogger.w(tag, "" + content, tr);
213 | } else {
214 | Log.w(tag, "" + content, tr);
215 | }
216 | }
217 |
218 | public static void w(Throwable tr) {
219 | if (!allowLog || !allowW)
220 | return;
221 | StackTraceElement caller = getCallerStackTraceElement();
222 | String tag = generateTag(caller);
223 |
224 | if (customLogger != null) {
225 | customLogger.w(tag, tr);
226 | } else {
227 | Log.w(tag, tr);
228 | }
229 | }
230 |
231 |
232 | public static void wtf(String content) {
233 | if (!allowLog || !allowWtf)
234 | return;
235 | StackTraceElement caller = getCallerStackTraceElement();
236 | String tag = generateTag(caller);
237 |
238 | if (customLogger != null) {
239 | customLogger.wtf(tag, "" + content);
240 | } else {
241 | Log.wtf(tag, "" + content);
242 | }
243 | }
244 |
245 | public static void wtf(String content, Throwable tr) {
246 | if (!allowLog || !allowWtf)
247 | return;
248 | StackTraceElement caller = getCallerStackTraceElement();
249 | String tag = generateTag(caller);
250 |
251 | if (customLogger != null) {
252 | customLogger.wtf(tag, "" + content, tr);
253 | } else {
254 | Log.wtf(tag, "" + content, tr);
255 | }
256 | }
257 |
258 | public static void wtf(Throwable tr) {
259 | if (!allowLog || !allowWtf)
260 | return;
261 | StackTraceElement caller = getCallerStackTraceElement();
262 | String tag = generateTag(caller);
263 |
264 | if (customLogger != null) {
265 | customLogger.wtf(tag, tr);
266 | } else {
267 | Log.wtf(tag, tr);
268 | }
269 | }
270 |
271 | public static StackTraceElement getCallerStackTraceElement() {
272 | return Thread.currentThread().getStackTrace()[4];
273 | }
274 |
275 | }
276 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/actionbar_ic_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/actionbar_ic_cancel.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/actionbar_ic_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/actionbar_ic_copy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/actionbar_ic_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/actionbar_ic_delete.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/actionbar_ic_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/actionbar_ic_done.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/all_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/all_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/all_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/all_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/forward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/forward.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/gallery_toolbar_chinabrush_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/gallery_toolbar_chinabrush_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/hot_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/hot_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/hot_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/hot_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_menu_rotate_light_n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/ic_menu_rotate_light_n.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/jewelry_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/jewelry_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/jewelry_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/jewelry_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/line.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/line_nomal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/line_nomal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/line_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/line_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/smile_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/smile_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/smile_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/smile_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/text_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/text_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/text_select.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/text_select.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/wangge.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/drawable-hdpi/wangge.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_shape_blue.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_shape_focus.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_shape_green.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_shape_white.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/draw_selector_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_all_black.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_all_green.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_all_red.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_hot_black.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_hot_green.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_hot_red.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_jewelry_black.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_jewelry_green.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_jewelry_red.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_smile_black.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_smile_green.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_smile_red.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
33 |
34 |
39 |
40 |
48 |
49 |
58 |
67 |
76 |
77 |
78 |
79 |
81 |
82 |
83 |
93 |
94 |
104 |
105 |
115 |
116 |
126 |
127 |
136 |
137 |
146 |
157 |
167 |
177 |
178 |
182 |
183 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/draw_navigation_bar_layout.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
15 |
20 |
26 |
27 |
28 |
33 |
39 |
40 |
41 |
42 |
44 |
45 |
49 |
54 |
60 |
61 |
62 |
67 |
74 |
75 |
76 |
77 |
79 |
80 |
84 |
89 |
96 |
97 |
98 |
103 |
109 |
110 |
111 |
112 |
114 |
115 |
119 |
124 |
130 |
131 |
132 |
137 |
143 |
144 |
145 |
146 |
148 |
149 |
153 |
158 |
164 |
165 |
166 |
171 |
177 |
178 |
179 |
180 |
181 |
183 |
184 |
188 |
193 |
199 |
200 |
201 |
206 |
212 |
213 |
214 |
215 |
217 |
218 |
222 |
227 |
233 |
234 |
235 |
240 |
246 |
247 |
248 |
249 |
250 |
252 |
253 |
254 |
255 |
259 |
264 |
270 |
271 |
272 |
278 |
284 |
285 |
286 |
287 |
288 |
289 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DrawLayoutSample
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/lee/drawlayoutsample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.lee.drawlayoutsample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EnjoyAndroid/DrawLayoutSample/faa1906e097be400714047ea3b251c8cfbfe0b3e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Jul 22 22:06:08 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------