├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── ruffian
│ │ └── library
│ │ └── demo
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── fonts
│ │ │ ├── Roboto-Black.ttf
│ │ │ ├── Roboto-BlackItalic.ttf
│ │ │ ├── Roboto-Bold.ttf
│ │ │ ├── Roboto-BoldItalic.ttf
│ │ │ ├── Roboto-Italic.ttf
│ │ │ ├── Roboto-Light.ttf
│ │ │ ├── Roboto-LightItalic.ttf
│ │ │ ├── Roboto-Medium.ttf
│ │ │ ├── Roboto-MediumItalic.ttf
│ │ │ ├── Roboto-Regular.ttf
│ │ │ ├── Roboto-Thin.ttf
│ │ │ ├── Roboto-ThinItalic.ttf
│ │ │ ├── RobotoCondensed-Bold.ttf
│ │ │ ├── RobotoCondensed-BoldItalic.ttf
│ │ │ ├── RobotoCondensed-Italic.ttf
│ │ │ ├── RobotoCondensed-Light.ttf
│ │ │ ├── RobotoCondensed-LightItalic.ttf
│ │ │ ├── RobotoCondensed-Regular.ttf
│ │ │ ├── RobotoMono-Bold.ttf
│ │ │ ├── RobotoMono-BoldItalic.ttf
│ │ │ ├── RobotoMono-Italic.ttf
│ │ │ ├── RobotoMono-Light.ttf
│ │ │ ├── RobotoMono-LightItalic.ttf
│ │ │ ├── RobotoMono-Medium.ttf
│ │ │ ├── RobotoMono-MediumItalic.ttf
│ │ │ ├── RobotoMono-Regular.ttf
│ │ │ ├── RobotoMono-Thin.ttf
│ │ │ ├── RobotoMono-ThinItalic.ttf
│ │ │ ├── RobotoSlab-Bold.ttf
│ │ │ ├── RobotoSlab-Light.ttf
│ │ │ ├── RobotoSlab-Regular.ttf
│ │ │ ├── RobotoSlab-Thin.ttf
│ │ │ └── huakangshaonv.ttf
│ ├── java
│ │ └── com
│ │ │ └── ruffian
│ │ │ └── library
│ │ │ └── demo
│ │ │ ├── App.java
│ │ │ ├── CheckedActivity.java
│ │ │ ├── FragmentCorner.java
│ │ │ ├── FragmentState.java
│ │ │ ├── FragmentVersion.java
│ │ │ ├── GradientActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── REditTextActivity.java
│ │ │ ├── RImageViewActivity.java
│ │ │ ├── RTextViewActivity.java
│ │ │ ├── RViewActivity.java
│ │ │ ├── RViewGroupActivity.java
│ │ │ ├── RipperActivity.java
│ │ │ └── ShadowActivity.java
│ └── res
│ │ ├── drawable
│ │ ├── bg_selector.xml
│ │ └── tv_selected.xml
│ │ ├── layout
│ │ ├── activity_checked.xml
│ │ ├── activity_edittext.xml
│ │ ├── activity_gradient.xml
│ │ ├── activity_imageview.xml
│ │ ├── activity_list.xml
│ │ ├── activity_main.xml
│ │ ├── activity_ripper.xml
│ │ ├── activity_shadow.xml
│ │ ├── activity_textview_main.xml
│ │ ├── activity_view.xml
│ │ ├── activity_viewgroup.xml
│ │ ├── fmt_textview_corner.xml
│ │ ├── fmt_textview_state.xml
│ │ ├── fmt_textview_version.xml
│ │ └── item_list.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ ├── food.jpg
│ │ ├── ic_launcher.png
│ │ ├── icon_account.png
│ │ ├── icon_bg.png
│ │ ├── icon_bg_normal.png
│ │ ├── icon_bg_pressed.png
│ │ ├── icon_heart.png
│ │ ├── icon_help.png
│ │ ├── icon_man.png
│ │ ├── icon_man_pressed.jpg
│ │ ├── icon_phone.png
│ │ ├── icon_phone_normal.png
│ │ ├── icon_phone_pressed.png
│ │ ├── icon_phone_unable.png
│ │ ├── icon_psw.png
│ │ ├── icon_rb_green_default.png
│ │ ├── icon_rb_green_selected.png
│ │ ├── icon_settings.png
│ │ └── icon_star.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── array.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── ruffian
│ └── library
│ └── demo
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── ruffian
│ │ └── library
│ │ └── widget
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── ruffian
│ │ │ └── library
│ │ │ └── widget
│ │ │ ├── RCheckBox.java
│ │ │ ├── RConstraintLayout.java
│ │ │ ├── REditText.java
│ │ │ ├── RFrameLayout.java
│ │ │ ├── RImageView.java
│ │ │ ├── RLinearLayout.java
│ │ │ ├── RRadioButton.java
│ │ │ ├── RRelativeLayout.java
│ │ │ ├── RTextView.java
│ │ │ ├── RView.java
│ │ │ ├── clip
│ │ │ ├── ClipHelper.java
│ │ │ ├── ClipPathManager.java
│ │ │ └── IClip.java
│ │ │ ├── helper
│ │ │ ├── RBaseHelper.java
│ │ │ ├── RCheckHelper.java
│ │ │ ├── RImageViewHelper.java
│ │ │ └── RTextViewHelper.java
│ │ │ ├── iface
│ │ │ ├── ITextViewFeature.java
│ │ │ └── RHelper.java
│ │ │ ├── rounded
│ │ │ └── RoundDrawable.java
│ │ │ ├── shadow
│ │ │ ├── ShadowBitmapDrawable.java
│ │ │ └── ShadowDrawable.java
│ │ │ └── utils
│ │ │ ├── ReflectUtils.java
│ │ │ ├── RippleDrawableUtils.java
│ │ │ └── TextViewUtils.java
│ └── res
│ │ └── values
│ │ └── attr.xml
│ └── test
│ └── java
│ └── com
│ └── ruffian
│ └── library
│ └── widget
│ └── ExampleUnitTest.java
├── picture
├── Gradient.png
├── REditText.png
├── RImageView.png
├── RTextView_corner.png
├── RTextView_state.gif
├── RTextView_typeface.png
├── RView.png
├── RViewGroup.png
├── RWidgetHelper.gif
├── all.gif
├── part1.png
├── part2.png
├── part3.png
├── part4.png
├── part5.png
├── ripple.gif
└── shadow.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /.gradle
3 | /app/build
4 | /local.properties
5 | /gradle.properties
6 | /.idea
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RWidgetHelper
2 |
3 | ## 欢迎使用 RWidgetHelper >>> [iOS版本:ZTUIStyle](https://github.com/RuffianZhong/ZTUIStyle)
4 |
5 | ### 宗旨:专治原生控件各种不服
6 |
7 | ### 目标:Android UI 快速开发
8 |
9 | ### 说明
10 |
11 | > Android UI 开发常用:圆角,边框,Gradient背景渐变,控件State各个状态UI样式,阴影,水波纹
12 | >
13 | > 普通解决方案缺点:代码冗余,复用性差,自由度低
14 | >
15 | > RWidgetHelper优点:优化代码,简化使用,快速开发
16 | >
17 |
18 | ### 简介
19 |
20 | 通过继承原生控件,设置自定义属性,解决常用 Selector,Gradient,Shape, 阴影,水波纹等功能
21 |
22 | 原生控件都可实现 **基础功能** ,针对具体控件还有 **个性功能**
23 |
24 |
25 | ## 基础功能
26 |
27 | | 功能 | 属性值 | 可用State状态 | 特性 |
28 | | ------------- | ------------- | ------------- | ------------- |
29 | | 圆角 | 颜色 | 默认/按下/不可用/选中 | 四周圆角/单个方向圆角 |
30 | | 边框宽度 | 数值 | 默认/按下/不可用/选中 | 实线/虚线边框 |
31 | | 边框颜色 | 颜色 | 默认/按下/不可用/选中 | 实线/虚线边框 |
32 | | 背景 | 颜色/颜色数组/drawable | 默认/按下/不可用/选中 | 纯色/渐变/Drawable |
33 | | 水波纹 | -- | -- | 点击效果水波纹 |
34 | | 阴影 | -- | -- | 控件四周阴影 |
35 | | 裁剪布局 | -- | -- | 裁剪子控件内容 |
36 | #### 属性介绍
37 |
38 | | 属性 |说明 |
39 | | ------------- | :-------------|
40 | | corner_radius | 圆角 四周 >=正方形宽度/2实现圆形|
41 | | corner_radius_top_left | 圆角 左上 |
42 | | corner_radius_top_right | 圆角 右上 |
43 | | corner_radius_bottom_left | 圆角 左下 |
44 | | corner_radius_bottom_right | 圆角 右下 |
45 | | border_dash_width | 虚线边框 宽度 |
46 | | border_dash_gap | 虚线边框 间隔 |
47 | | border_width_normal | 边框宽度 默认 |
48 | | border_width_pressed | 边框宽度 按下 |
49 | | border_width_unable | 边框宽度 不可点击 |
50 | | border_width_checked | 边框宽度 选中 |
51 | | border_width_selected | 边框宽度 选择 |
52 | | border_color_normal | 边框颜色 默认 |
53 | | border_color_pressed | 边框颜色 按下 |
54 | | border_color_unable | 边框颜色 不可点击 |
55 | | border_color_checked | 边框颜色 选中 |
56 | | border_color_selected | 边框颜色 选择 |
57 | | background_normal | 背景 默认 |
58 | | background_pressed | 背景 按下 |
59 | | background_unable | 背景 不可点击 |
60 | | background_checked | 背景 选中 |
61 | | background_selected | 背景 选择 |
62 | | gradient_orientation | 渐变的方向 参考 GradientDrawable.Orientation:TOP_BOTTOM,TR_BL... |
63 | | gradient_type | 渐变的样式 linear线性,radial径向,sweep扫描式 默认:linear|
64 | | gradient_radius | 渐变半径 默认:(宽或高最小值)/ 2 |
65 | | gradient_centerX | 渐变中心点X坐标(0.0-1.0) 0.5表示中间 默认:0.5 |
66 | | gradient_centerY | 渐变中心点Y坐标(0.0-1.0) 0.5表示中间 默认:0.5 |
67 | | ripple | 是否开启水波纹效果,true/false |
68 | | ripple_color | 水波纹效果颜色 |
69 | | ripple_mask_style | 水波纹效果限制样式,none:无限制 normal:默认跟随控件背景形状 drawable:自定义形状 |
70 | | ripple_mask | 水波纹效果限制自定义drawable |
71 | | shadow_radius | 阴影大小 dp |
72 | | shadow_color | 阴影颜色 |
73 | | shadow_dx | 阴影水平方向偏移 负数向左,正数向右 dp |
74 | | shadow_dy | 阴影垂直方向偏移 负数向上,正数向下 dp |
75 | | clip_layout | 裁剪子控件内容 |
76 |
77 | > 1.background_xxx 纯色 渐变 drawable
78 | > 纯色: 颜色值 app:background_normal="#74EBD5"
79 | > 渐变: 颜色数组 >=2个 app:background_normal="@array/@colorArray"
80 | > drawable: 资源图片 app:background_normal="@mipmap/@drawable"
81 | >
82 | > 2.自定义属性对原生属性无效
83 | > 例如: `app:corner_radius="10dp"` 搭配 `app:background_normal="#74EBD5"` 而不是`background="#74EBD5"`
84 | >
85 | > 3.ripple 效果和 pressed 对立,启用 ripple 后,按下效果无效
86 | >
87 | > 4.shadow 内容需要开发者自行兼容,例如:`shadow_radius=10dp` , `shadow_dx=5dp` 则在水平方向需要 `padingLeft/right = 15 dp`
88 | >
89 | > 5.pressed/unable/checked/selected 等状态在未设置具体值时会默认设置 normal 值,方便开发者实现各种需求
90 | >
91 | > 6.clip_layout 是否裁剪控件,未设置此属性时,所有的圆角/圆形都是背景形状。 设置此属性后,在背景效果的同时真实裁剪控件
92 |
93 |
94 |
95 | #### 示例xml
96 | ```
97 |
156 | ```
157 |
158 | #### 示例java
159 |
160 | ```
161 | RView view = (RView) findViewById(R.id.view);
162 | //获取Helper
163 | RBaseHelper helper = view.getHelper();
164 | helper.setBackgroundColorNormal(getResources().getColor(R.color.blue))
165 | .setBorderColorNormal(getResources().getColor(R.color.red))
166 | .setBorderWidthNormal(12)
167 | .setCornerRadius(25);
168 | ```
169 |
170 | #### 效果图
171 |  
172 |  
173 |  
174 |  
175 |
176 | ## 个性功能
177 |
178 | #### RTextView
179 |
180 | - [x] `drawableLeft/Right/Top/Bottom icon大小`
181 | - [x] `drawableLeft/Right/Top/Bottom icon状态`
182 | - [x] `drawableLeft 和 text 一起居中`
183 | - [x] `文字根据状态变色 默认/按下/不可点击/选择`
184 | - [x] `设置字体样式`
185 |
186 | | 属性 |说明 |
187 | | ------------- | :-------------|
188 | | text_color_normal | 文字颜色 默认 |
189 | | text_color_pressed | 文字颜色 按下 |
190 | | text_color_unable | 文字颜色 不可点击 |
191 | | text_color_selected | 文字颜色 选择 |
192 | | icon_direction | drawable icon 位置{left,top,right,bottom} |
193 | | icon_with_text | 图片和文本一起居中 true/false |
194 | | text_typeface | 字体样式 |
195 |
196 | 老版本仅支持单一方向icon设置
197 |
198 | | | |
199 | | ------------- | :-------------|
200 | | icon_src_normal | drawable icon 默认 |
201 | | icon_src_pressed | drawable icon 按下 |
202 | | icon_src_unable | drawable icon 不可点击 |
203 | | icon_src_selected | drawable icon 选择 |
204 | | icon_height | drawable icon 高 |
205 | | icon_width | drawable icon 宽 |
206 |
207 | 新版本仅支持多个方向icon设置
208 |
209 | | | |
210 | | ------------- | :-------------|
211 | | icon_normal_left/right/top/bottom | 默认icon 各方向 |
212 | | icon_pressed_left/right/top/bottom | 按下icon 各方向 |
213 | | icon_unable_left/right/top/bottom | 不可用icon 各方向 |
214 | | icon_selected_left/right/top/bottom | 选中icon 各方向 |
215 | | icon_height_left/right/top/bottom | icon 各方向 高 |
216 | | icon_width_left/right/top/bottom | icon 各方向 宽 |
217 |
218 | > `RTextView` 控件新增支持多个方向同时设置 `icon`(老版本仅支持一个方向)为了兼容老版本用户,保留了原来字段 `icon_src_normal/pressed/unable/selected`
219 | >
220 | > 如果出现老版本属性默认开发者使用老版本逻辑(仅支持一个方向),新版请使用 `icon_normal_left/right/top/bottom` 等属性
221 |
222 | #### REditText
223 |
224 | > REditText 使用方法跟 RTextView 一致
225 |
226 | #### RLinearLayout / RRelativeLayout / RFrameLayout / RView / RConstraintLayout
227 |
228 | > 查看基础功能
229 | >
230 | > **重磅: ViewGroup 支持通过 clip_layout 设置是否裁剪子控件**
231 |
232 | #### RRadioButton / RCheckBox
233 |
234 | > 查看基础功能
235 | >
236 | > 查看 `RTextView` 所有功能
237 | >
238 | > 常使用选择属性 checked
239 | >
240 | > 支持 `RTextView` 的基础功能 自定义各个状态 `drawableLeft` 以及 icon与文本居中等
241 |
242 | | 属性 |说明 |
243 | | ------------- | :-------------|
244 | | border_width_checked | 边框宽度 选中 |
245 | | border_color_checked | 边框颜色 选中 |
246 | | background_checked | 背景 选中 |
247 | | text_color_checked | 文字颜色 选中 |
248 |
249 | 老版本仅支持单一方向icon设置
250 |
251 | | | |
252 | | ------------- | :-------------|
253 | | icon_src_normal | 图标 未选中 |
254 | | icon_src_checked | 图标 选中 |
255 |
256 | 新版本仅支持多个方向icon设置
257 |
258 | | | |
259 | | ------------- | :-------------|
260 | | icon_normal_left/right/top/bottom | 图标 未选中 各方向 |
261 | | icon_checked_left/right/top/bottom | 图标 选中 各方向 |
262 |
263 | > `RRadioButton / RCheckBox` 控件新增支持多个方向同时设置 `icon`(老版本仅支持一个方向)为了兼容老版本用户,保留了原来字段 `icon_src_checked`
264 | > 如果出现老版本属性默认开发者使用老版本逻辑(仅支持一个方向),新版请使用 `icon_checked_left/right/top/bottom` 等属性
265 |
266 |
267 | #### RImageView
268 |
269 | > RImageView 不提供state状态
270 | >
271 | > 1.圆形图片
272 | >
273 | > 2.圆角图片
274 | >
275 | > 3.指定某一方向圆角图片
276 | >
277 | > 4.边框
278 | >
279 |
280 | | 属性 |说明 |
281 | | ------------- | :-------------|
282 | | corner_radius | 圆角 四周 |
283 | | corner_radius_top_left | 圆角 左上 |
284 | | corner_radius_top_right | 圆角 右上 |
285 | | corner_radius_bottom_left | 圆角 左下 |
286 | | corner_radius_bottom_right | 圆角 右下 |
287 | | border_width | 边框宽度 |
288 | | border_color | 边框颜色 |
289 | | is_circle | 是否圆形图片 |
290 |
291 |
292 | ### 使用 (版本号根据更新历史使用最新版)
293 | #### JCenter仓库已经被关闭,新版本依赖方式 Jitpack
294 | ```
295 | //项目级别 build.gradle
296 | allprojects {
297 | repositories {
298 | ...
299 | maven { url "https://jitpack.io" }
300 | }
301 | }
302 |
303 |
304 | //support 版本
305 | dependencies {
306 | implementation 'com.github.RuffianZhong:RWidgetHelper:support.v0.0.14'
307 | }
308 |
309 | //androidx 版本
310 | dependencies {
311 | implementation 'com.github.RuffianZhong:RWidgetHelper:androidx.v0.0.14'
312 | }
313 | ```
314 | #### 老版本依赖方式 JCenter 2022 年 2 月 1 日开始无法使用
315 | ```
316 | //support 版本
317 | compile 'com.ruffian.library:RWidgetHelper:1.1.18'
318 |
319 | //androidx 版本
320 | compile 'com.ruffian.library:RWidgetHelper-AndroidX:0.0.9'
321 | ```
322 |
323 | ### 版本历史
324 |
325 | **support.v0.0.14/androidx.v0.0.14** `2023.05.08` Fix bug [issues#118](https://github.com/RuffianZhong/RWidgetHelper/issues/118) | [issues#121](https://github.com/RuffianZhong/RWidgetHelper/issues/121)
326 |
327 | **support.v0.0.13/androidx.v0.0.13** `2023.02.21` 支持 Android Studio Electric Eel | 2022.1.1 Patch 1 布局预览
328 |
329 | **support.v0.0.12/androidx.v0.0.12** `2023.02.21` 支持 Android Studio Chipmunk | 2021.2.1 Patch 1 布局预览
330 |
331 | **support.v0.0.11/androidx.v0.0.11** `2022.10.14` 优化性能,修改阴影实现方式
332 |
333 | **support.v0.0.10/androidx.v0.0.10** `2022.04.25` 圆角支持Right to left(从右到左布局)
334 |
335 | **support.v0.0.9/androidx.v0.0.9** `2022.03.17` 支持Right to left(从右到左布局)(left=left||start,right=right||end)
336 |
337 | **support.v0.0.7/androidx.v0.0.7|androidx.v0.0.8** `2021.09.23` 修复RTextView在5.0以下版本崩溃问题(v0.0.6修改不当导致)
338 |
339 | **support.v0.0.6/androidx.v0.0.6** `2021.09.15` 修复控件无法预览的问题
340 |
341 | **support.v0.0.5/androidx.v0.0.5** `2021.09.11` 适配原生drawableLeft/Right/Top/Bottom
342 |
343 | **support.v0.0.4/androidx.v0.0.4** `2021.08.18` 背景 || 边框 || 图标 ,未设置 "按下"/"选中"/"不可用"等状态时,使用默认状态的资源
344 |
345 | **support.v0.0.3/androidx.v0.0.3** `2021.07.19` bugfix:修复support.v0.0.1/androidx.v0.0.1版本引起的在代码中设置背景图不起效问题;修复重复设置背景图不起效问题
346 |
347 | **support.v0.0.2/androidx.v0.0.2** `2021.07.02` 基础控件继承自 Appcompat XX
348 |
349 | **support.v0.0.1/androidx.v0.0.1** `2021.05.25` 修改按下状态逻辑(背景/边框/文本颜色)
350 |
351 | **v1.1.18/v0.0.9** `2021.02.24` 修复 iconWithText Bug
352 |
353 | **v1.1.17/v0.0.8** `2021.01.30` Fix bug [issues#68](https://github.com/RuffianZhong/RWidgetHelper/issues/68) | [issues#73](https://github.com/RuffianZhong/RWidgetHelper/issues/73)
354 |
355 | **v1.1.16/v0.0.7** `2020.11.05` Fix bug:4.4.x版本上裁剪出现崩溃,内存泄漏[issues#78](https://github.com/RuffianZhong/RWidgetHelper/issues/78)
356 |
357 | **v1.1.15/v0.0.6** `2020.08.18` 重磅更新 ViewGroup 支持裁剪控件功能
358 |
359 | **v1.1.14/v0.0.5** `2020.07.23` RTextView 支持多方向icon,优化按下状态(背景/字体颜色)默认值
360 |
361 | **v1.1.13/v0.0.4** `2020.05.05` 修复RImageView未设置宽高时出错,圆角最大值不超过高度的1/2
362 |
363 | **v1.1.12/v0.0.3** `2020.04.02` 修复RImageView未设置src时不能绘制边框
364 |
365 | **v1.1.11/v0.0.2** `2020.01.14` ScaleType 的 center_inside 类型实现方式修改
366 |
367 | **v0.0.1** `2020.01.10` 单独支持 AndroidX ,方便开发者选择 (基于v1.1.10)
368 |
369 | **v1.1.10** `2020.01.10` 还原 Support 包支持,分离 AndroidX
370 |
371 | **v1.1.9** `2020.01.08` `androidx.appcompat` 和 `androidx.constraintlayout` 的依赖方式从编译时依赖到直接依赖,避免开发者未引入时不能正确使用
372 |
373 | **v1.1.8** `2020.01.03` RImageView重新实现,解决历史版本卡顿和内存溢出问题,新增RConstraintLayout控件,支持androidX
374 |
375 | **v1.1.7** `2019.12.03` 修复 Android 7.1 版本 Ripple 空指针问题 [issues#51](https://github.com/RuffianZhong/RWidgetHelper/issues/51)
376 |
377 | **v1.1.6** `2019.11.23` 修改 RImageView 实现方式。 Fix bug
378 |
379 | **v1.1.5** `2019.09.17` 修复 REditText 在Android 4.X 系统上无法正常使用
380 |
381 | **v1.1.4** `2019.09.17` 支持selected状态,Fix bug
382 |
383 | **v1.1.3** `2019.09.03` 支持阴影效果
384 |
385 | **v1.1.2** `2019.08.30` RippleDrawable 与 unable / checked 状态兼容,ripper -> ripple (更名:1.1.1版本名称写错了)
386 |
387 | **v1.1.1** `2019.08.28` 5.0 以上版本,支持 RippleDrawable 水波纹效果
388 |
389 | **v1.1.0** `2019.06.27` `RCheckBox` 和 `RRadioButton` 支持选中图片,支持继承 `RTextView` 的基础功能
390 |
391 | **v1.0.10** `2019.06.26` Fix bug [issues#33](https://github.com/RuffianZhong/RWidgetHelper/issues/33)
392 |
393 | **v1.0.9** `2019.06.21` RImageView支持ScaleType
394 |
395 | **v1.0.8** `2019.01.30` Fix bug [issues#25](https://github.com/RuffianZhong/RWidgetHelper/issues/25) and [issues#26](https://github.com/RuffianZhong/RWidgetHelper/issues/26)
396 |
397 | **v1.0.7** `2018.12.20` 优化代码,Fix bug
398 |
399 | **v1.0.6** `2018.12.18` 版本兼容,优化代码,`RFrameLayout`
400 |
401 | **v1.0.5** `2018.12.18` 1.DrawableWithText 图片和文本一起居中 2.Fix bug
402 |
403 | **v1.0.4** `2018.11.15` 1.背景支持图片类型 2.添加 `selector->checked`状态 添加 `RCheckBox` 和 `RRadioButton`
404 |
405 | **v1.0.3** `2018.11.09` Fix Bug [issues#17](https://github.com/RuffianZhong/RWidgetHelper/issues/17 "issues#17")
406 |
407 | **v1.0.2** `2018.10.09` 添加 Gradient 渐变功能
408 |
409 | **v1.0.1** `2018.08.20` Fix bug setEnabled [issues #7](https://github.com/RuffianZhong/RWidgetHelper/issues/7)
410 |
411 | **v1.0.0** `2018.04.26` 发布第一版本
412 |
413 |
414 | ## License
415 |
416 | ```
417 | MIT License
418 |
419 | Copyright (c) 2018 Ruffian-痞子
420 | ```
421 |
422 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 31
5 | defaultConfig {
6 | applicationId "com.ruffian.library.demo"
7 | minSdkVersion 14
8 | targetSdkVersion 31
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | android {
20 | lintOptions {
21 | abortOnError false
22 | }
23 | }
24 | }
25 |
26 | dependencies {
27 | implementation fileTree(dir: 'libs', include: ['*.jar'])
28 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
29 | exclude group: 'com.android.support', module: 'support-annotations'
30 | })
31 | implementation 'com.android.support:appcompat-v7:28.0.0'
32 | implementation 'com.android.support:recyclerview-v7:28.0.0'
33 | implementation 'com.android.support:support-v4:28.0.0'
34 | implementation 'com.github.bumptech.glide:glide:4.3.0'
35 | annotationProcessor 'com.github.bumptech.glide:compiler:4.3.0'
36 | testImplementation 'junit:junit:4.12'
37 | implementation project(':library')
38 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
39 | }
40 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/ruffian/library/demo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.ruffian.library.demo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-Black.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-BlackItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-BlackItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-BoldItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-Italic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-Light.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-LightItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-MediumItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-Thin.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Roboto-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/Roboto-ThinItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoCondensed-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoCondensed-Bold.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoCondensed-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoCondensed-BoldItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoCondensed-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoCondensed-Italic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoCondensed-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoCondensed-Light.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoCondensed-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoCondensed-LightItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoCondensed-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoCondensed-Regular.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-Bold.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-BoldItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-Italic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-Light.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-LightItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-Medium.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-MediumItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-Regular.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-Thin.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoMono-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoMono-ThinItalic.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoSlab-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoSlab-Bold.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoSlab-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoSlab-Light.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoSlab-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoSlab-Regular.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/RobotoSlab-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/RobotoSlab-Thin.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/huakangshaonv.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/assets/fonts/huakangshaonv.ttf
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/App.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | public class App extends Application {
7 |
8 | @Override
9 | public void attachBaseContext(Context context) {
10 | super.attachBaseContext(context);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/CheckedActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | /**
8 | * CheckedActivity
9 | *
10 | * @author ZhongDaFeng
11 | */
12 | public class CheckedActivity extends AppCompatActivity {
13 |
14 | @Override
15 | protected void onCreate(@Nullable Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_checked);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/FragmentCorner.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
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 |
9 | /**
10 | * 示例FragmentCorner
11 | * 备注:各种圆角使用示例
12 | *
13 | * @author ZhongDaFeng
14 | */
15 |
16 | public class FragmentCorner extends Fragment {
17 |
18 | @Override
19 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
20 | return LayoutInflater.from(getActivity()).inflate(R.layout.fmt_textview_corner, null);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/FragmentState.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
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 |
9 | /**
10 | * 示例FragmentState
11 | * 备注:各种边框,背景状态使用示例
12 | *
13 | * @author ZhongDaFeng
14 | */
15 |
16 | public class FragmentState extends Fragment {
17 |
18 | @Override
19 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
20 | View view = LayoutInflater.from(getActivity()).inflate(R.layout.fmt_textview_state, null);
21 | return view;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/FragmentVersion.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
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 |
9 | /**
10 | * 示例FragmentCorner
11 | *
12 | * @author ZhongDaFeng
13 | */
14 |
15 | public class FragmentVersion extends Fragment {
16 |
17 | private View mView;
18 |
19 | @Override
20 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
21 | mView = LayoutInflater.from(getActivity()).inflate(R.layout.fmt_textview_version, null);
22 | return mView;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/GradientActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | /**
8 | * Gradient相关演示
9 | *
10 | * @author ZhongDaFeng
11 | */
12 | public class GradientActivity extends AppCompatActivity {
13 |
14 | @Override
15 | protected void onCreate(@Nullable Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_gradient);
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_main);
14 | findViewById(R.id.tv).setOnClickListener(this);
15 | findViewById(R.id.iv).setOnClickListener(this);
16 | findViewById(R.id.et).setOnClickListener(this);
17 | findViewById(R.id.view_group).setOnClickListener(this);
18 | findViewById(R.id.view).setOnClickListener(this);
19 | findViewById(R.id.gradient).setOnClickListener(this);
20 | findViewById(R.id.checked).setOnClickListener(this);
21 | findViewById(R.id.ripper).setOnClickListener(this);
22 | findViewById(R.id.shadow).setOnClickListener(this);
23 | }
24 |
25 |
26 | @Override
27 | public void onClick(View view) {
28 | Intent intent = null;
29 | switch (view.getId()) {
30 | case R.id.tv:
31 | intent = new Intent(this, RTextViewActivity.class);
32 | break;
33 | case R.id.iv:
34 | intent = new Intent(this, RImageViewActivity.class);
35 | break;
36 | case R.id.et:
37 | intent = new Intent(this, REditTextActivity.class);
38 | break;
39 | case R.id.view_group:
40 | intent = new Intent(this, RViewGroupActivity.class);
41 | break;
42 | case R.id.view:
43 | intent = new Intent(this, RViewActivity.class);
44 | break;
45 | case R.id.gradient:
46 | intent = new Intent(this, GradientActivity.class);
47 | break;
48 | case R.id.checked:
49 | intent = new Intent(this, CheckedActivity.class);
50 | break;
51 | case R.id.ripper:
52 | intent = new Intent(this, RipperActivity.class);
53 | break;
54 | case R.id.shadow:
55 | intent = new Intent(this, ShadowActivity.class);
56 | break;
57 | }
58 | if (intent != null) {
59 | startActivity(intent);
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/REditTextActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | /**
8 | * EditText示例
9 | *
10 | * @author ZhongDaFeng
11 | */
12 | public class REditTextActivity extends AppCompatActivity {
13 |
14 | @Override
15 | protected void onCreate(@Nullable Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_edittext);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/RImageViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | /**
8 | * @author ZhongDaFeng
9 | */
10 | public class RImageViewActivity extends AppCompatActivity {
11 | @Override
12 | protected void onCreate(@Nullable Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_imageview);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/RTextViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 | import android.support.v4.view.ViewPager;
7 | import android.support.v7.app.AppCompatActivity;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | /**
13 | * @author ZhongDaFeng
14 | */
15 | public class RTextViewActivity extends AppCompatActivity {
16 |
17 | private ViewPager mViewPager;
18 | private FragmentPagerAdapter mAdapter;
19 | private List mFragmentList = new ArrayList();
20 |
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.activity_textview_main);
26 | initViews();
27 | initData();
28 | }
29 |
30 |
31 | private void initData() {
32 |
33 | mFragmentList.add(new FragmentCorner());
34 | mFragmentList.add(new FragmentState());
35 | mFragmentList.add(new FragmentVersion());
36 | mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
37 | @Override
38 | public int getCount() {
39 | return mFragmentList.size();
40 | }
41 |
42 | @Override
43 | public Fragment getItem(int position) {
44 | return mFragmentList.get(position);
45 | }
46 | };
47 |
48 | mViewPager.setAdapter(mAdapter);
49 | }
50 |
51 | private void initViews() {
52 | mViewPager = (ViewPager) findViewById(R.id.vp_content);
53 | }
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/RViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | /**
8 | * @author ZhongDaFeng
9 | */
10 | public class RViewActivity extends AppCompatActivity {
11 |
12 | @Override
13 | protected void onCreate(@Nullable Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_view);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/RViewGroupActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | /**
8 | * @author ZhongDaFeng
9 | */
10 | public class RViewGroupActivity extends AppCompatActivity {
11 |
12 | @Override
13 | protected void onCreate(@Nullable Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_viewgroup);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/RipperActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 | import com.ruffian.library.widget.RTextView;
9 |
10 |
11 | /**
12 | * 水波纹效果展示
13 | *
14 | * @author ZhongDaFeng
15 | */
16 | public class RipperActivity extends AppCompatActivity {
17 | private RTextView tvTag;
18 | private RTextView btnUpdate;
19 |
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_ripper);
24 | tvTag = (RTextView) findViewById(R.id.tv_tag);
25 | btnUpdate = (RTextView) findViewById(R.id.tv_update);
26 | btnUpdate.setOnClickListener(new View.OnClickListener() {
27 | @Override
28 | public void onClick(View v) {
29 | boolean enabled = tvTag.isEnabled();
30 | tvTag.setEnabled(!enabled);
31 | btnUpdate.setText(String.valueOf(!enabled));
32 | }
33 | });
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ruffian/library/demo/ShadowActivity.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.LinearLayoutManager;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.util.TypedValue;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.LinearLayout;
13 | import android.widget.TextView;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 |
19 | /**
20 | * 阴影效果展示
21 | *
22 | * @author ZhongDaFeng
23 | */
24 | public class ShadowActivity extends AppCompatActivity {
25 |
26 | private RecyclerView recyclerView;
27 | private MyAdapter adapter;
28 | private final boolean isAuthor = false;//作者自测逻辑
29 |
30 | @Override
31 | protected void onCreate(@Nullable Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | //demo 示例布局 activity_shadow
34 | setContentView(R.layout.activity_shadow);
35 |
36 | if (!isAuthor) return;
37 | /**
38 | * 以下代码为作者自测请忽略test
39 | */
40 | //test
41 | setContentView(R.layout.activity_list);
42 |
43 | List list = new ArrayList<>();
44 | for (int i = 0; i < 20; i++) list.add("Item" + (i + 1));
45 |
46 | recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
47 | adapter = new MyAdapter(list);
48 | recyclerView.setAdapter(adapter);
49 | recyclerView.setLayoutManager(new LinearLayoutManager(this));
50 | }
51 |
52 | class MyAdapter extends RecyclerView.Adapter {
53 |
54 | private List mList;
55 |
56 | public MyAdapter(List list) {
57 | this.mList = list;
58 | }
59 |
60 | @Override
61 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
62 | return new MyViewHolder(LayoutInflater.from(ShadowActivity.this).inflate(R.layout.item_list, parent, false));
63 | }
64 |
65 | @Override
66 | public void onBindViewHolder(MyViewHolder holder, int position) {
67 | holder.textView.setText(mList.get(position));
68 | //test
69 | int height = dp2px(150) + (position) * 20;
70 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
71 | holder.layout_ll.setLayoutParams(params);
72 | }
73 |
74 | @Override
75 | public int getItemCount() {
76 | return mList.size();
77 | }
78 | }
79 |
80 | class MyViewHolder extends RecyclerView.ViewHolder {
81 |
82 | private TextView textView;
83 | private LinearLayout layout_ll;
84 |
85 | public MyViewHolder(View itemView) {
86 | super(itemView);
87 | textView = itemView.findViewById(R.id.tv_text);
88 | layout_ll = itemView.findViewById(R.id.layout_ll);
89 | }
90 | }
91 |
92 | protected int dp2px(int dp) {
93 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tv_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_checked.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
14 |
15 |
20 |
21 |
34 |
35 |
47 |
48 |
61 |
62 |
63 |
64 |
70 |
71 |
87 |
88 |
103 |
104 |
120 |
121 |
122 |
123 |
128 |
129 |
134 |
135 |
146 |
147 |
161 |
162 |
173 |
174 |
175 |
176 |
181 |
182 |
196 |
197 |
214 |
215 |
230 |
231 |
232 |
233 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_edittext.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
17 |
18 |
32 |
33 |
50 |
51 |
68 |
69 |
73 |
74 |
90 |
91 |
92 |
106 |
107 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_gradient.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
27 |
28 |
39 |
40 |
41 |
42 |
47 |
48 |
58 |
59 |
70 |
71 |
72 |
73 |
74 |
79 |
80 |
91 |
92 |
104 |
105 |
109 |
110 |
122 |
123 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_imageview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
15 |
20 |
21 |
28 |
29 |
39 |
40 |
41 |
42 |
48 |
49 |
56 |
57 |
68 |
69 |
70 |
71 |
72 |
78 |
79 |
80 |
90 |
91 |
102 |
103 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
21 |
22 |
27 |
28 |
33 |
34 |
39 |
40 |
45 |
46 |
51 |
52 |
60 |
61 |
66 |
67 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_ripper.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
20 |
25 |
26 |
31 |
32 |
45 |
46 |
56 |
57 |
58 |
63 |
64 |
70 |
71 |
88 |
89 |
107 |
108 |
109 |
110 |
124 |
125 |
133 |
134 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_shadow.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
29 |
30 |
38 |
39 |
40 |
41 |
42 |
55 |
56 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_textview_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
22 |
23 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
41 |
47 |
48 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_viewgroup.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
28 |
29 |
30 |
31 |
40 |
41 |
49 |
50 |
51 |
52 |
63 |
64 |
72 |
73 |
74 |
75 |
83 |
84 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fmt_textview_corner.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
19 |
20 |
21 |
25 |
26 |
34 |
35 |
36 |
46 |
47 |
48 |
49 |
54 |
55 |
63 |
64 |
65 |
75 |
76 |
77 |
78 |
83 |
84 |
93 |
94 |
104 |
105 |
116 |
117 |
118 |
119 |
120 |
125 |
126 |
134 |
135 |
146 |
147 |
157 |
158 |
159 |
160 |
161 |
170 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fmt_textview_state.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
13 |
14 |
27 |
28 |
43 |
44 |
45 |
46 |
52 |
53 |
67 |
68 |
84 |
85 |
86 |
87 |
93 |
94 |
110 |
111 |
133 |
134 |
135 |
136 |
142 |
143 |
154 |
155 |
156 |
157 |
174 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fmt_textview_version.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
19 |
20 |
29 |
30 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/food.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/food.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_account.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_account.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_bg_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_bg_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_bg_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_bg_pressed.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_heart.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_help.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_man.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_man.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_man_pressed.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_man_pressed.jpg
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_phone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_phone.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_phone_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_phone_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_phone_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_phone_pressed.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_phone_unable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_phone_unable.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_psw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_psw.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_rb_green_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_rb_green_default.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_rb_green_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_rb_green_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/icon_star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xhdpi/icon_star.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/array.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | - @color/purple
7 | - @color/blue
8 | - @color/navy
9 | - @color/green
10 | - @color/yellow
11 | - @color/orange
12 | - @color/red
13 |
14 |
15 |
16 |
17 | - #FA8BFF
18 | - #2BD2FF
19 | - #2BFF88
20 |
21 |
22 |
23 |
24 | - #74EBD5
25 | - #9FACE6
26 |
27 |
28 |
29 |
30 | - #D9AFD9
31 | - #97D9E1
32 |
33 |
34 |
35 |
36 | - #FF3CAC
37 | - #784BA0
38 | - #2B86C5
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #eff1f3
7 | #DCDCDD
8 |
9 | #FF0000
10 | #FF7F00
11 | #FFFF00
12 | #00FF00
13 | #00FFFF
14 | #0000FF
15 | #8B00FF
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RWidgetHelper
3 | 子控件自行兼容父控件\nshadow_radius + shadow_dx/shadow_dy
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
22 |
23 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/test/java/com/ruffian/library/demo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.demo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | //serve to dependencies
6 | maven { url 'https://maven.aliyun.com/repository/central' }
7 | maven { url 'https://maven.aliyun.com/repository/public' }
8 | maven { url 'https://maven.aliyun.com/repository/google' }
9 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
10 |
11 | google()
12 | mavenCentral()
13 | }
14 | dependencies {
15 | classpath 'com.android.tools.build:gradle:7.2.1'
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | //serve to project
22 | maven { url 'https://maven.aliyun.com/repository/central' }
23 | maven { url 'https://maven.aliyun.com/repository/public' }
24 | maven { url 'https://maven.aliyun.com/repository/google' }
25 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
26 | maven { url "https://jitpack.io" }
27 | google()
28 | }
29 | tasks.withType(Javadoc) {
30 | options {
31 | encoding "UTF-8"
32 | charSet 'UTF-8'
33 | links "http://docs.oracle.com/javase/7/docs/api"
34 | }
35 | }
36 | }
37 |
38 | task clean(type: Delete) {
39 | delete rootProject.buildDir
40 | }
41 |
--------------------------------------------------------------------------------
/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 | #systemProp.https.proxyHost=127.0.0.1
19 | #systemProp.https.proxyPort=1080
20 | #systemProp.http.proxyHost=127.0.0.1
21 | #systemProp.http.proxyPort=1080
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Nov 05 16:59:03 CST 2020
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-7.3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 31
5 |
6 | defaultConfig {
7 | minSdkVersion 14
8 | targetSdkVersion 31
9 | versionCode 38
10 | versionName "support.v0.0.14"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | android {
20 | lintOptions {
21 | abortOnError false
22 |
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 | api fileTree(dir: 'libs', include: ['*.jar'])
29 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
30 | exclude group: 'com.android.support', module: 'support-annotations'
31 | })
32 | //直接依赖,避免开发者不能正常使用
33 | api 'com.android.support:appcompat-v7:28.0.0'
34 | api 'com.android.support.constraint:constraint-layout:1.1.3'
35 | testImplementation 'junit:junit:4.12'
36 | }
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/ruffian/library/widget/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.ruffian.library.widget.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/RCheckBox.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.support.v7.widget.AppCompatCheckBox;
6 | import android.util.AttributeSet;
7 | import android.view.MotionEvent;
8 |
9 | import com.ruffian.library.widget.helper.RCheckHelper;
10 | import com.ruffian.library.widget.iface.RHelper;
11 |
12 | /**
13 | * RCheckBox
14 | *
15 | * @author ZhongDaFeng
16 | */
17 | public class RCheckBox extends AppCompatCheckBox implements RHelper {
18 |
19 | private RCheckHelper mHelper;
20 |
21 | public RCheckBox(Context context) {
22 | this(context, null);
23 | }
24 |
25 | public RCheckBox(Context context, AttributeSet attrs) {
26 | super(context, attrs);
27 | mHelper = new RCheckHelper(context, this, attrs);
28 | }
29 |
30 | @Override
31 | public RCheckHelper getHelper() {
32 | return mHelper;
33 | }
34 |
35 | @Override
36 | public void setEnabled(boolean enabled) {
37 | super.setEnabled(enabled);
38 | if (mHelper != null) mHelper.setEnabled(enabled);
39 | }
40 |
41 | @Override
42 | public boolean onTouchEvent(MotionEvent event) {
43 | if (mHelper != null) mHelper.onTouchEvent(event);
44 | return super.onTouchEvent(event);
45 | }
46 |
47 | @Override
48 | public void setSelected(boolean selected) {
49 | if (mHelper != null) mHelper.setSelected(selected);
50 | super.setSelected(selected);
51 | }
52 |
53 | @Override
54 | public void setChecked(boolean checked) {
55 | if (mHelper != null) mHelper.setChecked(checked);
56 | super.setChecked(checked);
57 | }
58 |
59 | @Override
60 | protected void onDraw(Canvas canvas) {
61 | super.onDraw(canvas);
62 | if (mHelper != null) mHelper.drawIconWithText();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/RConstraintLayout.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.support.constraint.ConstraintLayout;
6 | import android.util.AttributeSet;
7 |
8 | import com.ruffian.library.widget.helper.RBaseHelper;
9 | import com.ruffian.library.widget.iface.RHelper;
10 |
11 | /**
12 | * RConstraintLayout
13 | *
14 | * @author ZhongDaFeng
15 | */
16 | public class RConstraintLayout extends ConstraintLayout implements RHelper {
17 |
18 | private RBaseHelper mHelper;
19 |
20 | public RConstraintLayout(Context context) {
21 | this(context, null);
22 | }
23 |
24 | public RConstraintLayout(Context context, AttributeSet attrs) {
25 | this(context, attrs, 0);
26 | }
27 |
28 | public RConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
29 | super(context, attrs, defStyleAttr);
30 | mHelper = new RBaseHelper(context, this, attrs);
31 | }
32 |
33 | @Override
34 | public RBaseHelper getHelper() {
35 | return mHelper;
36 | }
37 |
38 | @Override
39 | public void dispatchDraw(Canvas canvas) {
40 | super.dispatchDraw(canvas);
41 | mHelper.dispatchDraw(canvas);
42 | }
43 |
44 | @Override
45 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
46 | super.onLayout(changed, left, top, right, bottom);
47 | mHelper.onLayout(changed, left, top, right, bottom);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/REditText.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.AppCompatEditText;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 |
8 | import com.ruffian.library.widget.helper.RTextViewHelper;
9 | import com.ruffian.library.widget.iface.RHelper;
10 |
11 | /**
12 | * REditText
13 | *
14 | * @author ZhongDaFeng
15 | */
16 | public class REditText extends AppCompatEditText implements RHelper {
17 |
18 | private RTextViewHelper mHelper;
19 |
20 | public REditText(Context context) {
21 | this(context, null);
22 | }
23 |
24 | public REditText(Context context, AttributeSet attrs) {
25 | super(context, attrs);
26 | mHelper = new RTextViewHelper(context, this, attrs);
27 | }
28 |
29 | @Override
30 | public RTextViewHelper getHelper() {
31 | return mHelper;
32 | }
33 |
34 | @Override
35 | public void setEnabled(boolean enabled) {
36 | super.setEnabled(enabled);
37 | if (mHelper != null) mHelper.setEnabled(enabled);
38 | }
39 |
40 | @Override
41 | public boolean onTouchEvent(MotionEvent event) {
42 | if (mHelper != null) mHelper.onTouchEvent(event);
43 | return super.onTouchEvent(event);
44 | }
45 |
46 | @Override
47 | public void setSelected(boolean selected) {
48 | if (mHelper != null) mHelper.setSelected(selected);
49 | super.setSelected(selected);
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/RFrameLayout.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.util.AttributeSet;
6 | import android.widget.FrameLayout;
7 |
8 | import com.ruffian.library.widget.helper.RBaseHelper;
9 | import com.ruffian.library.widget.iface.RHelper;
10 |
11 | /**
12 | * RFrameLayout
13 | *
14 | * @author ZhongDaFeng
15 | */
16 | public class RFrameLayout extends FrameLayout implements RHelper {
17 |
18 | private RBaseHelper mHelper;
19 |
20 | public RFrameLayout(Context context) {
21 | this(context, null);
22 | }
23 |
24 | public RFrameLayout(Context context, AttributeSet attrs) {
25 | this(context, attrs, 0);
26 | }
27 |
28 | public RFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
29 | super(context, attrs, defStyleAttr);
30 | mHelper = new RBaseHelper(context, this, attrs);
31 | }
32 |
33 | @Override
34 | public RBaseHelper getHelper() {
35 | return mHelper;
36 | }
37 |
38 | @Override
39 | public void dispatchDraw(Canvas canvas) {
40 | super.dispatchDraw(canvas);
41 | mHelper.dispatchDraw(canvas);
42 | }
43 |
44 | @Override
45 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
46 | super.onLayout(changed, left, top, right, bottom);
47 | mHelper.onLayout(changed, left, top, right, bottom);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/RImageView.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.content.res.ColorStateList;
5 | import android.content.res.Resources;
6 | import android.content.res.TypedArray;
7 | import android.graphics.Bitmap;
8 | import android.graphics.Canvas;
9 | import android.graphics.Color;
10 | import android.graphics.ColorFilter;
11 | import android.graphics.PorterDuff;
12 | import android.graphics.PorterDuffColorFilter;
13 | import android.graphics.drawable.Drawable;
14 | import android.graphics.drawable.LayerDrawable;
15 | import android.os.Build;
16 | import android.util.AttributeSet;
17 |
18 | import android.support.annotation.ColorInt;
19 | import android.support.annotation.DrawableRes;
20 | import android.support.annotation.Nullable;
21 | import android.support.v7.widget.AppCompatImageView;
22 |
23 | import com.ruffian.library.widget.rounded.RoundDrawable;
24 |
25 | /**
26 | * RImageView
27 | *
28 | * @author ZhongDaFeng
29 | */
30 | public class RImageView extends AppCompatImageView {
31 |
32 | //圆角
33 | private float mCorner = -1;
34 | private float mCornerTopLeft = 0;
35 | private float mCornerTopRight = 0;
36 | private float mCornerBottomLeft = 0;
37 | private float mCornerBottomRight = 0;
38 | //边框
39 | private float mBorderWidth = 0;
40 | private int mBorderColor = Color.BLACK;
41 | //是否圆形
42 | private boolean mIsCircle = false;
43 |
44 | private Drawable mDrawable;
45 | private ScaleType mScaleType;
46 | private int mResource;
47 | private ColorFilter mColorFilter;
48 | private PorterDuff.Mode mTintMode = PorterDuff.Mode.SRC_ATOP;
49 |
50 | public RImageView(Context context) {
51 | this(context, null);
52 | }
53 |
54 | public RImageView(Context context, @Nullable AttributeSet attrs) {
55 | super(context, attrs);
56 | initAttributeSet(context, attrs);
57 | }
58 |
59 | /**
60 | * 初始化自定义属性
61 | *
62 | * @param attrs
63 | */
64 | private void initAttributeSet(Context context, AttributeSet attrs) {
65 | if (context == null || attrs == null) return;
66 |
67 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RImageView);
68 | mIsCircle = a.getBoolean(R.styleable.RImageView_is_circle, false);
69 | mCorner = a.getDimensionPixelSize(R.styleable.RImageView_corner_radius, -1);
70 | mCornerTopLeft = a.getDimensionPixelSize(R.styleable.RImageView_corner_radius_top_left, 0);
71 | mCornerTopRight = a.getDimensionPixelSize(R.styleable.RImageView_corner_radius_top_right, 0);
72 | mCornerBottomLeft = a.getDimensionPixelSize(R.styleable.RImageView_corner_radius_bottom_left, 0);
73 | mCornerBottomRight = a.getDimensionPixelSize(R.styleable.RImageView_corner_radius_bottom_right, 0);
74 | mBorderWidth = a.getDimensionPixelSize(R.styleable.RImageView_border_width, 0);
75 | mBorderColor = a.getColor(R.styleable.RImageView_border_color, Color.BLACK);
76 |
77 | //get system attrs
78 | String namespace = "http://schemas.android.com/apk/res/android";//android的命名空间
79 | int tintColor = attrs.getAttributeResourceValue(namespace, "tint", 0);
80 |
81 | int tintMode = attrs.getAttributeIntValue(namespace, "tintMode", 0);
82 | if (tintMode != 0) mTintMode = wrapTintMode(tintMode);
83 | //android studio 预览:需要区分版本或者使用 isInEditMode() 判断区分
84 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
85 | setImageTintList(getImageTintList());
86 | } else {
87 | if (tintColor != 0) {
88 | mColorFilter = new PorterDuffColorFilter(getResources().getColor(tintColor), mTintMode);
89 | }
90 | }
91 |
92 | a.recycle();
93 | updateDrawableAttrs();
94 | }
95 |
96 | @Override
97 | protected void drawableStateChanged() {
98 | super.drawableStateChanged();
99 | invalidate();
100 | }
101 |
102 | @Override
103 | public void setScaleType(ScaleType scaleType) {
104 | super.setScaleType(scaleType);
105 | if (mScaleType != scaleType) {
106 | mScaleType = scaleType;
107 | updateDrawableAttrs();
108 | invalidate();
109 | }
110 | }
111 |
112 | @Override
113 | public void setImageBitmap(Bitmap bm) {
114 | mResource = 0;
115 | mDrawable = RoundDrawable.fromBitmap(bm);
116 | updateDrawableAttrs();
117 | super.setImageDrawable(mDrawable);
118 | }
119 |
120 | @Override
121 | public void setImageDrawable(Drawable drawable) {
122 | mResource = 0;
123 | mDrawable = RoundDrawable.fromDrawable(drawable);
124 | updateDrawableAttrs();
125 | super.setImageDrawable(mDrawable);
126 | }
127 |
128 | @Override
129 | public void setImageResource(@DrawableRes int resId) {
130 | if (mResource != resId) {
131 | mResource = resId;
132 | mDrawable = resolveResource();
133 | updateDrawableAttrs();
134 | super.setImageDrawable(mDrawable);
135 | }
136 | }
137 |
138 | @Override
139 | public void setImageTintList(@Nullable ColorStateList tint) {
140 | super.setImageTintList(tint);
141 | if (tint != null) {
142 | this.mColorFilter = new PorterDuffColorFilter(tint.getDefaultColor(), mTintMode);
143 | }
144 | setColorFilter();
145 | }
146 |
147 | @Override
148 | public void setImageTintMode(@Nullable PorterDuff.Mode tintMode) {
149 | super.setImageTintMode(tintMode);
150 | this.mTintMode = tintMode;
151 | setColorFilter();
152 | }
153 |
154 | public void setColorFilter() {
155 | if (mColorFilter != null && mDrawable != null) {
156 | //ColorFilter filter = new PorterDuffColorFilter(Color.parseColor("#00FF00"), PorterDuff.Mode.SRC_ATOP);
157 | mDrawable.setColorFilter(mColorFilter);
158 | }
159 | }
160 |
161 | @Override
162 | protected void onDraw(Canvas canvas) {
163 | super.onDraw(canvas);
164 | drawEmptyBitmap();
165 | }
166 |
167 | private Drawable resolveResource() {
168 | Resources resources = getResources();
169 | if (resources == null) {
170 | return null;
171 | }
172 | Drawable d = null;
173 | if (mResource != 0) {
174 | try {
175 | d = resources.getDrawable(mResource);
176 | } catch (Exception e) {
177 | mResource = 0;
178 | }
179 | }
180 | return RoundDrawable.fromDrawable(d);
181 | }
182 |
183 | private void updateDrawableAttrs() {
184 | updateAttrs(mDrawable, mScaleType);
185 | setColorFilter();
186 | }
187 |
188 | private void updateAttrs(Drawable drawable, ScaleType scaleType) {
189 | if (drawable == null) return;
190 | if (drawable instanceof RoundDrawable) {
191 | ((RoundDrawable) drawable).setParams(scaleType, mBorderWidth, mBorderColor, mIsCircle, mCorner, mCornerTopLeft, mCornerTopRight, mCornerBottomLeft, mCornerBottomRight);
192 | } else if (drawable instanceof LayerDrawable) {
193 | LayerDrawable ld = ((LayerDrawable) drawable);
194 | for (int i = 0, layers = ld.getNumberOfLayers(); i < layers; i++) {
195 | updateAttrs(ld.getDrawable(i), scaleType);
196 | }
197 | }
198 | }
199 |
200 | /**
201 | * 绘制空Bitmap
202 | */
203 | private void drawEmptyBitmap() {
204 | if (mDrawable == null) {//未设置Bitmap
205 | int width = getMeasuredWidth();
206 | int height = getMeasuredHeight();
207 | if (width > 0 && height > 0) {
208 | Drawable background = getBackground();
209 | if (background != null) {
210 | background.setBounds(0, 0, width, height);
211 | setImageDrawable(background);
212 | } else {
213 | setImageBitmap(Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8));
214 | }
215 | }
216 | }
217 | }
218 |
219 | public RImageView isCircle(boolean isCircle) {
220 | this.mIsCircle = isCircle;
221 | updateDrawableAttrs();
222 | return this;
223 | }
224 |
225 | /************************
226 | * Border
227 | ************************/
228 | public float getBorderWidth() {
229 | return mBorderWidth;
230 | }
231 |
232 | public RImageView setBorderWidth(int borderWidth) {
233 | this.mBorderWidth = borderWidth;
234 | updateDrawableAttrs();
235 | return this;
236 | }
237 |
238 | public int getBorderColor() {
239 | return mBorderColor;
240 | }
241 |
242 | public RImageView setBorderColor(@ColorInt int borderColor) {
243 | this.mBorderColor = borderColor;
244 | updateDrawableAttrs();
245 | return this;
246 | }
247 |
248 | /************************
249 | * Corner
250 | ************************/
251 | public float getCorner() {
252 | return mCorner;
253 | }
254 |
255 | public RImageView setCorner(float corner) {
256 | this.mCorner = corner;
257 | updateDrawableAttrs();
258 | return this;
259 | }
260 |
261 | public float getCornerTopLeft() {
262 | return mCornerTopLeft;
263 | }
264 |
265 | public RImageView setCornerTopLeft(float cornerTopLeft) {
266 | this.mCorner = -1;
267 | this.mCornerTopLeft = cornerTopLeft;
268 | updateDrawableAttrs();
269 | return this;
270 | }
271 |
272 | public float getCornerTopRight() {
273 | return mCornerTopRight;
274 | }
275 |
276 | public RImageView setCornerTopRight(float cornerTopRight) {
277 | this.mCorner = -1;
278 | this.mCornerTopRight = cornerTopRight;
279 | updateDrawableAttrs();
280 | return this;
281 | }
282 |
283 | public float getCornerBottomLeft() {
284 | return mCornerBottomLeft;
285 | }
286 |
287 | public RImageView setCornerBottomLeft(float cornerBottomLeft) {
288 | this.mCorner = -1;
289 | this.mCornerBottomLeft = cornerBottomLeft;
290 | updateDrawableAttrs();
291 | return this;
292 | }
293 |
294 | public float getCornerBottomRight() {
295 | return mCornerBottomRight;
296 | }
297 |
298 | public RImageView setCornerBottomRight(float cornerBottomRight) {
299 | this.mCorner = -1;
300 | this.mCornerBottomRight = cornerBottomRight;
301 | updateDrawableAttrs();
302 | return this;
303 | }
304 |
305 | public RImageView setCorner(float topLeft, float topRight, float bottomRight, float bottomLeft) {
306 | this.mCorner = -1;
307 | this.mCornerTopLeft = topLeft;
308 | this.mCornerTopRight = topRight;
309 | this.mCornerBottomRight = bottomRight;
310 | this.mCornerBottomLeft = bottomLeft;
311 | updateDrawableAttrs();
312 | return this;
313 | }
314 |
315 | /**
316 | * 转化TintMode
317 | *
318 | * @param tintMode
319 | * @return
320 | */
321 | private PorterDuff.Mode wrapTintMode(int tintMode) {
322 | switch (tintMode) {
323 | case 3:
324 | return PorterDuff.Mode.SRC_OVER;
325 | case 5:
326 | return PorterDuff.Mode.SRC_IN;
327 | case 14:
328 | return PorterDuff.Mode.MULTIPLY;
329 | case 15:
330 | return PorterDuff.Mode.SCREEN;
331 | case 16:
332 | return PorterDuff.Mode.ADD;
333 | case 9:
334 | default:
335 | return PorterDuff.Mode.SRC_ATOP;
336 | }
337 | }
338 | }
339 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/RLinearLayout.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.util.AttributeSet;
6 | import android.widget.LinearLayout;
7 |
8 | import com.ruffian.library.widget.helper.RBaseHelper;
9 | import com.ruffian.library.widget.iface.RHelper;
10 |
11 | /**
12 | * RLinearLayout
13 | *
14 | * @author ZhongDaFeng
15 | */
16 | public class RLinearLayout extends LinearLayout implements RHelper {
17 |
18 | private RBaseHelper mHelper;
19 |
20 | public RLinearLayout(Context context) {
21 | this(context, null);
22 | }
23 |
24 | public RLinearLayout(Context context, AttributeSet attrs) {
25 | this(context, attrs, 0);
26 | }
27 |
28 | public RLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
29 | super(context, attrs, defStyleAttr);
30 | mHelper = new RBaseHelper(context, this, attrs);
31 | }
32 |
33 | @Override
34 | public RBaseHelper getHelper() {
35 | return mHelper;
36 | }
37 |
38 | @Override
39 | public void dispatchDraw(Canvas canvas) {
40 | super.dispatchDraw(canvas);
41 | mHelper.dispatchDraw(canvas);
42 | }
43 |
44 | @Override
45 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
46 | super.onLayout(changed, left, top, right, bottom);
47 | mHelper.onLayout(changed, left, top, right, bottom);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/RRadioButton.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.support.v7.widget.AppCompatRadioButton;
6 | import android.util.AttributeSet;
7 | import android.view.MotionEvent;
8 |
9 | import com.ruffian.library.widget.helper.RCheckHelper;
10 | import com.ruffian.library.widget.iface.RHelper;
11 |
12 | /**
13 | * RRadioButton
14 | *
15 | * @author ZhongDaFeng
16 | */
17 | public class RRadioButton extends AppCompatRadioButton implements RHelper {
18 |
19 | private RCheckHelper mHelper;
20 |
21 | public RRadioButton(Context context) {
22 | this(context, null);
23 | }
24 |
25 | public RRadioButton(Context context, AttributeSet attrs) {
26 | super(context, attrs);
27 | mHelper = new RCheckHelper(context, this, attrs);
28 | }
29 |
30 | @Override
31 | public RCheckHelper getHelper() {
32 | return mHelper;
33 | }
34 |
35 | @Override
36 | public void setEnabled(boolean enabled) {
37 | super.setEnabled(enabled);
38 | if (mHelper != null) mHelper.setEnabled(enabled);
39 | }
40 |
41 | @Override
42 | public boolean onTouchEvent(MotionEvent event) {
43 | if (mHelper != null) mHelper.onTouchEvent(event);
44 | return super.onTouchEvent(event);
45 | }
46 |
47 | @Override
48 | public void setSelected(boolean selected) {
49 | if (mHelper != null) mHelper.setSelected(selected);
50 | super.setSelected(selected);
51 | }
52 |
53 | @Override
54 | public void setChecked(boolean checked) {
55 | if (mHelper != null) mHelper.setChecked(checked);
56 | super.setChecked(checked);
57 | }
58 |
59 | @Override
60 | protected void onDraw(Canvas canvas) {
61 | super.onDraw(canvas);
62 | if (mHelper != null) mHelper.drawIconWithText();
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/RRelativeLayout.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.util.AttributeSet;
6 | import android.widget.LinearLayout;
7 | import android.widget.RelativeLayout;
8 |
9 | import com.ruffian.library.widget.helper.RBaseHelper;
10 | import com.ruffian.library.widget.iface.RHelper;
11 |
12 | /**
13 | * RRelativeLayout
14 | *
15 | * @author ZhongDaFeng
16 | */
17 | public class RRelativeLayout extends RelativeLayout implements RHelper {
18 |
19 | private RBaseHelper mHelper;
20 |
21 | public RRelativeLayout(Context context) {
22 | this(context, null);
23 | }
24 |
25 | public RRelativeLayout(Context context, AttributeSet attrs) {
26 | this(context, attrs, 0);
27 | }
28 |
29 | public RRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
30 | super(context, attrs, defStyleAttr);
31 | mHelper = new RBaseHelper(context, this, attrs);
32 | }
33 |
34 | @Override
35 | public RBaseHelper getHelper() {
36 | return mHelper;
37 | }
38 |
39 | @Override
40 | public void dispatchDraw(Canvas canvas) {
41 | super.dispatchDraw(canvas);
42 | mHelper.dispatchDraw(canvas);
43 | }
44 |
45 | @Override
46 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
47 | super.onLayout(changed, left, top, right, bottom);
48 | mHelper.onLayout(changed, left, top, right, bottom);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/RTextView.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.support.v7.widget.AppCompatTextView;
6 | import android.util.AttributeSet;
7 | import android.view.MotionEvent;
8 |
9 | import com.ruffian.library.widget.helper.RTextViewHelper;
10 | import com.ruffian.library.widget.iface.RHelper;
11 |
12 | /**
13 | * RTextView
14 | *
15 | * @author ZhongDaFeng
16 | */
17 | public class RTextView extends AppCompatTextView implements RHelper {
18 |
19 | private RTextViewHelper mHelper;
20 |
21 | public RTextView(Context context) {
22 | this(context, null);
23 | }
24 |
25 | public RTextView(Context context, AttributeSet attrs) {
26 | super(context, attrs);
27 | mHelper = new RTextViewHelper(context, this, attrs);
28 | }
29 |
30 | @Override
31 | public RTextViewHelper getHelper() {
32 | return mHelper;
33 | }
34 |
35 | @Override
36 | public void setEnabled(boolean enabled) {
37 | super.setEnabled(enabled);
38 | if (mHelper != null) mHelper.setEnabled(enabled);
39 | }
40 |
41 | @Override
42 | public boolean onTouchEvent(MotionEvent event) {
43 | if (mHelper != null) mHelper.onTouchEvent(event);
44 | return super.onTouchEvent(event);
45 | }
46 |
47 | @Override
48 | public void setSelected(boolean selected) {
49 | if (mHelper != null) mHelper.setSelected(selected);
50 | super.setSelected(selected);
51 | }
52 |
53 | @Override
54 | protected void onDraw(Canvas canvas) {
55 | super.onDraw(canvas);
56 | if (mHelper != null) mHelper.drawIconWithText();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/RView.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 |
7 | import com.ruffian.library.widget.helper.RBaseHelper;
8 | import com.ruffian.library.widget.iface.RHelper;
9 |
10 | /**
11 | * RView
12 | *
13 | * @author ZhongDaFeng
14 | */
15 | public class RView extends View implements RHelper {
16 |
17 |
18 | private RBaseHelper mHelper;
19 |
20 | public RView(Context context) {
21 | this(context, null);
22 | }
23 |
24 | public RView(Context context, AttributeSet attrs) {
25 | this(context, attrs, 0);
26 | }
27 |
28 | public RView(Context context, AttributeSet attrs, int defStyleAttr) {
29 | super(context, attrs, defStyleAttr);
30 | mHelper = new RBaseHelper(context, this, attrs);
31 | }
32 |
33 | @Override
34 | public RBaseHelper getHelper() {
35 | return mHelper;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/clip/ClipHelper.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.clip;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Color;
5 | import android.graphics.Paint;
6 | import android.graphics.Path;
7 | import android.graphics.PorterDuff;
8 | import android.graphics.PorterDuffXfermode;
9 | import android.os.Build;
10 | import android.support.v4.view.ViewCompat;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 |
14 | /**
15 | * ClipHelper
16 | *
17 | * @author ZhongDaFeng
18 | */
19 | public class ClipHelper implements IClip {
20 |
21 | private final Paint clipPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
22 | protected PorterDuffXfermode DST_OUT_MODE = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
23 | protected PorterDuffXfermode DST_IN_MODE = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
24 | private final Path clipPath = new Path();
25 | private final Path rectView = new Path();
26 |
27 | private ClipPathManager clipPathManager = new ClipPathManager();
28 |
29 | private boolean requestShapeUpdate = true;
30 |
31 | private View mView;
32 | private boolean mClipLayout;
33 |
34 | public ClipHelper() {
35 | clipPaint.setAntiAlias(true);
36 | clipPaint.setColor(Color.BLUE);
37 | clipPaint.setStyle(Paint.Style.FILL);
38 | clipPaint.setStrokeWidth(1);
39 | }
40 |
41 |
42 | /**
43 | * 初始化Clip
44 | *
45 | * @param view
46 | * @param clipLayout
47 | * @param clipPathCreator
48 | */
49 | public void initClip(View view, boolean clipLayout, ClipPathManager.ClipPathCreator clipPathCreator) {
50 | this.mView = view;
51 | this.mClipLayout = clipLayout;
52 | if (!canClip()) return;
53 |
54 | getView().setDrawingCacheEnabled(true);
55 | getView().setWillNotDraw(false);
56 |
57 | if (Build.VERSION.SDK_INT <= 27) {
58 | clipPaint.setXfermode(DST_IN_MODE);
59 | getView().setLayerType(View.LAYER_TYPE_SOFTWARE, clipPaint); //Only works for software layers
60 | } else {
61 | clipPaint.setXfermode(DST_OUT_MODE);
62 | getView().setLayerType(View.LAYER_TYPE_SOFTWARE, null); //Only works for software layers
63 | }
64 |
65 | //设置clip
66 | clipPathManager.setClipPathCreator(clipPathCreator);
67 |
68 | requestShapeUpdate();
69 | }
70 |
71 |
72 | @Override
73 | public void dispatchDraw(Canvas canvas) {
74 | if (!canClip()) return;
75 |
76 | if (requestShapeUpdate) {
77 | calculateLayout(canvas.getWidth(), canvas.getHeight());
78 | requestShapeUpdate = false;
79 | }
80 | if (Build.VERSION.SDK_INT <= 27) {
81 | canvas.drawPath(clipPath, clipPaint);
82 | } else {
83 | canvas.drawPath(rectView, clipPaint);
84 | }
85 |
86 | if (Build.VERSION.SDK_INT <= 27) {
87 | getView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
88 | }
89 | }
90 |
91 | @Override
92 | public void onLayout(boolean changed, int left, int top, int right, int bottom) {
93 | if (!canClip()) return;
94 | if (changed) requestShapeUpdate();
95 | }
96 |
97 |
98 | private void calculateLayout(int width, int height) {
99 | rectView.reset();
100 | rectView.addRect(0f, 0f, 1f * getView().getWidth(), 1f * getView().getHeight(), Path.Direction.CW);
101 |
102 | if (width > 0 && height > 0) {
103 | clipPathManager.setupClipLayout(width, height);
104 | clipPath.reset();
105 | clipPath.set(clipPathManager.getClipPath());
106 |
107 | //invert the path for android P
108 | if (Build.VERSION.SDK_INT > 27) {
109 | final boolean success = rectView.op(clipPath, Path.Op.DIFFERENCE);
110 | }
111 |
112 | //this needs to be fixed for 25.4.0
113 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && ViewCompat.getElevation(getView()) > 0f) {
114 | try {
115 | getView().setOutlineProvider(getView().getOutlineProvider());
116 | } catch (Exception e) {
117 | e.printStackTrace();
118 | }
119 | }
120 | }
121 |
122 | getView().postInvalidate();
123 | }
124 |
125 | /**
126 | * 请求更新
127 | */
128 | public void requestShapeUpdate() {
129 | this.requestShapeUpdate = true;
130 | getView().postInvalidate();
131 | }
132 |
133 | public View getView() {
134 | return mView;
135 | }
136 |
137 | /**
138 | * 是否满足裁剪条件
139 | *
140 | * @return
141 | */
142 | public boolean canClip() {
143 | return getView() != null && getView() instanceof ViewGroup && mClipLayout;
144 | }
145 |
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/clip/ClipPathManager.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.clip;
2 |
3 | import android.graphics.Path;
4 |
5 | public class ClipPathManager {
6 |
7 | protected final Path path = new Path();
8 |
9 | public ClipPathManager() {
10 | }
11 |
12 | /**
13 | * 设置裁剪布局
14 | *
15 | * @param width
16 | * @param height
17 | */
18 | public void setupClipLayout(int width, int height) {
19 | path.reset();
20 | Path clipPath = null;
21 | if (createClipPath != null) {
22 | clipPath = createClipPath.createClipPath(width, height);
23 | }
24 | if (clipPath != null) {
25 | path.set(clipPath);
26 | }
27 | }
28 |
29 | /**
30 | * 设置裁剪路径
31 | *
32 | * @return
33 | */
34 | public Path getClipPath() {
35 | return path;
36 | }
37 |
38 | /**
39 | * 创建Path接口
40 | */
41 | private ClipPathCreator createClipPath = null;
42 |
43 | public void setClipPathCreator(ClipPathCreator createClipPath) {
44 | this.createClipPath = createClipPath;
45 | }
46 |
47 | public interface ClipPathCreator {
48 | Path createClipPath(int width, int height);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/clip/IClip.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.clip;
2 |
3 | import android.graphics.Canvas;
4 |
5 | /**
6 | * IClip
7 | *
8 | * @author ZhongDaFeng
9 | */
10 | public interface IClip {
11 |
12 | public void dispatchDraw(Canvas canvas);
13 |
14 | public void onLayout(boolean changed, int left, int top, int right, int bottom);
15 | }
16 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/helper/RCheckHelper.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.helper;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.CompoundButton;
6 |
7 | /**
8 | * Check-Helper
9 | *
10 | * @author ZhongDaFeng
11 | */
12 | public class RCheckHelper extends RTextViewHelper {
13 |
14 | public RCheckHelper(Context context, CompoundButton view, AttributeSet attrs) {
15 | super(context, view, attrs);
16 | }
17 |
18 | @Override
19 | protected boolean isCompoundButtonChecked() {
20 | if (mView != null) return ((CompoundButton) mView).isChecked();
21 | return false;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/iface/ITextViewFeature.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.iface;
2 |
3 | import android.view.MotionEvent;
4 | import android.view.View;
5 |
6 | /**
7 | * TextView特性功能接口
8 | *
9 | * @author ZhongDaFeng
10 | */
11 | public interface ITextViewFeature {
12 | public void setEnabled(boolean enabled);
13 |
14 | public void onTouchEvent(MotionEvent event);
15 |
16 | public void setSelected(boolean selected);
17 |
18 | public void drawIconWithText();
19 | }
20 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/iface/RHelper.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.iface;
2 |
3 | import com.ruffian.library.widget.helper.RBaseHelper;
4 |
5 | /**
6 | * Helper
7 | *
8 | * @author ZhongDaFeng
9 | */
10 | public interface RHelper {
11 | T getHelper();
12 | }
13 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/rounded/RoundDrawable.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.rounded;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapShader;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.ColorFilter;
8 | import android.graphics.Matrix;
9 | import android.graphics.Paint;
10 | import android.graphics.Path;
11 | import android.graphics.PixelFormat;
12 | import android.graphics.Rect;
13 | import android.graphics.RectF;
14 | import android.graphics.Shader;
15 | import android.graphics.drawable.BitmapDrawable;
16 | import android.graphics.drawable.Drawable;
17 | import android.graphics.drawable.LayerDrawable;
18 | import android.support.annotation.NonNull;
19 | import android.support.annotation.Nullable;
20 | import android.widget.ImageView;
21 |
22 | /**
23 | * Round Drawable
24 | *
25 | * @author ZhongDaFeng
26 | */
27 | public class RoundDrawable extends Drawable {
28 |
29 | private Bitmap mBitmap;
30 | private final int mBitmapWidth;
31 | private final int mBitmapHeight;
32 | private final RectF mBitmapRect = new RectF();
33 |
34 | private final Paint mBitmapPaint;
35 | private final Paint mBorderPaint;
36 |
37 | private final RectF mBorderRect = new RectF();
38 | private final RectF mDrawableRect = new RectF();
39 |
40 | private Path mPath = new Path();
41 | private RectF mRectF = new RectF();
42 | private final RectF mBounds = new RectF();
43 | private final RectF mBoundsFinal = new RectF();
44 |
45 | private boolean mRebuildShader = true;
46 | private final Matrix mShaderMatrix = new Matrix();
47 | private ImageView.ScaleType mScaleType = ImageView.ScaleType.FIT_CENTER;
48 |
49 | //圆角
50 | private float mCorner = -1;
51 | private float mCornerTopLeft = 0;
52 | private float mCornerTopRight = 0;
53 | private float mCornerBottomLeft = 0;
54 | private float mCornerBottomRight = 0;
55 | private float mCornerRadii[] = new float[8];
56 | //边框
57 | private float mBorderWidth = 0;
58 | private int mBorderColor = Color.BLACK;
59 | //是否圆形
60 | private boolean mCircle = true;
61 |
62 | public RoundDrawable(Bitmap bitmap) {
63 | mBitmap = bitmap;
64 | mBitmapWidth = bitmap.getWidth();
65 | mBitmapHeight = bitmap.getHeight();
66 | mBitmapRect.set(0, 0, mBitmapWidth, mBitmapHeight);
67 |
68 | mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
69 | mBitmapPaint.setStyle(Paint.Style.FILL);
70 | mBitmapPaint.setAntiAlias(true);
71 |
72 | mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
73 | mBorderPaint.setStyle(Paint.Style.STROKE);
74 | mBorderPaint.setAntiAlias(true);
75 | updateBorder();
76 | }
77 |
78 | @Override
79 | protected void onBoundsChange(Rect bounds) {
80 | super.onBoundsChange(bounds);
81 | mBoundsFinal.set(bounds);//更新Bounds
82 | updateShaderMatrix();//更新变化矩阵
83 | updateConner();//更新圆角
84 | }
85 |
86 | @Override
87 | public void setAlpha(int alpha) {
88 | mBitmapPaint.setAlpha(alpha);
89 | invalidateSelf();
90 | }
91 |
92 | @Override
93 | public void setColorFilter(@Nullable ColorFilter colorFilter) {
94 | mBitmapPaint.setColorFilter(colorFilter);
95 | invalidateSelf();
96 | }
97 |
98 | @Override
99 | public int getOpacity() {
100 | return PixelFormat.TRANSLUCENT;
101 | }
102 |
103 | @Override
104 | public void draw(@NonNull Canvas canvas) {
105 |
106 | if (mRebuildShader) {
107 | BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
108 | bitmapShader.setLocalMatrix(mShaderMatrix);// Shader.TileMode.CLAMP
109 | mBitmapPaint.setShader(bitmapShader);
110 | mRebuildShader = false;
111 | }
112 |
113 | if (mCircle) {
114 | // mDrawableRect 宽高是实际显示图片的宽高,类似于 marginTop 了 mDrawableRect.left
115 | float cx = mDrawableRect.width() / 2f + mDrawableRect.left;
116 | float cy = mDrawableRect.height() / 2f + mDrawableRect.top;
117 | float radiusX = mDrawableRect.width() / 2f;
118 | float radiusY = mDrawableRect.height() / 2f;
119 | float radiusDrawable = Math.min(radiusX, radiusY);
120 | float radiusBitmap = Math.min(mBitmapHeight, mBitmapWidth);
121 | float radius = Math.min(radiusBitmap, radiusDrawable);
122 | canvas.drawCircle(cx, cy, radius, mBitmapPaint);
123 |
124 | if (mBorderWidth > 0) {
125 | cx = mBorderRect.width() / 2f + mBorderRect.left;
126 | cy = mBorderRect.height() / 2f + mBorderRect.top;
127 | radiusX = mBorderRect.width() / 2f;
128 | radiusY = mBorderRect.height() / 2f;
129 | radiusDrawable = Math.min(radiusX, radiusY);
130 | radiusBitmap = Math.min(mBitmapHeight, mBitmapWidth);
131 | radius = Math.min(radiusBitmap, radiusDrawable);
132 | canvas.drawCircle(cx, cy, radius, mBorderPaint);
133 | }
134 | } else {
135 | updateDrawablePath();
136 | canvas.drawPath(mPath, mBitmapPaint);
137 | if (mBorderWidth > 0) {
138 | updateBorderPath();
139 | canvas.drawPath(mPath, mBorderPaint);
140 | }
141 | }
142 | }
143 |
144 | /**
145 | * 更新圆角
146 | */
147 | private void updateConner() {
148 | if (mCorner >= 0) {
149 | for (int i = 0; i < mCornerRadii.length; i++) {
150 | mCornerRadii[i] = mCorner;
151 | }
152 | return;
153 | }
154 |
155 | if (mCorner < 0) {
156 | mCornerRadii[0] = mCornerTopLeft;
157 | mCornerRadii[1] = mCornerTopLeft;
158 | mCornerRadii[2] = mCornerTopRight;
159 | mCornerRadii[3] = mCornerTopRight;
160 | mCornerRadii[4] = mCornerBottomRight;
161 | mCornerRadii[5] = mCornerBottomRight;
162 | mCornerRadii[6] = mCornerBottomLeft;
163 | mCornerRadii[7] = mCornerBottomLeft;
164 | return;
165 | }
166 | }
167 |
168 | /**
169 | * 更新Drawable路径
170 | */
171 | private void updateDrawablePath() {
172 | mPath.reset();//must重置
173 | mPath.addRoundRect(mDrawableRect, mCornerRadii, Path.Direction.CCW);
174 | }
175 |
176 | /**
177 | * 更新边框路径
178 | */
179 | private void updateBorderPath() {
180 | mPath.reset();//must重置
181 | mPath.addRoundRect(mBorderRect, mCornerRadii, Path.Direction.CCW);
182 | }
183 |
184 | /**
185 | * 根据ScaleType更新ShaderMatrix
186 | * 此函数涉及更新的属性:mBorderWidth || mScaleType || mCircle
187 | */
188 | private void updateShaderMatrix() {
189 | float scale;
190 | float dx = 0, dy = 0;
191 | float height, width;
192 | float half = mBorderWidth / 2f;
193 | mBounds.set(mBoundsFinal);
194 | switch (mScaleType) {
195 | case CENTER_INSIDE:
196 | if (mBitmapWidth <= mBounds.width() && mBitmapHeight <= mBounds.height()) {
197 | scale = 1.0f;
198 | height = mBitmapHeight;
199 | width = mBitmapWidth;
200 | } else {//bitmap > drawable
201 | scale = Math.min(mBounds.width() / (float) mBitmapWidth, mBounds.height() / (float) mBitmapHeight);
202 | if (mBounds.height() < mBounds.width()) {//高<宽
203 | height = mBounds.height();
204 | width = mBitmapWidth * scale;
205 | } else if (mBounds.height() > mBounds.width()) {//宽<高
206 | height = mBitmapHeight * scale;
207 | width = mBounds.width();
208 | } else {//宽=高
209 | height = mBitmapHeight * scale;
210 | width = mBitmapWidth * scale;
211 | }
212 | }
213 | //X,Y偏移
214 | dx = (int) ((mBounds.width() - mBitmapWidth * scale) * 0.5f + 0.5f);
215 | dy = (int) ((mBounds.height() - mBitmapHeight * scale) * 0.5f + 0.5f);
216 |
217 | mRectF = new RectF(dx, dy, width + dx, height + dy);
218 | mRectF.inset(mCircle ? mBorderWidth : half, mCircle ? mBorderWidth : half);//非圆 1/2兼容圆角
219 | mShaderMatrix.reset();
220 | mShaderMatrix.setScale(scale, scale);
221 | mShaderMatrix.postTranslate(dx, dy);
222 | break;
223 | case CENTER:
224 | height = Math.min(mBounds.height(), mBitmapRect.height());
225 | width = Math.min(mBounds.width(), mBitmapRect.width());
226 | //裁剪或者Margin(如果View大,则 margin Bitmap,如果View小则裁剪Bitmap)
227 | float cutOrMarginH = mBounds.height() - mBitmapRect.height();
228 | float cutOrMarginW = mBounds.width() - mBitmapRect.width();
229 | float halfH = cutOrMarginH / 2f, halfW = cutOrMarginW / 2f;
230 | float top = halfH > 0 ? halfH : 0;
231 | float left = halfW > 0 ? halfW : 0;
232 | dx = halfW;
233 | dy = halfH;
234 |
235 | mRectF = new RectF(left, top, left + width, top + height);
236 | mRectF.inset(mCircle ? mBorderWidth : half, mCircle ? mBorderWidth : half);//非圆 1/2兼容圆角
237 | mShaderMatrix.reset();
238 | mShaderMatrix.postTranslate((int) (dx + 0.5f) + half, (int) (dy + 0.5f) + half);
239 | break;
240 | case CENTER_CROP:
241 | mRectF.set(mBounds);
242 | mRectF.inset(mCircle ? mBorderWidth : half, mCircle ? mBorderWidth : half);//非圆 1/2兼容圆角
243 | if (mBitmapWidth * mRectF.height() > mRectF.width() * mBitmapHeight) {
244 | scale = mRectF.height() / (float) mBitmapHeight;
245 | dx = (mRectF.width() - mBitmapWidth * scale) * 0.5f;
246 | } else {
247 | scale = mRectF.width() / (float) mBitmapWidth;
248 | dy = (mRectF.height() - mBitmapHeight * scale) * 0.5f;
249 | }
250 | mShaderMatrix.reset();
251 | mShaderMatrix.setScale(scale, scale);
252 | mShaderMatrix.postTranslate((int) (dx + 0.5f) + half, (int) (dy + 0.5f) + half);
253 | break;
254 | default:
255 | case FIT_CENTER:
256 | case FIT_END:
257 | case FIT_START:
258 | mBounds.inset(mCircle ? mBorderWidth : half, mCircle ? mBorderWidth : half);//非圆 1/2兼容圆角
259 | mRectF.set(mBitmapRect);
260 | mShaderMatrix.setRectToRect(mBitmapRect, mBounds, scaleTypeToScaleToFit(mScaleType));
261 | mShaderMatrix.mapRect(mRectF);
262 | mShaderMatrix.setRectToRect(mBitmapRect, mRectF, Matrix.ScaleToFit.FILL);
263 | break;
264 | case FIT_XY:
265 | mBounds.inset(mCircle ? mBorderWidth : half, mCircle ? mBorderWidth : half);//非圆 1/2兼容圆角
266 | mRectF.set(mBounds);
267 | mShaderMatrix.reset();
268 | mShaderMatrix.setRectToRect(mBitmapRect, mRectF, Matrix.ScaleToFit.FILL);
269 | break;
270 | }
271 | if (mCircle) {
272 | mBorderRect.set(mRectF.left - half, mRectF.top - half, mRectF.right + half, mRectF.bottom + half);//还原
273 | } else {
274 | mBorderRect.set(mBoundsFinal);
275 | mBorderRect.inset(half, half);
276 | }
277 | mDrawableRect.set(mRectF);
278 | mRebuildShader = true;
279 | }
280 |
281 | /**
282 | * 更新边框
283 | */
284 | private void updateBorder() {
285 | mBorderPaint.setColor(mBorderColor);
286 | mBorderPaint.setStrokeWidth(mBorderWidth);
287 | }
288 |
289 | public Bitmap getBitmap() {
290 | return mBitmap;
291 | }
292 |
293 | /**
294 | * 统一设置参数
295 | */
296 | public void setParams(ImageView.ScaleType scaleType, float borderWidth, int borderColor, boolean circle, float corner, float topLeft, float topRight, float bottomLeft, float bottomRight) {
297 | //scaleType
298 | if (scaleType == null) {
299 | scaleType = ImageView.ScaleType.FIT_CENTER;
300 | }
301 | if (mScaleType != scaleType) {
302 | mScaleType = scaleType;
303 | }
304 |
305 | //borderWidth
306 | mBorderWidth = borderWidth;
307 | //borderColor
308 | mBorderColor = borderColor;
309 | updateBorder();
310 |
311 | //circle
312 | mCircle = circle;
313 |
314 | //corner
315 | mCorner = corner;
316 | mCornerTopLeft = topLeft;
317 | mCornerTopRight = topRight;
318 | mCornerBottomLeft = bottomLeft;
319 | mCornerBottomRight = bottomRight;
320 | updateConner();
321 |
322 | //update
323 | updateShaderMatrix();//更新变化矩阵
324 | invalidateSelf();//更新
325 | }
326 |
327 | public RoundDrawable setScaleType(ImageView.ScaleType scaleType) {
328 | if (scaleType == null) {
329 | scaleType = ImageView.ScaleType.FIT_CENTER;
330 | }
331 | if (mScaleType != scaleType) {
332 | mScaleType = scaleType;
333 | updateShaderMatrix();//更新变化矩阵
334 | invalidateSelf();
335 | }
336 | return this;
337 | }
338 |
339 | public RoundDrawable setCircle(boolean circle) {
340 | mCircle = circle;
341 | updateShaderMatrix();//更新变化矩阵
342 | invalidateSelf();
343 | return this;
344 | }
345 |
346 | public RoundDrawable setBorderWidth(float borderWidth) {
347 | mBorderWidth = borderWidth;
348 | updateBorder();
349 | updateShaderMatrix();//更新变化矩阵
350 | invalidateSelf();
351 | return this;
352 | }
353 |
354 | public RoundDrawable setBorderColor(int borderColor) {
355 | mBorderColor = borderColor;
356 | updateBorder();
357 | invalidateSelf();
358 | return this;
359 | }
360 |
361 | public RoundDrawable setConner(float corner, float topLeft, float topRight, float bottomLeft, float bottomRight) {
362 | mCorner = corner;
363 | mCornerTopLeft = topLeft;
364 | mCornerTopRight = topRight;
365 | mCornerBottomLeft = bottomLeft;
366 | mCornerBottomRight = bottomRight;
367 | updateConner();
368 | invalidateSelf();
369 | return this;
370 | }
371 |
372 | public static RoundDrawable fromBitmap(Bitmap bitmap) {
373 | if (bitmap != null) {
374 | return new RoundDrawable(bitmap);
375 | } else {
376 | return null;
377 | }
378 | }
379 |
380 | public static Drawable fromDrawable(Drawable drawable) {
381 | if (drawable != null) {
382 | if (drawable instanceof RoundDrawable) {
383 | // just return if it's already a RoundedDrawable
384 | return drawable;
385 | } else if (drawable instanceof LayerDrawable) {
386 | ConstantState cs = drawable.mutate().getConstantState();
387 | LayerDrawable ld = (LayerDrawable) (cs != null ? cs.newDrawable() : drawable);
388 |
389 | int num = ld.getNumberOfLayers();
390 |
391 | // loop through layers to and change to RoundedDrawables if possible
392 | for (int i = 0; i < num; i++) {
393 | Drawable d = ld.getDrawable(i);
394 | ld.setDrawableByLayerId(ld.getId(i), fromDrawable(d));
395 | }
396 | return ld;
397 | }
398 |
399 | // try to get a bitmap from the drawable and
400 | Bitmap bm = drawableToBitmap(drawable);
401 | if (bm != null) {
402 | return new RoundDrawable(bm);
403 | }
404 | }
405 | return drawable;
406 | }
407 |
408 | public static Bitmap drawableToBitmap(Drawable drawable) {
409 | if (drawable instanceof BitmapDrawable) {
410 | return ((BitmapDrawable) drawable).getBitmap();
411 | }
412 |
413 | Bitmap bitmap;
414 | int width = Math.max(drawable.getIntrinsicWidth(), 2);
415 | int height = Math.max(drawable.getIntrinsicHeight(), 2);
416 | try {
417 | bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
418 | Canvas canvas = new Canvas(bitmap);
419 | drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
420 | drawable.draw(canvas);
421 | } catch (Throwable e) {
422 | e.printStackTrace();
423 | bitmap = null;
424 | }
425 |
426 | return bitmap;
427 | }
428 |
429 | private static Matrix.ScaleToFit scaleTypeToScaleToFit(ImageView.ScaleType st) {
430 | /**
431 | * 根据源码改造 sS2FArray[st.nativeInt - 1]
432 | */
433 | switch (st) {
434 | case FIT_XY:
435 | return Matrix.ScaleToFit.FILL;
436 | case FIT_START:
437 | return Matrix.ScaleToFit.START;
438 | case FIT_END:
439 | return Matrix.ScaleToFit.END;
440 | case FIT_CENTER:
441 | return Matrix.ScaleToFit.CENTER;
442 | default:
443 | return Matrix.ScaleToFit.CENTER;
444 | }
445 | }
446 | }
447 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/shadow/ShadowBitmapDrawable.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.shadow;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.Path;
7 | import android.graphics.Rect;
8 | import android.graphics.RectF;
9 | import android.graphics.drawable.BitmapDrawable;
10 |
11 | import com.ruffian.library.widget.utils.ReflectUtils;
12 |
13 | import java.util.Arrays;
14 |
15 | /**
16 | * ShadowBitmapDrawable
17 | *
18 | * @author ZhongDaFeng
19 | */
20 | public class ShadowBitmapDrawable extends BitmapDrawable {
21 |
22 |
23 | private int mShadowColor;//阴影颜色
24 | private float mShadowRadius;//阴影半径
25 | private float[] mRoundRadii;//矩形圆角半径
26 | private int mShadowDx;//阴影x偏移
27 | private int mShadowDy;//阴影y偏移
28 |
29 | private RectF mBoundsF;
30 |
31 | public ShadowBitmapDrawable() {
32 | mBoundsF = new RectF();
33 | }
34 |
35 | /**
36 | * RBaseHelp中属性修改时调用
37 | *
38 | * @param shadowColor
39 | * @param shadowRadius
40 | * @param shadowDx
41 | * @param shadowDy
42 | * @param roundRadii
43 | */
44 | public void updateParameter(int shadowColor, float shadowRadius, int shadowDx, int shadowDy, float[] roundRadii) {
45 | boolean needUpdate = false;
46 | if (mShadowColor != shadowColor || mShadowRadius != shadowRadius
47 | || mShadowDx != shadowDx || mShadowDy != shadowDy
48 | || !Arrays.equals(mRoundRadii, roundRadii)) {
49 | needUpdate = true;
50 | }
51 | this.mShadowColor = shadowColor;
52 | this.mRoundRadii = roundRadii;
53 | this.mShadowRadius = shadowRadius;
54 | this.mShadowDx = shadowDx;
55 | this.mShadowDy = shadowDy;
56 |
57 | if (needUpdate) {
58 | //重新创建bitmap
59 | Bitmap bitmap = makeShadowBitmap((int) mBoundsF.width(), (int) mBoundsF.height(), mShadowRadius, mShadowDx, mShadowDy, mShadowColor, mRoundRadii);
60 |
61 | //反射调用函数 setBitmap 更新阴影图片
62 | ReflectUtils.invokeMethod(this, "setBitmap", new Class[]{Bitmap.class}, new Object[]{bitmap});
63 | }
64 |
65 |
66 | }
67 |
68 | @Override
69 | protected void onBoundsChange(Rect bounds) {
70 | super.onBoundsChange(bounds);
71 | if (bounds.right - bounds.left > 0 && bounds.bottom - bounds.top > 0) {
72 | updateBounds(bounds);
73 | }
74 | }
75 |
76 | /**
77 | * 更新Bounds
78 | *
79 | * @param bounds
80 | */
81 | private void updateBounds(Rect bounds) {
82 | if (bounds == null) bounds = getBounds();
83 |
84 | float left = bounds.left + mShadowRadius + Math.abs(mShadowDx);
85 | float right = bounds.right - mShadowRadius - Math.abs(mShadowDx);
86 | float top = bounds.top + mShadowRadius + Math.abs(mShadowDy);
87 | float bottom = bounds.bottom - mShadowRadius - Math.abs(mShadowDy);
88 |
89 | mBoundsF.set(left, top, right, bottom);
90 |
91 | //重新创建bitmap(不等高列表复用时可能会出现内存抖动,待优化)
92 | Bitmap bitmap = makeShadowBitmap((int) mBoundsF.width(), (int) mBoundsF.height(), mShadowRadius, mShadowDx, mShadowDy, mShadowColor, mRoundRadii);
93 |
94 | //反射调用函数 setBitmap 更新阴影图片
95 | ReflectUtils.invokeMethod(this, "setBitmap", new Class[]{Bitmap.class}, new Object[]{bitmap});
96 |
97 | }
98 |
99 |
100 | /**
101 | * 创建阴影Bitmap
102 | *
103 | * @param shadowWidth
104 | * @param shadowHeight
105 | * @param shadowRadius
106 | * @param dx
107 | * @param dy
108 | * @param shadowColor
109 | * @param radii
110 | * @return
111 | */
112 | public Bitmap makeShadowBitmap(int shadowWidth, int shadowHeight, float shadowRadius,
113 | float dx, float dy, int shadowColor, float[] radii) {
114 |
115 | //容错处理
116 | if (shadowWidth <= 0 || shadowHeight <= 0)
117 | return Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_4444);
118 |
119 |
120 | //阴影bitmap
121 | Bitmap output = Bitmap.createBitmap(shadowWidth, shadowHeight, Bitmap.Config.ARGB_4444);
122 | Canvas canvas = new Canvas(output);
123 |
124 | RectF shadowRect = new RectF(shadowRadius, shadowRadius, shadowWidth - shadowRadius, shadowHeight - shadowRadius);
125 |
126 |
127 | //存在偏移时重新计算阴影矩形大小
128 | shadowRect.top += Math.abs(dy);
129 | shadowRect.bottom -= Math.abs(dy);
130 | shadowRect.left += Math.abs(dx);
131 | shadowRect.right -= Math.abs(dx);
132 |
133 | //阴影画笔
134 | Paint shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
135 | shadowPaint.setColor(shadowColor);
136 | shadowPaint.setShadowLayer(shadowRadius, dx, dy, shadowColor);
137 |
138 | //路径
139 | Path path = new Path();
140 | path.addRoundRect(shadowRect, radii, Path.Direction.CW);
141 | canvas.drawPath(path, shadowPaint);
142 |
143 | return output;
144 | }
145 |
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/shadow/ShadowDrawable.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.shadow;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.ColorFilter;
5 | import android.graphics.Paint;
6 | import android.graphics.Path;
7 | import android.graphics.PixelFormat;
8 | import android.graphics.Rect;
9 | import android.graphics.RectF;
10 | import android.graphics.drawable.Drawable;
11 | import android.support.annotation.Nullable;
12 |
13 | /**
14 | * Shadow Drawable
15 | *
16 | * @author ZhongDaFeng
17 | */
18 | public class ShadowDrawable extends Drawable {
19 |
20 | private int mShadowColor;//阴影颜色
21 | private float mShadowRadius;//阴影半径
22 | private float[] mRoundRadii;//矩形圆角半径
23 | private int mShadowDx;//阴影x偏移
24 | private int mShadowDy;//阴影y偏移
25 |
26 | private Path mPath;
27 | private Paint mPaint;
28 | private RectF mBoundsF;
29 |
30 | public ShadowDrawable() {
31 | mPath = new Path();
32 | mBoundsF = new RectF();
33 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
34 | }
35 |
36 | public void updateParameter(int shadowColor, float shadowRadius, int shadowDx, int shadowDy, float[] roundRadii) {
37 | this.mShadowColor = shadowColor;
38 | this.mRoundRadii = roundRadii;
39 | this.mShadowRadius = shadowRadius;
40 | this.mShadowDx = shadowDx;
41 | this.mShadowDy = shadowDy;
42 | /**
43 | * 设置阴影
44 | */
45 | mPaint.setColor(mShadowColor);
46 | mPaint.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor);
47 | }
48 |
49 | @Override
50 | protected void onBoundsChange(Rect bounds) {
51 | super.onBoundsChange(bounds);
52 | if (bounds.right - bounds.left > 0 && bounds.bottom - bounds.top > 0) {
53 | updateBounds(bounds);
54 | }
55 | }
56 |
57 | /**
58 | * 更新Bounds
59 | *
60 | * @param bounds
61 | */
62 | private void updateBounds(Rect bounds) {
63 | if (bounds == null) bounds = getBounds();
64 | /**
65 | * 算法1 => 存在偏移的方向增加宽度 (效果不是很好)
66 | */
67 | /* float left = bounds.left + getShadowOffsetHalf() + offset;
68 | left = mShadowDx < 0 ? left + Math.abs(mShadowDx) : left;
69 |
70 | float right = bounds.right - getShadowOffsetHalf() - offset;
71 | right = mShadowDx > 0 ? right - Math.abs(mShadowDx) : right;
72 |
73 | float top = bounds.top + getShadowOffsetHalf() + offset;
74 | top = mShadowDy < 0 ? top + Math.abs(mShadowDy) : top;
75 |
76 | float bottom = bounds.bottom - getShadowOffsetHalf() - offset;
77 | bottom = mShadowDy > 0 ? bottom - Math.abs(mShadowDy) : bottom;*/
78 |
79 | /**
80 | * 算法2 => 水平/垂直存在偏移,对应方向增加间距
81 | */
82 | float left = bounds.left + getShadowOffset() + Math.abs(mShadowDx);
83 | float right = bounds.right - getShadowOffset() - Math.abs(mShadowDx);
84 | float top = bounds.top + getShadowOffset() + Math.abs(mShadowDy);
85 | float bottom = bounds.bottom - getShadowOffset() - Math.abs(mShadowDy);
86 |
87 | mBoundsF.set(left, top, right, bottom);
88 | mPath.reset();//must重置
89 | mPath.addRoundRect(mBoundsF, mRoundRadii, Path.Direction.CW);
90 | }
91 |
92 | @Override
93 | public void draw(Canvas canvas) {
94 | canvas.drawPath(mPath, mPaint);
95 | }
96 |
97 | @Override
98 | public void setAlpha(int alpha) {
99 | mPaint.setAlpha(alpha);
100 | }
101 |
102 | @Override
103 | public void setColorFilter(@Nullable ColorFilter colorFilter) {
104 | mPaint.setColorFilter(colorFilter);
105 | }
106 |
107 | @Override
108 | public int getOpacity() {
109 | return PixelFormat.TRANSLUCENT;
110 | }
111 |
112 | public float getShadowOffset() {
113 | return mShadowRadius;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/utils/ReflectUtils.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.utils;
2 |
3 | import java.lang.reflect.InvocationTargetException;
4 | import java.lang.reflect.Method;
5 |
6 | /**
7 | * 反射工具类
8 | *
9 | * @author ZhongDaFeng
10 | */
11 | public class ReflectUtils {
12 |
13 | /**
14 | * 循环向上转型, 获取对象的 DeclaredMethod
15 | *
16 | * @param object 子类对象
17 | * @param methodName 父类中的方法名
18 | * @param parameterTypes 父类中的方法参数类型
19 | * @return 父类中的方法对象
20 | */
21 | public static Method getDeclaredMethod(Object object, String methodName, Class>... parameterTypes) {
22 | Method method = null;
23 | for (Class> clazz = object.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
24 | try {
25 | method = clazz.getDeclaredMethod(methodName, parameterTypes);
26 | return method;
27 | } catch (Exception e) {
28 | //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。
29 | //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
30 | }
31 | }
32 | return null;
33 | }
34 |
35 | /**
36 | * 直接调用对象方法, 而忽略修饰符(private, protected, default)
37 | *
38 | * @param object 子类对象
39 | * @param methodName 父类中的方法名
40 | * @param parameterTypes 父类中的方法参数类型
41 | * @param parameters 父类中的方法参数
42 | * @return 父类中方法的执行结果
43 | */
44 | public static Object invokeMethod(Object object, String methodName, Class>[] parameterTypes, Object[] parameters) {
45 | //根据 对象、方法名和对应的方法参数 通过反射 调用上面的方法获取 Method 对象
46 | Method method = getDeclaredMethod(object, methodName, parameterTypes);
47 | try {
48 | if (null != method) {
49 | //抑制Java对方法进行检查,主要是针对私有方法而言
50 | method.setAccessible(true);
51 | //调用object 的 method 所代表的方法,其方法的参数是 parameters
52 | return method.invoke(object, parameters);
53 | }
54 | } catch (IllegalArgumentException e) {
55 | e.printStackTrace();
56 | } catch (IllegalAccessException e) {
57 | e.printStackTrace();
58 | } catch (InvocationTargetException e) {
59 | e.printStackTrace();
60 | }
61 | return null;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/utils/RippleDrawableUtils.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.utils;
2 |
3 | import android.content.res.ColorStateList;
4 | import android.graphics.drawable.Drawable;
5 | import android.graphics.drawable.RippleDrawable;
6 | import android.os.Build;
7 | import android.support.annotation.NonNull;
8 | import android.support.annotation.RequiresApi;
9 |
10 |
11 | /**
12 | * RippleDrawable包装类
13 | * 备注:此类没有实质意义,纯粹是绕一圈支持新版Android studio预览自定义View
14 | */
15 | public class RippleDrawableUtils {
16 |
17 | private Drawable contentDrawable, maskDrawable;
18 |
19 | /**
20 | * 此处的参数必须为Object类型,否则导致 Android studio 无法预览
21 | *
22 | * @param content
23 | * @param mask
24 | */
25 | public RippleDrawableUtils(Object content, Object mask) {
26 | this.contentDrawable = content == null ? null : (Drawable) content;
27 | this.maskDrawable = mask == null ? null : (Drawable) mask;
28 | }
29 |
30 | /**
31 | *
32 | * 新版Android studio 奇葩报错
33 | *
34 | * Exception Details java.lang.VerifyError: Bad type on operand stack Exception
35 | * Details: Location: com/ruffian/library/widget/helper/RBaseHelper.getRippleDrawableWithTag(ZI)[Ljava/lang/Object; @233: invokespecial
36 | * Reason: Type 'java/lang/Object' (current frame, stack[2]) is not assignable to 'android/graphics/drawable/Drawable'
37 | * Current Frame:
38 | * bci: @233
39 | * flags: { }
40 | * locals: { 'com/ruffian/library/widget/helper/RBaseHelper', integer, integer, 'java/lang/Object', 'java/lang/Object', '[[I', '[I', 'android/content/res/ColorStateList' }
41 | * stack: { uninitialized 226, uninitialized 226, 'java/lang/Object', 'java/lang/Object' }
42 | *
43 | */
44 |
45 | /**
46 | * 获取 RippleDrawable
47 | * 新版 Android studio 有个BUG,目标接收 Drawable 的参数,如果开发者传递 null 会报错:'java/lang/Object' is not assignable to 'android/graphics/drawable/Drawable
48 | * 这里曲线救国,改为 Object 接收 content 和 mask
49 | */
50 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
51 | public RippleDrawable getRippleDrawable(@NonNull ColorStateList color) {
52 | //color – The ripple color
53 | //content – The content drawable, may be null
54 | //mask – The mask drawable, may be null
55 | return new RippleDrawable(color, contentDrawable, maskDrawable);
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/library/src/main/java/com/ruffian/library/widget/utils/TextViewUtils.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget.utils;
2 |
3 | import android.graphics.Paint;
4 | import android.widget.TextView;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Collections;
8 |
9 | /**
10 | * TextView工具类
11 | *
12 | * @author ZhongDaFeng
13 | */
14 | public class TextViewUtils {
15 |
16 | private static TextViewUtils instance = null;
17 |
18 | private TextViewUtils() {
19 | }
20 |
21 | public static TextViewUtils get() {
22 | if (instance == null) {
23 | synchronized (TextViewUtils.class) {
24 | if (instance == null) {
25 | instance = new TextViewUtils();
26 | }
27 | }
28 | }
29 | return instance;
30 | }
31 |
32 |
33 | /**
34 | * 获取Text实际宽度
35 | * 备注:单行最大宽度
36 | *
37 | * @param view view
38 | * @param drawableWidth drawable宽度
39 | * @param paddingLeft 内边距-左
40 | * @param paddingRight 内边距-右
41 | * @param drawablePaddingHorizontal 水平方向上drawable间距
42 | * @return
43 | */
44 | public float getTextWidth(TextView view, int drawableWidth, int paddingLeft, int paddingRight, int drawablePaddingHorizontal) {
45 | if (view == null) return 0;
46 |
47 | float textWidth;
48 | /**
49 | * 1.是否存在\n换行(获取宽度最大的值)
50 | * 2.不存在\n获取单行宽度值(判断是否自动换行临界值)
51 | */
52 | String originalText = view.getText().toString();
53 | if (originalText.contains("\n")) {
54 | String[] originalTextArray;
55 | ArrayList widthList;
56 | originalTextArray = originalText.split("\n");
57 | int arrayLen = originalTextArray.length;
58 | widthList = new ArrayList<>(arrayLen);
59 | for (int i = 0; i < arrayLen; i++) {
60 | widthList.add(view.getPaint().measureText(originalTextArray[i]));
61 | }
62 | textWidth = Collections.max(widthList);
63 | } else {
64 | textWidth = view.getPaint().measureText(originalText);
65 | }
66 |
67 | //计算自动换行临界值,不允许超过换行临界值
68 | int maxWidth = view.getWidth() - drawableWidth - paddingLeft - paddingRight - drawablePaddingHorizontal;
69 | if (textWidth > maxWidth) {
70 | textWidth = maxWidth;
71 | }
72 | return textWidth;
73 | }
74 |
75 | /**
76 | * 获取Text实际高度
77 | * 备注:多行最大高度
78 | *
79 | * @param view view
80 | * @param drawableHeight drawable高度
81 | * @param paddingTop 内边距-左
82 | * @param paddingBottom 内边距-右
83 | * @param drawablePaddingVertical 垂直方向上drawable间距
84 | * @return
85 | */
86 | public float getTextHeight(TextView view, int drawableHeight, int paddingTop, int paddingBottom, int drawablePaddingVertical) {
87 | if (view == null) return 0;
88 |
89 | /**
90 | * 1.单行高度*行数
91 | * 2.最大高度临界值
92 | */
93 | Paint.FontMetrics fontMetrics = view.getPaint().getFontMetrics();
94 | float singleLineHeight = Math.abs((fontMetrics.bottom - fontMetrics.top));//单行高度
95 | float textHeight = singleLineHeight * view.getLineCount();
96 |
97 | //最大高度临界值,不允许超过最大高度临界值
98 | int maxHeight = view.getHeight() - drawableHeight - paddingTop - paddingBottom - drawablePaddingVertical;//最大允许的宽度
99 | if (textHeight > maxHeight) {
100 | textHeight = maxHeight;
101 | }
102 | return textHeight;
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/library/src/test/java/com/ruffian/library/widget/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ruffian.library.widget;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/picture/Gradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/Gradient.png
--------------------------------------------------------------------------------
/picture/REditText.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/REditText.png
--------------------------------------------------------------------------------
/picture/RImageView.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/RImageView.png
--------------------------------------------------------------------------------
/picture/RTextView_corner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/RTextView_corner.png
--------------------------------------------------------------------------------
/picture/RTextView_state.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/RTextView_state.gif
--------------------------------------------------------------------------------
/picture/RTextView_typeface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/RTextView_typeface.png
--------------------------------------------------------------------------------
/picture/RView.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/RView.png
--------------------------------------------------------------------------------
/picture/RViewGroup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/RViewGroup.png
--------------------------------------------------------------------------------
/picture/RWidgetHelper.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/RWidgetHelper.gif
--------------------------------------------------------------------------------
/picture/all.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/all.gif
--------------------------------------------------------------------------------
/picture/part1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/part1.png
--------------------------------------------------------------------------------
/picture/part2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/part2.png
--------------------------------------------------------------------------------
/picture/part3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/part3.png
--------------------------------------------------------------------------------
/picture/part4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/part4.png
--------------------------------------------------------------------------------
/picture/part5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/part5.png
--------------------------------------------------------------------------------
/picture/ripple.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/ripple.gif
--------------------------------------------------------------------------------
/picture/shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RuffianZhong/RWidgetHelper/377b1598641a0a7d07a770a543da5e80d0cf59f6/picture/shadow.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library', ':library'
2 |
--------------------------------------------------------------------------------