├── .gitignore
├── .idea
├── gradle.xml
├── markdown-navigator.xml
├── markdown-navigator
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── xiaweizi
│ │ └── androidmd
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── xiaweizi
│ │ │ └── androidmd
│ │ │ ├── Constants.kt
│ │ │ ├── FloatActionBarBehavior.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── MyAdapter.kt
│ │ │ ├── MyClient.kt
│ │ │ ├── MyService.kt
│ │ │ ├── TestFragment.kt
│ │ │ ├── WeaponBean.kt
│ │ │ ├── WeaponDetailActivity.kt
│ │ │ └── WeaponFragment.kt
│ └── res
│ │ ├── drawable-hdpi
│ │ ├── ic_action_add.png
│ │ ├── ic_action_arrow_up.png
│ │ └── ic_action_name.png
│ │ ├── drawable-mdpi
│ │ ├── ic_action_add.png
│ │ ├── ic_action_arrow_up.png
│ │ └── ic_action_name.png
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xhdpi
│ │ ├── ic_action_add.png
│ │ ├── ic_action_arrow_up.png
│ │ └── ic_action_name.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_action_add.png
│ │ ├── ic_action_arrow_up.png
│ │ └── ic_action_name.png
│ │ ├── drawable
│ │ ├── about.png
│ │ ├── ic_launcher_background.xml
│ │ ├── joke.png
│ │ ├── news.png
│ │ ├── robot.png
│ │ └── today.png
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_weapon_detail.xml
│ │ ├── fragment_test.xml
│ │ ├── fragment_weapon.xml
│ │ ├── item_weapon_info.xml
│ │ └── nav_header.xml
│ │ ├── menu
│ │ ├── bottom_menu.xml
│ │ ├── menu.xml
│ │ └── nav_menu.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── xiaweizi
│ └── androidmd
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | Abstraction issuesJava
36 |
37 |
38 | AccessibilityLintAndroid
39 |
40 |
41 | Android
42 |
43 |
44 | Annotations verifyingGroovy
45 |
46 |
47 | Assignment issuesGroovy
48 |
49 |
50 | Assignment issuesJava
51 |
52 |
53 | Bidirectional TextInternationalizationLintAndroid
54 |
55 |
56 | Bitwise operation issuesJava
57 |
58 |
59 | C/C++
60 |
61 |
62 | Chrome OSCorrectnessLintAndroid
63 |
64 |
65 | Class metricsJava
66 |
67 |
68 | Class structureJava
69 |
70 |
71 | Cloning issuesJava
72 |
73 |
74 | Code style issuesJava
75 |
76 |
77 | Concurrency annotation issuesJava
78 |
79 |
80 | Control FlowGroovy
81 |
82 |
83 | Control flow issuesJava
84 |
85 |
86 | CorrectnessLintAndroid
87 |
88 |
89 | Data flow analysisC/C++
90 |
91 |
92 | Data flow issuesJava
93 |
94 |
95 | Declaration redundancyJava
96 |
97 |
98 | Dependency issuesJava
99 |
100 |
101 | Encapsulation issuesJava
102 |
103 |
104 | Error handlingGroovy
105 |
106 |
107 | Error handlingJava
108 |
109 |
110 | Finalization issuesJava
111 |
112 |
113 | General
114 |
115 |
116 | GeneralC/C++
117 |
118 |
119 | Google Cloud Endpoints
120 |
121 |
122 | Groovy
123 |
124 |
125 | HTML
126 |
127 |
128 | IconsUsabilityLintAndroid
129 |
130 |
131 | ImportsJava
132 |
133 |
134 | Inheritance issuesJava
135 |
136 |
137 | Initialization issuesJava
138 |
139 |
140 | Internationalization issues
141 |
142 |
143 | Internationalization issuesJava
144 |
145 |
146 | InternationalizationLintAndroid
147 |
148 |
149 | J2ME issuesJava
150 |
151 |
152 | JSON
153 |
154 |
155 | JUnit issuesJava
156 |
157 |
158 | Java
159 |
160 |
161 | Java 5Java language level migration aidsJava
162 |
163 |
164 | Java 7Java language level migration aidsJava
165 |
166 |
167 | Java 8Java language level migration aidsJava
168 |
169 |
170 | Java interop issuesKotlin
171 |
172 |
173 | Java language level migration aidsJava
174 |
175 |
176 | JavaBeans issuesJava
177 |
178 |
179 | Javadoc issuesJava
180 |
181 |
182 | Kotlin
183 |
184 |
185 | Kotlin Android
186 |
187 |
188 | Language Injection
189 |
190 |
191 | LintAndroid
192 |
193 |
194 | LintLintAndroid
195 |
196 |
197 | Logging issuesJava
198 |
199 |
200 | Memory issuesJava
201 |
202 |
203 | MessagesCorrectnessLintAndroid
204 |
205 |
206 | Method MetricsGroovy
207 |
208 |
209 | Method metricsJava
210 |
211 |
212 | Modularization issuesJava
213 |
214 |
215 | Naming ConventionsGroovy
216 |
217 |
218 | Naming conventionsJava
219 |
220 |
221 | Naming conventionsKotlin
222 |
223 |
224 | Numeric issuesJava
225 |
226 |
227 | Other problemsKotlin
228 |
229 |
230 | Packaging issuesJava
231 |
232 |
233 | Performance issuesJava
234 |
235 |
236 | PerformanceLintAndroid
237 |
238 |
239 | Portability issuesJava
240 |
241 |
242 | Potentially confusing code constructsGroovy
243 |
244 |
245 | Probable bugsGroovy
246 |
247 |
248 | Probable bugsJava
249 |
250 |
251 | Probable bugsKotlin
252 |
253 |
254 | Properties Files
255 |
256 |
257 | Redundant constructsKotlin
258 |
259 |
260 | RegExp
261 |
262 |
263 | Resource management issuesJava
264 |
265 |
266 | Security issuesJava
267 |
268 |
269 | SecurityLintAndroid
270 |
271 |
272 | Serialization issuesJava
273 |
274 |
275 | Style issuesKotlin
276 |
277 |
278 | TestNGJava
279 |
280 |
281 | Threading issuesGroovy
282 |
283 |
284 | Threading issuesJava
285 |
286 |
287 | Type checksC/C++
288 |
289 |
290 | TypographyUsabilityLintAndroid
291 |
292 |
293 | UsabilityLintAndroid
294 |
295 |
296 | Verbose or redundant code constructsJava
297 |
298 |
299 | Visibility issuesJava
300 |
301 |
302 | XML
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 | 1.8
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 准备
2 | 我分享主题为『Material Design In Android』。因为之前毕设项目[趣闻](https://github.com/xiaweizi/QNews)中有用到「Support Design」库中的控件,对其比较熟悉。我分三部分准备:
3 |
4 |
5 | 1. `APP`准备
6 | 2. 文档准备
7 | 3. `Keynote`准备
8 |
9 | # 一、APP准备
10 | 项目已经上传到`GitHub`上:[AndroidMD](https://github.com/xiaweizi/AndroidMD)
11 |
12 | 运行效果
13 |
14 | 
15 |
16 | 花了两个多小时做了这个`APP`,主要作为`MD`控件的功能展示,如果需要额外的特殊功能,请自行添加。
17 |
18 | 先说说完成这个`APP`的事前准备:
19 |
20 | #### 1. 主题
21 | 主题是最近非常火的[**「终结者2:审判日」**](https://t2.16163.com/thread-3414567-1-1.html)
22 | #### 2. 数据
23 | 数据是自己在本地写的`json`数据,很是尴尬,然后部署到**[七牛云](https://www.qiniu.com/)**上。地址是:[WeaponInfo](http://owj4ejy7m.bkt.clouddn.com/weaponInfo),这样就可以直接访问地址获取`json`数据。
24 |
25 | #### 3. 语言
26 | 用的语言是之前学的**`Kotlin`**。[Kotlin学习笔记](http://www.jianshu.com/p/f132e368b88d)
27 | #### 4. 风格
28 | 整体的风格就是我这次分享的主题 `Material Desing`风格。
29 |
30 | # 二、整体内容结构的准备
31 |
32 | 在做`PPT`之前,先把结构搭好,并且把`PPT`的内容先准备好,到时候直接就可以复制到`PPT`中。
33 |
34 | 整体结构:
35 |
36 | > 1. 什么是 `Material Design`
37 | > 2. `Material Desing`的特点
38 | > 3. 从四个特点结合`Android`的应用剖析
39 | > 4. 在我的公司「口袋」项目中的应用
40 |
41 | 当然内容需要看官方的文档和其他资料加上总结才能完成,所以在此感谢一下文章的帮助:
42 |
43 | > [Material Design 学习笔记](http://www.uisdc.com/comprehensive-material-design-note)
44 | > [Material Design 官网介绍文档](https://material.io/guidelines/)
45 | > [Material Design 中文介绍](http://md.maxoxo.design/#)
46 | > [Material Design in Android Developer](https://developer.android.com/training/material/index.html)
47 |
48 | # 三、`PPT`的准备
49 |
50 | 有了之前内容的编写,做`PPT`就方便一点。但是因为刚买的`MAC`,但又不想再装`WPS`套餐,于是用的是自带的`keynote`,所以使用上会有点生疏。不过,整个`PPT`制作下来对其使用也熟练了起来。
51 |
52 | 如果需要的话,可以加个QQ发给你。
53 |
54 | ### 1、封面
55 |
56 | 
57 |
58 | > 进入`MD`官网首页就是这张图片。
59 |
60 | ### 2、介绍
61 |
62 | 
63 |
64 | > 从`MD`上截取的动画作为入口,大概讲解一下`MD`的基础概念和特点。
65 |
66 | ### 3、特点
67 |
68 | 
69 |
70 | > 这里抽取了四个点:`Material`、`Elevation`、`Color`和`Animation`进行分析。
71 |
72 | ### 4、风格背景
73 |
74 | > 文字采用圆角+阴影进行包裹,至于高度和圆角效果因为时间紧迫,没有按照严格规范进行设置,如果对这方面有要求可以参考官网详细的规范要求。
75 |
76 | 
77 |
78 | ### 5、动画效果
79 |
80 | > 说起动画,为了能够模仿`MD`的交互,也是现学现卖了一把。
81 |
82 | 
83 |
84 | 其实就是背景的放大效果,再加上文字的位移效果。
85 |
86 |
87 | ----------
88 |
89 | ----------
90 |
91 | 我--------------是--------------分--------------割--------------线
92 |
93 | ----------
94 |
95 | ----------
96 |
97 |
98 | # **Material Design in Android**
99 |
100 | 接下来开始分享这次分享的主要内容,因为`MD`的介绍和规范在官网上都有非常详细全面的介绍,所以我就不赘述了,建议自己先看一遍官方网站的介绍,这样你对`MD`的理解会更加深入一些。那我把链接再列出一下:
101 |
102 | > [Material Design`官网介绍文档](https://material.io/guidelines/)
103 | > [Material Design 中文介绍](http://md.maxoxo.design/#)
104 |
105 | 当你把官网的内容大致浏览一遍,相信也对`MD`有个初步的了解,当然要想全部弄懂的话,还得需要消化一阵子,毕竟`MD`的设计规范细致入微。越读越能感受到它的妙处,假如你能严格按照它的规范进行开发项目,哪怕你不是专业的UI设计师,相信你的产品一定不会难看的。
106 |
107 | 那接下来就主要介绍一下`Material Desing`在`Android`中应用。。
108 |
109 | 跟随着15年`Android 5.0`的问世,谷歌设计师们还给我们带来的一系列的具有`Material Design`风格控件。这些控件被统一放置在`support design`库中,以供开发中使用。使用这些库的前提是`API>=21`,当然如果你想在 5.0 一下的设备这些控件的话,需要添加`appcompat`包进行向下兼容。
110 |
111 | 
112 |
113 | 我的`design`版本是`26.1.0`,上图大概就是`design`提供的`API`,这里我只做简单的使用介绍,如果想了解其原理的话,可以看一下官方的介绍。
114 |
115 | > 这么多我该从何说起呢?我想了下,就按照我做这个小项目,需要的控件顺序说起吧,这样也相当于大家跟我一起做出一个具有`Material Design`风格的`APP`了。
116 |
117 | ### 1、主题
118 | 一个项目的开始,你得先确定这个项目的主题颜色是什么?你可以使用谷歌给你提供的`Material Theme`:
119 |
120 | - `@android:style/Theme.Material`(深色版本)
121 | - `@android:style/Theme.Material.Light`(浅色版本)
122 | - `@android:style/Theme.Material.Light.DarkActionBar`
123 |
124 | 当然,也可以使用自定义的主题,先看一下最为常见的图片:
125 |
126 | 
127 |
128 | 可以通过定制不同的类别的主题颜色,来达到预期的主题效果。
129 |
130 | - `colorPrimary` 项目主颜色,一般是`Titlebar`的背景颜色
131 | - `colorPrimaryDark` 比主颜色深一点颜色,一般是状态栏颜色
132 | - `textColorPrimary` 文字的主颜色
133 | - `windowBackground` 窗口背景颜色
134 | - `navigationBarColor` 导航栏颜色
135 |
136 | 通过在`styles`中配置颜色来定制您的主题,并在`AndroidManifest`中应用。
137 |
138 |
139 |
140 | ### 2、BottomNavigationView
141 |
142 | 主题构建好了,下面就是主要内容架构,我大致分为四个模块:武器简介、人物简介、配件简介和空投简介。那么底下就需要一个`tab`进行切换,`BottomNavigationView`便开始登场。从名字就可以看出 「底部导航`view`」,主要的作用在于给每个模块一个导航定位的功能,相信大家在众多`App`中都能发下底部导航`view`的身影。
143 |
144 | 先看一下效果:
145 |
146 | 
147 |
148 |
149 | 1. 在`menu/`下创建菜单文件:
150 |
151 |
160 |
161 | 2. `XML`中进行引用
162 |
163 |
171 |
172 | 3. 代码中设置点击事件
173 |
174 | navigation!!.setOnNavigationItemSelectedListener {}
175 |
176 |
177 | ### 3、DrawerLayout、NavigationView
178 |
179 | 和`BottomNavigationView`相对应的,不得不介绍一下`NavigationView`,这两者都是导航`View`,后者一般需要配合`DrawerLayout`实现侧滑菜单效果。
180 |
181 | 请看效果:
182 |
183 | 
184 |
185 | 在`XML`直接引用
186 |
187 |
192 |
193 |
198 |
199 |
200 |
201 |
208 |
209 |
210 | 通过配置`layout_gravity`的属性来设置侧滑的方向:`start`:从左侧划出,`end`从右侧划出。
211 |
212 | headerLayout: 设置其头布局
213 | menu: 设置菜单布局
214 |
215 | 详细使用请看我之前写的一篇博客:[高大上的`DrawerLayout`](http://www.jianshu.com/p/ce8a7a20c03c)
216 |
217 | ### 4、Toolbar
218 |
219 | 整体的架构搭建好了,剩下就是开始每个模块的内容了,内容当然少不了标题,那么就开始介绍一下`Toolbar`。
220 |
221 | `Toolbar`作为早期`Android`中`ActionBar`的替代品,定制性和操作性挺高了不少。使用的时候需要设置`NoActionBar`的主题。
222 |
223 |
224 |
225 | ### 5、RecyclerView+SwipeRefreshLayout
226 |
227 | 项目中列表肯定是少不了的,那么这就不得不提`RecyclerView`了,强大之处不用多说,感兴趣的话看一下我之前写的博客,对其使用有个简单的介绍:[简单粗暴`RecyclerView`](https://www.jianshu.com/p/60819de9eb42)
228 |
229 | 那如果想实现侧滑删除和长按拖拽的功能怎么办呢?`RecyclerView`原生就支持这些,只需要继承`ItemTouchHelper.Callback`的类,并实现它几个抽象方法即可。
230 |
231 | 1. 创建实现`ItemTouchHelper.Callback`的类
232 |
233 | internal inner class ItemTouchHelperCallback : ItemTouchHelper.Callback() {
234 | override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
235 | val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
236 | val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
237 | return makeMovementFlags(dragFlags, swipeFlags)
238 | }
239 |
240 | override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
241 | myAdapter!!.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
242 | return false
243 | }
244 |
245 | override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
246 | myAdapter!!.onItemDismiss(viewHolder.adapterPosition)
247 | }
248 | }
249 |
250 | 2. 和`RecyclerView`建立连接
251 |
252 | val mItemTouchHelper = ItemTouchHelper(ItemTouchHelperCallback())
253 | mItemTouchHelper.attachToRecyclerView(mRecyclerView)
254 |
255 | 实现效果如下:
256 |
257 | 
258 |
259 | ### 6、CardView
260 |
261 | 列表结构写好了,里面内容得优化吧,`CardView`自带圆角和阴影效果,让每个`Item`看起来就非常的自然,正如其名像卡片一样,也符合了`Material Design`特点。
262 |
263 | 作为`ViewGroup`包裹子`View`实现圆角和阴影的效果:
264 |
265 |
271 |
272 |
273 | 主要由两个属性控制:
274 |
275 | - `cardCornerRadius`:圆角半径
276 | - `cardElevation`:高度(直接影响阴影的大小)
277 |
278 |
279 | ### 7、CoordinatorLayout+AppBarLayout+Toolbar
280 |
281 | 列表写好了,接下来就是滑动的交互,`CoordinatorLayout`:作为根`View`或者是一个活多个子`View`特定的容器,用于协调子`View`之间滑动的交互,可以说`CoordinatorLayout`是整个`Design`库中最核心的控件。
282 |
283 | `AppBarLayout`其实就是`LinearLayout`,通过`layout_scrollFlags`来控制滑动的效果。前提是滑动`view`必须实现`NestedScrollingChild`的接口,且需要配置`behavior`,最基本的使用就是:
284 |
285 |
290 |
291 |
295 |
304 |
305 |
306 |
311 |
316 |
317 |
318 |
319 |
320 | 有两个重点:
321 |
322 | - 滑动的`view`必须实现`NestedScrollingChild`接口。比如`RecyclerView`、`NestedScrollView`.
323 | - 必须配置`behavior`。`app:layout_behavior="@string/appbar_scrolling_view_behavior"`
324 |
325 | 重点看一下`layout_scrollFlags`有哪些属性,为了方便理解,将可以滑动的`view`简称为`ScrollView`,设置了`layout_scrollFlags`称为`DependentView`,两者滑动事件的传递通过配置不同的`layout_scrollFlags`达到不同的交互效果。
326 |
327 | #### 1. scroll
328 | 子`view`必须设置该属性其他的属性的才会生效,这个是最基本的属性。
329 |
330 | #### 2. scroll|enterAlways
331 |
332 | `DependentView`事件处理的优先级要大于`ScrollView`,当手指在屏幕上滑动,滑动事件便首先交给`DependentView`处理,当`DependentView`滑动结束才会将事件交给`ScorllView`。也就是下面的效果:
333 |
334 | 
335 |
336 | #### 3. scroll|enterAlwaysCollapsed
337 |
338 | 当`ScrollView`向下滑动时,`DependentView`先折叠到最小高度(这里是0),然后将事件交给`ScrollView`,当`ScrollView`滑动结束,`DependentView`才继续滑动事件,直至展开,如下图所示:
339 |
340 | 
341 |
342 | #### 4. scroll|enterAlwaysCollapsed|enterAlways
343 |
344 | 这边就展示一下折叠的效果,我们先设置最小的高度
345 |
346 |
351 |
352 | 展示一下效果:
353 |
354 | 
355 |
356 | #### 5. scroll|exitUntilCollapsed
357 |
358 | 这个搭配重点在于上拉的时候,`DependentView`会先折叠到最小高度,然后事件全部交给`ScrollView`。那下拉的时候就是当`ScrollView`滑动结束,才开始`DependentView`的滑动事件。
359 |
360 | 
361 |
362 | #### 6. scroll|enterAlways|snap
363 |
364 | 这个`snap`就是在上面的基础上多了一个回弹的效果,一般需要配合上其他属性使用才会有效果。当`DependentView`正在滑动,此时手指离开屏幕时,`DependentView`会自动移动到离自己较近的终点或者始点。效果如下:
365 |
366 | 
367 |
368 |
369 | 上面的属性完全可以像第四种情况叠加使用,至于效果自己尝试了了才能感觉到它的奥妙之处。
370 |
371 | ### 8、转场动画
372 |
373 | 交互有了,现在看是添加点击跳转效果了。咱们之前跳转动画都是在`startActivity`之后调用`overridePendingTransition`方法,传入进入和退出的动画实现跳转动画。`Android 5.0`提供了强大的转场动画,给每个`item`赋予了生命,我们可以把`Activity`的跳转比作一次搬迁大运动,而布局中的每个`view`都参与到了这次搬迁运动中。
374 |
375 | 使用时,需在`setContentView()`之前加上
376 |
377 | window.requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)
378 |
379 | 跳转时候这样写:
380 |
381 | startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle())
382 |
383 | 跳转的界面设置转场动画或者出场动画:
384 |
385 | window.enterTransition = Explode()
386 | window.exitTransition = Slide()
387 |
388 | 谷歌给我提供了三种转场方式:
389 |
390 | - Explode() 突然的变形
391 | - Slide() 自然的滑动
392 | - Fade() 渐变
393 |
394 | 为了看出效果我设置了2s的延迟:
395 |
396 | 
397 |
398 | ### 9、Toast、SnackBar和AlertDialog
399 |
400 | 基本的界面写完了,剩下的就是一些逻辑上的操作啦,比如「提示」。那么`Android`提示分为三种:
401 |
402 | - 友好的`Toast`(比如网络失败)
403 | - 拥有附加行为的提示`SnackBar`(比如误删信息回撤)
404 | - 强制让用户做出选择的`AlertDialg`(比如未登录)
405 |
406 | 那么这三种的效果是什么呢?
407 |
408 | 
409 |
410 | 大概先讲这些,有时间再进行后续补充。
411 |
412 | # `Material Design`在「口袋」中的应用
413 |
414 | 其实在咱们的「口袋贵金属」项目中也到找到很多`MD`的元素。
415 |
416 | 首先是点击的水波纹效果:
417 |
418 | 
419 |
420 | 其次是交易圈的滑动交互:
421 |
422 | 
423 |
424 | 还有就是本人在「口袋」接手的第二个需求,「个人中心」。看一下效果:
425 |
426 | 
427 |
428 |
429 | > 严格按照`Material Design`风格进行开发,相信一定能开发出非常漂亮的`APP`!!
430 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 |
5 | apply plugin: 'kotlin-android-extensions'
6 |
7 | android {
8 | compileSdkVersion 26
9 | defaultConfig {
10 | applicationId "com.xiaweizi.androidmd"
11 | minSdkVersion 21
12 | targetSdkVersion 26
13 | versionCode 1
14 | versionName "1.0"
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
28 | implementation 'com.android.support:appcompat-v7:26.1.0'
29 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
30 | testImplementation 'junit:junit:4.12'
31 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
32 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
33 |
34 | //鸿洋大神封装的okhttpUtils
35 | implementation 'com.zhy:okhttputils:2.6.2'
36 | //Material Design
37 | implementation 'com.android.support:design:26.1.0'
38 | //Gson
39 | implementation 'com.google.code.gson:gson:2.3.1'
40 | //图片加载框架 Glide
41 | implementation 'com.github.bumptech.glide:glide:3.7.0'
42 | //卡片式布局
43 | implementation 'com.android.support:cardview-v7:26.1.0'
44 | //recyclerview
45 | implementation 'com.android.support:recyclerview-v7:26.1.0'
46 | //工具集合
47 | implementation 'com.blankj:utilcode:1.3.6'
48 | //baseAdapter
49 | compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.8.0'
50 |
51 | //Retrofit
52 | implementation 'com.squareup.retrofit2:retrofit:2.2.0'
53 | implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
54 | implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
55 | //RxJava
56 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
57 | implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
58 | //http拦截器
59 | implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1'
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/xiaweizi/androidmd/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import android.support.test.InstrumentationRegistry
4 | import android.support.test.runner.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getTargetContext()
22 | assertEquals("com.xiaweizi.androidmd", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | /**
4 | *
5 | * author : xiaweizi
6 | * class : com.xiaweizi.androidmd.Constants
7 | * e-mail : 1012126908@qq.com
8 | * time : 2017/12/09
9 | * desc : 存放常亮的地方
10 | *
11 | */
12 | interface Constants {
13 | companion object {
14 | /**
15 | * 头部 ImageView 的链接地址
16 | */
17 | const val HEAD_IMAGE_URL = "https://t2.res.netease.com/pc/fab/20171115143133/img/icon_bb93fd9.png"
18 | /**
19 | * 项目的 master 地址
20 | */
21 | const val MASTER_URL = "http://owj4ejy7m.bkt.clouddn.com/"
22 | const val EXTRA_WEAPON_BEAN = "weapon_bean"
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/FloatActionBarBehavior.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import android.content.Context
4 | import android.support.design.widget.CoordinatorLayout
5 | import android.support.design.widget.FloatingActionButton
6 | import android.support.v4.view.ViewCompat
7 | import android.util.AttributeSet
8 | import android.util.Log
9 | import android.view.View
10 |
11 |
12 | /**
13 | *
14 | * author : xiaweizi
15 | * class : com.xiaweizi.androidmd.FloatActionBarBehavior
16 | * e-mail : 1012126908@qq.com
17 | * time : 2017/12/12
18 | * desc :
19 | *
20 | */
21 | class FloatActionBarBehavior(context: Context, attrs: AttributeSet) : FloatingActionButton.Behavior() {
22 |
23 | override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton,
24 | directTargetChild: View, target: View, nestedScrollAxes: Int): Boolean {
25 | return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes)
26 | }
27 |
28 | override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton,
29 | target: View, dxConsumed: Int, dyConsumed: Int,
30 | dxUnconsumed: Int, dyUnconsumed: Int) {
31 | super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed)
32 |
33 | if (dyConsumed > 0 && child.visibility == View.VISIBLE) {
34 | child.hide()
35 | } else if (dyConsumed < 0 && child.visibility != View.VISIBLE) {
36 | child.show()
37 | }
38 | }
39 |
40 | override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton, directTargetChild: View, target: View, axes: Int, type: Int): Boolean {
41 | Log.i("floatAcitonBar", type.toString())
42 | return super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type)
43 | }
44 |
45 | override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton, target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, type: Int) {
46 | Log.i("floatAcitonBar", dxConsumed.toString())
47 | super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type)
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import android.os.Bundle
4 | import android.support.design.widget.NavigationView
5 | import android.support.design.widget.Snackbar
6 | import android.support.v4.app.Fragment
7 | import android.support.v4.widget.DrawerLayout
8 | import android.support.v7.app.AlertDialog
9 | import android.support.v7.app.AppCompatActivity
10 | import android.view.Window
11 | import android.widget.ImageView
12 | import android.widget.Toast
13 | import com.bumptech.glide.Glide
14 | import kotlinx.android.synthetic.main.activity_main.*
15 |
16 | /**
17 | *
18 | * author : xiaweizi
19 | * class : com.xiaweizi.androidmd.MainActivity
20 | * e-mail : 1012126908@qq.com
21 | * time : 2017/12/10
22 | * desc : 主界面
23 | *
24 | */
25 | class MainActivity : AppCompatActivity() {
26 |
27 | private lateinit var mIvHead: ImageView
28 | private lateinit var mDrawerLayout: DrawerLayout
29 | private var currentFragment: Fragment? = null
30 |
31 |
32 | private var weaponFragment: WeaponFragment ?= null
33 | private var peopleFragment: TestFragment ?= null
34 | private var subFragment: TestFragment ?= null
35 | private var thingsFragment: TestFragment ?= null
36 |
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | super.onCreate(savedInstanceState)
39 | window.requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)
40 | setContentView(R.layout.activity_main)
41 | initView()
42 | initData()
43 | initListener()
44 | if (weaponFragment == null) {
45 | weaponFragment = WeaponFragment()
46 | }
47 | switchFragment(weaponFragment!!)
48 | }
49 |
50 | /**
51 | * 初始化 view
52 | */
53 | private fun initView() {
54 | mDrawerLayout = findViewById(R.id.dl_main)
55 | val nav: NavigationView = findViewById(R.id.nv_left)
56 | mIvHead = nav.getHeaderView(0).findViewById(R.id.iv_head)
57 | }
58 |
59 |
60 | /**
61 | * 初始化数据
62 | */
63 | private fun initData() {
64 | Glide.with(this).load(Constants.HEAD_IMAGE_URL)
65 | .into(mIvHead)
66 | }
67 |
68 | /**
69 | * 初始化 listener
70 | */
71 | private fun initListener() {
72 | // 左侧侧滑菜单选择事件
73 | nv_left!!.setCheckedItem(R.id.nav_weapon_inc)
74 | nv_left!!.setNavigationItemSelectedListener { item ->
75 | nv_left!!.setCheckedItem(item.itemId)
76 | dl_main!!.closeDrawers()
77 | when (item.itemId) {
78 | R.id.nav_weapon_inc -> {
79 | if (weaponFragment == null) {
80 | weaponFragment = WeaponFragment()
81 | }
82 | switchFragment(weaponFragment!!)
83 | navigation.selectedItemId = R.id.bottom_weapon_inc
84 | }
85 | R.id.nav_people_inc -> {
86 | if (peopleFragment == null) {
87 | peopleFragment = TestFragment.getInstance(getString(R.string.people_inc))
88 | }
89 | switchFragment(peopleFragment!!)
90 | navigation.selectedItemId = R.id.bottom_people_inc
91 | }
92 | R.id.nav_sub_inc -> {
93 | if (subFragment == null) {
94 | subFragment = TestFragment.getInstance(getString(R.string.sub_inc))
95 | }
96 | switchFragment(subFragment!!)
97 | navigation.selectedItemId = R.id.bottom_sub_inc
98 | }
99 | R.id.nav_things_inc -> {
100 | if (thingsFragment == null) {
101 | thingsFragment = TestFragment.getInstance(getString(R.string.thing_inc))
102 | }
103 | switchFragment(thingsFragment!!)
104 | navigation.selectedItemId = R.id.bottom_things_inc
105 | }
106 |
107 | R.id.nav_bottom_dialog -> {
108 |
109 | }
110 | R.id.nav_snack_bar -> {
111 | // 弹出 SnackBar 和 Toast
112 | Snackbar.make(weaponFragment!!.mFloatButton, "弹出 SnackBar", Snackbar.LENGTH_SHORT).setAction("Cancel") {
113 | Toast.makeText(this@MainActivity, "Cancel this action", Toast.LENGTH_SHORT).show()
114 | }.show()
115 | }
116 | R.id.nav_alert_dialog -> {
117 | // 弹出 AlertDialog
118 | AlertDialog.Builder(this).setTitle("title").setMessage("message").setNegativeButton("确认", null)
119 | .setPositiveButton("取消", null).show()
120 | }
121 | }
122 | false
123 | }
124 |
125 | // 底部 view 点击事件处理
126 | navigation!!.setOnNavigationItemSelectedListener {
127 | when(it.itemId) {
128 | R.id.bottom_weapon_inc -> {
129 | if (weaponFragment == null) {
130 | weaponFragment = WeaponFragment()
131 | }
132 | switchFragment(weaponFragment!!)
133 | nv_left.setCheckedItem(R.id.nav_weapon_inc)
134 | }
135 | R.id.bottom_people_inc -> {
136 | if (peopleFragment == null) {
137 | peopleFragment = TestFragment.getInstance(getString(R.string.people_inc))
138 | }
139 | switchFragment(peopleFragment!!)
140 | nv_left.setCheckedItem(R.id.nav_people_inc)
141 | }
142 | R.id.bottom_sub_inc -> {
143 | if (subFragment == null) {
144 | subFragment = TestFragment.getInstance(getString(R.string.sub_inc))
145 | }
146 | switchFragment(subFragment!!)
147 | nv_left.setCheckedItem(R.id.nav_sub_inc)
148 | }
149 | R.id.bottom_things_inc -> {
150 | if (thingsFragment == null) {
151 | thingsFragment = TestFragment.getInstance(getString(R.string.thing_inc))
152 | }
153 | switchFragment(thingsFragment!!)
154 | nv_left.setCheckedItem(R.id.nav_things_inc)
155 | }
156 | }
157 | true
158 | }
159 | }
160 |
161 | /**
162 | * 打开 bottomSheetDialog 对话框
163 | */
164 | private fun openBottomSheetDialog() {
165 | // val parent = LinearLayout(this)
166 | // parent.orientation = LinearLayout.VERTICAL
167 | // val title = TextView(this)
168 | // title.text = "枪械简介"
169 | // title.textSize = 20f
170 | // title.setPadding(15, 15, 15, 0)
171 | // parent.addView(title)
172 | //
173 | // val recyclerView = RecyclerView(this)
174 | // recyclerView.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
175 | // recyclerView.adapter = myAdapter
176 | // parent.addView(recyclerView)
177 | //
178 | // val dialog = BottomSheetDialog(this)
179 | // dialog.setContentView(parent)
180 | // dialog.show()
181 |
182 | }
183 |
184 | /**
185 | * 切换Fragment的显示
186 |
187 | * @param target 要切换的 Fragment
188 | */
189 | private fun switchFragment(target: Fragment) {
190 |
191 | // 如果当前的fragment 就是要替换的fragment 就直接return
192 | if (currentFragment === target) return
193 |
194 | // 获得 Fragment 事务
195 | val transaction = supportFragmentManager.beginTransaction()
196 |
197 | // 如果当前Fragment不为空,则隐藏当前的Fragment
198 | if (currentFragment != null) {
199 | transaction.hide(currentFragment)
200 | }
201 |
202 | // 如果要显示的Fragment 已经添加了,那么直接 show
203 | if (target.isAdded) {
204 | transaction.show(target)
205 | } else {
206 | // 如果要显示的Fragment没有添加,就添加进去
207 | transaction.add(R.id.fl_content, target, target.javaClass.name)
208 | }
209 |
210 | // 事务进行提交
211 | transaction.commit()
212 |
213 | //并将要显示的Fragment 设为当前的 Fragment
214 | currentFragment = target
215 | }
216 |
217 |
218 |
219 | }
220 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/MyAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import com.bumptech.glide.Glide
4 | import com.chad.library.adapter.base.BaseQuickAdapter
5 | import com.chad.library.adapter.base.BaseViewHolder
6 |
7 | /**
8 | *
9 | * author : xiaweizi
10 | * class : com.xiaweizi.androidmd.MyAdapter
11 | * e-mail : 1012126908@qq.com
12 | * time : 2017/12/08
13 | * desc :
14 | *
15 | */
16 | class MyAdapter(layoutResId: Int) : BaseQuickAdapter(layoutResId), IItemHelper{
17 | override fun onItemMove(fromPosition: Int, toPosition: Int) {
18 | val prev = mData.removeAt(fromPosition)
19 | mData.add(if (toPosition > fromPosition) toPosition - 1 else toPosition, prev)
20 | notifyItemMoved(fromPosition, toPosition)
21 | }
22 |
23 | override fun onItemDismiss(position: Int) {
24 | mData.removeAt(position)
25 | notifyItemRemoved(position)
26 | }
27 |
28 | constructor() : this(layoutResId = R.layout.item_weapon_info)
29 |
30 | override fun convert(helper: BaseViewHolder?, item: WeaponBean?) {
31 | Glide.with(mContext).load(item?.imageUrl).into(helper!!.getView(R.id.iv_weapon))
32 | helper.setText(R.id.tv_weapon_name, item!!.name)
33 | }
34 |
35 | }
36 |
37 | interface IItemHelper {
38 | fun onItemMove(fromPosition: Int, toPosition: Int)
39 | fun onItemDismiss(position: Int)
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/MyClient.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
4 | import okhttp3.OkHttpClient
5 | import okhttp3.logging.HttpLoggingInterceptor
6 | import retrofit2.Retrofit
7 | import retrofit2.converter.gson.GsonConverterFactory
8 | import java.util.concurrent.TimeUnit
9 |
10 | /**
11 | *
12 | * author : xiaweizi
13 | * class : com.xiaweizi.androidmd.MyClient
14 | * e-mail : 1012126908@qq.com
15 | * time : 2017/12/08
16 | * desc : 用于请求网络的客户端
17 |
*
18 | */
19 |
20 | class MyClient private constructor() {
21 |
22 | private var mBuilder: OkHttpClient.Builder? = null
23 |
24 | init {
25 | initSetting()
26 | }
27 |
28 | /**
29 | * 创建相应的服务接口
30 | */
31 | fun create(service: Class, baseUrl: String): T {
32 | checkNotNull(service, "service is null")
33 | checkNotNull(baseUrl, "baseUrl is null")
34 |
35 | return Retrofit.Builder()
36 | .baseUrl(baseUrl)
37 | .client(mBuilder!!.build())
38 | .addConverterFactory(GsonConverterFactory.create())
39 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
40 | .build()
41 | .create(service)
42 | }
43 |
44 | private fun checkNotNull(`object`: T?, message: String): T {
45 | if (`object` == null) {
46 | throw NullPointerException(message)
47 | }
48 | return `object`
49 | }
50 |
51 | private fun initSetting() {
52 |
53 | //初始化OkHttp
54 | mBuilder = OkHttpClient.Builder()
55 | .connectTimeout(9, TimeUnit.SECONDS) //设置连接超时 9s
56 | .readTimeout(10, TimeUnit.SECONDS) //设置读取超时 10s
57 |
58 | if (BuildConfig.DEBUG) { // 判断是否为debug
59 | // 如果为 debug 模式,则添加日志拦截器
60 | val interceptor = HttpLoggingInterceptor()
61 | interceptor.level = HttpLoggingInterceptor.Level.BODY
62 | mBuilder!!.addInterceptor(interceptor)
63 | }
64 |
65 | }
66 |
67 | companion object {
68 |
69 | private var mMyClient: MyClient? = null
70 |
71 | val instance: MyClient
72 | get() {
73 | if (mMyClient == null) {
74 | synchronized(MyClient::class.java) {
75 | if (mMyClient == null) {
76 | mMyClient = MyClient()
77 | }
78 | }
79 | }
80 | return mMyClient!!
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/MyService.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import io.reactivex.Observable
4 | import retrofit2.http.GET
5 |
6 | /**
7 | *
8 | * author : xiaweizi
9 | * class : com.xiaweizi.androidmd.MyService
10 | * e-mail : 1012126908@qq.com
11 | * time : 2017/12/10
12 | * desc : 不同请求存放的位置
13 | *
14 | */
15 | interface MyService {
16 | @get:GET("/weaponInfo")
17 | val weaponInfo: Observable
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/TestFragment.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import android.os.Bundle
4 | import android.support.v4.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 |
10 | /**
11 | *
12 | * author : xiaweizi
13 | * class : com.xiaweizi.androidmd.TestFragment
14 | * e-mail : 1012126908@qq.com
15 | * time : 2017/12/18
16 | * desc :
17 | *
18 | */
19 | class TestFragment : Fragment(){
20 |
21 | private lateinit var mConetent: String
22 |
23 | override fun onCreate(savedInstanceState: Bundle?) {
24 | super.onCreate(savedInstanceState)
25 | val arguments = arguments
26 | if (arguments != null) {
27 | mConetent = arguments.getString("content")
28 | }
29 | }
30 |
31 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
32 | val view = inflater!!.inflate(R.layout.fragment_test, null)
33 | val tvContent = view.findViewById(R.id.tv_content)
34 | tvContent.text = mConetent
35 | return view
36 | }
37 |
38 | public companion object {
39 |
40 | fun getInstance(content: String): TestFragment {
41 | val testFragment = TestFragment()
42 | val bundle = Bundle()
43 | bundle.putString("content", content)
44 | testFragment.arguments = bundle
45 | return testFragment
46 | }
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/WeaponBean.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import android.os.Parcel
4 | import android.os.Parcelable
5 |
6 | /**
7 | *
8 | * author : xiaweizi
9 | * class : com.xiaweizi.androidmd.WeaponBean
10 | * e-mail : 1012126908@qq.com
11 | * time : 2017/12/08
12 | * desc : 获取武器信息的 bean 和 modelInfo
13 | *
14 | */
15 | data class WeaponBean(var id: Int, var name: String, var content: String, var imageUrl: String, var symbol: String) : Parcelable {
16 | constructor(parcel: Parcel) : this(
17 | parcel.readInt(),
18 | parcel.readString(),
19 | parcel.readString(),
20 | parcel.readString(),
21 | parcel.readString()) {
22 | }
23 |
24 | override fun writeToParcel(parcel: Parcel, flags: Int) {
25 | parcel.writeInt(id)
26 | parcel.writeString(name)
27 | parcel.writeString(content)
28 | parcel.writeString(imageUrl)
29 | parcel.writeString(symbol)
30 | }
31 |
32 | override fun describeContents(): Int {
33 | return 0
34 | }
35 |
36 | companion object CREATOR : Parcelable.Creator {
37 | override fun createFromParcel(parcel: Parcel): WeaponBean {
38 | return WeaponBean(parcel)
39 | }
40 |
41 | override fun newArray(size: Int): Array {
42 | return arrayOfNulls(size)
43 | }
44 | }
45 | }
46 |
47 | data class WeaponModelnfo(var status: Int, var desc: String, var data: ArrayList)
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/WeaponDetailActivity.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import android.R.id
4 | import android.os.Bundle
5 | import android.support.v7.app.AppCompatActivity
6 | import android.support.v7.widget.Toolbar
7 | import android.transition.Explode
8 | import android.transition.Slide
9 | import android.view.MenuItem
10 | import android.view.Window
11 | import android.view.WindowManager
12 | import android.widget.ImageView
13 | import android.widget.TextView
14 | import com.bumptech.glide.Glide
15 |
16 | /**
17 | *
18 | * author : xiaweizi
19 | * class : com.xiaweizi.androidmd.WeaponDetailActivity
20 | * e-mail : 1012126908@qq.com
21 | * time : 2017/12/10
22 | * desc : 武器详情界面
23 | *
24 | */
25 | class WeaponDetailActivity : AppCompatActivity() {
26 |
27 | private lateinit var mBean: WeaponBean
28 | private lateinit var mIvDetail: ImageView
29 | private lateinit var mTvDetail: TextView
30 | private lateinit var mTbName: Toolbar
31 | override fun onCreate(savedInstanceState: Bundle?) {
32 | super.onCreate(savedInstanceState)
33 | window.requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)
34 | // 透明导航栏
35 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
36 | // 透明状态栏
37 | window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
38 | // 设置转场动画
39 | window.enterTransition = Explode()
40 | window.exitTransition = Slide()
41 | setContentView(R.layout.activity_weapon_detail)
42 | initView()
43 | setSupportActionBar(mTbName)
44 | supportActionBar!!.setDisplayHomeAsUpEnabled(true)
45 | initData()
46 | }
47 |
48 | /**
49 | * 初始化数据
50 | */
51 | private fun initData() {
52 | mBean = intent.getParcelableExtra(Constants.EXTRA_WEAPON_BEAN)
53 | Glide.with(this).load(mBean.imageUrl).into(mIvDetail)
54 | mTvDetail.text = mBean.content
55 | mTbName.title = mBean.symbol
56 | }
57 |
58 | /**
59 | * 初始化 view
60 | */
61 | private fun initView() {
62 | mIvDetail = findViewById(R.id.iv_weapon_detail)
63 | mTvDetail = findViewById(R.id.tv_weapon_detail)
64 | mTbName = findViewById(R.id.tb_weapon_name)
65 | }
66 |
67 | override fun onOptionsItemSelected(item: MenuItem?): Boolean {
68 | if (item?.itemId == id.home) {
69 | finish()
70 | }
71 | return super.onOptionsItemSelected(item)
72 | }
73 |
74 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaweizi/androidmd/WeaponFragment.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import android.app.ActivityOptions
4 | import android.content.Intent
5 | import android.graphics.Color
6 | import android.os.Bundle
7 | import android.support.design.widget.FloatingActionButton
8 | import android.support.v4.app.Fragment
9 | import android.support.v4.widget.SwipeRefreshLayout
10 | import android.support.v7.widget.RecyclerView
11 | import android.support.v7.widget.StaggeredGridLayoutManager
12 | import android.support.v7.widget.Toolbar
13 | import android.support.v7.widget.helper.ItemTouchHelper
14 | import android.transition.Explode
15 | import android.view.LayoutInflater
16 | import android.view.View
17 | import android.view.ViewGroup
18 | import android.widget.Toast
19 | import com.chad.library.adapter.base.BaseQuickAdapter
20 | import com.chad.library.adapter.base.listener.OnItemClickListener
21 | import io.reactivex.android.schedulers.AndroidSchedulers
22 | import io.reactivex.schedulers.Schedulers
23 | import java.util.*
24 |
25 | /**
26 | *
27 | * author : xiaweizi
28 | * class : com.xiaweizi.androidmd.WeaponFragment
29 | * e-mail : 1012126908@qq.com
30 | * time : 2017/12/18
31 | * desc :
32 | *
33 | */
34 | class WeaponFragment : Fragment() {
35 |
36 | private var myAdapter: MyAdapter? = null
37 | private lateinit var mRecyclerView: RecyclerView
38 | private lateinit var mRefreshLayout: SwipeRefreshLayout
39 | private lateinit var mToolbar: Toolbar
40 | private lateinit var mView: View
41 | lateinit var mFloatButton: FloatingActionButton
42 |
43 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
44 | mView = inflater!!.inflate(R.layout.fragment_weapon, null)
45 | initView()
46 | initData()
47 | initListener()
48 | mRefreshLayout.isRefreshing = true
49 | getData(0)
50 | return mView
51 | }
52 |
53 | /**
54 | * 初始化 view
55 | */
56 | private fun initView() {
57 | mRecyclerView = mView.findViewById(R.id.recyclerView)
58 | mRefreshLayout = mView.findViewById(R.id.refresh_layout)
59 | mToolbar = mView.findViewById(R.id.toolbar)
60 | mFloatButton = mView.findViewById(R.id.fab)
61 | }
62 |
63 |
64 | /**
65 | * 初始化数据
66 | */
67 | private fun initData() {
68 | myAdapter = MyAdapter()
69 | staggeredVertical()
70 | mRecyclerView.adapter = myAdapter
71 | mRefreshLayout.setColorSchemeColors(Color.RED, Color.BLUE, Color.GREEN)
72 | val mItemTouchHelper = ItemTouchHelper(ItemTouchHelperCallback())
73 | mItemTouchHelper.attachToRecyclerView(mRecyclerView)
74 | }
75 |
76 | /**
77 | * 初始化 listener
78 | */
79 | private fun initListener() {
80 | mRefreshLayout.setOnRefreshListener {
81 | mRefreshLayout.isRefreshing = true
82 | getData(1)
83 | }
84 | mRecyclerView.addOnItemTouchListener(object : OnItemClickListener() {
85 | override fun onSimpleItemClick(adapter: BaseQuickAdapter<*, *>?, view: View?, position: Int) {
86 | if (adapter is MyAdapter) {
87 | activity.window.exitTransition = Explode()
88 | val weaponBean = adapter.data[position]
89 | val intent = Intent(activity, WeaponDetailActivity::class.java)
90 | intent.putExtra(Constants.EXTRA_WEAPON_BEAN, weaponBean)
91 | startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle())
92 | }
93 | }
94 | })
95 | myAdapter!!.setOnLoadMoreListener {
96 | getData(2)
97 | }
98 | mFloatButton.setOnClickListener {
99 | mRecyclerView.smoothScrollToPosition(0)
100 | }
101 |
102 | }
103 |
104 |
105 | /**
106 | * 获取数据
107 | * 0 第一次进入
108 | * 1 下拉刷新
109 | * 2 上啦加载更多
110 | */
111 | private fun getData(state: Int) {
112 | MyClient.instance
113 | .create(MyService::class.java, Constants.MASTER_URL)
114 | .weaponInfo
115 | .subscribeOn(Schedulers.io())
116 | .observeOn(AndroidSchedulers.mainThread())
117 | .subscribe({
118 | val status = it.status
119 | if (status == 0) {
120 | setData(state, it)
121 | } else {
122 | showError()
123 | }
124 | }, {
125 | showError()
126 | })
127 | }
128 |
129 | /**
130 | * 获取数据失败
131 | */
132 | private fun showError() {
133 | mRefreshLayout.isRefreshing = false
134 | Toast.makeText(activity, "获取数据失败!", Toast.LENGTH_SHORT).show()
135 | }
136 |
137 | /**
138 | * 成功获取数据
139 | */
140 | private fun setData(state: Int, it: WeaponModelnfo) {
141 | when (state) {
142 | 0 -> {
143 | myAdapter!!.setNewData(it.data)
144 | mRefreshLayout.isRefreshing = false
145 | }
146 | 1 -> {
147 | Toast.makeText(activity, "刷新成功!", Toast.LENGTH_SHORT).show()
148 | Collections.shuffle(it.data)
149 | myAdapter!!.setNewData(it.data)
150 | mRefreshLayout.isRefreshing = false
151 | }
152 | 2 -> {
153 | Thread(Runnable {
154 | Thread.sleep(800)
155 | activity.runOnUiThread {
156 | myAdapter!!.addData(it.data)
157 | myAdapter!!.loadMoreComplete()
158 | }
159 | }).start()
160 |
161 | }
162 | }
163 | }
164 |
165 | internal inner class ItemTouchHelperCallback : ItemTouchHelper.Callback() {
166 | override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
167 | val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
168 | val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
169 | return makeMovementFlags(dragFlags, swipeFlags)
170 | }
171 |
172 | override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
173 | myAdapter!!.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
174 | return false
175 | }
176 |
177 | override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
178 | myAdapter!!.onItemDismiss(viewHolder.adapterPosition)
179 | }
180 | }
181 |
182 | /**
183 | * 垂直瀑布流
184 | */
185 | private fun staggeredVertical() {
186 | myAdapter!!.openLoadAnimation(BaseQuickAdapter.SLIDEIN_LEFT)
187 | mRecyclerView.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
188 | }
189 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-hdpi/ic_action_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_arrow_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-hdpi/ic_action_arrow_up.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-hdpi/ic_action_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-mdpi/ic_action_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_arrow_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-mdpi/ic_action_arrow_up.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-mdpi/ic_action_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-xhdpi/ic_action_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_arrow_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-xhdpi/ic_action_arrow_up.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-xhdpi/ic_action_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-xxhdpi/ic_action_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_arrow_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-xxhdpi/ic_action_arrow_up.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable-xxhdpi/ic_action_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable/about.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/joke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable/joke.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/news.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable/news.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/robot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable/robot.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/today.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/drawable/today.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
30 |
31 |
32 |
33 |
34 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_weapon_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
22 |
23 |
32 |
33 |
39 |
40 |
41 |
42 |
46 |
47 |
55 |
56 |
63 |
64 |
65 |
66 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_weapon.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
15 |
16 |
26 |
27 |
28 |
33 |
34 |
39 |
40 |
41 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_weapon_info.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
18 |
19 |
23 |
24 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
26 |
27 |
36 |
37 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/nav_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidMD
3 | open
4 | close
5 | linearHorizontal
6 | linearVertical
7 | gridHorizontal
8 | gridVertical
9 | staggeredHorizontal
10 | staggeredVertical
11 | 枪械简介
12 | 人物简介
13 | 配件简介
14 | 空投简介
15 | BottomSheetDialog
16 | SnackBar+Toast
17 | AlertDialog
18 | 攻略
19 | 简介
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/xiaweizi/androidmd/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.xiaweizi.androidmd
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.1.51'
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.1'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | maven { url "https://jitpack.io" }
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaweizi/AndroidMD/eabf020a13dcdb2393c1565bf603bdc8c27f0c90/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Dec 08 13:44:31 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-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 initData
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 initData
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 | :initData
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------