├── .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 | 36 | 37 | 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 | 16 | 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 | 314 | 315 | 316 | 317 | 318 | 1.8 319 | 320 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 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 | 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 | ![MD.gif](http://upload-images.jianshu.io/upload_images/4043475-69724c76b1f4a3d3.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![封面](http://upload-images.jianshu.io/upload_images/4043475-e5c6b96043664d11.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 57 | 58 | > 进入`MD`官网首页就是这张图片。 59 | 60 | ### 2、介绍 61 | 62 | ![介绍.gif](http://upload-images.jianshu.io/upload_images/4043475-82acd36ec2a5e1d5.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 63 | 64 | > 从`MD`上截取的动画作为入口,大概讲解一下`MD`的基础概念和特点。 65 | 66 | ### 3、特点 67 | 68 | ![特点.gif](http://upload-images.jianshu.io/upload_images/4043475-9530c68384a306db.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 69 | 70 | > 这里抽取了四个点:`Material`、`Elevation`、`Color`和`Animation`进行分析。 71 | 72 | ### 4、风格背景 73 | 74 | > 文字采用圆角+阴影进行包裹,至于高度和圆角效果因为时间紧迫,没有按照严格规范进行设置,如果对这方面有要求可以参考官网详细的规范要求。 75 | 76 | ![image.png](http://upload-images.jianshu.io/upload_images/4043475-293024e20bdcfa9d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 77 | 78 | ### 5、动画效果 79 | 80 | > 说起动画,为了能够模仿`MD`的交互,也是现学现卖了一把。 81 | 82 | ![交互.gif](http://upload-images.jianshu.io/upload_images/4043475-5fda106fc9875d3e.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![image.png](http://upload-images.jianshu.io/upload_images/4043475-eff26b8e6f76e5d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![image.png](http://upload-images.jianshu.io/upload_images/4043475-8325db1456ddf0d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![bottomNavigationView.gif](http://upload-images.jianshu.io/upload_images/4043475-6e02ff6f1cafcc39.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 147 | 148 | 149 | 1. 在`menu/`下创建菜单文件: 150 | 151 | 152 | 153 | 157 | 158 | 159 | 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 | ![DrawerLayout.gif](http://upload-images.jianshu.io/upload_images/4043475-c386ac73a2c4877e.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![RecyclerView.gif](http://upload-images.jianshu.io/upload_images/4043475-276e4cc24cd6a09b.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![enterAlways.gif](http://upload-images.jianshu.io/upload_images/4043475-df42e9245f9747ed.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 335 | 336 | #### 3. scroll|enterAlwaysCollapsed 337 | 338 | 当`ScrollView`向下滑动时,`DependentView`先折叠到最小高度(这里是0),然后将事件交给`ScrollView`,当`ScrollView`滑动结束,`DependentView`才继续滑动事件,直至展开,如下图所示: 339 | 340 | ![enterAlwaysCollapsed.gif](http://upload-images.jianshu.io/upload_images/4043475-2941d0adaa3ada9c.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 341 | 342 | #### 4. scroll|enterAlwaysCollapsed|enterAlways 343 | 344 | 这边就展示一下折叠的效果,我们先设置最小的高度 345 | 346 | 351 | 352 | 展示一下效果: 353 | 354 | ![see.gif](http://upload-images.jianshu.io/upload_images/4043475-24e0d5bd7a84b488.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 355 | 356 | #### 5. scroll|exitUntilCollapsed 357 | 358 | 这个搭配重点在于上拉的时候,`DependentView`会先折叠到最小高度,然后事件全部交给`ScrollView`。那下拉的时候就是当`ScrollView`滑动结束,才开始`DependentView`的滑动事件。 359 | 360 | ![exitUntilCollapsed.gif](http://upload-images.jianshu.io/upload_images/4043475-a125be21d3383259.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 361 | 362 | #### 6. scroll|enterAlways|snap 363 | 364 | 这个`snap`就是在上面的基础上多了一个回弹的效果,一般需要配合上其他属性使用才会有效果。当`DependentView`正在滑动,此时手指离开屏幕时,`DependentView`会自动移动到离自己较近的终点或者始点。效果如下: 365 | 366 | ![snap.gif](http://upload-images.jianshu.io/upload_images/4043475-5f1f30e9b70ca8ad.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | ![Transition.gif](http://upload-images.jianshu.io/upload_images/4043475-fe29a3732dfc83f6.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 397 | 398 | ### 9、Toast、SnackBar和AlertDialog 399 | 400 | 基本的界面写完了,剩下的就是一些逻辑上的操作啦,比如「提示」。那么`Android`提示分为三种: 401 | 402 | - 友好的`Toast`(比如网络失败) 403 | - 拥有附加行为的提示`SnackBar`(比如误删信息回撤) 404 | - 强制让用户做出选择的`AlertDialg`(比如未登录) 405 | 406 | 那么这三种的效果是什么呢? 407 | 408 | ![TSA.gif](http://upload-images.jianshu.io/upload_images/4043475-18678d48084a5701.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 409 | 410 | 大概先讲这些,有时间再进行后续补充。 411 | 412 | # `Material Design`在「口袋」中的应用 413 | 414 | 其实在咱们的「口袋贵金属」项目中也到找到很多`MD`的元素。 415 | 416 | 首先是点击的水波纹效果: 417 | 418 | ![ripple.gif](http://upload-images.jianshu.io/upload_images/4043475-a19996587c89e708.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 419 | 420 | 其次是交易圈的滑动交互: 421 | 422 | ![circle.gif](http://upload-images.jianshu.io/upload_images/4043475-9ecae2ddb8be50ef.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 423 | 424 | 还有就是本人在「口袋」接手的第二个需求,「个人中心」。看一下效果: 425 | 426 | ![personal.gif](http://upload-images.jianshu.io/upload_images/4043475-4431f1f722e17eb2.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 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 | 3 | 4 | 8 | 12 | 16 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 13 | 17 | 21 | 25 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/menu/nav_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 38 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------