├── .gitignore
├── LICENSE.md
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── panxiaohe
│ │ └── springboard
│ │ └── demo
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── panxiaohe
│ │ │ └── springboard
│ │ │ └── demo
│ │ │ ├── ImageUtil.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MyAdapter.java
│ │ │ └── MyButtonItem.java
│ └── res
│ │ ├── drawable-xhdpi
│ │ ├── detail_icon_back_normal.png
│ │ ├── detail_icon_fav_normal.png
│ │ ├── detail_icon_share_normal.png
│ │ ├── ugly_edittext_bg.9.png
│ │ └── ugly_folder_background.png
│ │ ├── drawable
│ │ ├── account_bg.png
│ │ ├── folder_icon.png
│ │ └── new_phone.png
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── item.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── panxiaohe
│ └── springboard
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── panxiaohe
│ │ └── springboard
│ │ └── library
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ │ └── com
│ │ │ └── panxiaohe
│ │ │ └── springboard
│ │ │ └── library
│ │ │ ├── FavoritesItem.java
│ │ │ ├── FingerFlowViewManager.java
│ │ │ ├── FolderView.java
│ │ │ ├── MenuView.java
│ │ │ ├── SpringboardAdapter.java
│ │ │ └── SpringboardView.java
│ └── res
│ │ ├── anim
│ │ ├── cycle_7.xml
│ │ ├── shake.xml
│ │ └── shake_rotate.xml
│ │ ├── drawable-hdpi
│ │ └── icon_delete.png
│ │ ├── drawable
│ │ └── folder_background.xml
│ │ ├── layout
│ │ └── folder_layout.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ └── style.xml
│ └── test
│ └── java
│ └── com
│ └── panxiaohe
│ └── springboardlib
│ └── ExampleUnitTest.java
├── pic
└── screenShot1.gif
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | .idea/
18 | build/
19 | /springboard.iml
20 |
21 |
22 | # Local configuration file (sdk path, etc)
23 | local.properties
24 |
25 | # Proguard folder generated by Eclipse
26 | proguard/
27 |
28 | # Log Files
29 | *.log
30 |
31 | # Android Studio Navigation editor temp files
32 | .navigation/
33 |
34 | # Android Studio captures folder
35 | captures/
36 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # springboard View
2 | this is a view that can drag sort buttons and merge buttons to a folder.
3 | 能够拖动排序菜单,和合并文件夹,删除按钮View。
4 | 效果类似桌面和招商手机银行app最爱菜单.
5 | # Features
6 | 1:drag sort the buttons.拖动排序
7 | 2:drag button into a folder.把按钮拖进文件夹
8 | 3:drag button out of a folder.把按钮拖出文件夹
9 | 4:delete buttons in menu and folder.能够删除菜单和文件夹中的按钮
10 | 5:rename the folder.文件夹重命名.
11 | # view
12 | 
13 | # How to Work with the Source
14 | 1:make your data model extends com.panxiaohe.springboard.library.FavoritesItem;
15 |
16 | 2:make your adapter extends com.panxiaohe.springboard.library.SpringboardAdapter;
17 |
18 | 3:set the adapter to com.panxiaohe.springboard.library.MenuView;
19 |
20 | 4:springboardAdapter.onDataChange() will notice you data has change
21 | (when sortted change,moved in or out of folder,deleted button,changed folder name)
22 | you should save the change.
23 |
24 | 5:func setOnPageChangedListener(),setOnItemClickListener() is usefull too;
25 |
26 | 6:the attrs of the view :
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | # notice
44 | this view is not well tested.
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /app.iml
3 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.3"
6 |
7 | defaultConfig {
8 | applicationId "com.panxiaohe.springboard"
9 | minSdkVersion 16
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
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(include: ['*.jar'], dir: 'libs')
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.2.1'
26 | compile project(':library')
27 | }
28 |
--------------------------------------------------------------------------------
/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 /Users/panxiaohe/Library/Android/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 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/panxiaohe/springboard/demo/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.demo;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/panxiaohe/springboard/demo/ImageUtil.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.panxiaohe.springboard.demo;
5 |
6 | import java.io.ByteArrayOutputStream;
7 |
8 | import android.content.Context;
9 | import android.graphics.Bitmap;
10 | import android.graphics.Bitmap.CompressFormat;
11 | import android.graphics.Bitmap.Config;
12 | import android.graphics.BitmapFactory;
13 | import android.graphics.Canvas;
14 | import android.graphics.Paint;
15 | import android.graphics.drawable.BitmapDrawable;
16 | import android.graphics.drawable.Drawable;
17 | import android.graphics.drawable.StateListDrawable;
18 | import android.util.Base64;
19 |
20 | /**
21 | * @author panxiaohe
22 | */
23 | public class ImageUtil
24 | {
25 |
26 | private Context context;
27 |
28 | public ImageUtil(Context context)
29 | {
30 | this.context = context;
31 | }
32 |
33 | private static Drawable createDrawable(Drawable d, Paint p)
34 | {
35 |
36 | BitmapDrawable bd = (BitmapDrawable) d;
37 | Bitmap b = bd.getBitmap();
38 | Bitmap bitmap = Bitmap.createBitmap(bd.getIntrinsicWidth(), bd.getIntrinsicHeight(), Config.ARGB_8888);
39 | Canvas canvas = new Canvas(bitmap);
40 | canvas.drawBitmap(b, 0, 0, p); // 关键代码,使用新的Paint画原图,
41 |
42 | return new BitmapDrawable(bitmap);
43 | }
44 |
45 | /**
46 | * 设置Selector。 本次只增加点击变暗的效果,注释的代码为更多的效果
47 | */
48 | public static StateListDrawable createSLD(Drawable drawable)
49 | {
50 | StateListDrawable bg = new StateListDrawable();
51 | Paint p = new Paint();
52 | p.setColor(0x40222222); // Paint ARGB色值,A = 0x40 不透明。RGB222222 暗色
53 |
54 | Drawable normal = drawable;
55 | Drawable pressed = createDrawable(drawable, p);
56 | // p = new Paint();
57 | // p.setColor(0x8000FF00);
58 | // Drawable focused = createDrawable(drawable, p);
59 | // p = new Paint();
60 | // p.setColor(0x800000FF);
61 | // Drawable unable = createDrawable(drawable, p);
62 | // View.PRESSED_ENABLED_STATE_SET
63 | bg.addState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}, pressed);
64 | // View.ENABLED_FOCUSED_STATE_SET
65 | // bg.addState(new int[] { android.R.attr.state_enabled,
66 | // android.R.attr.state_focused }, focused);
67 | // View.ENABLED_STATE_SET
68 | bg.addState(new int[]{android.R.attr.state_enabled}, normal);
69 | // View.FOCUSED_STATE_SET
70 | // bg.addState(new int[] { android.R.attr.state_focused }, focused);
71 | // // View.WINDOW_FOCUSED_STATE_SET
72 | // bg.addState(new int[] { android.R.attr.state_window_focused },
73 | // unable);
74 | // View.EMPTY_STATE_SET
75 | bg.addState(new int[]{}, normal);
76 | return bg;
77 | }
78 |
79 | // /**
80 | // * 获取客户端本地图片
81 | // * */
82 | // public static Drawable getImageDrawable(String imageName, Context context) {
83 | // Util util = new Util(context);
84 | // int id = util.getDrawableId(imageName);
85 | // if (id != 0) {
86 | // return context.getResources().getDrawable(id);
87 | // } else {
88 | // return null;
89 | // }
90 | // }
91 | //
92 | public static Drawable getStateListDrawable(Drawable background)
93 | {
94 | // TODO Auto-generated method stub
95 | return createSLD(background);
96 | }
97 |
98 | // /**
99 | // * 获取带点击效果的图片对象
100 | // * */
101 | // public static StateListDrawable getStateListDrawable(int imageName, Context context) {
102 | // return getStateListDrawable(imageName, context);
103 | // }
104 |
105 | /**
106 | * @param imageName drawable的名称
107 | * @param context 包名
108 | * @return
109 | */
110 | public static StateListDrawable getStateListDrawable(int imageName, Context context)
111 | {
112 | Drawable drawable;
113 | drawable = context.getResources().getDrawable(imageName);
114 | if (drawable != null)
115 | {
116 | return createSLD(drawable);
117 | } else
118 | {
119 | return null;
120 | }
121 | }
122 |
123 | /**
124 | * 将Bitmap转换成字符串
125 | *
126 | * @param bitmap
127 | * @return
128 | * @author guo_fenghua
129 | */
130 | public static String bitmaptoString(Bitmap bitmap)
131 | {
132 | if (bitmap == null)
133 | {
134 | return "";
135 | }
136 | String string = null;
137 | ByteArrayOutputStream bStream = new ByteArrayOutputStream();
138 | bitmap.compress(CompressFormat.PNG, 100, bStream);
139 | byte[] bytes = bStream.toByteArray();
140 | string = Base64.encodeToString(bytes, Base64.DEFAULT);
141 | return string;
142 | }
143 |
144 | /**
145 | * 将字符串转换成Bitmap类型
146 | *
147 | * @param string
148 | * @return
149 | * @author guo_fenghua
150 | */
151 | public static Bitmap stringtoBitmap(String string)
152 | {
153 | Bitmap bitmap = null;
154 | try
155 | {
156 | byte[] bitmapArray;
157 | bitmapArray = Base64.decode(string, Base64.DEFAULT);
158 | bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length);
159 | } catch (Exception e)
160 | {
161 | e.printStackTrace();
162 | }
163 |
164 | return bitmap;
165 | }
166 |
167 | }
168 |
--------------------------------------------------------------------------------
/app/src/main/java/com/panxiaohe/springboard/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.demo;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 |
6 | import com.panxiaohe.springboard.library.FavoritesItem;
7 | import com.panxiaohe.springboard.library.MenuView;
8 | import com.panxiaohe.springboard.library.SpringboardView;
9 |
10 | import java.util.ArrayList;
11 |
12 | public class MainActivity extends AppCompatActivity
13 | {
14 |
15 | private MenuView springboard;
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState)
19 | {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_main);
22 | springboard = (MenuView) findViewById(R.id.springboard);
23 |
24 | ArrayList buttons = new ArrayList();
25 | buttons.add(new MyButtonItem("0", "item0", R.drawable.detail_icon_back_normal));
26 | buttons.add(new MyButtonItem("1", "item1", R.drawable.detail_icon_fav_normal));
27 | buttons.add(new MyButtonItem("2", "item2", R.drawable.detail_icon_share_normal));
28 | buttons.add(new MyButtonItem("3", "item3", R.drawable.detail_icon_back_normal));
29 | buttons.add(new MyButtonItem("4", "item4", R.drawable.detail_icon_fav_normal));
30 | buttons.add(new MyButtonItem("5", "item5", R.drawable.detail_icon_share_normal));
31 | buttons.add(new MyButtonItem("6", "item6", R.drawable.detail_icon_back_normal));
32 | buttons.add(new MyButtonItem("7", "item7", R.drawable.detail_icon_fav_normal));
33 | buttons.add(new MyButtonItem("8", "item8", R.drawable.detail_icon_share_normal));
34 | buttons.add(new MyButtonItem("9", "item9", R.drawable.detail_icon_back_normal));
35 | buttons.add(new MyButtonItem("10", "item10", R.drawable.detail_icon_fav_normal));
36 | buttons.add(new MyButtonItem("11", "item11", R.drawable.detail_icon_share_normal));
37 | buttons.add(new MyButtonItem("12", "item12", R.drawable.detail_icon_back_normal));
38 | buttons.add(new MyButtonItem("13", "item13", R.drawable.detail_icon_back_normal));
39 | buttons.add(new MyButtonItem("14", "item14", R.drawable.detail_icon_back_normal));
40 | buttons.add(new MyButtonItem("15", "item15", R.drawable.detail_icon_back_normal));
41 | buttons.add(new MyButtonItem("16", "item16", R.drawable.detail_icon_back_normal));
42 | buttons.add(new MyButtonItem("17", "item17", R.drawable.detail_icon_back_normal));
43 | buttons.add(new MyButtonItem("18", "item18", R.drawable.detail_icon_back_normal));
44 | buttons.add(new MyButtonItem("19", "item19", R.drawable.detail_icon_back_normal));
45 | buttons.add(new MyButtonItem("20", "item20", R.drawable.detail_icon_back_normal));
46 | buttons.add(new MyButtonItem("21", "item21", R.drawable.detail_icon_back_normal));
47 | buttons.add(new MyButtonItem("22", "item22", R.drawable.detail_icon_back_normal));
48 |
49 | MyAdapter myAdapter = new MyAdapter(buttons);
50 | springboard.setAdapter(myAdapter);
51 | springboard.setOnItemClickListener(new SpringboardView.OnItemClickListener()
52 | {
53 | @Override
54 | public void onItemClick(FavoritesItem item)
55 | {
56 | MyButtonItem myItem = (MyButtonItem) item;
57 | // Toast.makeText(MainActivity.this, " button : " + myItem.getData().getName() + "is clicked", Toast.LENGTH_SHORT).show();
58 | }
59 | });
60 |
61 | springboard.setOnPageChangedListener(new SpringboardView.OnPageChangedListener()
62 | {
63 | @Override
64 | public void onPageScroll(int from, int to)
65 | {
66 | // Toast.makeText(MainActivity.this, " springboardview scroll from page#" + from + " to page#" + to, Toast.LENGTH_SHORT).show();
67 | }
68 |
69 | @Override
70 | public void onPageCountChange(int oldCount, int newCount)
71 | {
72 | // Toast.makeText(MainActivity.this, "springboardview page count has changed from #" + oldCount + " to #" + newCount, Toast.LENGTH_SHORT).show();
73 | }
74 | });
75 | }
76 |
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/panxiaohe/springboard/demo/MyAdapter.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.demo;
2 |
3 | import android.graphics.drawable.Drawable;
4 | import android.graphics.drawable.StateListDrawable;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.FrameLayout;
9 | import android.widget.ImageView;
10 | import android.widget.LinearLayout;
11 | import android.widget.TextView;
12 | import android.widget.Toast;
13 |
14 | import com.panxiaohe.springboard.library.SpringboardAdapter;
15 |
16 | import java.util.ArrayList;
17 |
18 | /**
19 | * Created by panxiaohe on 16/3/20.
20 | * ff
21 | */
22 | public class MyAdapter extends SpringboardAdapter
23 | {
24 |
25 | public MyAdapter(ArrayList items)
26 | {
27 | setItems(items);
28 | }
29 |
30 | @Override
31 | public FrameLayout initItemView(int position, ViewGroup parent)
32 | {
33 | return (FrameLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
34 | }
35 |
36 | @Override
37 | public void configItemView(int position, FrameLayout view)
38 | {
39 | MyButtonItem item = getItem(position);
40 | ImageView menu_icon = (ImageView) view.findViewById(R.id.menu_icon);
41 | // ImageView menu_redDot = (ImageView)view.findViewById(R.id.redDot);
42 | TextView menu_name = (TextView) view.findViewById(R.id.menu_name);
43 | // ImageView menu_del = (ImageView)view.findViewById(R.id.menu_del);
44 | LinearLayout folder = (LinearLayout) view.findViewById(R.id.folder);
45 | // FrameLayout menu_container = (FrameLayout) view.findViewById(R.id.menu_container);
46 | menu_name.setText(item.getActionName());
47 | if (item.isFolder())
48 | {
49 | // menu_container.setBackgroundResource(R.drawable.folder_icon);
50 | menu_icon.setVisibility(View.GONE);
51 | folder.setVisibility(View.VISIBLE);
52 | ImageView[] images = new ImageView[4];
53 | images[0] = (ImageView) folder.findViewById(R.id.folder_button1);
54 | images[1] = (ImageView) folder.findViewById(R.id.folder_button2);
55 | images[2] = (ImageView) folder.findViewById(R.id.folder_button3);
56 | images[3] = (ImageView) folder.findViewById(R.id.folder_button4);
57 | for (int i = 0; i < 4; i++)
58 | {
59 | if (item.getSubItemCount() > i)
60 | {
61 | MyButtonItem button = item.getSubItem(i);
62 | Drawable drawable = view.getResources().getDrawable(button.getIcon());
63 | images[i].setImageDrawable(drawable);
64 | images[i].setVisibility(View.VISIBLE);
65 | } else
66 | {
67 | images[i].setVisibility(View.INVISIBLE);
68 | }
69 | }
70 | } else
71 | {
72 | // menu_container.setBackgroundResource(R.drawable.folder_icon);
73 | // menu_container.setBackgroundResource(0);
74 | menu_icon.setVisibility(View.VISIBLE);
75 | folder.setVisibility(View.GONE);
76 | StateListDrawable drawable = ImageUtil.getStateListDrawable(item.getIcon(), view.getContext());
77 | menu_icon.setImageDrawable(drawable);
78 | }
79 | }
80 |
81 | @Override
82 | public FrameLayout initSubItemView(int folderPosition, int position, ViewGroup parent)
83 | {
84 | return (FrameLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
85 | }
86 |
87 | @Override
88 | public void configSubItemView(int folderPosition, int position, FrameLayout view)
89 | {
90 | MyButtonItem item = getSubItem(folderPosition, position);
91 | ImageView menu_icon = (ImageView) view.findViewById(R.id.menu_icon);
92 | // ImageView menu_redDot = (ImageView)view.findViewById(R.id.redDot);
93 | TextView menu_name = (TextView) view.findViewById(R.id.menu_name);
94 | // ImageView menu_del = (ImageView)view.findViewById(R.id.menu_del);
95 | LinearLayout folder = (LinearLayout) view.findViewById(R.id.folder);
96 | // FrameLayout menu_container = (FrameLayout) view.findViewById(R.id.menu_container);
97 | menu_name.setText(item.getActionName());
98 | if (item.isFolder())
99 | {
100 | // menu_container.setBackgroundResource(R.drawable.folder_icon);
101 | menu_icon.setVisibility(View.GONE);
102 | folder.setVisibility(View.VISIBLE);
103 | ImageView[] images = new ImageView[4];
104 | images[0] = (ImageView) folder.findViewById(R.id.folder_button1);
105 | images[1] = (ImageView) folder.findViewById(R.id.folder_button2);
106 | images[2] = (ImageView) folder.findViewById(R.id.folder_button3);
107 | images[3] = (ImageView) folder.findViewById(R.id.folder_button4);
108 | for (int i = 0; i < 4; i++)
109 | {
110 | if (item.getSubItemCount() > i)
111 | {
112 | MyButtonItem button = item.getSubItem(i);
113 | Drawable drawable = view.getResources().getDrawable(button.getIcon());
114 | images[i].setImageDrawable(drawable);
115 | images[i].setVisibility(View.VISIBLE);
116 | } else
117 | {
118 | images[i].setVisibility(View.INVISIBLE);
119 | }
120 | }
121 | } else
122 | {
123 | // menu_container.setBackgroundResource(R.drawable.folder_icon);
124 | // menu_container.setBackgroundResource(0);
125 | menu_icon.setVisibility(View.VISIBLE);
126 | folder.setVisibility(View.GONE);
127 | StateListDrawable drawable = ImageUtil.getStateListDrawable(item.getIcon(), view.getContext());
128 | menu_icon.setImageDrawable(drawable);
129 | }
130 | }
131 |
132 | @Override
133 | public boolean ifCanMerge(int fromPosition, int toPosition)
134 | {
135 | return super.ifCanMerge(fromPosition, toPosition);
136 | }
137 |
138 | @Override
139 | public void onDataChange()
140 | {
141 | Toast.makeText(getSpringboardView().getContext(), "数据有变化", Toast.LENGTH_SHORT).show();
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/app/src/main/java/com/panxiaohe/springboard/demo/MyButtonItem.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.demo;
2 |
3 | import com.panxiaohe.springboard.library.FavoritesItem;
4 |
5 | import java.util.ArrayList;
6 |
7 | /**
8 | * Created by panxiaohe on 16/3/20.
9 | * 继承
10 | */
11 | public class MyButtonItem extends FavoritesItem
12 | {
13 |
14 | private String actionName;
15 |
16 | private String actionId;
17 |
18 | private int icon;
19 |
20 | private ArrayList menuList;
21 |
22 |
23 | @Override
24 | public void setActionName(String actionName)
25 | {
26 | this.actionName = actionName;
27 | }
28 |
29 | @Override
30 | public String getActionName()
31 | {
32 | return actionName;
33 | }
34 |
35 | @Override
36 | public void setActionId(String actionId)
37 | {
38 | this.actionId = actionId;
39 | }
40 |
41 | @Override
42 | public String getActionId()
43 | {
44 | return actionId;
45 | }
46 |
47 | @Override
48 | public boolean isFolder()
49 | {
50 | return menuList != null;
51 | }
52 |
53 | @Override
54 | public void addSubButton(FavoritesItem item, String defaultFolderName)
55 | {
56 |
57 | if (menuList == null || menuList.size() == 0)
58 | {
59 | menuList = new ArrayList<>();
60 | MyButtonItem newItem = new MyButtonItem();
61 | newItem.copy(this);
62 | menuList.add(newItem);
63 | setActionId("-1");
64 | setActionName(defaultFolderName);
65 | }
66 | menuList.add((MyButtonItem) item);
67 | }
68 |
69 | @Override
70 | protected void addSubItem(int position, FavoritesItem item)
71 | {
72 | menuList.add(position, (MyButtonItem) item);
73 | }
74 |
75 | @Override
76 | protected MyButtonItem removeSubItem(int position)
77 | {
78 | return menuList.remove(position);
79 | }
80 |
81 | @Override
82 | public void removeSubButton(int position)
83 | {
84 | menuList.remove(position);
85 |
86 | if (menuList.size() == 1)
87 | {
88 | copy(menuList.get(0));
89 | menuList = null;
90 | }
91 | }
92 |
93 | private void copy(MyButtonItem myButtonItem)
94 | {
95 | this.actionName = myButtonItem.actionName;
96 | this.actionId = myButtonItem.actionId;
97 | this.icon = myButtonItem.icon;
98 | }
99 |
100 | @Override
101 | public int getSubItemCount()
102 | {
103 | return menuList == null ? 0 : menuList.size();
104 | }
105 |
106 | @Override
107 | public MyButtonItem getSubItem(int position)
108 | {
109 | if (menuList != null)
110 | {
111 | if (menuList.size() > position)
112 | {
113 | return menuList.get(position);
114 | }
115 |
116 | }
117 | throw new IllegalStateException("按钮列表是空");
118 | }
119 |
120 | public int getIcon()
121 | {
122 | return icon;
123 | }
124 |
125 | public MyButtonItem(String actionId, String actionName, int icon)
126 | {
127 | this.actionName = actionName;
128 | this.actionId = actionId;
129 | this.icon = icon;
130 | }
131 |
132 | public MyButtonItem()
133 | {
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/detail_icon_back_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/drawable-xhdpi/detail_icon_back_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/detail_icon_fav_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/drawable-xhdpi/detail_icon_fav_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/detail_icon_share_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/drawable-xhdpi/detail_icon_share_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ugly_edittext_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/drawable-xhdpi/ugly_edittext_bg.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ugly_folder_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/drawable-xhdpi/ugly_folder_background.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/account_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/drawable/account_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/folder_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/drawable/folder_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/new_phone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/drawable/new_phone.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
22 |
23 |
31 |
32 |
38 |
39 |
44 |
45 |
51 |
52 |
59 |
60 |
61 |
62 |
67 |
68 |
74 |
75 |
82 |
83 |
84 |
85 |
86 |
87 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #99cdcdcd
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SpringboardDemo
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/panxiaohe/springboard/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/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:1.5.0'
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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Oct 21 11:34:03 PDT 2015
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-2.8-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 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /library.iml
3 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.3"
6 |
7 | defaultConfig {
8 | minSdkVersion 16
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | testCompile 'junit:junit:4.12'
24 | compile 'com.android.support:appcompat-v7:23.2.1'
25 | }
26 |
--------------------------------------------------------------------------------
/library/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 /Users/panxiaohe/Library/Android/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 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/panxiaohe/springboard/library/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.library;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/library/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/library/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/library/src/main/java/com/panxiaohe/springboard/library/FavoritesItem.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.library;
2 |
3 |
4 | import java.io.Serializable;
5 |
6 | /**
7 | * item model
8 | *
9 | * @author panxiaohe
10 | */
11 | public abstract class FavoritesItem implements Serializable
12 | {
13 |
14 | public abstract boolean isFolder();
15 |
16 | public abstract String getActionName();
17 |
18 | public abstract void setActionName(String name);
19 |
20 | public abstract void setActionId(String id);
21 |
22 | /**
23 | * 如果this是文件夹,返回"-1"
24 | * 否则请返回该按钮的唯一识别.
25 | */
26 | public abstract String getActionId();
27 |
28 | /**
29 | * 从文件夹中删除按钮
30 | */
31 | public abstract void removeSubButton(int position);
32 |
33 | public abstract void addSubButton(FavoritesItem item, String defaultFolderName);
34 |
35 | protected abstract void addSubItem(int position, FavoritesItem item);
36 |
37 | protected abstract FavoritesItem removeSubItem(int position);
38 |
39 | public abstract int getSubItemCount();
40 |
41 | public abstract FavoritesItem getSubItem(int position);
42 |
43 | @Override
44 | public int hashCode()
45 | {
46 | final int prime = 31;
47 | int result = 1;
48 | String actionId = getActionId();
49 | result = prime * result + ((actionId == null) ? 0 : actionId.hashCode());
50 | return result;
51 | }
52 |
53 | @Override
54 | public boolean equals(Object obj)
55 | {
56 | if (this == obj)
57 | return true;
58 | if (obj == null)
59 | return false;
60 | if (getClass() != obj.getClass())
61 | return false;
62 | FavoritesItem other = (FavoritesItem) obj;
63 | String actionId = getActionId();
64 | if (actionId == null)
65 | {
66 | if (other.getActionId() != null)
67 | return false;
68 | } else if (!actionId.equals(other.getActionId()))
69 | return false;
70 | return true;
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/library/src/main/java/com/panxiaohe/springboard/library/FingerFlowViewManager.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.library;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.PixelFormat;
6 | import android.view.Gravity;
7 | import android.view.WindowManager;
8 | import android.view.ViewGroup.LayoutParams;
9 | import android.widget.ImageView;
10 |
11 | /**
12 | * Created by panxiaohe on 16/3/9.
13 | *
14 | */
15 | public class FingerFlowViewManager
16 | {
17 |
18 | private static FingerFlowViewManager instance;
19 |
20 | private FingerFlowViewManager()
21 | {
22 | super();
23 | }
24 |
25 | public static FingerFlowViewManager getInstance()
26 | {
27 | if (instance == null)
28 | {
29 | instance = new FingerFlowViewManager();
30 | }
31 | return instance;
32 | }
33 |
34 | public WindowManager init(Context context)
35 | {
36 | if (figerFlowWindowManager == null)
37 | {
38 | figerFlowWindowManager = (WindowManager) context.getSystemService(
39 | Context.WINDOW_SERVICE);
40 | }
41 | return figerFlowWindowManager;
42 | }
43 |
44 | public void setUp(Context context, Bitmap bitmap, int x, int y)
45 | {
46 |
47 | WindowManager.LayoutParams windowParams = getLayoutParams();
48 |
49 | windowParams.x = x;
50 |
51 | windowParams.y = y;
52 |
53 | getDrawImageView(context).setImageBitmap(bitmap);
54 |
55 | init(context).addView(drawImageView, windowParams);
56 | }
57 |
58 | public ImageView getDrawImageView(Context context)
59 | {
60 |
61 | if (drawImageView == null)
62 | {
63 | drawImageView = new ImageView(context);
64 | }
65 |
66 | return drawImageView;
67 | }
68 |
69 | public void updatePosition(int x, int y)
70 | {
71 |
72 | WindowManager.LayoutParams windowParams = getLayoutParams();
73 |
74 | windowParams.x = x;
75 |
76 | windowParams.y = y;
77 |
78 | figerFlowWindowManager.updateViewLayout(drawImageView, windowParams);
79 | }
80 |
81 | public void remove()
82 | {
83 | figerFlowWindowManager.removeView(drawImageView);
84 | drawImageView = null;
85 | }
86 |
87 |
88 | private WindowManager figerFlowWindowManager;
89 |
90 | private ImageView drawImageView;
91 |
92 | private WindowManager.LayoutParams windowParams;
93 |
94 | private WindowManager.LayoutParams getLayoutParams()
95 | {
96 | if (windowParams == null)
97 | {
98 | windowParams = new WindowManager.LayoutParams();
99 | windowParams.gravity = Gravity.TOP | Gravity.START;
100 | windowParams.height = LayoutParams.WRAP_CONTENT;
101 | windowParams.width = LayoutParams.WRAP_CONTENT;
102 | windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
103 | | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
104 | | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
105 | | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
106 | windowParams.format = PixelFormat.TRANSLUCENT;
107 | windowParams.windowAnimations = 0;
108 | windowParams.alpha = 0.8f;
109 | }
110 | return windowParams;
111 | }
112 |
113 |
114 | public static void onDestory()
115 | {
116 | instance = null;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/library/src/main/java/com/panxiaohe/springboard/library/FolderView.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.library;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.KeyEvent;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 | import android.widget.FrameLayout;
9 |
10 |
11 | /**
12 | * Created by panxiaohe on 16/3/9.
13 | * 展示文件夹的View
14 | */
15 | public class FolderView extends SpringboardView
16 | {
17 |
18 |
19 | private boolean isOutOfFolder = false;
20 |
21 | private MenuView parentLayout;
22 |
23 | private FavoritesItem dragOutItem;
24 |
25 | private int folderPosition;
26 |
27 | public FolderView(Context context)
28 | {
29 | super(context);
30 | }
31 |
32 | public FolderView(Context context, AttributeSet attrs)
33 | {
34 | super(context, attrs);
35 | }
36 |
37 | public FolderView(Context context, AttributeSet attrs, int defStyle)
38 | {
39 | super(context, attrs, defStyle);
40 | }
41 |
42 | /**
43 | * 判断是否手指移动到文件夹外边了
44 | */
45 | public boolean moveOutFolder(int x, int y)
46 | {
47 | return x < 0 || y < 0 || x > getWidth() || y > getHeight();
48 | }
49 |
50 | @Override
51 | public void onBeingDragging(MotionEvent event, float v)
52 | {
53 |
54 | int x = (int) event.getX();
55 | int y = (int) event.getY();
56 |
57 | if (!isOutOfFolder && moveOutFolder(x, y))
58 | {
59 | // Log.e("FolderLayout", "拖动中,拖出文件夹区域了");
60 | getParentLayout().hideFolder();
61 | dragOutItem = getAdapter().tempRemoveItem(folderPosition, temChangPosition);
62 | isOutOfFolder = true;
63 | dragPosition = -1;
64 | }
65 |
66 | if (v < getmMinimumVelocity())
67 | {
68 | if (isOutOfFolder)
69 | {
70 | parentLayout.dragOnChild(dragOutItem, event);
71 | } else
72 | {
73 | if (dragPosition != -1 && temChangPosition != dragPosition)
74 | {
75 | // Log.e("FolderLayout", "交换位置 " + temChangPosition + " -->" + dragPosition);
76 | onExchange();
77 | }
78 | countPageChange(x);
79 | }
80 |
81 | }
82 | }
83 |
84 | @Override
85 | public void onDragFinished(MotionEvent event)
86 | {
87 |
88 | // int x = (int) event.getRawX();
89 | // int y = (int) event.getRawY();
90 | if (isOutOfFolder)
91 | {
92 | getParentLayout().onActionFolderClosed(dragOutItem, event);
93 | } else
94 | {
95 | // Log.e("FolderLayout", "拖动结束,安置在" + temChangPosition + "位置");
96 | getChildAt(temChangPosition).setVisibility(View.VISIBLE);
97 | // setAnimationEnd();
98 | // showDropAnimation(x, y);
99 | }
100 | }
101 |
102 | @Override
103 | public void onExchange()
104 | {
105 | getAdapter().exChangeSubItem(folderPosition, temChangPosition, dragPosition);
106 | getChildAt(dragPosition).setVisibility(View.INVISIBLE);
107 | temChangPosition = dragPosition;
108 | }
109 |
110 | @Override
111 | public boolean ifCanMove(int position)
112 | {
113 | return true;
114 | }
115 |
116 | @Override
117 | public boolean ifCanDelete(int position)
118 | {
119 | return getAdapter().ifCanDelete(folderPosition, position);
120 | }
121 |
122 |
123 | public MenuView getParentLayout()
124 | {
125 | return parentLayout;
126 | }
127 |
128 | public void setParentLayout(MenuView parentLayout)
129 | {
130 | this.parentLayout = parentLayout;
131 | }
132 |
133 | public int getFolderPosition()
134 | {
135 | return folderPosition;
136 | }
137 |
138 | public void setFolderPosition(int folderPosition)
139 | {
140 | this.folderPosition = folderPosition;
141 | }
142 |
143 |
144 | public void setAdapter(SpringboardAdapter mAdapter)
145 | {
146 | mAdapter.setFolderView(this);
147 | super.setAdapter(mAdapter);
148 | }
149 |
150 | @Override
151 | public void onItemClick(int position)
152 | {
153 | if (getAdapter().isEditting())
154 | {
155 | getAdapter().setEditing(false);
156 | } else
157 | {
158 | if (getOnItemClickListener() != null)
159 | {
160 | getOnItemClickListener().onItemClick(getAdapter().getSubItem(folderPosition, position));
161 | }
162 | }
163 |
164 |
165 | }
166 |
167 | @Override
168 | public int getItemCount()
169 | {
170 | return getAdapter().getSubItemCount(folderPosition);
171 | }
172 |
173 | @Override
174 | public FrameLayout initItemView(int position)
175 | {
176 | FrameLayout view = mAdapter.initSubItemView(folderPosition, position, this);
177 | mAdapter.configSubItemView(folderPosition, position, view);
178 | return view;
179 | }
180 |
181 | @Override
182 | public void onDelete(int position)
183 | {
184 | getAdapter().deleteItem(folderPosition, position);
185 | computePageCountChange(false);
186 | }
187 |
188 | @Override
189 | public boolean dispatchKeyEvent(KeyEvent event)
190 | {
191 | if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
192 | {
193 | getParentLayout().removeFolder();
194 | return true;
195 | }
196 | return super.dispatchKeyEvent(event);
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/library/src/main/java/com/panxiaohe/springboard/library/MenuView.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.library;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.PixelFormat;
6 | import android.graphics.drawable.Drawable;
7 | import android.os.Build;
8 | import android.text.TextUtils;
9 | import android.util.AttributeSet;
10 | import android.util.TypedValue;
11 | import android.view.LayoutInflater;
12 | import android.view.MotionEvent;
13 | import android.view.View;
14 | import android.view.WindowManager;
15 | import android.view.KeyEvent;
16 | import android.view.animation.Animation;
17 | import android.view.animation.AnimationUtils;
18 | import android.widget.EditText;
19 | import android.widget.FrameLayout;
20 | import android.widget.ImageView;
21 | import android.widget.LinearLayout;
22 |
23 | /**
24 | * Created by panxiaohe on 16/3/9.
25 | * 使用这个布局显示按钮
26 | */
27 | public class MenuView extends SpringboardView
28 | {
29 |
30 | // 文件夹相关
31 |
32 | private View folderView;
33 |
34 | private WindowManager windowManager;
35 |
36 | private WindowManager getWindowManager()
37 | {
38 | if (windowManager == null)
39 | {
40 | windowManager = (WindowManager) getContext().getSystemService(
41 | Context.WINDOW_SERVICE);
42 | }
43 | return windowManager;
44 | }
45 |
46 |
47 | private WindowManager.LayoutParams getWindowParams()
48 | {
49 | WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams();
50 | windowParams.height = LayoutParams.MATCH_PARENT;
51 | windowParams.width = LayoutParams.MATCH_PARENT;
52 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
53 | {
54 | windowParams.flags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
55 | } else
56 | {
57 | windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
58 | }
59 | windowParams.format = PixelFormat.TRANSLUCENT;
60 | windowParams.windowAnimations = 0;
61 | windowParams.x = 0;
62 | windowParams.y = 0;
63 | return windowParams;
64 | }
65 |
66 | private int folderColCount = 3;
67 | private int folderRowCount = 3;
68 |
69 | private Drawable folderDialogBackground;
70 | private Drawable folderViewBackground;
71 | private Drawable editTextBackground;
72 | private int folder_editText_textColor;
73 | private float folder_editText_textSize;
74 |
75 | public MenuView(Context context)
76 | {
77 | this(context, null);
78 | }
79 |
80 | public MenuView(Context context, AttributeSet attrs)
81 | {
82 | this(context, attrs, R.style.Springboard);
83 | }
84 |
85 | public MenuView(Context context, AttributeSet attrs, int defStyle)
86 | {
87 | super(context, attrs, defStyle);
88 | init(context, attrs, defStyle, 0);
89 | }
90 |
91 | private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
92 | {
93 | final TypedArray a = context.obtainStyledAttributes(
94 | attrs, R.styleable.Springboard, defStyleAttr, defStyleRes);
95 | folderDialogBackground = a.getDrawable(R.styleable.Springboard_folder_dialog_background);
96 | folderViewBackground = a.getDrawable(R.styleable.Springboard_folder_view_background);
97 | editTextBackground = a.getDrawable(R.styleable.Springboard_folder_edittext_background);
98 | folderColCount = a.getInt(R.styleable.Springboard_folder_column_count, 3);
99 | folderRowCount = a.getInt(R.styleable.Springboard_folder_row_count, 3);
100 | folder_editText_textColor = a.getColor(R.styleable.Springboard_folder_edittext_textcolor, 0);
101 | folder_editText_textSize = a.getDimensionPixelSize(R.styleable.Springboard_folder_edittext_textsize, 15);
102 | a.recycle();
103 | // 点击区域外取消编辑状态
104 | this.setOnClickListener(new OnClickListener()
105 | {
106 |
107 | @Override
108 | public void onClick(View v)
109 | {
110 | getAdapter().setEditing(false);
111 | }
112 | });
113 | }
114 |
115 |
116 | @Override
117 | public void onItemClick(int position)
118 | {
119 | if (getAdapter().getItem(position).isFolder())
120 | {
121 | showFolder(position);
122 | } else
123 | {
124 | if (getAdapter().isEditting())
125 | {
126 | getAdapter().setEditing(false);
127 | } else
128 | {
129 | if (getOnItemClickListener() != null)
130 | {
131 | getOnItemClickListener().onItemClick(getAdapter().getItem(position));
132 | }
133 | }
134 | }
135 | }
136 |
137 | @Override
138 | public int getItemCount()
139 | {
140 | return getAdapter().getCount();
141 | }
142 |
143 | @Override
144 | public FrameLayout initItemView(int position)
145 | {
146 | FrameLayout view = mAdapter.initItemView(position, this);
147 | mAdapter.configItemView(position, view);
148 | return view;
149 | }
150 |
151 | @Override
152 | public void onBeingDragging(MotionEvent event, float v)
153 | {
154 |
155 | int x = (int) event.getX();
156 | // int y = (int)event.getY();
157 | if (v < getmMinimumVelocity())
158 | {
159 | // Log.e("速度",v+"");
160 | //初始位置和触摸位置不同时
161 | if (dragPosition != -1 && dragPosition != temChangPosition)
162 | {
163 | // 如果在头部或尾部区域,不进行操作
164 | if (ifCanMove(dragPosition))
165 | {
166 | //如果被拖动的是文件夹或者不在item内部区域,交换位置
167 | if ((getAdapter().getItem(temChangPosition).isFolder()) || (!isInCenter(dragPosition, event)))
168 | {
169 | // Log.e("MenuView", "拖动中,交换位置,从" + temChangPosition + "到" + dragPosition);
170 | onExchange();
171 | }
172 | // else
173 | // {
174 | // Log.e("MenuView", "在文件夹中dragPosition = "+dragPosition);
175 | // }
176 | }
177 | }
178 | countPageChange(x);
179 | }
180 | // else
181 | // {
182 | // Log.e("MenuView", "speed too fast v= "+v);
183 | // }
184 | }
185 |
186 | @Override
187 | protected void onLayout(boolean changed, int l, int t, int r, int b)
188 | {
189 | super.onLayout(changed, l, t, r, b);
190 |
191 | }
192 |
193 | @Override
194 | public void onDragFinished(MotionEvent event)
195 | {
196 | // int x = (int) event.getX();
197 | // int y = (int) event.getY();
198 | //可以合并
199 | if (getAdapter().ifCanMerge(temChangPosition, dragPosition))
200 | {
201 | //在目标位置中心区域
202 | if (dragPosition != -1 && temChangPosition != dragPosition && isInCenter(dragPosition, event))
203 | {
204 | onMerge(temChangPosition, dragPosition);
205 | }
206 | }
207 | // getChildAt(temChangPosition).setVisibility(View.VISIBLE);
208 | // setAnimationEnd();
209 | // showDropAnimation(x, y);
210 | }
211 |
212 | @Override
213 | public void onExchange()
214 | {
215 | mAdapter.exchangeItem(temChangPosition, dragPosition);
216 | temChangPosition = dragPosition;
217 | // movePostionAnimation(temChangPosition, dragPosition);
218 | getChildAt(dragPosition).setVisibility(View.INVISIBLE);
219 |
220 | }
221 |
222 | @Override
223 | public boolean ifCanMove(int position)
224 | {
225 | return position >= getStableHeaderCount() && !(position == getChildCount() - 1 && isLastItemStable());
226 |
227 | }
228 |
229 | @Override
230 | public boolean ifCanDelete(int position)
231 | {
232 | if (position < getStableHeaderCount())
233 | {
234 | return false;
235 | }
236 | return !(position == getChildCount() - 1 && isLastItemStable()) && getAdapter().ifCanDelete(position);
237 |
238 | }
239 |
240 | protected void onActionFolderClosed(FavoritesItem dragOutItem, MotionEvent event)
241 | {
242 | int x = (int) event.getRawX();
243 | int y = (int) event.getRawY();
244 | removeFolder();
245 | if (temChangPosition != -1)
246 | {
247 | getChildAt(temChangPosition).setVisibility(View.VISIBLE);
248 | } else
249 | {
250 | int[] locations = new int[2];
251 | this.getLocationOnScreen(locations);
252 | x = x - locations[0];
253 | y = y - locations[1];
254 | dragPosition = pointToPosition(x, y);
255 | // Log.e("dragPosition = ",dragPosition+"");
256 | if (dragPosition != -1 && isInCenter(dragPosition, event) && ifCanMove(dragPosition))
257 | {
258 | // Log.e("ScrollLayout", "拖动结束,合并到文件夹 position = "+dragOutItem);
259 | getAdapter().addItemToFolder(dragPosition, dragOutItem, defaultFolderName);
260 | } else
261 | {
262 | // Log.e("ScrollLayout", "拖动结束,添加按钮到最后");
263 | int position = getChildCount();
264 | if (isLastItemStable())
265 | {
266 | position--;
267 | }
268 | getAdapter().addItem(position, dragOutItem);
269 |
270 | computePageCountChange(true);
271 |
272 | if (getmCurScreen() < getTotalPage() - 1)
273 | {
274 | snapToScreen(getTotalPage() - 1);
275 | }
276 | }
277 | }
278 | dragPosition = temChangPosition = -1;
279 | }
280 |
281 | /**
282 | * @param event 触摸点位置
283 | * @param dragOutItem 被拖出的按钮
284 | */
285 | protected void dragOnChild(FavoritesItem dragOutItem, MotionEvent event)
286 | {
287 |
288 | if (!mScroller.isFinished() || mLayoutTransition.isRunning())
289 | {
290 | return;
291 | }
292 |
293 | int x = (int) event.getRawX();
294 | int y = (int) event.getRawY();
295 | int[] locations = new int[2];
296 | this.getLocationOnScreen(locations);
297 | x = x - locations[0];
298 | y = y - locations[1];
299 | dragPosition = pointToPosition(x, y);
300 | // Log.e("dragOnChild", "mCurScreen" + getmCurScreen() + " dragPosition = " + dragPosition + " temChangPosition = " + temChangPosition);
301 | if (dragPosition != -1)
302 | {
303 | if (temChangPosition != -1)
304 | {
305 | if (isLastItemStable() && dragPosition == getItemCount() - 1)
306 | {
307 | // Log.e("dragOnChild", "在最后区域不交换");
308 | } else
309 | {
310 | if (temChangPosition != dragPosition && ifCanMove(dragPosition))
311 | {
312 | if (isInCenter(dragPosition, event))
313 | {
314 | // Log.e("dragOnChild", "删除位置是temChangPosition 的按钮");
315 | onDelete(temChangPosition);
316 | temChangPosition = -1;
317 | } else
318 | {
319 | // Log.e("dragOnChild","交换位置 "+temChangPosition +""+dragPosition);
320 | onExchange();
321 | }
322 | } else
323 | {
324 | // Log.e("dragOnChild","位置没变");
325 | }
326 | }
327 | } else
328 | {
329 | if (isLastItemStable() && dragPosition == getItemCount() - 1)
330 | {
331 | // Log.e("dragOnChild","添加按钮到位置 "+dragPosition);
332 | getAdapter().addItem(dragPosition, dragOutItem);
333 | temChangPosition = dragPosition;
334 | getChildAt(temChangPosition).setVisibility(View.INVISIBLE);
335 | computePageCountChange(true);
336 | } else
337 | {
338 | if (!isInCenter(dragPosition, event) && ifCanMove(dragPosition))
339 | {
340 | // Log.e("dragOnChild","添加按钮到位置 "+dragPosition);
341 | getAdapter().addItem(dragPosition, dragOutItem);
342 | temChangPosition = dragPosition;
343 | getChildAt(temChangPosition).setVisibility(View.INVISIBLE);
344 | computePageCountChange(true);
345 | } else
346 | {
347 | // Log.e("dragOnChild","在文件夹中或者"+dragPosition);
348 | }
349 | }
350 | }
351 | } else if (temChangPosition != -1)
352 | {
353 | // Log.e("dragOnChild","移除View区域,删除位置是"+temChangPosition + " 的按钮");
354 | onDelete(temChangPosition);
355 | temChangPosition = -1;
356 | }
357 | countPageChange(x);
358 | }
359 |
360 | /**
361 | * 显示文件夹
362 | */
363 | public void showFolder(int position)
364 | {
365 | if (getAdapter().isEditting())
366 | {
367 | stopShake();
368 | isStopShake = true;
369 | }
370 | FavoritesItem info = getAdapter().getItem(position);
371 | folderView = LayoutInflater.from(getContext()).inflate(R.layout.folder_layout, this, false);
372 | if (folderDialogBackground != null)
373 | {
374 | folderView.setBackground(folderDialogBackground);
375 | }
376 | LinearLayout linearLayout = (LinearLayout) folderView.findViewById(R.id.folder_container);
377 |
378 | if (folderViewBackground != null)
379 | {
380 | linearLayout.setBackground(folderViewBackground);
381 | }
382 | EditText editText = (EditText) folderView.findViewById(R.id.editText1);
383 | if (editTextBackground != null)
384 | {
385 | editText.setBackground(editTextBackground);
386 | }
387 | if (folder_editText_textColor != 0)
388 | {
389 | editText.setTextColor(folder_editText_textColor);
390 | }
391 | editText.setTextSize(TypedValue.COMPLEX_UNIT_PX, folder_editText_textSize);
392 | editText.setText(info.getActionName());
393 |
394 | FolderView layout = (FolderView) folderView.findViewById(R.id.container);
395 |
396 | layout.setParentLayout(this);
397 | layout.setColCount(folderColCount);
398 | layout.setRowCount(folderRowCount);
399 | layout.setFolderPosition(position);
400 | layout.setAdapter(getAdapter());
401 | layout.setOnItemClickListener(getOnItemClickListener());
402 | folderView.setOnClickListener(new OnClickListener()
403 | {
404 |
405 | @Override
406 | public void onClick(View v)
407 | {
408 | removeFolder();
409 | }
410 | });
411 | getWindowManager().addView(folderView, getWindowParams());
412 |
413 | getAdapter().initFolderEditingMode();
414 |
415 | }
416 |
417 | public void stopShake()
418 | {
419 | int count = getChildCount();
420 | for (int i = 0; i < count; i++)
421 | {
422 | View child = getChildAt(i);
423 | ImageView imageView = (ImageView) child.findViewById(R.id.delete_button_id);
424 | FrameLayout layout = (FrameLayout) child.findViewById(R.id.shake_zone_id);
425 | ;
426 | imageView.clearAnimation();
427 | layout.clearAnimation();
428 | }
429 | }
430 |
431 | public void startShake()
432 | {
433 | int count = getChildCount();
434 | for (int i = 0; i < count; i++)
435 | {
436 | View child = getChildAt(i);
437 | ImageView imageView = (ImageView) child.findViewById(R.id.delete_button_id);
438 | FrameLayout layout = (FrameLayout) child.findViewById(R.id.shake_zone_id);
439 | Animation shake;
440 | if (ifCanMove(i))
441 | {
442 | if (imageView.getVisibility() == View.VISIBLE)
443 | {
444 | shake = AnimationUtils.loadAnimation(getContext(), R.anim.shake);
445 | imageView.startAnimation(shake);
446 | }
447 | shake = AnimationUtils.loadAnimation(getContext(), R.anim.shake_rotate);
448 | layout.startAnimation(shake);
449 | }
450 | }
451 | }
452 |
453 | /**
454 | * 隐藏View
455 | */
456 | public void hideFolder()
457 | {
458 | // Log.e("ScrollLayout", "隐藏文件夹");
459 | if (folderView != null)
460 | {
461 | WindowManager.LayoutParams params = getWindowParams();
462 | params.alpha = 0;
463 | getWindowManager().updateViewLayout(folderView, params);
464 | }
465 |
466 | if (getAdapter().isEditting())
467 | {
468 | if (isStopShake == true)
469 | {
470 | startShake();
471 | isStopShake = false;
472 | }
473 | }
474 | }
475 |
476 | private boolean isStopShake = false;
477 |
478 | /**
479 | * 清除View
480 | */
481 | public void removeFolder()
482 | {
483 | // Log.e("ScrollLayout", "是否在编辑状态"+getAdapter().isEditting());
484 | if (getAdapter().isEditting())
485 | {
486 | if (isStopShake == true)
487 | {
488 | startShake();
489 | isStopShake = false;
490 | }
491 | }
492 |
493 | if (folderView != null)
494 | {
495 |
496 | EditText editText = (EditText) folderView.findViewById(R.id.editText1);
497 | String name = editText.getText().toString();
498 | if (TextUtils.isEmpty(name))
499 | {
500 | name = defaultFolderName;
501 | }
502 | getAdapter().changeFolderName(name);
503 | getWindowManager().removeView(folderView);
504 | folderView = null;
505 | getAdapter().removeFolder();
506 | }
507 | }
508 |
509 |
510 | @Override
511 | public boolean dispatchKeyEvent(KeyEvent event)
512 | {
513 |
514 | if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && getAdapter().isEditting())
515 | {
516 | getAdapter().setEditing(false);
517 | return true;
518 | }
519 |
520 | return super.dispatchKeyEvent(event);
521 | }
522 |
523 | public boolean isShowingFolder()
524 | {
525 | return folderView != null;
526 | }
527 |
528 |
529 | public void setAdapter(SpringboardAdapter mAdapter)
530 | {
531 | mAdapter.setSpringboardView(this);
532 | super.setAdapter(mAdapter);
533 | }
534 |
535 | @Override
536 | public void onDelete(int position)
537 | {
538 | getAdapter().deleteItem(position);
539 | computePageCountChange(true);
540 | }
541 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/panxiaohe/springboard/library/SpringboardAdapter.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.library;
2 |
3 |
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.FrameLayout;
7 |
8 | import java.lang.ref.SoftReference;
9 | import java.util.ArrayList;
10 |
11 | /**
12 | * Created by panxiaohe on 16/3/19.
13 | * 适配器.
14 | */
15 | public abstract class SpringboardAdapter
16 | {
17 | private ArrayList items;
18 |
19 | private boolean isEditing = false;
20 |
21 | private boolean isTouching = false;
22 |
23 | private SoftReference springboardView;
24 |
25 | private SoftReference folderView;
26 |
27 | /**
28 | * 首个层级数量
29 | */
30 | public int getCount()
31 | {
32 | return items.size();
33 | }
34 |
35 | /**
36 | * 文件夹里按钮数量
37 | */
38 | public int getSubItemCount(int position)
39 | {
40 | return items.get(position).getSubItemCount();
41 | }
42 |
43 | /**
44 | * 首个层级item
45 | */
46 | public T getItem(int position)
47 | {
48 | return items.get(position);
49 | }
50 |
51 | /**
52 | * 首个层级item
53 | */
54 | public T getSubItem(int folderPosition, int position)
55 | {
56 | return (T) items.get(folderPosition).getSubItem(position);
57 | }
58 |
59 | /**
60 | * @return 只需返回所需的view, 所有设置请在configUI里完成
61 | */
62 | public abstract FrameLayout initItemView(int position, ViewGroup parent);
63 |
64 | public abstract void configItemView(int position, FrameLayout frameLayout);
65 |
66 | /**
67 | * @return 只需返回所需的view, 所有设置请在configUI里完成
68 | */
69 | public abstract FrameLayout initSubItemView(int folderPosition, int position, ViewGroup parent);
70 |
71 | public abstract void configSubItemView(int folderPosition, int position, FrameLayout frameLayout);
72 |
73 | public void exchangeItem(int fromPosition, int toPosition)
74 | {
75 | // Log.e("SpringboardAdapter","exchangeItem fromPosition = "+fromPosition+" toPosition = "+toPosition);
76 | T item = items.remove(fromPosition);
77 |
78 | SpringboardView container = getSpringboardView();
79 |
80 | FrameLayout view = (FrameLayout) container.getChildAt(fromPosition);
81 |
82 | container.removeView(view);
83 |
84 | items.add(toPosition, item);
85 |
86 | dataChange();
87 |
88 | container.addView(view, toPosition);
89 |
90 | getSpringboardView().setEditingMode(toPosition, view, isEditing, true);
91 |
92 | }
93 |
94 | public void exChangeSubItem(int folderPosition, int fromPosition, int toPosition)
95 | {
96 | // Log.e("SpringboardAdapter","exChangeSubItem folderPosition = "+folderPosition +" fromPosition = "+fromPosition+" toPosition = "+toPosition);
97 | T folder = items.get(folderPosition);
98 |
99 | T item = (T) folder.removeSubItem(fromPosition);
100 | // (T)folder.getMenuList().remove(fromPosition);
101 |
102 | SpringboardView container = getFolderView();
103 |
104 | FrameLayout view = (FrameLayout) container.getChildAt(fromPosition);
105 |
106 | container.removeView(view);
107 |
108 | folder.addSubItem(toPosition, item);
109 |
110 | dataChange();
111 |
112 | container.addView(view, toPosition);
113 |
114 | configItemView(folderPosition, (FrameLayout) getSpringboardView().getChildAt(folderPosition));
115 |
116 | getFolderView().setEditingMode(toPosition, view, isEditing, true);
117 |
118 | }
119 |
120 | public void deleteItem(int position)
121 | {
122 | // Log.e("SpringboardAdapter","deleteItem position = "+position);
123 | items.remove(position);
124 |
125 | onDataChange();
126 |
127 | getSpringboardView().removeViewAt(position);
128 | }
129 |
130 | public void deleteItem(int folderPosition, int position)
131 | {
132 | // Log.e("SpringboardAdapter","deleteItem folderPosition = "+folderPosition+" position = "+position);
133 | T folder = items.get(folderPosition);
134 |
135 | folder.removeSubButton(position);
136 |
137 | onDataChange();
138 |
139 | getFolderView().removeViewAt(position);
140 |
141 | FrameLayout view = (FrameLayout) getSpringboardView().getChildAt(folderPosition);
142 |
143 | configItemView(folderPosition, view);
144 |
145 | if (!folder.isFolder())
146 | {
147 | getSpringboardView().setEditingMode(folderPosition, view, isEditing, true);
148 | getSpringboardView().removeFolder();
149 | } else
150 | {
151 | getSpringboardView().setEditingMode(folderPosition, view, isEditing, false);
152 | }
153 | }
154 |
155 |
156 | public void mergeItem(int fromPosition, int toPosition, String defaultFolderName)
157 | {
158 | // Log.e("SpringboardAdapter","mergeItem fromPosition = "+fromPosition+" toPosition = "+toPosition);
159 | T fromItem = items.get(fromPosition);
160 |
161 | T toItem = items.get(toPosition);
162 |
163 | toItem.addSubButton(fromItem, defaultFolderName);
164 |
165 | FrameLayout view = (FrameLayout) getSpringboardView().getChildAt(toPosition);
166 |
167 | configItemView(toPosition, view);
168 |
169 | getSpringboardView().setEditingMode(toPosition, view, isEditing, true);
170 |
171 | items.remove(fromPosition);
172 |
173 | dataChange();
174 |
175 | getSpringboardView().removeViewAt(fromPosition);
176 | }
177 |
178 | public T tempRemoveItem(int folderPosition, int position)
179 | {
180 | T folder = items.get(folderPosition);
181 |
182 | T item = (T) folder.getSubItem(position);
183 |
184 | folder.removeSubButton(position);
185 |
186 | FrameLayout view = (FrameLayout) getSpringboardView().getChildAt(folderPosition);
187 |
188 | configItemView(folderPosition, view);
189 |
190 | getSpringboardView().setEditingMode(folderPosition, view, isEditing, true);
191 |
192 | return item;
193 | }
194 |
195 | public void addItem(int position, T item)
196 | {
197 | // Log.e("SpringboardAdapter","addItem position = "+position);
198 | items.add(position, item);
199 |
200 | dataChange();
201 |
202 | FrameLayout view = getSpringboardView().initItemView(position);
203 | getSpringboardView().configView(view);
204 | getSpringboardView().addView(view, position);
205 |
206 | getSpringboardView().setEditingMode(position, view, isEditing, true);
207 |
208 | }
209 |
210 | public void addItemToFolder(int dragPosition, T dragOutItem, String defaultName)
211 | {
212 | // Log.e("SpringboardAdapter","addItemToFolder position = "+dragPosition);
213 | T folder = items.get(dragPosition);
214 |
215 | folder.addSubButton(dragOutItem, defaultName);
216 |
217 | dataChange();
218 |
219 | configItemView(dragPosition, (FrameLayout) getSpringboardView().getChildAt(dragPosition));
220 | }
221 |
222 | private void dataChange()
223 | {
224 | if (!isTouching)
225 | {
226 | onDataChange();
227 | }
228 | }
229 |
230 |
231 | public MenuView getSpringboardView()
232 | {
233 | return springboardView.get();
234 | }
235 |
236 | public void setSpringboardView(MenuView mSpringboardView)
237 | {
238 | this.springboardView = new SoftReference<>(mSpringboardView);
239 | }
240 |
241 | public FolderView getFolderView()
242 | {
243 | if (folderView != null)
244 | {
245 | return folderView.get();
246 |
247 | }
248 | return null;
249 | }
250 |
251 | public void setFolderView(FolderView folderView)
252 | {
253 | this.folderView = new SoftReference<>(folderView);
254 | }
255 |
256 | /**
257 | * @param position 位置
258 | * @return true 可以删除
259 | */
260 | public boolean ifCanDelete(int position)
261 | {
262 | // Log.e("SpringboardAdapter",getItem(position).toString());
263 | return !getItem(position).isFolder();
264 | }
265 |
266 | /**
267 | * @param position 位置
268 | * @return true 可以删除
269 | */
270 | public boolean ifCanDelete(int folderPosition, int position)
271 | {
272 | return !getSubItem(folderPosition, position).isFolder();
273 | }
274 |
275 | public boolean ifCanMerge(int fromPosition, int toPosition)
276 | {
277 | return !(getItem(fromPosition).isFolder() || (!getSpringboardView().ifCanMove(toPosition)));
278 | }
279 |
280 | public void changeFolderName(String name)
281 | {
282 | int folderPosition = getFolderView().getFolderPosition();
283 | T item = items.get(folderPosition);
284 | if (item.isFolder())
285 | {
286 | String oldName = items.get(folderPosition).getActionName();
287 | if (!oldName.equals(name))
288 | {
289 | items.get(folderPosition).setActionName(name);
290 |
291 | onDataChange();
292 |
293 | configItemView(folderPosition, (FrameLayout) getSpringboardView().getChildAt(folderPosition));
294 | }
295 | }
296 | }
297 |
298 | public void setEditing(boolean isEditing)
299 | {
300 | if (this.isEditing != isEditing)
301 | {
302 | // Log.e("SpringboardAdapter", "编辑模式" + isEditing);
303 | this.isEditing = isEditing;
304 | FolderView folder;
305 | if (folderView != null && (folder = folderView.get()) != null)
306 | {
307 | int count = folder.getChildCount();
308 | for (int i = 0; i < count; i++)
309 | {
310 | View child = folder.getChildAt(i);
311 | folder.setEditingMode(i, child, isEditing, true);
312 | }
313 | if (isEditting())
314 | {
315 | folder.requestFocus();
316 | }
317 | int count1 = getSpringboardView().getChildCount();
318 | for (int i = 0; i < count1; i++)
319 | {
320 | View child1 = getSpringboardView().getChildAt(i);
321 | getSpringboardView().setEditingMode(i, child1, isEditing, false);
322 | }
323 | } else
324 | {
325 | if (isEditting())
326 | {
327 | getSpringboardView().requestFocus();
328 | }
329 | int count1 = getSpringboardView().getChildCount();
330 | for (int i = 0; i < count1; i++)
331 | {
332 | View child1 = getSpringboardView().getChildAt(i);
333 | getSpringboardView().setEditingMode(i, child1, isEditing, true);
334 | }
335 | }
336 | }
337 | }
338 |
339 | public void initFolderEditingMode()
340 | {
341 | if (isEditing)
342 | {
343 | FolderView folder;
344 | if (folderView != null && (folder = folderView.get()) != null)
345 | {
346 | int count = folder.getChildCount();
347 | for (int i = 0; i < count; i++)
348 | {
349 | View child = folder.getChildAt(i);
350 | folder.setEditingMode(i, child, isEditing, true);
351 | }
352 | if (isEditting())
353 | {
354 | folder.requestFocus();
355 | }
356 | }
357 | }
358 | }
359 |
360 | public boolean isEditting()
361 | {
362 | return isEditing;
363 | }
364 |
365 | public void removeFolder()
366 | {
367 | setFolderView(null);
368 | }
369 |
370 | public abstract void onDataChange();
371 |
372 | public ArrayList getItems()
373 | {
374 | return items;
375 | }
376 |
377 | public void setItems(ArrayList items)
378 | {
379 | this.items = items;
380 | }
381 |
382 |
383 | protected boolean isTouching()
384 | {
385 | return isTouching;
386 | }
387 |
388 | protected void setIsTouching(boolean isTouching)
389 | {
390 | this.isTouching = isTouching;
391 | }
392 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/panxiaohe/springboard/library/SpringboardView.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard.library;
2 |
3 | import android.animation.LayoutTransition;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Bitmap;
7 | import android.graphics.Canvas;
8 | import android.graphics.Paint;
9 | import android.graphics.Rect;
10 | import android.graphics.RectF;
11 | import android.graphics.drawable.Drawable;
12 | import android.util.AttributeSet;
13 | import android.view.Gravity;
14 | import android.view.MotionEvent;
15 | import android.view.VelocityTracker;
16 | import android.view.View;
17 | import android.view.ViewConfiguration;
18 | import android.view.ViewGroup;
19 | import android.view.animation.Animation;
20 | import android.view.animation.AnimationUtils;
21 | import android.widget.FrameLayout;
22 | import android.widget.ImageView;
23 | import android.widget.Scroller;
24 |
25 |
26 | /**
27 | * Created by panxiaohe on 16/3/9.
28 | *
29 | * 这个类提供布局相关,各种监听的设置和基本事件的处理
30 | *
31 | * 具体的各种触摸事件处理请使用子类
32 | */
33 | public abstract class SpringboardView extends ViewGroup
34 | {
35 |
36 | // #页面相关
37 | /**
38 | * callback onPageCountChange() at totalPage count change
39 | * callback onPageScroll() at mCurScreen change
40 | * 在页面数量和当面页面发生变化时回调
41 | */
42 | private OnPageChangedListener onPageChangedListener;
43 | /**
44 | * 适配器
45 | */
46 | protected SpringboardAdapter mAdapter;
47 | /**
48 | * 总页面数量
49 | * will count totalPage at setAdapter,merge into Folder,delete item,add item,remove out Folder
50 | */
51 | private int totalPage = 0;
52 | /**
53 | * 现在页面
54 | */
55 | private int mCurScreen = 0;
56 |
57 |
58 | // #触摸相关
59 | /**
60 | * 开始时的x坐标
61 | */
62 | private int startX = 0;
63 | /**
64 | * 速度计算
65 | */
66 | private VelocityTracker mVelocityTracker;
67 | /**
68 | * 最后的触摸位置X
69 | */
70 | private float mLastMotionX;
71 | /**
72 | * 最后的触摸位置Y
73 | */
74 | private float mLastMotionY;
75 | /**
76 | * 触摸点距离View左边的距离
77 | */
78 | private int dragPointX;
79 | /**
80 | * 触摸点距离View顶部的距离
81 | */
82 | private int dragPointY;
83 | /**
84 | * view左边距离屏幕的距离
85 | */
86 | private int dragOffsetX;
87 | /**
88 | * view上边距离屏幕的距离
89 | */
90 | private int dragOffsetY;
91 | /**
92 | * 当前手指触摸的位置
93 | */
94 | protected int dragPosition = -1;
95 | /**
96 | * 拖动开始时和顺序交换之后被拖动View的位置
97 | */
98 | protected int temChangPosition = -1;
99 | protected Scroller mScroller;
100 | private int mTouchSlop;
101 | private int mMinimumVelocity;
102 | private int mMaximumVelocity;
103 | private MODE mode = MODE.FREE;
104 |
105 | enum MODE
106 | {
107 | //普通时,按钮被长按之后,进入这个模式,滚动模式
108 | FREE, DRAGGING, SCROLL
109 | }
110 |
111 |
112 | // #各种属性
113 | /**
114 | * 删除按钮
115 | */
116 | private Drawable deleteIcon;
117 | /**
118 | * 几行
119 | */
120 | private int rowCount;
121 | /**
122 | * 几列
123 | */
124 | private int colCount;
125 | /**
126 | * 合并按钮,产生文件夹时的默认按钮
127 | */
128 | protected String defaultFolderName;
129 | protected int dividerWidth;
130 | protected int dividerColor;
131 | private boolean isLastItemStable;
132 | private int stableHeaderCount;
133 | protected int page_divider_width;
134 |
135 |
136 | private Paint mPaint;
137 | protected LayoutTransition mLayoutTransition;
138 | // private int halfBitmapWidth;
139 | // private int halfBitmapHeight;
140 |
141 | public SpringboardView(Context context)
142 | {
143 | this(context, null);
144 | }
145 |
146 | public SpringboardView(Context context, AttributeSet attrs)
147 | {
148 | this(context, attrs, R.style.Springboard);
149 | }
150 |
151 | public SpringboardView(Context context, AttributeSet attrs, int defStyle)
152 | {
153 | super(context, attrs, defStyle);
154 | initSpringboardView(context, attrs, defStyle, 0);
155 | }
156 |
157 | private void initSpringboardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
158 | {
159 | final TypedArray a = context.obtainStyledAttributes(
160 | attrs, R.styleable.Springboard, defStyleAttr, defStyleRes);
161 | deleteIcon = a.getDrawable(R.styleable.Springboard_delete_icon);
162 | rowCount = a.getInt(R.styleable.Springboard_row_count, 3);
163 | colCount = a.getInt(R.styleable.Springboard_column_count, 3);
164 | defaultFolderName = a.getString(R.styleable.Springboard_default_folder_name);
165 | dividerWidth = a.getDimensionPixelOffset(R.styleable.Springboard_divider_width, 0);
166 | dividerColor = a.getColor(R.styleable.Springboard_divider_color, 0);
167 | isLastItemStable = a.getBoolean(R.styleable.Springboard_is_last_item_stable, false);
168 | stableHeaderCount = a.getInt(R.styleable.Springboard_stable_header_count, 0);
169 | page_divider_width = a.getDimensionPixelOffset(R.styleable.Springboard_page_divider_width, 0);
170 |
171 | if (dividerWidth != 0 && dividerColor != 0)
172 | {
173 | setWillNotDraw(false);
174 | }
175 | a.recycle();
176 | setFocusable(true);
177 | setFocusableInTouchMode(true);
178 | this.mScroller = new Scroller(getContext());
179 | FingerFlowViewManager.getInstance().init(getContext());
180 | setOverScrollMode(OVER_SCROLL_ALWAYS);
181 | final ViewConfiguration configuration = ViewConfiguration.get(getContext());
182 | mTouchSlop = configuration.getScaledTouchSlop();
183 | mMinimumVelocity = 700;
184 | mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
185 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
186 | mLayoutTransition = new LayoutTransition();
187 | mLayoutTransition.setAnimator(LayoutTransition.DISAPPEARING, null);
188 | mLayoutTransition.setAnimator(LayoutTransition.APPEARING, null);
189 | setLayoutTransition(mLayoutTransition);
190 | }
191 |
192 | @Override
193 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
194 | {
195 |
196 | int childHeight;
197 | int measuredHeight;
198 | //父给出的宽度,不管什么模式用完
199 | int width = MeasureSpec.getSize(widthMeasureSpec);
200 | // int widthMode = MeasureSpec.getMode(widthMeasureSpec);
201 |
202 | //可以使用的宽度
203 | int usedWidth = width - getPaddingLeft() - getPaddingRight() - (colCount + 1)
204 | * dividerWidth;
205 | int childWidth = usedWidth / colCount;
206 | int height = MeasureSpec.getSize(heightMeasureSpec);
207 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
208 | //如果有准确高度,按准确高度计算.
209 | if (heightMode == MeasureSpec.EXACTLY)
210 | {
211 | int usedHeight = height - getPaddingTop() - getPaddingBottom() - (rowCount + 1)
212 | * dividerWidth;
213 |
214 | childHeight = usedHeight / rowCount;
215 |
216 | measuredHeight = height;
217 |
218 | } else
219 | {
220 | childHeight = usedWidth / colCount;
221 |
222 | measuredHeight = childHeight * rowCount + (rowCount + 1) * dividerWidth + getPaddingTop() + getPaddingBottom();
223 |
224 | if (heightMode == MeasureSpec.AT_MOST)
225 | {
226 | if (measuredHeight > height)
227 | {
228 | measuredHeight = height;
229 | }
230 | }
231 | }
232 |
233 | int childWidthSpec = getChildMeasureSpec(
234 | MeasureSpec
235 | .makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
236 | 0, childWidth);
237 |
238 | int childHeightSpec = getChildMeasureSpec(
239 | MeasureSpec
240 | .makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
241 | 0, childHeight);
242 | final int count = getChildCount();
243 | for (int i = 0; i < count; i++)
244 | {
245 | View child = getChildAt(i);
246 | child.measure(childWidthSpec, childHeightSpec);
247 |
248 | }
249 | setMeasuredDimension(width, measuredHeight);
250 | }
251 |
252 | @Override
253 | protected void onLayout(boolean changed, int l, int t, int r, int b)
254 | {
255 | final int childCount = getChildCount();
256 |
257 | int measuredWidth = getMeasuredWidth();
258 |
259 | for (int i = 0; i < childCount; i++)
260 | {
261 | final View childView = getChildAt(i);
262 | if (childView.getVisibility() != View.GONE)
263 | {
264 |
265 | int page = i / rowCount / colCount;
266 |
267 | int row = i / colCount % rowCount;
268 |
269 | int col = i % colCount;
270 |
271 | int left = getPaddingLeft() + page * (measuredWidth + page_divider_width) + col
272 | * (dividerWidth + childView.getMeasuredWidth()) + dividerWidth;
273 |
274 | int top = getPaddingTop() + dividerWidth + row * (dividerWidth + childView.getMeasuredHeight());
275 |
276 | childView.layout(left, top, left + childView.getMeasuredWidth(),
277 | top + childView.getMeasuredHeight());
278 |
279 | }
280 | }
281 | }
282 |
283 | @Override
284 | protected void onDraw(Canvas canvas)
285 | {
286 | super.onDraw(canvas);
287 | mPaint.setColor(dividerColor);
288 | int childHeight = getChildHeight();
289 | int childWidth = getChildWidth();
290 | int rowCount = getRowCount() + 1;
291 |
292 | int pageCount = getTotalPage();
293 |
294 | for (int j = 0; j < pageCount; j++)
295 | {
296 | for (int i = 0; i < rowCount; i++)
297 | {
298 | int count = (childHeight + dividerWidth) * i;
299 |
300 | canvas.drawRect(j * (getWidth() + page_divider_width), count, (j + 1) * getWidth() + j * page_divider_width, count + dividerWidth, mPaint);
301 | }
302 |
303 | int colCount = getColCount() + 1;
304 | for (int i = 0; i < colCount; i++)
305 | {
306 | int count = (childWidth + dividerWidth) * i + j * (getWidth() + page_divider_width);
307 | canvas.drawRect(count, 0, count + dividerWidth, getHeight(), mPaint);
308 | }
309 | }
310 | }
311 |
312 |
313 | @Override
314 | public boolean onInterceptTouchEvent(MotionEvent ev)
315 | {
316 | // Log.e("onInterceptTouchEvent", ev.toString());
317 | int action = ev.getAction();
318 |
319 | if ((action == MotionEvent.ACTION_MOVE) && (mode == MODE.DRAGGING))
320 | {
321 | initVelocityTrackerIfNotExists();
322 | mVelocityTracker.addMovement(ev);
323 | return true;
324 | }
325 |
326 | float x = ev.getX();
327 | float y = ev.getY();
328 |
329 | switch (action)
330 | {
331 | case MotionEvent.ACTION_DOWN:
332 | startX = (int) x;
333 | dragOffsetX = (int) (ev.getRawX() - x);
334 | dragOffsetY = (int) (ev.getRawY() - y);
335 | mLastMotionX = x;
336 | mLastMotionY = y;
337 | initOrResetVelocityTracker();
338 | mVelocityTracker.addMovement(ev);
339 | stopScroll();
340 | if (mAdapter != null)
341 | {
342 | mAdapter.setIsTouching(true);
343 | }
344 | break;
345 | case MotionEvent.ACTION_MOVE:
346 | initVelocityTrackerIfNotExists();
347 | mVelocityTracker.addMovement(ev);
348 | int deltaX = (int) (mLastMotionX - x);
349 | if (ifCanScroll(deltaX))
350 | {
351 | mode = MODE.SCROLL;
352 | getParent().requestDisallowInterceptTouchEvent(true);
353 | recycleVelocityTracker();
354 | return true;
355 | }
356 | break;
357 | case MotionEvent.ACTION_CANCEL:
358 | getAdapter().setEditing(false);
359 | case MotionEvent.ACTION_UP:
360 | if (mAdapter != null)
361 | {
362 | mAdapter.setIsTouching(false);
363 | }
364 | if (mode == MODE.DRAGGING)
365 | {
366 | dragPosition = pointToPosition((int) x, (int) y);
367 | onDragFinished(ev);
368 | endDrag();
369 | } else if (mode == MODE.SCROLL)
370 | {
371 | float distance = ev.getRawX() - startX;
372 | endScroll(distance);
373 | }
374 | if (mode != MODE.FREE)
375 | {
376 | getParent().requestDisallowInterceptTouchEvent(false);
377 | }
378 | startX = 0;
379 | mode = MODE.FREE;
380 | recycleVelocityTracker();
381 | break;
382 | }
383 | return false;
384 | }
385 |
386 | @Override
387 | public boolean onTouchEvent(MotionEvent event)
388 | {
389 | // Log.e("onTouchEvent", event.toString());
390 | int action = event.getAction();
391 | int x = (int) event.getX();
392 | int y = (int) event.getY();
393 |
394 | switch (action)
395 | {
396 | case MotionEvent.ACTION_MOVE:
397 | switch (mode)
398 | {
399 | case DRAGGING:
400 | int viewX = x - dragPointX + dragOffsetX;
401 | int viewY = y - dragPointY + dragOffsetY;
402 | onFling(viewX, viewY);
403 | mVelocityTracker.addMovement(event);
404 | mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
405 | // 判断速度如果速度大于highSpeed,不处理移动
406 | dragPosition = pointToPosition(x, y);
407 | if (mScroller.isFinished() && (!mLayoutTransition.isRunning()))
408 | {
409 | float v = calculateV(mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
410 | onBeingDragging(event, v);
411 | }
412 | break;
413 | case SCROLL:
414 | int deltaX = (int) (mLastMotionX - x);
415 | mLastMotionX = x;
416 | scrollBy(deltaX, 0);
417 | break;
418 | case FREE:
419 | int deltaX1 = (int) (mLastMotionX - x);
420 | if (ifCanScroll(deltaX1))
421 | {
422 | getParent().requestDisallowInterceptTouchEvent(true);
423 | mode = MODE.SCROLL;
424 | }
425 | break;
426 | }
427 | break;
428 | case MotionEvent.ACTION_CANCEL:
429 | getAdapter().setEditing(false);
430 | case MotionEvent.ACTION_UP:
431 | if (mAdapter != null)
432 | {
433 | mAdapter.setIsTouching(false);
434 | }
435 | if (mode == MODE.DRAGGING)
436 | {
437 | dragPosition = pointToPosition(x, y);
438 | onDragFinished(event);
439 | endDrag();
440 | } else if (mode == MODE.SCROLL)
441 | {
442 | float distance = event.getRawX() - startX;
443 | endScroll(distance);
444 | } else
445 | {
446 | getAdapter().setEditing(false);
447 | }
448 | if (mode != MODE.FREE)
449 | {
450 | getParent().requestDisallowInterceptTouchEvent(false);
451 | }
452 | startX = 0;
453 | mode = MODE.FREE;
454 | recycleVelocityTracker();
455 | break;
456 | }
457 | return true;
458 | }
459 |
460 | private float calculateV(float xVelocity, float yVelocity)
461 | {
462 | return (float) Math.sqrt(xVelocity * xVelocity + yVelocity * yVelocity);
463 | }
464 |
465 | /**
466 | * 拖动时处理
467 | */
468 | public abstract void onBeingDragging(MotionEvent event, float v);
469 |
470 | public abstract void onDragFinished(MotionEvent event);
471 |
472 | public abstract void onExchange();
473 |
474 | /**
475 | * 拖动开始时的初始化
476 | */
477 | public void onStartFling(View itemView, int x, int y)
478 | {
479 | itemView.destroyDrawingCache();
480 | itemView.setDrawingCacheEnabled(true);
481 | Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());
482 | itemView.setVisibility(View.INVISIBLE);
483 | dragPointX = x - itemView.getLeft() + getmCurScreen() * getMeasuredWidth();
484 | dragPointY = y - itemView.getTop();
485 | int viewX = x - dragPointX + dragOffsetX;
486 | int viewy = y - dragPointY + dragOffsetY;
487 | FingerFlowViewManager.getInstance().setUp(getContext(), bm, viewX, viewy);
488 | }
489 |
490 | @Override
491 | protected void onDetachedFromWindow()
492 | {
493 | super.onDetachedFromWindow();
494 | // Log.e("SpringboardView", "onDetachedFromWindow");
495 | FingerFlowViewManager.onDestory();
496 | }
497 |
498 | /**
499 | * 开始拖动
500 | */
501 | private void startDrag(View itemView)
502 | {
503 | mode = MODE.DRAGGING;
504 | getParent().requestDisallowInterceptTouchEvent(true);
505 | // halfBitmapWidth = itemView.getWidth() / 2;
506 | // halfBitmapHeight = itemView.getHeight() / 2;
507 | temChangPosition = dragPosition = getChildIndex(itemView);
508 | // Log.e("初始拖动位置", "temChangPosition = " + temChangPosition);
509 | initOrResetVelocityTracker();
510 | }
511 |
512 | public void endDrag()
513 | {
514 | mode = MODE.FREE;
515 | if (temChangPosition != -1)
516 | {
517 | getChildAt(temChangPosition).setVisibility(View.VISIBLE);
518 | }
519 | // showDropAnimation(x, y);
520 | getParent().requestDisallowInterceptTouchEvent(false);
521 | dragPosition = temChangPosition = -1;
522 | FingerFlowViewManager.getInstance().remove();
523 | }
524 |
525 | private void recycleVelocityTracker()
526 | {
527 | if (mVelocityTracker != null)
528 | {
529 | mVelocityTracker.recycle();
530 | mVelocityTracker = null;
531 | }
532 | }
533 |
534 | private void initOrResetVelocityTracker()
535 | {
536 | if (mVelocityTracker == null)
537 | {
538 | mVelocityTracker = VelocityTracker.obtain();
539 | } else
540 | {
541 | mVelocityTracker.clear();
542 | }
543 | }
544 |
545 | private void initVelocityTrackerIfNotExists()
546 | {
547 | if (mVelocityTracker == null)
548 | {
549 | mVelocityTracker = VelocityTracker.obtain();
550 | }
551 | }
552 |
553 | /**
554 | * 更新拖动的坐标,让图标跟随手一起动
555 | *
556 | * @param x view左上角坐标X
557 | * @param y view左上角坐标Y
558 | */
559 | public void onFling(int x, int y)
560 | {
561 | FingerFlowViewManager.getInstance().updatePosition(x, y);
562 | }
563 |
564 |
565 | /**
566 | * 如果正在进行滑动动画,就停止动画
567 | */
568 | protected void stopScroll()
569 | {
570 | if (!mScroller.isFinished())
571 | {
572 | // 中止移动动画
573 | mScroller.abortAnimation();
574 | }
575 | }
576 |
577 | /**
578 | * 判断能否进行滑动
579 | */
580 | protected boolean ifCanScroll(int deltaX)
581 | {
582 |
583 | if (Math.abs(deltaX) > mTouchSlop)
584 | {
585 | if (deltaX < 0)
586 | {
587 | if (getScrollX() > 0)
588 | {
589 | return true;
590 | }
591 | } else
592 | {
593 | if (getScrollX() < (getTotalPage() - 1) * getMeasuredWidth())
594 | {
595 | return true;
596 | }
597 | }
598 | }
599 | return false;
600 | }
601 |
602 | protected void countPageChange(int x)
603 | {
604 | // Log.e("countPageChange"," x = " +x );
605 | if (x > getWidth() - 40
606 | && mCurScreen < getTotalPage() - 1 && mScroller.isFinished()
607 | && x > startX + 10)
608 | {
609 | snapToScreen(mCurScreen + 1);
610 | } else if (x < 40
611 | && mCurScreen > 0 && mScroller.isFinished() && x < startX - 10)
612 | {
613 | snapToScreen(mCurScreen - 1);
614 | }
615 | }
616 |
617 |
618 | public void endScroll(float distance)
619 | {
620 | if (distance > getMeasuredWidth() / 6 && getmCurScreen() > 0)
621 | {
622 | snapToScreen(getmCurScreen() - 1);
623 | } else if (distance < -getMeasuredWidth() / 6
624 | && getmCurScreen() < getTotalPage() - 1)
625 | {
626 | snapToScreen(getmCurScreen() + 1);
627 | } else
628 | {
629 | final int screenWidth = getWidth();
630 | final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;
631 | if (destScreen >= 0 && destScreen < getTotalPage())
632 | {
633 | snapToScreen(destScreen);
634 | }
635 | }
636 | }
637 |
638 |
639 | public void snapToScreen(int whichScreen)
640 | {
641 | // get the valid layout page
642 | // Log.e("snapToScreen","whichScreen" + whichScreen );
643 | whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
644 | if (getScrollX() != (whichScreen * getWidth()))
645 | {
646 | final int delta = whichScreen * (getWidth() + page_divider_width) - getScrollX();
647 |
648 | if (whichScreen != mCurScreen && onPageChangedListener != null)
649 | {
650 | onPageChangedListener.onPageScroll(mCurScreen, whichScreen);
651 | }
652 | mScroller.startScroll(getScrollX(), 0, delta, 0, 800);
653 | mCurScreen = whichScreen;
654 | postInvalidate();// Redraw the layout
655 | }
656 | }
657 |
658 |
659 | @Override
660 | public void computeScroll()
661 | {
662 | if (mScroller.computeScrollOffset())
663 | {
664 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
665 | postInvalidate();
666 | }
667 | }
668 |
669 | /**
670 | * 判断是否在文件夹内
671 | */
672 | public boolean isInCenter(int position, MotionEvent event)
673 | {
674 |
675 | FrameLayout child = (FrameLayout) getChildAt(position);
676 | View view = child.findViewById(R.id.shake_zone_id).findViewById(R.id.center_zone_id);
677 |
678 | int[] location = new int[2];
679 | // 获取控件在屏幕中的位置,返回的数组分别为控件左顶点的 x、y 的值
680 | view.getLocationOnScreen(location);
681 |
682 | float x = event.getRawX(); // 获取相对于屏幕左上角的 x 坐标值
683 | float y = event.getRawY();
684 | RectF rect = new RectF(location[0], location[1], location[0] + view.getWidth(),
685 | location[1] + view.getHeight());
686 |
687 | return rect.contains(x, y);
688 | }
689 |
690 |
691 | protected void setEditingMode(int position, View child, boolean isEditing, boolean ifShake)
692 | {
693 | ImageView imageView = (ImageView) child.findViewById(R.id.delete_button_id);
694 | FrameLayout layout = (FrameLayout) child.findViewById(R.id.shake_zone_id);
695 |
696 | if (isEditing)
697 | {
698 | if (ifCanDelete(position))
699 | {
700 | imageView.setVisibility(View.VISIBLE);
701 | // Log.e("setEditingMode","position = canDelete" + position);
702 | } else
703 | {
704 | // Log.e("setEditingMode", "position = cannotDelete" + position);
705 | imageView.clearAnimation();
706 | imageView.setVisibility(View.GONE);
707 | }
708 |
709 | if (ifCanMove(position) && ifShake)
710 | {
711 | Animation shake;
712 | if (imageView.getVisibility() == View.VISIBLE)
713 | {
714 | shake = AnimationUtils.loadAnimation(getContext(), R.anim.shake);
715 | imageView.startAnimation(shake);
716 | }
717 | shake = AnimationUtils.loadAnimation(getContext(), R.anim.shake_rotate);
718 | layout.startAnimation(shake);
719 | } else
720 | {
721 | if (imageView.getVisibility() == View.VISIBLE)
722 | {
723 | imageView.clearAnimation();
724 | }
725 | layout.clearAnimation();
726 | }
727 | } else
728 | {
729 | imageView.setVisibility(View.GONE);
730 | imageView.clearAnimation();
731 | layout.clearAnimation();
732 | }
733 |
734 | }
735 |
736 | public abstract boolean ifCanMove(int position);
737 |
738 | public abstract boolean ifCanDelete(int position);
739 |
740 | /**
741 | * 获得View在父容器中的位置
742 | */
743 | public int getChildIndex(View view)
744 | {
745 | if (view != null)
746 | {
747 | final int childCount = ((ViewGroup) view.getParent())
748 | .getChildCount();
749 | for (int i = 0; i < childCount; i++)
750 | {
751 | if (view == ((ViewGroup) view.getParent()).getChildAt(i))
752 | {
753 | return i;
754 | }
755 | }
756 | }
757 | return -1;
758 | }
759 |
760 | /**
761 | * @param x,y 触摸点所在的位置
762 | * 如果不在位置上返回-1,在的话返回位置
763 | */
764 | public int pointToPosition(int x, int y)
765 | {
766 | int locX = x + mCurScreen * getWidth();
767 | Rect frame = new Rect();
768 | final int count = getChildCount();
769 | for (int i = count - 1; i >= 0; i--)
770 | {
771 | final View child = getChildAt(i);
772 | child.getHitRect(frame);
773 | if (frame.contains(locX, y))
774 | {
775 | return i;
776 | }
777 | }
778 | return -1;
779 | }
780 |
781 | /**
782 | * 当长按时开启编辑模式
783 | * 并开始滑动
784 | */
785 | protected boolean onItemLongClick(View v)
786 | {
787 | if (mode != MODE.DRAGGING)
788 | {
789 | int index = getChildIndex(v);
790 | // Log.e("SpringboardView", "onItemLongClick 长按 位置是 " + index);
791 | getAdapter().setEditing(true);
792 | if (ifCanMove(index))
793 | {
794 | startDrag(v);
795 | onStartFling(v, (int) mLastMotionX, (int) mLastMotionY);
796 | }
797 | return true;
798 | }
799 | return false;
800 | }
801 |
802 | public abstract void onItemClick(int position);
803 |
804 | /**
805 | * 计算有几页
806 | */
807 | protected void computePageCountChange(boolean ifCallback)
808 | {
809 | int pages = (int) Math.ceil(getChildCount() * 1.0 / getPageItemCount());
810 |
811 | if (pages == 0)
812 | {
813 | pages++;
814 | }
815 |
816 | if (pages != totalPage)
817 | {
818 | if (this.onPageChangedListener != null && ifCallback)
819 | {
820 | onPageChangedListener.onPageCountChange(totalPage, pages);
821 | }
822 | totalPage = pages;
823 | }
824 | }
825 |
826 | protected void onMerge(int fromPosition, int toPosition)
827 | {
828 | getAdapter().mergeItem(fromPosition, toPosition, defaultFolderName);
829 | temChangPosition = -1;
830 | computePageCountChange(true);
831 | }
832 |
833 | public void configView(FrameLayout view)
834 | {
835 | view.setOnLongClickListener(new View.OnLongClickListener()
836 | {
837 | @Override
838 | public boolean onLongClick(View v)
839 | {
840 | return onItemLongClick(v);
841 | }
842 | });
843 |
844 | view.setOnClickListener(new View.OnClickListener()
845 | {
846 | @Override
847 | public void onClick(View arg0)
848 | {
849 | int position = indexOfChild(arg0);
850 | onItemClick(position);
851 | }
852 | });
853 | ImageView imageView = new ImageView(getContext());
854 | imageView.setImageDrawable(deleteIcon);
855 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
856 | params.gravity = Gravity.TOP | Gravity.END;
857 | params.setMargins(0, 4, 4, 0);
858 | imageView.setId(R.id.delete_button_id);
859 | view.addView(imageView, params);
860 | imageView.setVisibility(View.GONE);
861 | imageView.setOnClickListener(new OnClickListener()
862 | {
863 | @Override
864 | public void onClick(View v)
865 | {
866 | int index = getChildIndex((ViewGroup) v.getParent());
867 | delete(index);
868 | }
869 | });
870 | }
871 |
872 |
873 | public void setAdapter(SpringboardAdapter mAdapter)
874 | {
875 | this.mAdapter = mAdapter;
876 | refreshView();
877 | computePageCountChange(false);
878 | }
879 |
880 | /**
881 | * 刷新页面
882 | */
883 | private void refreshView()
884 | {
885 | removeAllViews();
886 | int count = getItemCount();
887 |
888 | for (int i = 0; i < count; i++)
889 | {
890 | FrameLayout view = initItemView(i);
891 | configView(view);
892 | this.addView(view);
893 | }
894 | }
895 |
896 | public abstract int getItemCount();
897 |
898 | public abstract FrameLayout initItemView(int position);
899 |
900 | public void delete(int position)
901 | {
902 | onDelete(position);
903 | if (totalPage <= mCurScreen)
904 | {
905 | snapToScreen(totalPage - 1);
906 | }
907 | }
908 |
909 | public abstract void onDelete(int position);
910 |
911 |
912 | // /**
913 | // * 往下掉的动画
914 | // */
915 | // protected void showDropAnimation(int x, int y) {
916 | // ViewGroup moveView = (ViewGroup) getChildAt(temChangPosition);
917 | // TranslateAnimation animation = new TranslateAnimation(x
918 | // - halfBitmapWidth - moveView.getLeft(), 0, y - halfBitmapHeight
919 | // - moveView.getTop(), 0);
920 | // animation.setFillAfter(false);
921 | // animation.setDuration(300);
922 | // moveView.setAnimation(animation);
923 | // for (int i = 0; i < getChildCount(); i++) {
924 | // getChildAt(i).clearAnimation();
925 | // }
926 | // }
927 |
928 | // public PointF positionToPoint2(int position) {
929 | // PointF point = new PointF();
930 | //
931 | // int page = position / getColCount() / getRowCount();
932 | //
933 | // int row = position / getColCount() % getRowCount();
934 | //
935 | // int col = (position - (page * getPageItemCount())) % getColCount();
936 | //
937 | //
938 | // int left = getPaddingLeft() + (getWidth() + page_divider_width) * page + col * (dividerWidth + getChildWidth()) + dividerWidth;
939 | //
940 | // int top = getPaddingTop() + row * (dividerWidth + getChildHeight());
941 | //
942 | // point.x = left;
943 | //
944 | // point.y = top;
945 | //
946 | // return point;
947 | // }
948 |
949 | public int getmMinimumVelocity()
950 | {
951 | return mMinimumVelocity;
952 | }
953 |
954 | public int getColCount()
955 | {
956 | return colCount;
957 | }
958 |
959 | public int getPageItemCount()
960 | {
961 | return rowCount * colCount;
962 | }
963 |
964 | public void setColCount(int colCount)
965 | {
966 | this.colCount = colCount;
967 | }
968 |
969 | public int getmCurScreen()
970 | {
971 | return mCurScreen;
972 | }
973 |
974 | public int getRowCount()
975 | {
976 | return rowCount;
977 | }
978 |
979 | public void setRowCount(int rowCount)
980 | {
981 | this.rowCount = rowCount;
982 | }
983 |
984 | public int getChildHeight()
985 | {
986 | return getChildAt(0).getWidth();
987 | }
988 |
989 | public int getChildWidth()
990 | {
991 | return getChildAt(0).getHeight();
992 | }
993 |
994 | public int getTotalPage()
995 | {
996 | return totalPage;
997 | }
998 |
999 | public SpringboardAdapter getAdapter()
1000 | {
1001 | return mAdapter;
1002 | }
1003 |
1004 | public OnPageChangedListener getOnPageChangedListener()
1005 | {
1006 | return onPageChangedListener;
1007 | }
1008 |
1009 | public void setOnPageChangedListener(OnPageChangedListener onPageChangedListener)
1010 | {
1011 | this.onPageChangedListener = onPageChangedListener;
1012 | }
1013 |
1014 | public interface OnPageChangedListener
1015 | {
1016 | void onPageScroll(int from, int to);
1017 |
1018 | void onPageCountChange(int oldCount, int newCount);
1019 | }
1020 |
1021 | public interface OnItemClickListener
1022 | {
1023 | void onItemClick(FavoritesItem item);
1024 | }
1025 |
1026 | private OnItemClickListener onItemClickListener;
1027 |
1028 | public OnItemClickListener getOnItemClickListener()
1029 | {
1030 | return onItemClickListener;
1031 | }
1032 |
1033 | public void setOnItemClickListener(OnItemClickListener onItemClickListener)
1034 | {
1035 | this.onItemClickListener = onItemClickListener;
1036 | }
1037 |
1038 | public int getStableHeaderCount()
1039 | {
1040 | return stableHeaderCount;
1041 | }
1042 |
1043 | public void setStableHeaderCount(int stableHeaderCount)
1044 | {
1045 | this.stableHeaderCount = stableHeaderCount;
1046 | }
1047 |
1048 | public boolean isLastItemStable()
1049 | {
1050 | return isLastItemStable;
1051 | }
1052 |
1053 | public void setIsLastItemStable(boolean isLastItemStable)
1054 | {
1055 | this.isLastItemStable = isLastItemStable;
1056 | }
1057 |
1058 | }
1059 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/cycle_7.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/shake.xml:
--------------------------------------------------------------------------------
1 |
15 |
16 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/anim/shake_rotate.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable-hdpi/icon_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/library/src/main/res/drawable-hdpi/icon_delete.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable/folder_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/folder_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
23 |
24 |
25 |
40 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/library/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 文件夹
3 | SpringBoard
4 |
5 |
6 |
--------------------------------------------------------------------------------
/library/src/main/res/values/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/library/src/test/java/com/panxiaohe/springboardlib/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.panxiaohe.springboard;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/pic/screenShot1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohepan/springboardView/e78fc77bd1dd81a84c20b59591853b154b349f96/pic/screenShot1.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------