├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── build
│ └── outputs
│ │ └── apk
│ │ └── app-debug.apk
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── cy
│ │ └── cyflowlayout
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── cy
│ │ │ └── cyflowlayout
│ │ │ ├── BaseActivity.java
│ │ │ ├── LayoutBean.java
│ │ │ ├── LayoutMultiScrollActivity.java
│ │ │ ├── LayoutScrollActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── TVActivity.java
│ │ │ └── TVScrollActivity.java
│ └── res
│ │ ├── drawable-xxhdpi
│ │ ├── close.png
│ │ ├── pic1.jpg
│ │ └── pic2.jpg
│ │ ├── drawable
│ │ ├── bg_shape.xml
│ │ └── line_rect_huise.xml
│ │ ├── layout
│ │ ├── activity_layout.xml
│ │ ├── activity_layout_multi_scroll.xml
│ │ ├── activity_main.xml
│ │ ├── activity_tv.xml
│ │ ├── activity_tvscroll.xml
│ │ ├── item_layout.xml
│ │ ├── item_layout2.xml
│ │ └── item_tv.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
│ └── cy
│ └── cyflowlayout
│ └── ExampleUnitTest.java
├── build.gradle
├── cyflowlayoutlibrary
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── cy
│ │ └── cyflowlayoutlibrary
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── cy
│ │ │ └── cyflowlayoutlibrary
│ │ │ ├── FlowLayout.java
│ │ │ ├── FlowLayoutAdapter.java
│ │ │ └── FlowLayoutScrollView.java
│ └── res
│ │ └── values
│ │ ├── attrs.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── cy
│ └── cyflowlayoutlibrary
│ └── ExampleUnitTest.java
├── gif
├── 1.gif
├── 2.gif
├── 3.gif
└── 4.gif
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
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 | 微信公众号
2 | 
3 |
4 | [简书](https://www.jianshu.com/u/b8159d455c69)
5 |
6 | [APK下载](https://github.com/AnJiaoDe/MultiFlowLayout/blob/master/app/build/outputs/apk/app-debug.apk)
7 |
8 |
9 |
10 | **使用方法**
11 |
12 | 将libray模块复制到项目中,或者直接在build.gradle中依赖:
13 |
14 | ```
15 | allprojects {
16 | repositories {
17 |
18 | maven { url 'https://jitpack.io' }
19 | }
20 | }
21 | ```
22 |
23 | ```
24 | dependencies {
25 | compile 'com.github.AnJiaoDe:MultiFlowLayout:V1.1.2'
26 | }
27 | ```
28 |
29 | **注意:如果sync报错,是因为和com.android.tools.build:gradle 3.0有关,**
30 | **可以改将compile改为implementation 或者api**
31 |
32 | **1.TextView**
33 |
34 | 
35 |
36 | ```
37 |
38 |
47 |
48 |
49 |
50 | ```
51 |
52 | ```
53 |
54 |
55 | public class TVActivity extends BaseActivity {
56 |
57 | private FlowLayoutAdapter flowLayoutAdapter;
58 | @Override
59 | protected void onCreate(Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 | setContentView(R.layout.activity_tv);
62 | List list=new ArrayList<>();
63 | list.add("环境");
64 | list.add("环境");
65 | list.add("如果皇太后");
66 | list.add("人皇太后");
67 | list.add("环境");
68 | list.add("然后");
69 | list.add("环境");
70 | list.add("环境");
71 | list.add("然后钛合金");
72 | list.add("环境");
73 | list.add("任何人挺好");
74 | list.add("环境");
75 | list.add("发个黄庭坚");
76 | list.add("环境");
77 | list.add("分分然后");
78 | list.add("环境");
79 | list.add("环境");
80 | list.add("凤凰台和");
81 | list.add("环境");
82 | list.add("环境");
83 | list.add("环境");
84 | list.add("发个荣誉感");
85 | list.add("环境");
86 | list.add("复合肥");
87 | list.add("环境");
88 | list.add("发然后");
89 | list.add("环的风格让他很认同和境");
90 | list.add("的富贵华庭");
91 | list.add("的富");
92 | flowLayoutAdapter=new FlowLayoutAdapter(list) {
93 | @Override
94 | public void bindDataToView(ViewHolder holder, int position, String bean) {
95 | holder.setText(R.id.tv,bean);
96 | }
97 |
98 | @Override
99 | public void onItemClick(int position, String bean) {
100 |
101 | showToast("点击"+position);
102 | }
103 |
104 | @Override
105 | public int getItemLayoutID(int position, String bean) {
106 | return R.layout.item_tv;
107 | }
108 | };
109 | ((FlowLayout)findViewById(R.id.fl)).setAdapter(flowLayoutAdapter);
110 | }
111 |
112 | @Override
113 | public void onClick(View v) {
114 |
115 | }
116 | }
117 |
118 | ```
119 | **2.TextView+Scroll**
120 |
121 | 
122 |
123 | ```
124 |
125 |
134 |
135 |
136 |
137 | ```
138 |
139 | ```
140 |
141 | public class TVScrollActivity extends BaseActivity {
142 | private FlowLayoutAdapter flowLayoutAdapter;
143 | @Override
144 | protected void onCreate(Bundle savedInstanceState) {
145 | super.onCreate(savedInstanceState);
146 | setContentView(R.layout.activity_tvscroll);
147 | List list=new ArrayList<>();
148 | list.add("环境");
149 | list.add("环境");
150 | list.add("如果皇太后");
151 | list.add("人皇太后");
152 | list.add("环境");
153 | list.add("然后");
154 | list.add("环境");
155 | list.add("环境");
156 | list.add("然后钛合金");
157 | list.add("环境");
158 | list.add("任何人挺好");
159 | list.add("环境");
160 | list.add("发个黄庭坚");
161 | list.add("环境");
162 | list.add("分分然后");
163 | list.add("环境");
164 | list.add("环境");
165 | list.add("凤凰台和");
166 | list.add("环境");
167 | list.add("环境");
168 | list.add("环境");
169 | list.add("发个荣誉感");
170 | list.add("环境");
171 | list.add("复合肥");
172 | list.add("环境");
173 | list.add("发然后");
174 | list.add("环的风格让他很认同和境");
175 | list.add("的富贵华庭");
176 | list.add("环境");
177 | list.add("环境");
178 | list.add("如果皇太后");
179 | list.add("人皇太后");
180 | list.add("环境");
181 | list.add("然后");
182 | list.add("环境");
183 | list.add("环境");
184 | list.add("然后钛合金");
185 | list.add("环境");
186 | list.add("任何人挺好");
187 | list.add("环境");
188 | list.add("发个黄庭坚");
189 | list.add("环境");
190 | list.add("分分然后");
191 | list.add("环境");
192 | list.add("环境");
193 | list.add("凤凰台和");
194 | list.add("环境");
195 | list.add("环境");
196 | list.add("环境");
197 | list.add("发个荣誉感");
198 | list.add("环境");
199 | list.add("复合肥");
200 | list.add("环境");
201 | list.add("发然后");
202 | list.add("环的风格让他很认同和境");
203 | list.add("的富贵华庭");
204 | list.add("环境");
205 | list.add("环境");
206 | list.add("如果皇太后");
207 | list.add("人皇太后");
208 | list.add("环境");
209 | list.add("然后");
210 | list.add("环境");
211 | list.add("环境");
212 | list.add("然后钛合金");
213 | list.add("环境");
214 | list.add("任何人挺好");
215 | list.add("环境");
216 | list.add("发个黄庭坚");
217 | list.add("环境");
218 | list.add("分分然后");
219 | list.add("环境");
220 | list.add("环境");
221 | list.add("凤凰台和");
222 | list.add("环境");
223 | list.add("环境");
224 | list.add("环境");
225 | list.add("发个荣誉感");
226 | list.add("环境");
227 | list.add("复合肥");
228 | list.add("环境");
229 | list.add("发然后");
230 | list.add("环的风格让他很认同和境");
231 | list.add("的富贵华庭");
232 | flowLayoutAdapter=new FlowLayoutAdapter(list) {
233 | @Override
234 | public void bindDataToView(ViewHolder holder, int position, String bean) {
235 | holder.setText(R.id.tv,bean);
236 | }
237 |
238 | @Override
239 | public void onItemClick(int position, String bean) {
240 |
241 | showToast("点击"+position);
242 | }
243 |
244 | @Override
245 | public int getItemLayoutID(int position, String bean) {
246 | return R.layout.item_tv;
247 | }
248 | };
249 | ((FlowLayoutScrollView)findViewById(R.id.flsv)).setAdapter(flowLayoutAdapter);
250 | }
251 |
252 | @Override
253 | public void onClick(View v) {
254 |
255 | }
256 | }
257 |
258 | ```
259 | **3.layout+scroll+remove+add**
260 |
261 | 
262 |
263 | ```
264 |
265 |
272 |
273 |
274 |
275 | ```
276 |
277 | ```
278 |
279 |
280 | public class LayoutScrollActivity extends BaseActivity {
281 | private FlowLayoutAdapter flowLayoutAdapter;
282 |
283 | @Override
284 | protected void onCreate(Bundle savedInstanceState) {
285 | super.onCreate(savedInstanceState);
286 | setContentView(R.layout.activity_layout);
287 |
288 | List list=new ArrayList<>();
289 | list.add("环境");
290 | list.add("环境");
291 | list.add("如果皇太后");
292 | list.add("人皇太后");
293 | list.add("环境");
294 | list.add("然后");
295 | list.add("环境");
296 | list.add("环境");
297 | list.add("然后钛合金");
298 | list.add("环境");
299 | list.add("任何人挺好");
300 | list.add("环境");
301 | list.add("发个黄庭坚");
302 | list.add("环境");
303 | list.add("分分然后");
304 | list.add("环境");
305 | list.add("环境");
306 | list.add("凤凰台和");
307 | list.add("环境");
308 | list.add("环境");
309 | list.add("环境");
310 | list.add("发个荣誉感");
311 | list.add("环境");
312 | list.add("复合肥");
313 | list.add("环境");
314 | list.add("发然后");
315 | list.add("环的风格让他很认同和境");
316 | list.add("的富贵华庭");
317 | list.add("环境");
318 | list.add("环境");
319 | list.add("如果皇太后");
320 | list.add("人皇太后");
321 | list.add("环境");
322 | list.add("然后");
323 | list.add("环境");
324 | list.add("环境");
325 | list.add("然后钛合金");
326 | list.add("环境");
327 | list.add("任何人挺好");
328 | list.add("环境");
329 | list.add("发个黄庭坚");
330 | list.add("环境");
331 | list.add("分分然后");
332 | list.add("环境");
333 | list.add("环境");
334 | list.add("凤凰台和");
335 | list.add("环境");
336 | list.add("环境");
337 | list.add("环境");
338 | list.add("发个荣誉感");
339 | list.add("环境");
340 | list.add("复合肥");
341 | list.add("环境");
342 | list.add("发然后");
343 | list.add("环的风格让他很认同和境");
344 | list.add("的富贵华庭");
345 | list.add("环境");
346 | list.add("环境");
347 | list.add("如果皇太后");
348 | list.add("人皇太后");
349 | list.add("环境");
350 | list.add("然后");
351 | list.add("环境");
352 | list.add("环境");
353 | list.add("然后钛合金");
354 | list.add("环境");
355 | list.add("任何人挺好");
356 | list.add("环境");
357 | list.add("发个黄庭坚");
358 | list.add("环境");
359 | list.add("分分然后");
360 | list.add("环境");
361 | list.add("环境");
362 | list.add("凤凰台和");
363 | list.add("环境");
364 | list.add("环境");
365 | list.add("环境");
366 | list.add("发个荣誉感");
367 | list.add("环境");
368 | list.add("复合肥");
369 | list.add("环境");
370 | list.add("发然后");
371 | list.add("环的风格让他很认同和境");
372 | list.add("的富贵华庭");
373 | flowLayoutAdapter = new FlowLayoutAdapter(list) {
374 | @Override
375 | public void bindDataToView(ViewHolder holder, int position, String bean) {
376 |
377 | holder.setText(R.id.tv,bean);
378 | }
379 |
380 | @Override
381 | public void onItemClick(int position, String bean) {
382 |
383 | remove(position);
384 |
385 | }
386 |
387 | @Override
388 | public int getItemLayoutID(int position, String bean) {
389 | return R.layout.item_layout;
390 | }
391 | };
392 | ((FlowLayoutScrollView)findViewById(R.id.flsv)).setAdapter(flowLayoutAdapter);
393 | }
394 |
395 | @Override
396 | public void onClick(View v) {
397 |
398 | }
399 | }
400 |
401 | ```
402 |
403 | **4.layout+multi+scroll+remove+add**
404 |
405 |
406 | 
407 |
408 | ```
409 |
410 |
417 |
418 |
419 |
420 | ```
421 |
422 | ```
423 |
424 | public class LayoutMultiScrollActivity extends BaseActivity {
425 | private FlowLayoutAdapter flowLayoutAdapter;
426 |
427 | @Override
428 | protected void onCreate(Bundle savedInstanceState) {
429 | super.onCreate(savedInstanceState);
430 | setContentView(R.layout.activity_layout_multi_scroll);
431 |
432 | List list=new ArrayList<>();
433 | list.add("会囧哥");
434 | list.add("环境");
435 | list.add("如果皇太后");
436 | list.add("人皇太后");
437 | list.add("环境");
438 | list.add("然后");
439 | list.add("环境");
440 | list.add("环境");
441 | list.add("然后钛合金");
442 | list.add("环境");
443 | list.add("任何人挺好");
444 | list.add("环境");
445 | list.add("发个黄庭坚");
446 | list.add("环境");
447 | list.add("分分然后");
448 | list.add("环境");
449 | list.add("环境");
450 | list.add("凤凰台和");
451 | list.add("环境");
452 | list.add("环境");
453 | list.add("环境");
454 | list.add("发个荣誉感");
455 | list.add("环境");
456 | list.add("复合肥");
457 | list.add("环境");
458 | list.add("发然后");
459 | list.add("环的风格让他很认同和境");
460 | list.add("的富贵华庭");
461 | list.add("环境");
462 | list.add("环境");
463 | list.add("如果皇太后");
464 | list.add("人皇太后");
465 | list.add("环境");
466 | list.add("然后");
467 | list.add("环境");
468 | list.add("环境");
469 | list.add("然后钛合金");
470 | list.add("环境");
471 | list.add("任何人挺好");
472 | list.add("环境");
473 | list.add("发个黄庭坚");
474 | list.add("环境");
475 | list.add("分分然后");
476 | list.add("环境");
477 | list.add("环境");
478 | list.add("凤凰台和");
479 | list.add("环境");
480 | list.add("环境");
481 | list.add("环境");
482 | list.add("发个荣誉感");
483 | list.add("环境");
484 | list.add("复合肥");
485 | list.add("环境");
486 | list.add("发然后");
487 | list.add("环的风格让他很认同和境");
488 | list.add("的富贵华庭");
489 | list.add("环境");
490 | list.add("环境");
491 | list.add("如果皇太后");
492 | list.add("人皇太后");
493 | list.add("环境");
494 | list.add("然后");
495 | list.add("环境");
496 | list.add("环境");
497 | list.add("然后钛合金");
498 | list.add("环境");
499 | list.add("任何人挺好");
500 | list.add("环境");
501 | list.add("发个黄庭坚");
502 | list.add("环境");
503 | list.add("分分然后");
504 | list.add("环境");
505 | list.add("环境");
506 | list.add("凤凰台和");
507 | list.add("环境");
508 | list.add("环境");
509 | list.add("环境");
510 | list.add("发个荣誉感");
511 | list.add("环境");
512 | list.add("复合肥");
513 | list.add("环境");
514 | list.add("发然后");
515 | list.add("环的风格让他很认同和境");
516 | list.add("的富贵华庭");
517 | flowLayoutAdapter = new FlowLayoutAdapter(list) {
518 | @Override
519 | public void bindDataToView(ViewHolder holder, int position, String bean) {
520 |
521 | holder.setText(R.id.tv,bean);
522 |
523 |
524 | }
525 |
526 | @Override
527 | public void onItemClick(int position, String bean) {
528 |
529 | if (position==0||position==1||position==2){
530 |
531 | return;
532 | }
533 | remove(position);
534 |
535 | }
536 |
537 | @Override
538 | public int getItemLayoutID(int position, String bean) {
539 | if (position==0||position==1||position==2){
540 | return R.layout.item_layout2;
541 | }
542 | return R.layout.item_layout;
543 | }
544 | };
545 | ((FlowLayoutScrollView)findViewById(R.id.flsv)).setAdapter(flowLayoutAdapter);
546 | }
547 |
548 | @Override
549 | public void onClick(View v) {
550 |
551 | }
552 | }
553 |
554 | ```
555 | **FlowLayoutAdapter:**
556 |
557 |
558 | ```
559 |
560 |
561 | public abstract class FlowLayoutAdapter {
562 | private OnDataSetChangedListener onDataSetChangedListener;
563 | private List list_bean;
564 |
565 | public FlowLayoutAdapter( List list_bean) {
566 | this.list_bean = list_bean;
567 | }
568 |
569 | public int getCount() {
570 | return list_bean.size();
571 | }
572 |
573 | public final View getView(FlowLayout parent, final int position) {
574 |
575 | View view = LayoutInflater.from(parent.getContext()).inflate(getItemLayoutID(position, list_bean.get(position)), parent, false);
576 |
577 | view.setOnClickListener(new View.OnClickListener() {
578 | @Override
579 | public void onClick(View v) {
580 | onItemClick(position, list_bean.get(position));
581 | }
582 | });
583 | view.setOnLongClickListener(new View.OnLongClickListener() {
584 | @Override
585 | public boolean onLongClick(View v) {
586 | onItemLongClick(position,list_bean.get(position));
587 | return true;
588 | }
589 | });
590 | bindDataToView(new ViewHolder(view), position, list_bean.get(position));
591 | return view;
592 |
593 | }
594 |
595 |
596 | //填充数据
597 | public abstract void bindDataToView(ViewHolder holder, int position, T bean);
598 | /*
599 | ItemView的单击事件
600 |
601 | @param position
602 | */
603 |
604 | public abstract void onItemClick(int position, T bean);
605 | public void onItemLongClick(int position, T bean){}
606 |
607 | /*
608 | 取得ItemView的布局文件
609 | @return
610 | */
611 | public abstract int getItemLayoutID(int position, T bean);
612 |
613 |
614 | public void remove(int position) {
615 | list_bean.remove(position);
616 | notifyDataSetChanged();
617 | }
618 |
619 | public void add(T bean) {
620 | list_bean.add(bean);
621 |
622 | notifyDataSetChanged();
623 | }
624 | public void notifyDataSetChanged(){
625 | if(onDataSetChangedListener!=null){
626 |
627 | onDataSetChangedListener.onDataSetChanged();
628 | }
629 | }
630 |
631 | public void addNoNotify(T bean) {
632 | list_bean.add(bean);
633 | }
634 |
635 | public void addToHead(T bean) {
636 | list_bean.add(0, bean);
637 | }
638 |
639 | public int addAll(List beans) {
640 | list_bean.addAll(beans);
641 |
642 | notifyDataSetChanged();
643 |
644 | return beans.size();
645 | }
646 |
647 | public void addAll(Collection c) {
648 | list_bean.addAll(c);
649 | notifyDataSetChanged();
650 |
651 |
652 | }
653 |
654 | public int clearAddAll(List beans) {
655 | list_bean.clear();
656 | list_bean.addAll(beans);
657 |
658 | notifyDataSetChanged();
659 |
660 | return beans.size();
661 | }
662 |
663 | public void addAllToHead(List beans) {
664 | list_bean.addAll(0, beans);
665 | notifyDataSetChanged();
666 |
667 | }
668 |
669 | public void clear() {
670 | list_bean.clear();
671 | notifyDataSetChanged();
672 |
673 | }
674 |
675 | public void setOnDataSetChangedListener(OnDataSetChangedListener onDataSetChangedListener) {
676 | this.onDataSetChangedListener = onDataSetChangedListener;
677 | }
678 |
679 | public interface OnDataSetChangedListener{
680 | public void onDataSetChanged();
681 | }
682 | public static class ViewHolder {
683 | private View itemView;
684 | private SparseArray array_view;
685 |
686 | public ViewHolder(View itemView) {
687 | this.itemView = itemView;
688 |
689 | array_view = new SparseArray();
690 |
691 | }
692 |
693 |
694 | public T getView(int viewId) {
695 |
696 | View view = array_view.get(viewId);
697 | if (view == null) {
698 | view = itemView.findViewById(viewId);
699 | array_view.put(viewId, view);
700 | }
701 | return (T) view;
702 | }
703 |
704 |
705 |
706 |
707 |
708 | public ViewHolder setVisible(int res_id) {
709 | getView(res_id).setVisibility(View.VISIBLE);
710 | return this;
711 | }
712 |
713 | public ViewHolder setInVisible(int res_id) {
714 | getView(res_id).setVisibility(View.INVISIBLE);
715 | return this;
716 | }
717 |
718 | public void setViewGone(int res_id) {
719 | getView(res_id).setVisibility(View.GONE);
720 | }
721 |
722 | public void setViewVisible(int res_id) {
723 | getView(res_id).setVisibility(View.VISIBLE);
724 | }
725 |
726 |
727 | public void setText(int tv_id, String text) {
728 | TextView tv = getView(tv_id);
729 |
730 |
731 | tv.setText(nullToString(text));
732 | }
733 |
734 | public String nullToString(Object object) {
735 | return object == null ? "" : object.toString();
736 | }
737 |
738 | public void setPriceText(int tv_id, String text) {
739 | TextView tv = getView(tv_id);
740 |
741 | tv.setText("¥" + text);
742 | }
743 |
744 | public void setCountText(int tv_id, String text) {
745 | TextView tv = getView(tv_id);
746 |
747 | tv.setText("x" + text);
748 | }
749 |
750 | public void setCountText(int tv_id, int text) {
751 | TextView tv = getView(tv_id);
752 |
753 | tv.setText("x" + text);
754 | }
755 |
756 | public void setPriceText(int tv_id, int text) {
757 | TextView tv = getView(tv_id);
758 |
759 | tv.setText("¥" + text);
760 | }
761 |
762 | public void setPriceText(int tv_id, float text) {
763 | TextView tv = getView(tv_id);
764 |
765 | tv.setText("¥" + text);
766 | }
767 |
768 | public void setText(int tv_id, int text) {
769 | TextView tv = getView(tv_id);
770 | tv.setText(String.valueOf(nullToString(text)));
771 | }
772 |
773 | public void setTextColor(int tv_id, int color) {
774 | TextView tv = getView(tv_id);
775 | tv.setTextColor(color);
776 | }
777 |
778 | public String getTVText(int tv_id) {
779 | TextView tv = getView(tv_id);
780 | return tv.getText().toString().trim();
781 | }
782 |
783 | public String getETText(int tv_id) {
784 | EditText tv = getView(tv_id);
785 | return tv.getText().toString().trim();
786 | }
787 |
788 | public void setBackgroundResource(int v_id, int resid) {
789 | View view = getView(v_id);
790 | view.setBackgroundResource(resid);
791 | }
792 |
793 | public void setImageBitmap(int v_id, Bitmap bitmap) {
794 | ImageView view = getView(v_id);
795 | view.setImageBitmap(bitmap);
796 | }
797 |
798 | public void setImageResource(int v_id, int resID) {
799 | ImageView view = getView(v_id);
800 | view.setImageResource(resID);
801 | }
802 |
803 | public void setProgress(int progress_id, int progress) {
804 | ProgressBar progressBar = getView(progress_id);
805 | progressBar.setProgress(progress);
806 |
807 | }
808 |
809 | public void setOnClickListener(int res_id, View.OnClickListener onClickListener) {
810 | getView(res_id).setOnClickListener(onClickListener);
811 | }
812 |
813 | public void setOnLongClickListener(int res_id, View.OnLongClickListener onLongClickListener) {
814 | getView(res_id).setOnLongClickListener(onLongClickListener);
815 | }
816 | }
817 |
818 |
819 | }
820 |
821 | ```
822 |
823 |
824 |
825 |
826 | **更新日志**
827 |
828 | *V1.1.1*
829 | - Android 流式布局FlowLayout(搜索历史),可多布局、点击删除、添加等操作,暂无类似RecyclerView布局复用的处理,所以数据不应添加过多
830 |
831 |
832 |
833 | **License**
834 |
835 | Copyright [AnJiaoDe] [name of copyright owner]
836 |
837 | Licensed under the Apache License, Version 2.0 (the "License");
838 | you may not use this file except in compliance with the License.
839 | You may obtain a copy of the License at
840 |
841 | http://www.apache.org/licenses/LICENSE-2.0
842 |
843 | Unless required by applicable law or agreed to in writing, software
844 | distributed under the License is distributed on an "AS IS" BASIS,
845 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
846 | See the License for the specific language governing permissions and
847 | limitations under the License.
848 |
849 | [GitHub](https://github.com/AnJiaoDe)
850 |
851 | 关注专题[Android开发常用开源库](https://www.jianshu.com/c/3ff4b3951dc5)
852 |
853 | [简书](https://www.jianshu.com/u/b8159d455c69)
854 |
855 | 微信公众号
856 | 
857 |
858 | QQ群
859 | 
860 |
861 |
862 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 | defaultConfig {
7 | applicationId "com.cy.cyflowlayout"
8 | minSdkVersion 19
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:25.3.1'
28 | testCompile 'junit:junit:4.12'
29 | compile project(':cyflowlayoutlibrary')
30 | }
31 |
--------------------------------------------------------------------------------
/app/build/outputs/apk/app-debug.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/app/build/outputs/apk/app-debug.apk
--------------------------------------------------------------------------------
/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 D:\AndroidSDK/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/cy/cyflowlayout/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayout;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.cy.cyflowlayout", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/cy/cyflowlayout/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayout;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.content.pm.PackageManager;
7 | import android.graphics.Color;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 | import android.support.annotation.NonNull;
11 | import android.support.annotation.Nullable;
12 | import android.support.v4.app.ActivityCompat;
13 | import android.support.v4.app.Fragment;
14 | import android.support.v4.app.FragmentManager;
15 | import android.support.v4.app.FragmentTransaction;
16 | import android.support.v7.app.AppCompatActivity;
17 | import android.view.View;
18 | import android.view.Window;
19 | import android.view.WindowManager;
20 | import android.widget.Toast;
21 |
22 |
23 | /**
24 | * Created by lenovo on 2017/4/25.
25 | */
26 |
27 | public abstract class BaseActivity extends AppCompatActivity implements View.OnClickListener {
28 | private String toast_permission;
29 | private OnPermissionHaveListener onPermissionHaveListener;
30 | public SharedPreferences sharedPreferences;
31 |
32 |
33 | public SharedPreferences.Editor editor;
34 |
35 |
36 | public Context context_applicaiton;
37 |
38 | @Override
39 | protected void onCreate(@Nullable Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 |
42 |
43 | // setStatusBarTransparent();
44 |
45 | sharedPreferences = getSharedPreferences("SP", Context.MODE_PRIVATE);
46 |
47 | editor = sharedPreferences.edit();
48 |
49 | context_applicaiton = getApplicationContext();
50 |
51 | }
52 |
53 | public Context getContext_applicaiton() {
54 | return context_applicaiton;
55 | }
56 |
57 | public void setContext_applicaiton(Context context_applicaiton) {
58 | this.context_applicaiton = context_applicaiton;
59 | }
60 |
61 |
62 |
63 |
64 |
65 | //??????????????????????????????????????????????????????????????????????
66 |
67 | /*
68 | Acitivity跳转
69 | */
70 | public void showToast(String msg) {
71 | Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
72 | }
73 |
74 | public void showToast(int string_id) {
75 | Toast.makeText(this, getResources().getString(string_id), Toast.LENGTH_SHORT).show();
76 | }
77 |
78 |
79 | public void startAppcompatActivity(Class> cls) {
80 | startActivity(new Intent(this, cls));
81 | }
82 |
83 |
84 | public SharedPreferences.Editor getEditor() {
85 | return editor;
86 | }
87 |
88 | public void setEditor(SharedPreferences.Editor editor) {
89 | this.editor = editor;
90 | }
91 |
92 | public SharedPreferences getSharedPreferences() {
93 | return sharedPreferences;
94 | }
95 |
96 | public void setSharedPreferences(SharedPreferences sharedPreferences) {
97 | this.sharedPreferences = sharedPreferences;
98 | }
99 |
100 |
101 | public void initData() {
102 | }
103 | /*
104 | 状态栏全透明去阴影
105 | */
106 |
107 | public void setStatusBarTransparent() {
108 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
109 | Window window = getWindow();
110 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
111 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
112 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
113 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
114 | window.setStatusBarColor(Color.TRANSPARENT);
115 | }
116 | }
117 | /*
118 | 状态栏隐藏
119 | */
120 |
121 | public void setStatusBarHide() {
122 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
123 | Window window = getWindow();
124 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
125 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
126 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
127 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
128 | window.setStatusBarColor(Color.TRANSPARENT);
129 | }
130 | }
131 | /*
132 |
133 | */
134 |
135 | public void replaceFragment(int framelayout_id, Fragment fragment) {
136 | FragmentManager fragmentManager = getSupportFragmentManager();
137 | FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
138 | fragmentTransaction.replace(framelayout_id, fragment).commitAllowingStateLoss();
139 | }
140 |
141 |
142 | public Fragment createFragment(int position) {
143 | return null;
144 | }
145 |
146 | /*
147 | 6.0权限检查
148 | */
149 | public void checkPermission(String[] permission, String toast_permission, OnPermissionHaveListener onPermissionHaveListener) {
150 | ActivityCompat.requestPermissions(this, permission, 1);
151 | this.toast_permission = toast_permission;
152 |
153 | this.onPermissionHaveListener = onPermissionHaveListener;
154 |
155 | }
156 |
157 | @Override
158 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
159 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
160 |
161 | for (int i = 0; i < permissions.length; i++) {
162 | if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
163 |
164 | showToast(toast_permission);
165 | return;
166 | }
167 | }
168 | if (onPermissionHaveListener != null) {
169 | onPermissionHaveListener.onPermissionHave();
170 | }
171 |
172 |
173 | }
174 |
175 | public interface OnPermissionHaveListener {
176 | public void onPermissionHave();
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/app/src/main/java/com/cy/cyflowlayout/LayoutBean.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayout;
2 |
3 | /**
4 | * Created by cy on 2018/4/14.
5 | */
6 |
7 | public class LayoutBean {
8 | private String text ;
9 | private int resID;
10 |
11 | public LayoutBean(String text, int resID) {
12 | this.text = text;
13 | this.resID = resID;
14 | }
15 |
16 | public String getText() {
17 | return text;
18 | }
19 |
20 | public void setText(String text) {
21 | this.text = text;
22 | }
23 |
24 | public int getResID() {
25 | return resID;
26 | }
27 |
28 | public void setResID(int resID) {
29 | this.resID = resID;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/cy/cyflowlayout/LayoutMultiScrollActivity.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayout;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 |
6 | import com.cy.cyflowlayoutlibrary.FlowLayoutAdapter;
7 | import com.cy.cyflowlayoutlibrary.FlowLayoutScrollView;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class LayoutMultiScrollActivity extends BaseActivity {
13 | private FlowLayoutAdapter flowLayoutAdapter;
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_layout_multi_scroll);
19 |
20 | List list=new ArrayList<>();
21 | list.add("会囧哥");
22 | list.add("环境");
23 | list.add("如果皇太后");
24 | list.add("人皇太后");
25 | list.add("环境");
26 | list.add("然后");
27 | list.add("环境");
28 | list.add("环境");
29 | list.add("然后钛合金");
30 | list.add("环境");
31 | list.add("任何人挺好");
32 | list.add("环境");
33 | list.add("发个黄庭坚");
34 | list.add("环境");
35 | list.add("分分然后");
36 | list.add("环境");
37 | list.add("环境");
38 | list.add("凤凰台和");
39 | list.add("环境");
40 | list.add("环境");
41 | list.add("环境");
42 | list.add("发个荣誉感");
43 | list.add("环境");
44 | list.add("复合肥");
45 | list.add("环境");
46 | list.add("发然后");
47 | list.add("环的风格让他很认同和境");
48 | list.add("的富贵华庭");
49 | list.add("环境");
50 | list.add("环境");
51 | list.add("如果皇太后");
52 | list.add("人皇太后");
53 | list.add("环境");
54 | list.add("然后");
55 | list.add("环境");
56 | list.add("环境");
57 | list.add("然后钛合金");
58 | list.add("环境");
59 | list.add("任何人挺好");
60 | list.add("环境");
61 | list.add("发个黄庭坚");
62 | list.add("环境");
63 | list.add("分分然后");
64 | list.add("环境");
65 | list.add("环境");
66 | list.add("凤凰台和");
67 | list.add("环境");
68 | list.add("环境");
69 | list.add("环境");
70 | list.add("发个荣誉感");
71 | list.add("环境");
72 | list.add("复合肥");
73 | list.add("环境");
74 | list.add("发然后");
75 | list.add("环的风格让他很认同和境");
76 | list.add("的富贵华庭");
77 | list.add("环境");
78 | list.add("环境");
79 | list.add("如果皇太后");
80 | list.add("人皇太后");
81 | list.add("环境");
82 | list.add("然后");
83 | list.add("环境");
84 | list.add("环境");
85 | list.add("然后钛合金");
86 | list.add("环境");
87 | list.add("任何人挺好");
88 | list.add("环境");
89 | list.add("发个黄庭坚");
90 | list.add("环境");
91 | list.add("分分然后");
92 | list.add("环境");
93 | list.add("环境");
94 | list.add("凤凰台和");
95 | list.add("环境");
96 | list.add("环境");
97 | list.add("环境");
98 | list.add("发个荣誉感");
99 | list.add("环境");
100 | list.add("复合肥");
101 | list.add("环境");
102 | list.add("发然后");
103 | list.add("环的风格让他很认同和境");
104 | list.add("的富贵华庭");
105 | flowLayoutAdapter = new FlowLayoutAdapter(list) {
106 | @Override
107 | public void bindDataToView(ViewHolder holder, int position, String bean) {
108 |
109 | holder.setText(R.id.tv,bean);
110 |
111 |
112 | }
113 |
114 | @Override
115 | public void onItemClick(int position, String bean) {
116 |
117 | if (position==0||position==1||position==2){
118 |
119 | return;
120 | }
121 | remove(position);
122 |
123 | }
124 |
125 | @Override
126 | public int getItemLayoutID(int position, String bean) {
127 | if (position==0||position==1||position==2){
128 | return R.layout.item_layout2;
129 | }
130 | return R.layout.item_layout;
131 | }
132 | };
133 | ((FlowLayoutScrollView)findViewById(R.id.flsv)).setAdapter(flowLayoutAdapter);
134 | }
135 |
136 | @Override
137 | public void onClick(View v) {
138 |
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/app/src/main/java/com/cy/cyflowlayout/LayoutScrollActivity.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayout;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 |
6 | import com.cy.cyflowlayoutlibrary.FlowLayoutAdapter;
7 | import com.cy.cyflowlayoutlibrary.FlowLayoutScrollView;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class LayoutScrollActivity extends BaseActivity {
13 | private FlowLayoutAdapter flowLayoutAdapter;
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_layout);
19 |
20 | List list=new ArrayList<>();
21 | list.add("环境");
22 | list.add("环境");
23 | list.add("如果皇太后");
24 | list.add("人皇太后");
25 | list.add("环境");
26 | list.add("然后");
27 | list.add("环境");
28 | list.add("环境");
29 | list.add("然后钛合金");
30 | list.add("环境");
31 | list.add("任何人挺好");
32 | list.add("环境");
33 | list.add("发个黄庭坚");
34 | list.add("环境");
35 | list.add("分分然后");
36 | list.add("环境");
37 | list.add("环境");
38 | list.add("凤凰台和");
39 | list.add("环境");
40 | list.add("环境");
41 | list.add("环境");
42 | list.add("发个荣誉感");
43 | list.add("环境");
44 | list.add("复合肥");
45 | list.add("环境");
46 | list.add("发然后");
47 | list.add("环的风格让他很认同和境");
48 | list.add("的富贵华庭");
49 | list.add("环境");
50 | list.add("环境");
51 | list.add("如果皇太后");
52 | list.add("人皇太后");
53 | list.add("环境");
54 | list.add("然后");
55 | list.add("环境");
56 | list.add("环境");
57 | list.add("然后钛合金");
58 | list.add("环境");
59 | list.add("任何人挺好");
60 | list.add("环境");
61 | list.add("发个黄庭坚");
62 | list.add("环境");
63 | list.add("分分然后");
64 | list.add("环境");
65 | list.add("环境");
66 | list.add("凤凰台和");
67 | list.add("环境");
68 | list.add("环境");
69 | list.add("环境");
70 | list.add("发个荣誉感");
71 | list.add("环境");
72 | list.add("复合肥");
73 | list.add("环境");
74 | list.add("发然后");
75 | list.add("环的风格让他很认同和境");
76 | list.add("的富贵华庭");
77 | list.add("环境");
78 | list.add("环境");
79 | list.add("如果皇太后");
80 | list.add("人皇太后");
81 | list.add("环境");
82 | list.add("然后");
83 | list.add("环境");
84 | list.add("环境");
85 | list.add("然后钛合金");
86 | list.add("环境");
87 | list.add("任何人挺好");
88 | list.add("环境");
89 | list.add("发个黄庭坚");
90 | list.add("环境");
91 | list.add("分分然后");
92 | list.add("环境");
93 | list.add("环境");
94 | list.add("凤凰台和");
95 | list.add("环境");
96 | list.add("环境");
97 | list.add("环境");
98 | list.add("发个荣誉感");
99 | list.add("环境");
100 | list.add("复合肥");
101 | list.add("环境");
102 | list.add("发然后");
103 | list.add("环的风格让他很认同和境");
104 | list.add("的富贵华庭");
105 | flowLayoutAdapter = new FlowLayoutAdapter(list) {
106 | @Override
107 | public void bindDataToView(ViewHolder holder, int position, String bean) {
108 |
109 | holder.setText(R.id.tv,bean);
110 | }
111 |
112 | @Override
113 | public void onItemClick(int position, String bean) {
114 |
115 | remove(position);
116 |
117 | }
118 |
119 | @Override
120 | public int getItemLayoutID(int position, String bean) {
121 | return R.layout.item_layout;
122 | }
123 | };
124 | ((FlowLayoutScrollView)findViewById(R.id.flsv)).setAdapter(flowLayoutAdapter);
125 | }
126 |
127 | @Override
128 | public void onClick(View v) {
129 |
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/app/src/main/java/com/cy/cyflowlayout/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayout;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 |
6 | public class MainActivity extends BaseActivity {
7 |
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | setContentView(R.layout.activity_main);
12 |
13 | findViewById(R.id.btn_tv).setOnClickListener(this);
14 | findViewById(R.id.btn_tv_scroll).setOnClickListener(this);
15 | findViewById(R.id.btn_layout_scroll).setOnClickListener(this);
16 | findViewById(R.id.btn_layout__multi_scroll).setOnClickListener(this);
17 | }
18 |
19 | @Override
20 | public void onClick(View v) {
21 | switch (v.getId()) {
22 | case R.id.btn_tv:
23 | startAppcompatActivity(TVActivity.class);
24 | break;
25 | case R.id.btn_tv_scroll:
26 | startAppcompatActivity(TVScrollActivity.class);
27 |
28 | break;
29 | case R.id.btn_layout_scroll:
30 | startAppcompatActivity(LayoutScrollActivity.class);
31 |
32 | break;
33 | case R.id.btn_layout__multi_scroll:
34 | startAppcompatActivity(LayoutMultiScrollActivity.class);
35 |
36 | break;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/cy/cyflowlayout/TVActivity.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayout;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 |
6 | import com.cy.cyflowlayoutlibrary.FlowLayout;
7 | import com.cy.cyflowlayoutlibrary.FlowLayoutAdapter;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class TVActivity extends BaseActivity {
13 |
14 | private FlowLayoutAdapter flowLayoutAdapter;
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_tv);
19 | List list=new ArrayList<>();
20 | list.add("环境");
21 | list.add("环境");
22 | list.add("如果皇太后");
23 | list.add("人皇太后");
24 | list.add("环境");
25 | list.add("然后");
26 | list.add("环境");
27 | list.add("环境");
28 | list.add("然后钛合金");
29 | list.add("环境");
30 | list.add("任何人挺好");
31 | list.add("环境");
32 | list.add("发个黄庭坚");
33 | list.add("环境");
34 | list.add("分分然后");
35 | list.add("环境");
36 | list.add("环境");
37 | list.add("凤凰台和");
38 | list.add("环境");
39 | list.add("环境");
40 | list.add("环境");
41 | list.add("发个荣誉感");
42 | list.add("环境");
43 | list.add("复合肥");
44 | list.add("环境");
45 | list.add("发然后");
46 | list.add("环的风格让他很认同和境");
47 | list.add("的富贵华庭");
48 | list.add("的富");
49 | flowLayoutAdapter=new FlowLayoutAdapter(list) {
50 | @Override
51 | public void bindDataToView(ViewHolder holder, int position, String bean) {
52 | holder.setText(R.id.tv,bean);
53 | }
54 |
55 | @Override
56 | public void onItemClick(int position, String bean) {
57 |
58 | showToast("点击"+position);
59 | }
60 |
61 | @Override
62 | public int getItemLayoutID(int position, String bean) {
63 | return R.layout.item_tv;
64 | }
65 | };
66 | ((FlowLayout)findViewById(R.id.fl)).setAdapter(flowLayoutAdapter);
67 | }
68 |
69 | @Override
70 | public void onClick(View v) {
71 |
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/cy/cyflowlayout/TVScrollActivity.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayout;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 |
6 | import com.cy.cyflowlayoutlibrary.FlowLayoutAdapter;
7 | import com.cy.cyflowlayoutlibrary.FlowLayoutScrollView;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class TVScrollActivity extends BaseActivity {
13 | private FlowLayoutAdapter flowLayoutAdapter;
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_tvscroll);
18 | List list=new ArrayList<>();
19 | list.add("环境");
20 | list.add("环境");
21 | list.add("如果皇太后");
22 | list.add("人皇太后");
23 | list.add("环境");
24 | list.add("然后");
25 | list.add("环境");
26 | list.add("环境");
27 | list.add("然后钛合金");
28 | list.add("环境");
29 | list.add("任何人挺好");
30 | list.add("环境");
31 | list.add("发个黄庭坚");
32 | list.add("环境");
33 | list.add("分分然后");
34 | list.add("环境");
35 | list.add("环境");
36 | list.add("凤凰台和");
37 | list.add("环境");
38 | list.add("环境");
39 | list.add("环境");
40 | list.add("发个荣誉感");
41 | list.add("环境");
42 | list.add("复合肥");
43 | list.add("环境");
44 | list.add("发然后");
45 | list.add("环的风格让他很认同和境");
46 | list.add("的富贵华庭");
47 | list.add("环境");
48 | list.add("环境");
49 | list.add("如果皇太后");
50 | list.add("人皇太后");
51 | list.add("环境");
52 | list.add("然后");
53 | list.add("环境");
54 | list.add("环境");
55 | list.add("然后钛合金");
56 | list.add("环境");
57 | list.add("任何人挺好");
58 | list.add("环境");
59 | list.add("发个黄庭坚");
60 | list.add("环境");
61 | list.add("分分然后");
62 | list.add("环境");
63 | list.add("环境");
64 | list.add("凤凰台和");
65 | list.add("环境");
66 | list.add("环境");
67 | list.add("环境");
68 | list.add("发个荣誉感");
69 | list.add("环境");
70 | list.add("复合肥");
71 | list.add("环境");
72 | list.add("发然后");
73 | list.add("环的风格让他很认同和境");
74 | list.add("的富贵华庭");
75 | list.add("环境");
76 | list.add("环境");
77 | list.add("如果皇太后");
78 | list.add("人皇太后");
79 | list.add("环境");
80 | list.add("然后");
81 | list.add("环境");
82 | list.add("环境");
83 | list.add("然后钛合金");
84 | list.add("环境");
85 | list.add("任何人挺好");
86 | list.add("环境");
87 | list.add("发个黄庭坚");
88 | list.add("环境");
89 | list.add("分分然后");
90 | list.add("环境");
91 | list.add("环境");
92 | list.add("凤凰台和");
93 | list.add("环境");
94 | list.add("环境");
95 | list.add("环境");
96 | list.add("发个荣誉感");
97 | list.add("环境");
98 | list.add("复合肥");
99 | list.add("环境");
100 | list.add("发然后");
101 | list.add("环的风格让他很认同和境");
102 | list.add("的富贵华庭");
103 | flowLayoutAdapter=new FlowLayoutAdapter(list) {
104 | @Override
105 | public void bindDataToView(ViewHolder holder, int position, String bean) {
106 | holder.setText(R.id.tv,bean);
107 | }
108 |
109 | @Override
110 | public void onItemClick(int position, String bean) {
111 |
112 | showToast("点击"+position);
113 | }
114 |
115 | @Override
116 | public int getItemLayoutID(int position, String bean) {
117 | return R.layout.item_tv;
118 | }
119 | };
120 | ((FlowLayoutScrollView)findViewById(R.id.flsv)).setAdapter(flowLayoutAdapter);
121 | }
122 |
123 | @Override
124 | public void onClick(View v) {
125 |
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/app/src/main/res/drawable-xxhdpi/close.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/pic1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/app/src/main/res/drawable-xxhdpi/pic1.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/pic2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/app/src/main/res/drawable-xxhdpi/pic2.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/line_rect_huise.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_layout_multi_scroll.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
20 |
21 |
26 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_tv.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_tvscroll.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
21 |
22 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_layout2.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_tv.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/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 |
4 | #3F51B5
5 | #303F9F
6 | #FF4081
7 |
8 |
9 | #ffffff
10 | #e6e6e6
11 | #00000000
12 | #66000000
13 | #20000000
14 |
15 | #333333
16 | #fb484c
17 | #77fb484c
18 | #11fb484c
19 | #eaebed
20 | #343434
21 | #999999
22 | #55999999
23 | #99000000
24 | #ffff00
25 | #22ffffff
26 |
27 |
28 | #2a5caa
29 |
30 | #2a5caa
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CYFlowLayout
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/cy/cyflowlayout/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayout;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.2'
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 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 19
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 | //---------------------------------------------下面的必加,加上下面的作用是在上传后会带上注释,不然会发现没有注释
24 | // 打包源码
25 | task sourcesJar(type: Jar) {
26 | from android.sourceSets.main.java.srcDirs
27 | classifier = 'sources'
28 | }
29 | artifacts {
30 | archives sourcesJar
31 | }
32 |
33 | dependencies {
34 | compile fileTree(dir: 'libs', include: ['*.jar'])
35 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
36 | exclude group: 'com.android.support', module: 'support-annotations'
37 | })
38 | compile 'com.android.support:appcompat-v7:25.3.1'
39 | testCompile 'junit:junit:4.12'
40 | }
41 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/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 D:\AndroidSDK/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 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/src/androidTest/java/com/cy/cyflowlayoutlibrary/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayoutlibrary;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.cy.cyflowlayoutlibrary.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/src/main/java/com/cy/cyflowlayoutlibrary/FlowLayout.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayoutlibrary;
2 |
3 |
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 |
14 | public class FlowLayout extends ViewGroup {
15 | /**
16 | * 存储行的集合,管理行
17 | */
18 | private List mLines = new ArrayList<>();
19 |
20 | /**
21 | * 水平和竖直的间距
22 | */
23 |
24 | private FlowLayoutAdapter flowLayoutAdapter;
25 | private float vertical_space;
26 | private float horizontal_space;
27 |
28 | // 当前行的指针
29 | private Line mCurrentLine;
30 |
31 | // 行的最大宽度,除去边距的宽度
32 | private int mMaxWidth;
33 |
34 |
35 | public void setAdapter(final FlowLayoutAdapter flowLayoutAdapter) {
36 | this.flowLayoutAdapter = flowLayoutAdapter;
37 |
38 | this.flowLayoutAdapter.setOnDataSetChangedListener(new FlowLayoutAdapter.OnDataSetChangedListener() {
39 | @Override
40 | public void onDataSetChanged() {
41 |
42 |
43 | setAdapter(FlowLayout.this.flowLayoutAdapter);
44 | }
45 | });
46 | removeAllViews();
47 |
48 | // 循环添加TextView到容器
49 | int size = flowLayoutAdapter.getCount();
50 | for (int i = 0; i < size; i++) {
51 |
52 | addView(flowLayoutAdapter.getView(this, i));
53 | }
54 | }
55 |
56 | public FlowLayout(Context context) {
57 | this(context, null);
58 | }
59 |
60 | public FlowLayout(Context context, float horizontal_space, float vertical_space) {
61 | this(context,null);
62 | this.horizontal_space = horizontal_space;
63 | this.vertical_space = vertical_space;
64 | }
65 |
66 | public FlowLayout(Context context, AttributeSet attrs) {
67 | super(context, attrs);
68 |
69 | // 获取自定义属性
70 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
71 | horizontal_space = array.getDimension(R.styleable.FlowLayout_width_space, 0);
72 | vertical_space = array.getDimension(R.styleable.FlowLayout_height_space, 0);
73 | array.recycle();
74 |
75 | }
76 |
77 | @Override
78 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
79 | // 每次测量之前都先清空集合,不让会覆盖掉以前
80 | mLines.clear();
81 | mCurrentLine = null;
82 |
83 | // 获取总宽度
84 | int width = MeasureSpec.getSize(widthMeasureSpec);
85 | // 计算最大的宽度
86 | mMaxWidth = width - getPaddingLeft() - getPaddingRight();
87 |
88 | // ******************** 测量孩子 ********************
89 | // 遍历获取孩子
90 | int childCount = this.getChildCount();
91 | for (int i = 0; i < childCount; i++) {
92 | View childView = getChildAt(i);
93 | // 测量孩子
94 | measureChild(childView, widthMeasureSpec, heightMeasureSpec);
95 |
96 | // 测量完需要将孩子添加到管理行的孩子的集合中,将行添加到管理行的集合中
97 |
98 | if (mCurrentLine == null) {
99 | // 初次添加第一个孩子的时候
100 | mCurrentLine = new Line(mMaxWidth, horizontal_space);
101 |
102 | if (i == childCount - 1) {
103 | mCurrentLine.setLast(true);
104 | }
105 | // 添加孩子
106 | mCurrentLine.addView(childView);
107 | // 添加行
108 | mLines.add(mCurrentLine);
109 |
110 | } else {
111 | // 行中有孩子的时候,判断时候能添加
112 | if (mCurrentLine.canAddView(childView)) {
113 | // 继续往该行里添加
114 | mCurrentLine.addView(childView);
115 | if (i == childCount - 1) {
116 | mCurrentLine.setLast(true);
117 | }
118 | } else {
119 | // 添加到下一行
120 | mCurrentLine = new Line(mMaxWidth, horizontal_space);
121 | mCurrentLine.addView(childView);
122 | if (i == childCount - 1) {
123 | mCurrentLine.setLast(true);
124 | }
125 | mLines.add(mCurrentLine);
126 | }
127 | }
128 | }
129 |
130 | // ******************** 测量自己 *********************
131 | // 测量自己只需要计算高度,宽度肯定会被填充满的
132 | int height = getPaddingTop() + getPaddingBottom();
133 | for (int i = 0; i < mLines.size(); i++) {
134 | // 所有行的高度
135 | height += mLines.get(i).height;
136 | }
137 | // 所有竖直的间距
138 | height += (mLines.size() - 1) * vertical_space;
139 |
140 | // 测量
141 | setMeasuredDimension(width, height);
142 | }
143 |
144 | @Override
145 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
146 | // 这里只负责高度的位置,具体的宽度和子孩子的位置让具体的行去管理
147 | l = getPaddingLeft();
148 | t = getPaddingTop();
149 | for (int i = 0; i < mLines.size(); i++) {
150 | // 获取行
151 | Line line = mLines.get(i);
152 | // 管理
153 | line.layout(t, l);
154 |
155 | // 更新高度
156 | t += line.height;
157 | if (i != mLines.size() - 1) {
158 | // 不是最后一条就添加间距
159 | t += vertical_space;
160 | }
161 | }
162 | }
163 |
164 | /**
165 | * 内部类,行管理器,管理每一行的孩子
166 | */
167 | public class Line {
168 | // 定义一个行的集合来存放子View
169 | private List views = new ArrayList<>();
170 | // 行的最大宽度
171 | private int maxWidth;
172 | // 行中已经使用的宽度
173 | private int usedWidth;
174 | // 行的高度
175 | private int height;
176 | // 孩子之间的距离
177 | private float space;
178 | private boolean isLast;
179 |
180 | // 通过构造初始化最大宽度和边距
181 | public Line(int maxWidth, float horizontalSpace) {
182 | this.maxWidth = maxWidth;
183 | this.space = horizontalSpace;
184 | }
185 |
186 | public boolean isLast() {
187 | return isLast;
188 | }
189 |
190 | public void setLast(boolean last) {
191 | isLast = last;
192 | }
193 |
194 | /**
195 | * 往集合里添加孩子
196 | */
197 | public void addView(View view) {
198 | int childWidth = view.getMeasuredWidth();
199 | int childHeight = view.getMeasuredHeight();
200 |
201 | // 更新行的使用宽度和高度
202 | if (views.size() == 0) {
203 | // 集合里没有孩子的时候
204 | if (childWidth > maxWidth) {
205 | usedWidth = maxWidth;
206 | height = childHeight;
207 | } else {
208 | usedWidth = childWidth;
209 | height = childHeight;
210 | }
211 | } else {
212 | usedWidth += childWidth + space;
213 | height = childHeight > height ? childHeight : height;
214 | }
215 |
216 | // 添加孩子到集合
217 | views.add(view);
218 | }
219 |
220 |
221 | /**
222 | * 判断当前的行是否能添加孩子
223 | *
224 | * @return
225 | */
226 | public boolean canAddView(View view) {
227 | // 集合里没有数据可以添加
228 | if (views.size() == 0) {
229 | return true;
230 | }
231 |
232 | // 最后一个孩子的宽度大于剩余宽度就不添加
233 | if (view.getMeasuredWidth() > (maxWidth - usedWidth - space)) {
234 | return false;
235 | }
236 |
237 | // 默认可以添加
238 | return true;
239 | }
240 |
241 | /**
242 | * 指定孩子显示的位置
243 | *
244 | * @param t
245 | * @param l
246 | */
247 | public void layout(int t, int l) {
248 | // 平分剩下的空间
249 | int avg = (maxWidth - usedWidth) / views.size();
250 |
251 | // 循环指定孩子位置
252 | for (View view : views) {
253 | // 获取宽高
254 | int measuredWidth = view.getMeasuredWidth();
255 | int measuredHeight = view.getMeasuredHeight();
256 |
257 | if (isLast) {
258 | // 重新测量
259 |
260 | view.measure(MeasureSpec.makeMeasureSpec(measuredWidth, MeasureSpec.EXACTLY),
261 | MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY));
262 | } else {
263 | // 重新测量
264 | view.measure(MeasureSpec.makeMeasureSpec(measuredWidth + avg, MeasureSpec.EXACTLY),
265 | MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY));
266 | }
267 |
268 |
269 | // 重新获取宽度值
270 | measuredWidth = view.getMeasuredWidth();
271 |
272 |
273 | int top = t;
274 | int left = l;
275 | int right = measuredWidth + left;
276 | int bottom = measuredHeight + top;
277 | // 指定位置
278 | view.layout(left, top, right, bottom);
279 |
280 | // 更新数据
281 | l += measuredWidth + space;
282 | }
283 | }
284 | }
285 | }
286 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/src/main/java/com/cy/cyflowlayoutlibrary/FlowLayoutAdapter.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayoutlibrary;
2 |
3 |
4 | import android.graphics.Bitmap;
5 | import android.util.SparseArray;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.widget.EditText;
9 | import android.widget.ImageView;
10 | import android.widget.ProgressBar;
11 | import android.widget.TextView;
12 |
13 | import java.util.Collection;
14 | import java.util.List;
15 |
16 | /**
17 | * Created by cy on 2018/2/8.
18 | */
19 |
20 | public abstract class FlowLayoutAdapter {
21 | private OnDataSetChangedListener onDataSetChangedListener;
22 | private List list_bean;
23 |
24 | public FlowLayoutAdapter( List list_bean) {
25 | this.list_bean = list_bean;
26 | }
27 |
28 | public int getCount() {
29 | return list_bean.size();
30 | }
31 |
32 | public View getView(FlowLayout parent, final int position) {
33 |
34 | View view = LayoutInflater.from(parent.getContext()).inflate(getItemLayoutID(position, list_bean.get(position)), parent, false);
35 |
36 | view.setOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | onItemClick(position, list_bean.get(position));
40 | }
41 | });
42 | view.setOnLongClickListener(new View.OnLongClickListener() {
43 | @Override
44 | public boolean onLongClick(View v) {
45 | onItemLongClick(position,list_bean.get(position));
46 | return true;
47 | }
48 | });
49 | bindDataToView(new ViewHolder(view), position, list_bean.get(position));
50 | return view;
51 |
52 | }
53 |
54 |
55 | //填充数据
56 | public abstract void bindDataToView(ViewHolder holder, int position, T bean);
57 | /*
58 | ItemView的单击事件
59 |
60 | @param position
61 | */
62 |
63 | public abstract void onItemClick(int position, T bean);
64 | public void onItemLongClick(int position, T bean){}
65 |
66 | /*
67 | 取得ItemView的布局文件
68 | @return
69 | */
70 | public abstract int getItemLayoutID(int position, T bean);
71 |
72 |
73 | public void remove(int position) {
74 | list_bean.remove(position);
75 | notifyDataSetChanged();
76 | }
77 |
78 | public void add(T bean) {
79 | list_bean.add(bean);
80 |
81 | notifyDataSetChanged();
82 | }
83 | public void notifyDataSetChanged(){
84 | if(onDataSetChangedListener!=null){
85 |
86 | onDataSetChangedListener.onDataSetChanged();
87 | }
88 | }
89 |
90 | public void addNoNotify(T bean) {
91 | list_bean.add(bean);
92 | }
93 |
94 | public void addToHead(T bean) {
95 | list_bean.add(0, bean);
96 | }
97 |
98 | public int addAll(List beans) {
99 | list_bean.addAll(beans);
100 |
101 | notifyDataSetChanged();
102 |
103 | return beans.size();
104 | }
105 |
106 | public void addAll(Collection c) {
107 | list_bean.addAll(c);
108 | notifyDataSetChanged();
109 |
110 |
111 | }
112 |
113 | public int clearAddAll(List beans) {
114 | list_bean.clear();
115 | list_bean.addAll(beans);
116 |
117 | notifyDataSetChanged();
118 |
119 | return beans.size();
120 | }
121 |
122 | public void addAllToHead(List beans) {
123 | list_bean.addAll(0, beans);
124 | notifyDataSetChanged();
125 |
126 | }
127 |
128 | public void clear() {
129 | list_bean.clear();
130 | notifyDataSetChanged();
131 |
132 | }
133 |
134 | public void setOnDataSetChangedListener(OnDataSetChangedListener onDataSetChangedListener) {
135 | this.onDataSetChangedListener = onDataSetChangedListener;
136 | }
137 |
138 | public interface OnDataSetChangedListener{
139 | public void onDataSetChanged();
140 | }
141 | public static class ViewHolder {
142 | private View itemView;
143 | private SparseArray array_view;
144 |
145 | public ViewHolder(View itemView) {
146 | this.itemView = itemView;
147 |
148 | array_view = new SparseArray();
149 |
150 | }
151 |
152 |
153 | public T getView(int viewId) {
154 |
155 | View view = array_view.get(viewId);
156 | if (view == null) {
157 | view = itemView.findViewById(viewId);
158 | array_view.put(viewId, view);
159 | }
160 | return (T) view;
161 | }
162 |
163 |
164 |
165 |
166 |
167 | public ViewHolder setVisible(int res_id) {
168 | getView(res_id).setVisibility(View.VISIBLE);
169 | return this;
170 | }
171 |
172 | public ViewHolder setInVisible(int res_id) {
173 | getView(res_id).setVisibility(View.INVISIBLE);
174 | return this;
175 | }
176 |
177 | public void setViewGone(int res_id) {
178 | getView(res_id).setVisibility(View.GONE);
179 | }
180 |
181 | public void setViewVisible(int res_id) {
182 | getView(res_id).setVisibility(View.VISIBLE);
183 | }
184 |
185 |
186 | public void setText(int tv_id, String text) {
187 | TextView tv = getView(tv_id);
188 |
189 |
190 | tv.setText(nullToString(text));
191 | }
192 |
193 | public String nullToString(Object object) {
194 | return object == null ? "" : object.toString();
195 | }
196 |
197 | public void setPriceText(int tv_id, String text) {
198 | TextView tv = getView(tv_id);
199 |
200 | tv.setText("¥" + text);
201 | }
202 |
203 | public void setCountText(int tv_id, String text) {
204 | TextView tv = getView(tv_id);
205 |
206 | tv.setText("x" + text);
207 | }
208 |
209 | public void setCountText(int tv_id, int text) {
210 | TextView tv = getView(tv_id);
211 |
212 | tv.setText("x" + text);
213 | }
214 |
215 | public void setPriceText(int tv_id, int text) {
216 | TextView tv = getView(tv_id);
217 |
218 | tv.setText("¥" + text);
219 | }
220 |
221 | public void setPriceText(int tv_id, float text) {
222 | TextView tv = getView(tv_id);
223 |
224 | tv.setText("¥" + text);
225 | }
226 |
227 | public void setText(int tv_id, int text) {
228 | TextView tv = getView(tv_id);
229 | tv.setText(String.valueOf(nullToString(text)));
230 | }
231 |
232 | public void setTextColor(int tv_id, int color) {
233 | TextView tv = getView(tv_id);
234 | tv.setTextColor(color);
235 | }
236 |
237 | public String getTVText(int tv_id) {
238 | TextView tv = getView(tv_id);
239 | return tv.getText().toString().trim();
240 | }
241 |
242 | public String getETText(int tv_id) {
243 | EditText tv = getView(tv_id);
244 | return tv.getText().toString().trim();
245 | }
246 |
247 | public void setBackgroundResource(int v_id, int resid) {
248 | View view = getView(v_id);
249 | view.setBackgroundResource(resid);
250 | }
251 |
252 | public void setImageBitmap(int v_id, Bitmap bitmap) {
253 | ImageView view = getView(v_id);
254 | view.setImageBitmap(bitmap);
255 | }
256 |
257 | public void setImageResource(int v_id, int resID) {
258 | ImageView view = getView(v_id);
259 | view.setImageResource(resID);
260 | }
261 |
262 | public void setProgress(int progress_id, int progress) {
263 | ProgressBar progressBar = getView(progress_id);
264 | progressBar.setProgress(progress);
265 |
266 | }
267 |
268 | public void setOnClickListener(int res_id, View.OnClickListener onClickListener) {
269 | getView(res_id).setOnClickListener(onClickListener);
270 | }
271 |
272 | public void setOnLongClickListener(int res_id, View.OnLongClickListener onLongClickListener) {
273 | getView(res_id).setOnLongClickListener(onLongClickListener);
274 | }
275 | }
276 |
277 |
278 | }
279 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/src/main/java/com/cy/cyflowlayoutlibrary/FlowLayoutScrollView.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayoutlibrary;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.util.AttributeSet;
6 | import android.widget.ScrollView;
7 |
8 | /**
9 | * Created by cy on 2018/4/14.
10 | */
11 |
12 | public class FlowLayoutScrollView extends ScrollView {
13 | private Context context;
14 | private FlowLayout flowLayout;
15 |
16 | public FlowLayoutScrollView(Context context) {
17 | this(context, null);
18 | }
19 |
20 | public FlowLayoutScrollView(Context context, AttributeSet attrs) {
21 | super(context, attrs);
22 | this.context = context;
23 | setOverScrollMode(OVER_SCROLL_NEVER);
24 | setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);
25 |
26 |
27 | // 获取自定义属性
28 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
29 | float horizontal_space = array.getDimension(R.styleable.FlowLayout_width_space, 0);
30 | float vertical_space = array.getDimension(R.styleable.FlowLayout_height_space, 0);
31 | array.recycle();
32 |
33 | flowLayout = new FlowLayout(context,horizontal_space,vertical_space);
34 |
35 |
36 | addView(flowLayout);
37 | }
38 |
39 | public void setAdapter(FlowLayoutAdapter flowLayoutAdapter) {
40 | flowLayout.setAdapter(flowLayoutAdapter);
41 | }
42 |
43 | public FlowLayout getFlowLayout() {
44 | return flowLayout;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CYFlowLayoutLibrary
3 |
4 |
--------------------------------------------------------------------------------
/cyflowlayoutlibrary/src/test/java/com/cy/cyflowlayoutlibrary/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.cy.cyflowlayoutlibrary;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/gif/1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/gif/1.gif
--------------------------------------------------------------------------------
/gif/2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/gif/2.gif
--------------------------------------------------------------------------------
/gif/3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/gif/3.gif
--------------------------------------------------------------------------------
/gif/4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AnJiaoDe/MultiFlowLayout/dc6ff3c3f87f151ccbe54c460a7d68b2b9fc7b55/gif/4.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':cyflowlayoutlibrary'
2 |
--------------------------------------------------------------------------------