├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE.txt ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── co │ │ └── ceryle │ │ └── radiorealbutton │ │ ├── BackgroundHelper.java │ │ ├── BackgroundView.java │ │ ├── ConversionHelper.java │ │ ├── RadioRealButton.java │ │ ├── RadioRealButtonGroup.java │ │ ├── RippleHelper.java │ │ ├── RoundHelper.java │ │ └── RoundedCornerLayout.java │ └── res │ └── values │ └── attrs.xml ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── fonts │ │ ├── aniron.ttf │ │ └── shaka_pow.ttf │ ├── java │ └── co │ │ └── ceryle │ │ └── radiorealbutton │ │ └── sample │ │ └── MainActivity.java │ └── res │ ├── drawable-nodpi │ ├── aragorn.png │ ├── b1.png │ ├── b11.png │ ├── b12.png │ ├── b13.png │ ├── b17.png │ ├── b2.png │ ├── b3.png │ ├── b4.png │ ├── b5.png │ ├── b6.png │ ├── b7.png │ ├── b8.png │ ├── b9.png │ ├── gimli.png │ └── legolas.png │ ├── drawable │ └── ic_android_black_24dp.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | Android API 15 Platform 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-RadioRealButton-green.svg?style=true)](https://android-arsenal.com/details/1/4258) [![](https://jitpack.io/v/ceryle/RadioRealButton.svg)](https://jitpack.io/#ceryle/RadioRealButton) 2 | 3 | ## Archived 4 | I stopped developing this library for a long time ago. I thought about revising it recently but I think there is no need for it anymore due to Jetpack Compose. As an alternative to this, I recommend you to use this library made with Jetpack Compose by Zack Klippenstein: https://gist.github.com/zach-klippenstein/7ae8874db304f957d6bb91263e292117 5 | 6 | Thank you all for your support. 7 | 8 | # RadioRealButton 9 | 10 | ![poster](https://cloud.githubusercontent.com/assets/20969019/18050549/f8399734-6df7-11e6-9a2c-511a22956193.png) 11 | 12 | Radio Real Button is a substitute of the Radio Button. Its purpose is to give more elegant view for Android users. 13 | 14 | ## Preview 15 | ![1](https://cloud.githubusercontent.com/assets/20969019/24070628/e081f5f8-0bc9-11e7-9791-9db6d4e25ece.gif) 16 |
17 | ![2](https://cloud.githubusercontent.com/assets/20969019/23513066/77a25146-ff6b-11e6-8af1-cbd68bf5aec4.gif) 18 |
19 | ![3a](https://cloud.githubusercontent.com/assets/20969019/18049724/9f878100-6df2-11e6-9b3d-e3a01a59727d.gif) 20 | ![3b](https://cloud.githubusercontent.com/assets/20969019/18049725/9f887a42-6df2-11e6-8974-413950c61ed5.gif) 21 |
22 | ![4](https://cloud.githubusercontent.com/assets/20969019/18049727/9f94a222-6df2-11e6-9271-83a4ad714703.gif) 23 |
24 | ![5](https://cloud.githubusercontent.com/assets/20969019/18049726/9f8d4c8e-6df2-11e6-8819-94d82c305667.gif) 25 |
26 | ![6](https://cloud.githubusercontent.com/assets/20969019/19188191/c70cc8ec-8c98-11e6-9bae-9571e43f645e.gif) 27 | 28 | 29 | ## Installation 30 | 31 | #### Gradle 32 | 33 | Add it to your build.gradle with: 34 | ```gradle 35 | allprojects { 36 | repositories { 37 | maven { url "https://jitpack.io" } 38 | } 39 | } 40 | ``` 41 | and: 42 | 43 | ```gradle 44 | dependencies { 45 | compile 'com.github.ceryle:RadioRealButton:v2.1.1' 46 | } 47 | ``` 48 | 49 | ### What has changed with version 2? 50 | - Border is now part of the round container layout. 51 | - android:padding and rest padding attributes were working not as expected. Now, they are fixed. 52 | - textTypeface attribute now works like button's typeface. You can give your typeface using textTypefacePath attribute. 53 | - Default scaling value is now 1 as it has to be. 54 | ##### What added? 55 | - New animations added. There was only a sliding view, but now 4 more added. You can use them with app:selectorAnimationType attribute. 56 | - enableDeselection attribute is added. With this attribute, you can deselect buttons if you re-click on them. 57 | - Each button has their own selector (sliding selector has still one) and you can give divider between them. 58 | - textGravity attribute is added which is actually android:gravity. You can give 3 values which are left, center, right. 59 | 60 | ##### What removed? 61 | - 'image' word is replaced with "drawable" word from all attributes which have them. Reason is everyone is used to 'drawable' word and 62 | how I have used ImageView in RadioRealButton is no different than regular drawable which is used in buttons expect animations. 63 | - rrbg_shadow, rrbg_shadowElevation and its margin attributes are removed. You can use android:elevation attribute. 64 | - rrbg_enabled is removed. You can use android:enabled attribute. 65 | 66 | 67 | ## Customization 68 | 69 | ### Some Attributes 70 | 71 | #### Radio Real Button 72 | | Option Name | Format | Description | 73 | | ----------------- | ----------- | --------------------------------------------------------- | 74 | | drawable | `integer` | set drawable to button | 75 | | drawablePadding | `dimension` | set padding between text and drawable | 76 | | drawableTint | `color` | set drawable tint by giving a color code or reference | 77 | | drawableWidth | `dimension` | change drawable's width | 78 | | drawableHeight | `dimension` | change drawable's height | 79 | | drawableGravity | `integer` | set drawable position relative to text | 80 | | text | `string` | set button's text | 81 | | textColor | `color` | change button's text color | 82 | | textSize | `dimension` | change button's text size | 83 | | textTypeface | `integer` | default typefaces offered by android itself | 84 | | textTypefacePath | `string` | give your typeface by giving its path | 85 | | textFillSpace | `boolean` | when enabled, it pushes drawable to edges of the button | 86 | | textStyle | `integer` | default styles offered by android itself | 87 | | textGravity | `integer` | give text gravity(not layout_gravity) | 88 | | ripple | `boolean` | set it true for default ripple | 89 | | rippleColor | `color` | give any color to achieve colorful ripples | 90 | | backgroundColor | `color` | give background color by giving a color code or reference | 91 | | checked | `boolean` | its usage is the same as radio button | 92 | 93 | #### Radio Real Button Group 94 | | Option Name | Format | Description | 95 | | ------------------------- | ----------- | ----------------------------- | 96 | | radius | `integer` | set radius to make radio real button group rounder | 97 | | borderSize | `dimension` | adds border to group with the given size | 98 | | borderColor | `dimension` | changes border color | 99 | | backgroundColor | `color` | give background color by giving a color code or reference | 100 | | enableDeselection | `color` | enable deselection to un-check a button | 101 | | dividerSize | `dimension` | set divider size for the line between buttons | 102 | | dividerPadding | `dimension` | gives padding to divider's top and bottom | 103 | | dividerColor | `color` | give color code or reference | 104 | | dividerRadius | `dimension` | give dimension to make divider's corners rounder | 105 | | selectorDividerSize | `dimension` | set selector divider size for the line between buttons | 106 | | selectorDividerPadding | `dimension` | gives padding to selector divider's top and bottom | 107 | | selectorDividerColor | `color` | give color code or reference | 108 | | selectorDividerRadius | `dimension` | give dimension to make selector divider's corners rounder | 109 | | bottomLineColor | `color` | set bottom line color | 110 | | bottomLineSize | `dimension` | set bottom line height | 111 | | bottomLineBringToFront | `boolean` | if it is true, it brings bottomLine on top of selector | 112 | | bottomLineRadius | `dimension` | give dimension to make bottomLine's corners rounder | 113 | | selectorTop | `boolean` | align selector to top | 114 | | selectorBottom | `boolean` | align selector to bottom | 115 | | selectorColor | `color` | set color of selector | 116 | | selectorSize | `dimension` | set height of selector | 117 | | selectorRadius | `dimension` | give dimension to make selector's corners rounder | 118 | | selectorBringToFront | `boolean` | if it is true, it brings selector on top of everything | 119 | | selectorAboveOfBottomLine | `boolean` | if it is true, it brings selector above of bottom line | 120 | | selectorFullSize | `boolean` | selector fills space up to button's height | 121 | | checkedPosition | `integer` | check a button by a position number | 122 | | checkedButton | `reference` | check a button by button's unique id | 123 | | animate | `boolean` | set animation on bottom moving view | 124 | | animateSelector | `integer` | gives interpolator to selector | 125 | | animateSelector_delay | `integer` | gives delay to selector's animation when it enters | 126 | | animateSelector_duration | `integer` | animation duration of selector in ms | 127 | | animateDrawables_scale | `float` | adjust drawable's size when it is checked | 128 | | animateDrawables_enter | `integer` | enter animation on drawable when button is checked | 129 | | animateDrawables_enterDuration | `integer` | enter animation duration of drawable in ms | 130 | | animateDrawables_exit | `integer` | exit animation on drawable when other button is checked | 131 | | animateDrawables_exitDuration | `integer` | exit animation duration of drawable in ms | 132 | | animateTexts_scale | `float` | adjust text's size when it is checked | 133 | | animateTexts_enter | `integer` | enter animation on text when button is checked | 134 | | animateTexts_enterDuration | `integer` | enter animation duration of text in ms | 135 | | animateTexts_exit | `integer` | exit animation on text when other button is checked | 136 | | animateTexts_exitDuration | `integer` | exit animation duration of text in ms | 137 | | animateDrawables_tintColorFrom | `color` | initial color for drawable's tint color transition animation | 138 | | animateDrawables_tintColorTo | `color` | final color for drawable's tint color transition animation | 139 | | animateDrawables_tintColor_duration | `integer` | total animation duration of drawable's tint transition in ms | 140 | | animateTexts_textColorFrom | `color` | initial color for text's text color transition animation | 141 | | animateTexts_textColorTo | `color` | final color for text's text color transition animation | 142 | | animateTexts_textColor_duration | `integer` | total animation duration of text's text color in ms | 143 | 144 | 145 | #### Examples 146 | 147 | ##### In Xml Layout 148 | 149 | ```xml 150 | 160 | 161 | 172 | 173 | 185 | 186 | ``` 187 | 188 | ##### Listener Example 189 | ```java 190 | final RadioRealButton button1 = (RadioRealButton) findViewById(R.id.button1); 191 | final RadioRealButton button2 = (RadioRealButton) findViewById(R.id.button2); 192 | 193 | RadioRealButtonGroup group = (RadioRealButtonGroup) findViewById(R.id.group); 194 | 195 | // onClickButton listener detects any click performed on buttons by touch 196 | group.setOnClickedButtonListener(new RadioRealButtonGroup.OnClickedButtonListener() { 197 | @Override 198 | public void onClickedButton(RadioRealButton button, int position) { 199 | Toast.makeText(MainActivity.this, "Clicked! Position: " + position, Toast.LENGTH_SHORT).show(); 200 | } 201 | }); 202 | 203 | // onPositionChanged listener detects if there is any change in position 204 | group.setOnPositionChangedListener(new RadioRealButtonGroup.OnPositionChangedListener() { 205 | @Override 206 | public void onPositionChanged(RadioRealButton button, int position) { 207 | Toast.makeText(MainActivity.this, "Position Changed! Position: " + position, Toast.LENGTH_SHORT).show(); 208 | } 209 | }); 210 | 211 | // onLongClickedButton detects long clicks which are made on any button in group. 212 | // return true if you only want to detect long click, nothing else 213 | // return false if you want to detect long click and change position when you release 214 | group.setOnLongClickedButtonListener(new RadioRealButtonGroup.OnLongClickedButtonListener() { 215 | @Override 216 | public boolean onLongClickedButton(RadioRealButton button, int position) { 217 | Toast.makeText(MainActivity.this, "Long Clicked! Position: " + position, Toast.LENGTH_SHORT).show(); 218 | return false; 219 | } 220 | }); 221 | ``` 222 | 223 | ## License 224 | 225 | This project is licensed under the Apache License Version 2.0 - see the [LICENSE.md](LICENSE.md) file for details 226 | 227 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.3' 9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | jcenter() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jul 19 11:30:51 EET 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto 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 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | group = 'com.github.ceryle' 5 | 6 | android { 7 | compileSdkVersion 25 8 | buildToolsVersion "25.0.2" 9 | 10 | defaultConfig { 11 | minSdkVersion 11 12 | targetSdkVersion 25 13 | versionCode 1 14 | versionName "1.0" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | // build a jar with source files 25 | task sourcesJar(type: Jar) { 26 | from android.sourceSets.main.java.srcDirs 27 | classifier = 'sources' 28 | } 29 | task javadoc(type: Javadoc) { 30 | failOnError false 31 | source = android.sourceSets.main.java.sourceFiles 32 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 33 | classpath += configurations.compile 34 | } 35 | // build a jar with javadoc 36 | task javadocJar(type: Jar, dependsOn: javadoc) { 37 | classifier = 'javadoc' 38 | from javadoc.destinationDir 39 | } 40 | 41 | artifacts { 42 | archives sourcesJar 43 | archives javadocJar 44 | } 45 | 46 | 47 | dependencies { 48 | compile fileTree(dir: 'libs', include: ['*.jar']) 49 | testCompile 'junit:junit:4.12' 50 | compile 'com.android.support:appcompat-v7:25.3.1' 51 | } 52 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /library/src/main/java/co/ceryle/radiorealbutton/BackgroundHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 ceryle 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package co.ceryle.radiorealbutton; 17 | 18 | import android.graphics.drawable.Drawable; 19 | import android.os.Build; 20 | import android.view.View; 21 | 22 | class BackgroundHelper { 23 | 24 | static void setBackground(View view, Drawable drawable) { 25 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 26 | view.setBackground(drawable); 27 | } else { 28 | view.setBackgroundDrawable(drawable); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/co/ceryle/radiorealbutton/BackgroundView.java: -------------------------------------------------------------------------------- 1 | package co.ceryle.radiorealbutton; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.support.annotation.Nullable; 6 | import android.support.annotation.RequiresApi; 7 | import android.util.AttributeSet; 8 | import android.view.View; 9 | 10 | public class BackgroundView extends View { 11 | public BackgroundView(Context context) { 12 | super(context); 13 | } 14 | 15 | public BackgroundView(Context context, @Nullable AttributeSet attrs) { 16 | super(context, attrs); 17 | } 18 | 19 | public BackgroundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 20 | super(context, attrs, defStyleAttr); 21 | } 22 | 23 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 24 | public BackgroundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 25 | super(context, attrs, defStyleAttr, defStyleRes); 26 | } 27 | 28 | @Override 29 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 30 | int w = 0, h = 0; 31 | 32 | w = Math.max(w, getSuggestedMinimumWidth()); 33 | h = Math.max(h, getSuggestedMinimumHeight()); 34 | 35 | int widthSize = resolveSizeAndState(w, widthMeasureSpec, 0); 36 | int heightSize = resolveSizeAndState(h, heightMeasureSpec, 0); 37 | setMeasuredDimension(widthSize, heightSize); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /library/src/main/java/co/ceryle/radiorealbutton/ConversionHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 ceryle 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package co.ceryle.radiorealbutton; 17 | 18 | import android.content.Context; 19 | 20 | class ConversionHelper { 21 | 22 | static float pxToDp(final Context context, final float px) { 23 | return px / context.getResources().getDisplayMetrics().density; 24 | } 25 | 26 | static int dpToPx(final Context context, final float dp) { 27 | return (int) (dp * context.getResources().getDisplayMetrics().density); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/co/ceryle/radiorealbutton/RadioRealButton.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 ceryle 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package co.ceryle.radiorealbutton; 17 | 18 | import android.animation.ArgbEvaluator; 19 | import android.animation.ValueAnimator; 20 | import android.annotation.TargetApi; 21 | import android.content.Context; 22 | import android.content.res.TypedArray; 23 | import android.graphics.Color; 24 | import android.graphics.Typeface; 25 | import android.graphics.drawable.Drawable; 26 | import android.os.Build; 27 | import android.support.v7.widget.AppCompatImageView; 28 | import android.support.v7.widget.AppCompatTextView; 29 | import android.util.AttributeSet; 30 | import android.util.TypedValue; 31 | import android.view.Gravity; 32 | import android.view.View; 33 | import android.view.ViewGroup; 34 | import android.view.animation.Interpolator; 35 | import android.widget.ImageView; 36 | import android.widget.LinearLayout; 37 | import android.widget.TextView; 38 | 39 | public class RadioRealButton extends LinearLayout { 40 | public RadioRealButton(Context context) { 41 | super(context); 42 | this.init(null); 43 | } 44 | 45 | public RadioRealButton(Context context, AttributeSet attrs) { 46 | super(context, attrs); 47 | this.init(attrs); 48 | } 49 | 50 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 51 | public RadioRealButton(Context context, AttributeSet attrs, int defStyleAttr) { 52 | super(context, attrs, defStyleAttr); 53 | this.init(attrs); 54 | } 55 | 56 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 57 | public RadioRealButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 58 | super(context, attrs, defStyleAttr, defStyleRes); 59 | this.init(attrs); 60 | } 61 | 62 | private void init(AttributeSet attrs) { 63 | getAttributes(attrs); 64 | 65 | initViews(); 66 | 67 | setDrawableGravity(); 68 | setState(); 69 | 70 | super.setPadding(0, 0, 0, 0); 71 | setPaddingAttrs(); 72 | } 73 | 74 | private AppCompatImageView imageView; 75 | private AppCompatTextView textView; 76 | 77 | private void initViews() { 78 | setLayoutParams(new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1)); 79 | setOrientation(HORIZONTAL); 80 | setGravity(Gravity.CENTER); 81 | 82 | imageView = new AppCompatImageView(getContext()); 83 | imageView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) {{ 84 | gravity = Gravity.CENTER; 85 | }}); 86 | setDrawableAttrs(); 87 | addView(imageView); 88 | 89 | textView = new AppCompatTextView(getContext()); 90 | textView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) {{ 91 | gravity = Gravity.CENTER; 92 | }}); 93 | setTextAttrs(); 94 | addView(textView); 95 | } 96 | 97 | private Typeface defaultTypeface, textTypeface; 98 | 99 | private String text, textTypefacePath; 100 | 101 | private int textStyle, textSize, drawable, drawableTint, drawableTintTo, textColor, textColorTo, rippleColor, drawableWidth, 102 | drawableHeight, selectorColor, padding, paddingLeft, paddingRight, paddingTop, paddingBottom, drawablePadding, 103 | backgroundColor, textGravity; 104 | 105 | private boolean hasPaddingLeft, hasPaddingRight, hasPaddingTop, hasPaddingBottom, hasDrawableTint, hasTextTypefacePath, 106 | hasDrawable, hasText, hasDrawableWidth, hasDrawableHeight, checked, enabled, hasEnabled, clickable, hasClickable, 107 | hasTextStyle, hasTextSize, hasTextColor, textFillSpace, hasRipple, hasRippleColor, hasSelectorColor, 108 | hasDrawableTintTo, hasTextColorTo; 109 | 110 | /*** 111 | * GET ATTRIBUTES FROM XML 112 | */ 113 | private void getAttributes(AttributeSet attrs) { 114 | TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.RadioRealButton); 115 | 116 | drawable = ta.getResourceId(R.styleable.RadioRealButton_rrb_drawable, -1); 117 | drawableTint = ta.getColor(R.styleable.RadioRealButton_rrb_drawableTint, 0); 118 | drawableTintTo = ta.getColor(R.styleable.RadioRealButton_rrb_drawableTintTo, 0); 119 | drawableWidth = ta.getDimensionPixelSize(R.styleable.RadioRealButton_rrb_drawableWidth, -1); 120 | drawableHeight = ta.getDimensionPixelSize(R.styleable.RadioRealButton_rrb_drawableHeight, -1); 121 | 122 | hasDrawable = ta.hasValue(R.styleable.RadioRealButton_rrb_drawable); 123 | hasDrawableTint = ta.hasValue(R.styleable.RadioRealButton_rrb_drawableTint); 124 | hasDrawableTintTo = ta.hasValue(R.styleable.RadioRealButton_rrb_drawableTintTo); 125 | hasDrawableWidth = ta.hasValue(R.styleable.RadioRealButton_rrb_drawableWidth); 126 | hasDrawableHeight = ta.hasValue(R.styleable.RadioRealButton_rrb_drawableHeight); 127 | 128 | text = ta.getString(R.styleable.RadioRealButton_rrb_text); 129 | hasText = ta.hasValue(R.styleable.RadioRealButton_rrb_text); 130 | textColor = ta.getColor(R.styleable.RadioRealButton_rrb_textColor, Color.BLACK); 131 | textColorTo = ta.getColor(R.styleable.RadioRealButton_rrb_textColorTo, Color.BLACK); 132 | 133 | hasTextColor = ta.hasValue(R.styleable.RadioRealButton_rrb_textColor); 134 | hasTextColorTo = ta.hasValue(R.styleable.RadioRealButton_rrb_textColorTo); 135 | textSize = ta.getDimensionPixelSize(R.styleable.RadioRealButton_rrb_textSize, -1); 136 | hasTextSize = ta.hasValue(R.styleable.RadioRealButton_rrb_textSize); 137 | textStyle = ta.getInt(R.styleable.RadioRealButton_rrb_textStyle, -1); 138 | hasTextStyle = ta.hasValue(R.styleable.RadioRealButton_rrb_textStyle); 139 | 140 | int typeface = ta.getInt(R.styleable.RadioRealButton_rrb_textTypeface, -1); 141 | switch (typeface) { 142 | case 0: 143 | textTypeface = Typeface.MONOSPACE; 144 | break; 145 | case 1: 146 | textTypeface = Typeface.DEFAULT; 147 | break; 148 | case 2: 149 | textTypeface = Typeface.SANS_SERIF; 150 | break; 151 | case 3: 152 | textTypeface = Typeface.SERIF; 153 | break; 154 | } 155 | textTypefacePath = ta.getString(R.styleable.RadioRealButton_rrb_textTypefacePath); 156 | hasTextTypefacePath = ta.hasValue(R.styleable.RadioRealButton_rrb_textTypefacePath); 157 | 158 | hasRipple = ta.getBoolean(R.styleable.RadioRealButton_rrb_ripple, true); 159 | rippleColor = ta.getColor(R.styleable.RadioRealButton_rrb_rippleColor, Color.GRAY); 160 | hasRippleColor = ta.hasValue(R.styleable.RadioRealButton_rrb_rippleColor); 161 | 162 | backgroundColor = ta.getColor(R.styleable.RadioRealButton_rrb_backgroundColor, Color.TRANSPARENT); 163 | 164 | int defaultPadding = ConversionHelper.dpToPx(getContext(), 10); 165 | padding = ta.getDimensionPixelSize(R.styleable.RadioRealButton_android_padding, defaultPadding); 166 | paddingLeft = ta.getDimensionPixelSize(R.styleable.RadioRealButton_android_paddingLeft, 0); 167 | paddingRight = ta.getDimensionPixelSize(R.styleable.RadioRealButton_android_paddingRight, 0); 168 | paddingTop = ta.getDimensionPixelSize(R.styleable.RadioRealButton_android_paddingTop, 0); 169 | paddingBottom = ta.getDimensionPixelSize(R.styleable.RadioRealButton_android_paddingBottom, 0); 170 | 171 | hasPaddingLeft = ta.hasValue(R.styleable.RadioRealButton_android_paddingLeft); 172 | hasPaddingRight = ta.hasValue(R.styleable.RadioRealButton_android_paddingRight); 173 | hasPaddingTop = ta.hasValue(R.styleable.RadioRealButton_android_paddingTop); 174 | hasPaddingBottom = ta.hasValue(R.styleable.RadioRealButton_android_paddingBottom); 175 | 176 | drawablePadding = ta.getDimensionPixelSize(R.styleable.RadioRealButton_rrb_drawablePadding, 4); 177 | 178 | drawableGravity = DrawableGravity.getById(ta.getInteger(R.styleable.RadioRealButton_rrb_drawableGravity, 0)); 179 | 180 | checked = ta.getBoolean(R.styleable.RadioRealButton_rrb_checked, false); 181 | 182 | enabled = ta.getBoolean(R.styleable.RadioRealButton_android_enabled, true); 183 | hasEnabled = ta.hasValue(R.styleable.RadioRealButton_android_enabled); 184 | clickable = ta.getBoolean(R.styleable.RadioRealButton_android_clickable, true); 185 | hasClickable = ta.hasValue(R.styleable.RadioRealButton_android_clickable); 186 | 187 | textGravity = ta.getInt(R.styleable.RadioRealButton_rrb_textGravity, Gravity.NO_GRAVITY); 188 | 189 | textFillSpace = ta.getBoolean(R.styleable.RadioRealButton_rrb_textFillSpace, false); 190 | 191 | selectorColor = ta.getColor(R.styleable.RadioRealButton_rrb_selectorColor, Color.TRANSPARENT); 192 | hasSelectorColor = ta.hasValue(R.styleable.RadioRealButton_rrb_selectorColor); 193 | 194 | ta.recycle(); 195 | } 196 | 197 | public int getTextColorTo() { 198 | return textColorTo; 199 | } 200 | 201 | public void setTextColorTo(int textColorTo) { 202 | this.textColorTo = textColorTo; 203 | } 204 | 205 | public boolean hasTextColorTo() { 206 | return hasTextColorTo; 207 | } 208 | 209 | public boolean hasTextColor() { 210 | return hasTextColor; 211 | } 212 | 213 | public void setHasTextColor(boolean hasTextColor) { 214 | this.hasTextColor = hasTextColor; 215 | } 216 | 217 | public void setHasTextColorTo(boolean hasTextColorTo) { 218 | this.hasTextColorTo = hasTextColorTo; 219 | } 220 | 221 | public boolean hasDrawableTintTo() { 222 | return hasDrawableTintTo; 223 | } 224 | 225 | public void setHasDrawableTintTo(boolean hasDrawableTintTo) { 226 | this.hasDrawableTintTo = hasDrawableTintTo; 227 | } 228 | 229 | public int getDrawableTintTo() { 230 | return drawableTintTo; 231 | } 232 | 233 | public void setDrawableTintTo(int drawableTintTo) { 234 | this.drawableTintTo = drawableTintTo; 235 | } 236 | 237 | public int getSelectorColor() { 238 | return selectorColor; 239 | } 240 | 241 | public void setSelectorColor(int selectorColor) { 242 | this.selectorColor = selectorColor; 243 | onSelectorColorChangedListener.onSelectorColorChanged(position, selectorColor); 244 | } 245 | 246 | public boolean hasSelectorColor() { 247 | return hasSelectorColor; 248 | } 249 | 250 | private OnSelectorColorChangedListener onSelectorColorChangedListener; 251 | private int position; 252 | 253 | void setOnSelectorColorChangedListener(OnSelectorColorChangedListener onSelectorColorChangedListener, int position) { 254 | this.onSelectorColorChangedListener = onSelectorColorChangedListener; 255 | this.position = position; 256 | } 257 | 258 | interface OnSelectorColorChangedListener { 259 | void onSelectorColorChanged(int position, int selectorColor); 260 | } 261 | 262 | public boolean hasEnabled() { 263 | return hasEnabled; 264 | } 265 | 266 | public boolean hasClickable() { 267 | return hasClickable; 268 | } 269 | 270 | private void setDrawableAttrs() { 271 | if (hasDrawable) { 272 | imageView.setImageResource(drawable); 273 | if (hasDrawableTint) 274 | imageView.setColorFilter(drawableTint); 275 | 276 | if (hasDrawableWidth) 277 | setDrawableWidth(drawableWidth); 278 | if (hasDrawableHeight) 279 | setDrawableHeight(drawableHeight); 280 | } else { 281 | imageView.setVisibility(GONE); 282 | } 283 | } 284 | 285 | private void setDrawableGravity() { 286 | if (!hasDrawable) 287 | return; 288 | 289 | if (drawableGravity == DrawableGravity.LEFT || drawableGravity == DrawableGravity.TOP) { 290 | if (getChildAt(0) instanceof AppCompatTextView) { 291 | removeViewAt(0); 292 | addView(textView, 1); 293 | 294 | if (textFillSpace) { 295 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams(); 296 | params.weight = 0; 297 | params.width = LayoutParams.WRAP_CONTENT; 298 | } 299 | } 300 | } else { 301 | if (getChildAt(0) instanceof AppCompatImageView) { 302 | removeViewAt(0); 303 | addView(imageView, 1); 304 | 305 | if (textFillSpace) { 306 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) textView.getLayoutParams(); 307 | params.weight = 1; 308 | params.width = 0; 309 | } 310 | } 311 | } 312 | 313 | if (hasText && hasDrawable) 314 | if (drawableGravity == DrawableGravity.TOP || drawableGravity == DrawableGravity.BOTTOM) 315 | setOrientation(VERTICAL); 316 | else 317 | setOrientation(HORIZONTAL); 318 | } 319 | 320 | private void setTextAttrs() { 321 | defaultTypeface = textView.getTypeface(); 322 | 323 | textView.setText(text); 324 | 325 | int gravity; 326 | 327 | if (textGravity == 2) { 328 | gravity = Gravity.END; 329 | } else if (textGravity == 1) { 330 | gravity = Gravity.CENTER; 331 | } else { 332 | gravity = Gravity.START; 333 | } 334 | 335 | textView.setGravity(gravity); 336 | 337 | if (hasTextColor) 338 | textView.setTextColor(textColor); 339 | if (hasTextSize) 340 | setTextSizePX(textSize); 341 | if (hasTextTypefacePath) 342 | setTypeface(textTypefacePath); 343 | else if (null != textTypeface) { 344 | setTypeface(textTypeface); 345 | } 346 | if (hasTextStyle) 347 | setTextStyle(textStyle); 348 | } 349 | 350 | private void setPaddingAttrs() { 351 | if (hasPaddingBottom || hasPaddingTop || hasPaddingLeft || hasPaddingRight) 352 | setPaddings(paddingLeft, paddingTop, paddingRight, paddingBottom); 353 | else 354 | setPaddings(padding, padding, padding, padding); 355 | } 356 | 357 | void colorTransitionDrawable(boolean hasAnimateDrawablesTint, int colorFrom, int colorTo, int duration, boolean hasAnimation, boolean onEnter) { 358 | int c1, c2; 359 | 360 | if (hasDrawableTintTo) { 361 | c1 = drawableTint; 362 | c2 = drawableTintTo; 363 | } else if (hasAnimateDrawablesTint) { 364 | c1 = colorFrom; 365 | c2 = colorTo; 366 | } else 367 | return; 368 | 369 | if (!onEnter) { 370 | int c = c1; 371 | c1 = c2; 372 | c2 = c; 373 | } 374 | 375 | if (hasAnimation) 376 | colorTransition(imageView, c1, c2, duration); 377 | else 378 | setDrawableTint(c2); 379 | } 380 | 381 | void colorTransitionText(boolean hasAnimateTextsColor, int colorFrom, int colorTo, int duration, boolean hasAnimation, boolean onEnter) { 382 | int c1, c2; 383 | 384 | if (hasTextColorTo) { 385 | c1 = textColor; 386 | c2 = textColorTo; 387 | } else if (hasAnimateTextsColor) { 388 | c1 = colorFrom; 389 | c2 = colorTo; 390 | } else 391 | return; 392 | 393 | if (!onEnter) { 394 | int c = c1; 395 | c1 = c2; 396 | c2 = c; 397 | } 398 | 399 | if (hasAnimation) 400 | colorTransition(textView, c1, c2, duration); 401 | else 402 | setTextColor(c2); 403 | } 404 | 405 | private void colorTransition(final View v, int colorFrom, int colorTo, int duration) { 406 | ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo); 407 | colorAnimation.setDuration(duration); 408 | colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 409 | @Override 410 | public void onAnimationUpdate(ValueAnimator animator) { 411 | if (v instanceof ImageView) { 412 | ((ImageView) v).setColorFilter((int) animator.getAnimatedValue()); 413 | } else { 414 | ((TextView) v).setTextColor((int) animator.getAnimatedValue()); 415 | } 416 | } 417 | }); 418 | colorAnimation.start(); 419 | } 420 | 421 | void bounceDrawable(float scale, int duration, Interpolator interpolator, boolean hasAnimation) { 422 | if (hasAnimation) 423 | bounce(imageView, scale, duration, interpolator); 424 | else 425 | bounceDrawable(scale); 426 | } 427 | 428 | void bounceText(float scale, int duration, Interpolator interpolator, boolean hasAnimation) { 429 | if (hasAnimation) 430 | bounce(textView, scale, duration, interpolator); 431 | else 432 | bounceText(scale); 433 | } 434 | 435 | private void bounce(View view, float scale, int duration, Interpolator interpolator) { 436 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { 437 | view.animate().setDuration(duration).setInterpolator(interpolator).scaleX(scale).scaleY(scale); 438 | } else { 439 | bounce(view, scale); 440 | } 441 | } 442 | 443 | /*private void bounce(View view, float scale, int duration, Interpolator interpolator) { 444 | ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", scale); 445 | ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", scale); 446 | 447 | AnimatorSet set = new AnimatorSet(); 448 | set.playTogether(scaleX, scaleY); 449 | set.setDuration(duration); 450 | set.setInterpolator(interpolator); 451 | set.start(); 452 | }*/ 453 | 454 | void bounceDrawable(float scale) { 455 | bounce(imageView, scale); 456 | } 457 | 458 | void bounceText(float scale) { 459 | bounce(textView, scale); 460 | } 461 | 462 | private void bounce(final View view, final float scale) { 463 | view.setScaleX(scale); 464 | view.setScaleY(scale); 465 | } 466 | 467 | /** 468 | * GRAVITY 469 | */ 470 | 471 | private DrawableGravity drawableGravity; 472 | 473 | public enum DrawableGravity { 474 | LEFT(0), 475 | TOP(1), 476 | RIGHT(2), 477 | BOTTOM(3); 478 | 479 | private int intValue; 480 | 481 | DrawableGravity(int intValue) { 482 | this.intValue = intValue; 483 | } 484 | 485 | private int getIntValue() { 486 | return intValue; 487 | } 488 | 489 | public static DrawableGravity getById(int id) { 490 | for (DrawableGravity e : values()) { 491 | if (e.intValue == id) return e; 492 | } 493 | return null; 494 | } 495 | 496 | public boolean isHorizontal() { 497 | return intValue == 0 || intValue == 2; 498 | } 499 | } 500 | 501 | /** 502 | * TEXT VIEW 503 | */ 504 | public AppCompatTextView getTextView() { 505 | return textView; 506 | } 507 | 508 | public int getTextColor() { 509 | return textColor; 510 | } 511 | 512 | public void setTextColor(int textColor) { 513 | this.textColor = textColor; 514 | 515 | textView.setTextColor(textColor); 516 | } 517 | 518 | void setCheckedTextColor(int color) { 519 | textView.setTextColor(color); 520 | } 521 | 522 | public String getText() { 523 | return text; 524 | } 525 | 526 | public void setText(String text) { 527 | this.text = text; 528 | 529 | textView.setText(text); 530 | } 531 | 532 | public void setTextSizePX(int size) { 533 | textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); 534 | } 535 | 536 | public void setTextSizeSP(float size) { 537 | textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, size); 538 | } 539 | 540 | public int getTextSize() { 541 | return textSize; 542 | } 543 | 544 | public int getTextStyle() { 545 | return textStyle; 546 | } 547 | 548 | public void setTextStyle(int typeface) { 549 | textView.setTypeface(textView.getTypeface(), typeface); 550 | } 551 | 552 | public void restoreTypeface() { 553 | textView.setTypeface(defaultTypeface); 554 | } 555 | 556 | public String getTypefacePath() { 557 | return textTypefacePath; 558 | } 559 | 560 | /** 561 | * Typeface.NORMAL: 0 562 | * Typeface.BOLD: 1 563 | * Typeface.ITALIC: 2 564 | * Typeface.BOLD_ITALIC: 3 565 | * 566 | * @param typeface you can use above variations using the bitwise OR operator 567 | */ 568 | public void setTypeface(Typeface typeface) { 569 | textView.setTypeface(typeface); 570 | } 571 | 572 | public void setTypeface(String location) { 573 | if (null != location && !location.equals("")) { 574 | Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), location); 575 | textView.setTypeface(typeface); 576 | } 577 | } 578 | 579 | public Typeface getDefaultTypeface() { 580 | return defaultTypeface; 581 | } 582 | 583 | /** 584 | * PADDING 585 | */ 586 | public int getPadding() { 587 | return padding; 588 | } 589 | 590 | public void setPaddings(int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) { 591 | this.paddingLeft = paddingLeft; 592 | this.paddingTop = paddingTop; 593 | this.paddingRight = paddingRight; 594 | this.paddingBottom = paddingBottom; 595 | 596 | updatePaddings(); 597 | } 598 | 599 | private void updatePaddings() { 600 | if (hasText) 601 | updatePadding(textView, hasDrawable); 602 | 603 | if (hasDrawable) 604 | updatePadding(imageView, hasText); 605 | } 606 | 607 | private void updatePadding(View view, boolean hasOtherView) { 608 | if (null == view) 609 | return; 610 | 611 | int[] paddings = {paddingLeft, paddingTop, paddingRight, paddingBottom}; 612 | 613 | if (hasOtherView) { 614 | int g = drawableGravity.getIntValue(); 615 | if (view instanceof AppCompatImageView) { 616 | g = g > 1 ? g - 2 : g + 2; 617 | } 618 | paddings[g] = drawablePadding / 2; 619 | } 620 | 621 | MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams(); 622 | params.setMargins(paddings[0], paddings[1], paddings[2], paddings[3]); 623 | } 624 | 625 | @Override 626 | public int getPaddingLeft() { 627 | return paddingLeft; 628 | } 629 | 630 | @Override 631 | public int getPaddingRight() { 632 | return paddingRight; 633 | } 634 | 635 | @Override 636 | public int getPaddingTop() { 637 | return paddingTop; 638 | } 639 | 640 | @Override 641 | public int getPaddingBottom() { 642 | return paddingBottom; 643 | } 644 | 645 | public boolean hasPaddingLeft() { 646 | return hasPaddingLeft; 647 | } 648 | 649 | public boolean hasPaddingRight() { 650 | return hasPaddingRight; 651 | } 652 | 653 | public boolean hasPaddingTop() { 654 | return hasPaddingTop; 655 | } 656 | 657 | public boolean hasPaddingBottom() { 658 | return hasPaddingBottom; 659 | } 660 | 661 | /** 662 | * DRAWABLE 663 | */ 664 | public AppCompatImageView getImageView() { 665 | return imageView; 666 | } 667 | 668 | public int getDrawable() { 669 | return drawable; 670 | } 671 | 672 | public void setDrawable(Drawable drawable) { 673 | imageView.setImageDrawable(drawable); 674 | } 675 | 676 | public void setDrawable(int drawable) { 677 | this.drawable = drawable; 678 | 679 | imageView.setImageResource(drawable); 680 | } 681 | 682 | public int getDrawableTint() { 683 | return drawableTint; 684 | } 685 | 686 | public void setDrawableTint(int color) { 687 | this.drawableTint = color; 688 | 689 | imageView.setColorFilter(color); 690 | } 691 | 692 | void setCheckedDrawableTint(int color) { 693 | imageView.setColorFilter(color); 694 | } 695 | 696 | public boolean hasDrawableTint() { 697 | return hasDrawableTint; 698 | } 699 | 700 | public void setDrawableTint(boolean hasColor) { 701 | this.hasDrawableTint = hasColor; 702 | 703 | if (hasColor) 704 | imageView.setColorFilter(drawableTint); 705 | else 706 | imageView.clearColorFilter(); 707 | } 708 | 709 | public int getDrawableWidth() { 710 | return drawableWidth; 711 | } 712 | 713 | public void setDrawableWidth(int drawableWidth) { 714 | this.drawableWidth = drawableWidth; 715 | 716 | ViewGroup.LayoutParams params = imageView.getLayoutParams(); 717 | if (null != params) { 718 | params.width = drawableWidth; 719 | } 720 | } 721 | 722 | public int getDrawableHeight() { 723 | return drawableHeight; 724 | } 725 | 726 | public void setDrawableHeight(int drawableHeight) { 727 | this.drawableHeight = drawableHeight; 728 | 729 | ViewGroup.LayoutParams params = imageView.getLayoutParams(); 730 | if (null != params) { 731 | params.height = drawableHeight; 732 | } 733 | } 734 | 735 | public void setDrawableSizeByPx(int width, int height) { 736 | this.drawableWidth = width; 737 | this.drawableHeight = height; 738 | 739 | ViewGroup.LayoutParams params = imageView.getLayoutParams(); 740 | if (null != params) { 741 | params.width = width; 742 | params.height = height; 743 | } 744 | } 745 | 746 | public void setDrawableSizeByDp(int width, int height) { 747 | width = ConversionHelper.dpToPx(getContext(), width); 748 | height = ConversionHelper.dpToPx(getContext(), height); 749 | setDrawableSizeByPx(width, height); 750 | } 751 | 752 | public DrawableGravity getDrawableGravity() { 753 | return drawableGravity; 754 | } 755 | 756 | public void setDrawableGravity(DrawableGravity gravity) { 757 | this.drawableGravity = gravity; 758 | 759 | setDrawableGravity(); 760 | setPaddingAttrs(); 761 | } 762 | 763 | public int getDrawablePadding() { 764 | return drawablePadding; 765 | } 766 | 767 | public void setDrawablePadding(int drawablePadding) { 768 | this.drawablePadding = drawablePadding; 769 | updatePaddings(); 770 | } 771 | 772 | /** 773 | * RIPPLE 774 | */ 775 | public int getRippleColor() { 776 | return rippleColor; 777 | } 778 | 779 | public void setRippleColor(int rippleColor) { 780 | this.rippleColor = rippleColor; 781 | setRippleColor(true); 782 | } 783 | 784 | public void setRippleColor(boolean state) { 785 | setRippleBackground(hasRippleColor = state); 786 | } 787 | 788 | public void setRipple(boolean state) { 789 | setRippleBackground(hasRipple = state); 790 | } 791 | 792 | private void setRippleBackground(boolean state) { 793 | if (state) { 794 | if (hasRippleColor) { 795 | RippleHelper.setRipple(this, rippleColor, backgroundColor); 796 | } else if (hasRipple) { 797 | RippleHelper.setSelectableItemBackground(getContext(), this); 798 | } 799 | } else { 800 | setBackgroundColor(backgroundColor); 801 | } 802 | } 803 | 804 | /** 805 | * GROUP 806 | */ 807 | private void setEnabledAlpha(boolean enabled) { 808 | float alpha = 1f; 809 | if (!enabled) 810 | alpha = 0.5f; 811 | setAlpha(alpha); 812 | } 813 | 814 | @Override 815 | public void setEnabled(boolean enabled) { 816 | super.setClickable(enabled); 817 | this.enabled = enabled; 818 | setEnabledAlpha(enabled); 819 | setRippleBackground(enabled); 820 | } 821 | 822 | @Override 823 | public void setClickable(boolean clickable) { 824 | super.setClickable(clickable); 825 | this.clickable = clickable; 826 | setRippleBackground(clickable); 827 | } 828 | 829 | private void setState() { 830 | if (hasEnabled) 831 | setEnabled(enabled); 832 | else 833 | setClickable(clickable); 834 | } 835 | 836 | @Override 837 | public boolean isClickable() { 838 | return clickable; 839 | } 840 | 841 | @Override 842 | public boolean isEnabled() { 843 | return enabled; 844 | } 845 | 846 | public void setChecked(boolean checked) { 847 | this.checked = checked; 848 | } 849 | 850 | public boolean isChecked() { 851 | return checked; 852 | } 853 | } 854 | -------------------------------------------------------------------------------- /library/src/main/java/co/ceryle/radiorealbutton/RadioRealButtonGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 ceryle 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package co.ceryle.radiorealbutton; 17 | 18 | import android.animation.AnimatorSet; 19 | import android.animation.ObjectAnimator; 20 | import android.content.Context; 21 | import android.content.res.TypedArray; 22 | import android.graphics.Color; 23 | import android.os.Build; 24 | import android.os.Bundle; 25 | import android.os.Parcelable; 26 | import android.support.v4.view.animation.FastOutLinearInInterpolator; 27 | import android.support.v4.view.animation.FastOutSlowInInterpolator; 28 | import android.support.v4.view.animation.LinearOutSlowInInterpolator; 29 | import android.util.AttributeSet; 30 | import android.view.Gravity; 31 | import android.view.View; 32 | import android.view.ViewGroup; 33 | import android.view.animation.AccelerateDecelerateInterpolator; 34 | import android.view.animation.AccelerateInterpolator; 35 | import android.view.animation.AnticipateInterpolator; 36 | import android.view.animation.AnticipateOvershootInterpolator; 37 | import android.view.animation.BounceInterpolator; 38 | import android.view.animation.CycleInterpolator; 39 | import android.view.animation.DecelerateInterpolator; 40 | import android.view.animation.Interpolator; 41 | import android.view.animation.LinearInterpolator; 42 | import android.view.animation.OvershootInterpolator; 43 | import android.widget.FrameLayout; 44 | import android.widget.LinearLayout; 45 | 46 | import java.util.ArrayList; 47 | import java.util.List; 48 | 49 | public class RadioRealButtonGroup extends RoundedCornerLayout implements RadioRealButton.OnSelectorColorChangedListener { 50 | 51 | public RadioRealButtonGroup(Context context) { 52 | super(context); 53 | init(null); 54 | } 55 | 56 | public RadioRealButtonGroup(Context context, AttributeSet attrs) { 57 | super(context, attrs); 58 | init(attrs); 59 | } 60 | 61 | public RadioRealButtonGroup(Context context, AttributeSet attrs, int defStyleAttr) { 62 | super(context, attrs, defStyleAttr); 63 | init(attrs); 64 | } 65 | 66 | @Override 67 | protected Parcelable onSaveInstanceState() { 68 | Bundle bundle = new Bundle(); 69 | bundle.putParcelable("state", super.onSaveInstanceState()); 70 | bundle.putInt("position", lastPosition); 71 | return bundle; 72 | } 73 | 74 | @Override 75 | protected void onRestoreInstanceState(Parcelable state) { 76 | if (state instanceof Bundle) { 77 | Bundle bundle = (Bundle) state; 78 | state = bundle.getParcelable("state"); 79 | int position = bundle.getInt("position"); 80 | 81 | if (lastPosition != position) { 82 | if (animationType == ANIM_TRANSLATE_X) { 83 | if (initialPosition != -1) 84 | v_selectors.get(initialPosition).setVisibility(INVISIBLE); 85 | v_selectors.get(position).setVisibility(VISIBLE); 86 | lastPosition = initialPosition = position; 87 | } 88 | setPosition(position, false); 89 | } 90 | } 91 | super.onRestoreInstanceState(state); 92 | } 93 | 94 | private View v_bottomLine; 95 | private LinearLayout container, selectorContainer; 96 | 97 | private List v_selectors = new ArrayList<>(); 98 | private List buttons = new ArrayList<>(); 99 | 100 | private void init(AttributeSet attrs) { 101 | getAttributes(attrs); 102 | 103 | setBorderAttrs(); 104 | initViews(); 105 | 106 | setBottomLineAttrs(); 107 | setSelectorAttrs(); 108 | 109 | initInterpolations(); 110 | 111 | setState(); 112 | } 113 | 114 | private void initViews() { 115 | setCornerRadius(radius); 116 | 117 | BackgroundView backgroundView = new BackgroundView(getContext()); 118 | backgroundView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 119 | backgroundView.setBackgroundColor(groupBackgroundColor); 120 | addView(backgroundView); 121 | 122 | selectorContainer = new LinearLayout(getContext()); 123 | selectorContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 124 | selectorContainer.setOrientation(LinearLayout.HORIZONTAL); 125 | selectorContainer.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); 126 | RoundHelper.makeDividerRound(selectorContainer, selectorDividerColor, selectorDividerRadius, selectorDividerSize); 127 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 128 | selectorContainer.setDividerPadding(selectorDividerPadding); 129 | } 130 | addView(selectorContainer); 131 | 132 | container = new LinearLayout(getContext()); 133 | container.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 134 | container.setOrientation(LinearLayout.HORIZONTAL); 135 | container.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); 136 | RoundHelper.makeDividerRound(container, dividerColor, dividerRadius, dividerSize); 137 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 138 | container.setDividerPadding(dividerPadding); 139 | } 140 | addView(container); 141 | 142 | v_bottomLine = new View(getContext()); 143 | v_bottomLine.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, 3)); 144 | addView(v_bottomLine); 145 | } 146 | 147 | private void setBottomLineAttrs() { 148 | FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) v_bottomLine.getLayoutParams(); 149 | 150 | layoutParams.height = bottomLineSize; 151 | 152 | if (bottomLineBringToFront) 153 | v_bottomLine.bringToFront(); 154 | 155 | updateViewBottomLine(); 156 | } 157 | 158 | private void setSelectorAttrs() { 159 | FrameLayout.LayoutParams selectorParams = (FrameLayout.LayoutParams) selectorContainer.getLayoutParams(); 160 | FrameLayout.LayoutParams bottomLineParams = (FrameLayout.LayoutParams) v_bottomLine.getLayoutParams(); 161 | 162 | if (selectorBringToFront) 163 | selectorContainer.bringToFront(); 164 | 165 | if (!selectorFullSize) 166 | selectorParams.height = selectorSize; 167 | 168 | int topMargin = 0, bottomMargin = 0; 169 | 170 | if (selectorTop) { 171 | selectorParams.gravity = Gravity.TOP; 172 | bottomLineParams.gravity = Gravity.TOP; 173 | topMargin = bottomLineSize; 174 | } else if (selectorBottom) { 175 | selectorParams.gravity = Gravity.BOTTOM; 176 | bottomLineParams.gravity = Gravity.BOTTOM; 177 | bottomMargin = bottomLineSize; 178 | } 179 | 180 | if (selectorAboveOfBottomLine) { 181 | selectorParams.setMargins(0, topMargin, 0, bottomMargin); 182 | } 183 | } 184 | 185 | private Interpolator interpolatorDrawablesEnter, interpolatorText, interpolatorSelector; 186 | private Interpolator interpolatorDrawablesExit, interpolatorTextExit; 187 | 188 | private void initInterpolations() { 189 | Class[] interpolations = { 190 | FastOutSlowInInterpolator.class, 191 | BounceInterpolator.class, 192 | LinearInterpolator.class, 193 | DecelerateInterpolator.class, 194 | CycleInterpolator.class, 195 | AnticipateInterpolator.class, 196 | AccelerateDecelerateInterpolator.class, 197 | AccelerateInterpolator.class, 198 | AnticipateOvershootInterpolator.class, 199 | FastOutLinearInInterpolator.class, 200 | LinearOutSlowInInterpolator.class, 201 | OvershootInterpolator.class}; 202 | 203 | try { 204 | interpolatorText = (Interpolator) interpolations[animateTextsEnter].newInstance(); 205 | interpolatorDrawablesEnter = (Interpolator) interpolations[animateDrawablesEnter].newInstance(); 206 | interpolatorSelector = (Interpolator) interpolations[animateSelector].newInstance(); 207 | 208 | interpolatorTextExit = (Interpolator) interpolations[animateTextsExit].newInstance(); 209 | interpolatorDrawablesExit = (Interpolator) interpolations[animateDrawablesExit].newInstance(); 210 | 211 | } catch (Exception e) { 212 | e.printStackTrace(); 213 | } 214 | } 215 | 216 | private void setBorderAttrs() { 217 | setStroke(hasBorder); 218 | setStrokeColor(borderColor); 219 | setStrokeSize(borderSize); 220 | } 221 | 222 | private int borderSize, borderColor, dividerColor, bottomLineColor, selectorColor, animateDrawablesEnter, animateTextsEnter, animationType, 223 | animateDrawablesEnterDuration, animateTextsEnterDuration, animateSelector, animateSelectorDuration, animateSelectorDelay, animateDrawablesExit, 224 | animateDrawablesExitDuration, animateTextsExit, animateTextsExitDuration, lastPosition, buttonPadding, 225 | buttonPaddingLeft, buttonPaddingRight, buttonPaddingTop, buttonPaddingBottom, groupBackgroundColor, 226 | dividerPadding, dividerSize, dividerRadius, bottomLineSize, bottomLineRadius, selectorSize, selectorRadius, initialPosition, 227 | selectorDividerSize, selectorDividerRadius, selectorDividerColor, selectorDividerPadding, checkedButtonId, 228 | animateTextsColorExit, animateTextsColorEnter, animateTextsColorDuration, animateTextsColorDurationExit, animateTextsColorDurationEnter, 229 | animateDrawablesTintExit, animateDrawablesTintEnter, animateDrawablesTintDuration, animateDrawablesTintDurationExit, animateDrawablesTintDurationEnter; 230 | 231 | private float radius, animateDrawablesScale, animateTextsScale; 232 | 233 | private boolean bottomLineBringToFront, selectorBringToFront, selectorAboveOfBottomLine, selectorTop, selectorBottom, hasPadding, 234 | hasPaddingLeft, hasPaddingRight, hasPaddingTop, hasPaddingBottom, clickable, enabled, 235 | enableDeselection, hasEnabled, hasClickable, hasBorder, hasAnimateDrawables, hasAnimateTexts, hasAnimation, selectorFullSize, 236 | hasAnimateTextsColor, hasAnimateDrawablesTint; 237 | 238 | private void getAttributes(AttributeSet attrs) { 239 | TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.RadioRealButtonGroup); 240 | 241 | hasAnimateTextsColor = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_textColorTo); 242 | animateTextsColorExit = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_textColorFrom, Color.GRAY); 243 | animateTextsColorEnter = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_textColorTo, Color.BLACK); 244 | int animateTextsColorDuration = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_textColor_duration, 500) / 2; 245 | animateTextsColorDurationExit = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_textColorFrom_duration, animateTextsColorDuration); 246 | animateTextsColorDurationEnter = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_textColorTo_duration, animateTextsColorDuration); 247 | 248 | hasAnimateDrawablesTint = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_tintColorTo); 249 | animateDrawablesTintExit = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_tintColorFrom, Color.GRAY); 250 | animateDrawablesTintEnter = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_tintColorTo, Color.BLACK); 251 | int animateDrawablesTintDuration = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_tintColor_duration, 500) / 2; 252 | animateDrawablesTintDurationExit = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_tintColorFrom_duration, animateDrawablesTintDuration); 253 | animateDrawablesTintDurationEnter = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_tintColorTo_duration, animateDrawablesTintDuration); 254 | 255 | 256 | bottomLineColor = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_bottomLineColor, Color.GRAY); 257 | bottomLineSize = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_bottomLineSize, 0); 258 | bottomLineBringToFront = ta.getBoolean(R.styleable.RadioRealButtonGroup_rrbg_bottomLineBringToFront, false); 259 | bottomLineRadius = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_bottomLineRadius, 0); 260 | 261 | selectorColor = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_selectorColor, Color.GRAY); 262 | selectorBringToFront = ta.getBoolean(R.styleable.RadioRealButtonGroup_rrbg_selectorBringToFront, false); 263 | selectorAboveOfBottomLine = ta.getBoolean(R.styleable.RadioRealButtonGroup_rrbg_selectorAboveOfBottomLine, false); 264 | selectorSize = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_selectorSize, 12); 265 | selectorRadius = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_selectorRadius, 0); 266 | 267 | animateSelector = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateSelector, 0); 268 | animateSelectorDuration = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateSelector_duration, 500); 269 | animateSelectorDelay = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateSelector_delay, 0); 270 | 271 | dividerSize = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_dividerSize, 0); 272 | boolean hasDividerSize = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_dividerSize); 273 | dividerRadius = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_dividerRadius, 0); 274 | dividerPadding = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_dividerPadding, 30); 275 | dividerColor = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_dividerColor, Color.TRANSPARENT); 276 | 277 | selectorDividerSize = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_selectorDividerSize, dividerSize); 278 | if (!hasDividerSize) { 279 | dividerSize = selectorDividerSize; 280 | } 281 | selectorDividerRadius = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_selectorDividerRadius, 0); 282 | selectorDividerPadding = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_selectorDividerPadding, 0); 283 | selectorDividerColor = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_selectorDividerColor, Color.TRANSPARENT); 284 | 285 | radius = ta.getDimension(R.styleable.RadioRealButtonGroup_rrbg_radius, 0); 286 | 287 | animateDrawablesEnter = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_enter, 0); 288 | hasAnimateDrawables = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_enter); 289 | animateDrawablesExit = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_exit, 0); 290 | int animateDrawablesDuration = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_duration, 500) / 2; 291 | animateDrawablesEnterDuration = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_enterDuration, animateDrawablesDuration); 292 | animateDrawablesExitDuration = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_exitDuration, animateDrawablesDuration); 293 | animateDrawablesScale = ta.getFloat(R.styleable.RadioRealButtonGroup_rrbg_animateDrawables_scale, 1.2f); 294 | 295 | animateTextsEnter = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_enter, 0); 296 | hasAnimateTexts = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_enter); 297 | animateTextsExit = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_exit, 0); 298 | int animateTextsDuration = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_duration, 500) / 2; 299 | animateTextsEnterDuration = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_enterDuration, animateTextsDuration); 300 | animateTextsExitDuration = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_exitDuration, animateTextsDuration); 301 | animateTextsScale = ta.getFloat(R.styleable.RadioRealButtonGroup_rrbg_animateTexts_scale, 1.2f); 302 | 303 | lastPosition = initialPosition = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_checkedPosition, -1); 304 | checkedButtonId = ta.getResourceId(R.styleable.RadioRealButtonGroup_rrbg_checkedButton, NO_ID); 305 | 306 | buttonPadding = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_buttonsPadding, 0); 307 | buttonPaddingLeft = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_buttonsPaddingLeft, 0); 308 | buttonPaddingRight = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_buttonsPaddingRight, 0); 309 | buttonPaddingTop = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_buttonsPaddingTop, 0); 310 | buttonPaddingBottom = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_buttonsPaddingBottom, 0); 311 | 312 | hasPadding = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_buttonsPadding); 313 | hasPaddingLeft = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_buttonsPaddingLeft); 314 | hasPaddingRight = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_buttonsPaddingRight); 315 | hasPaddingTop = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_buttonsPaddingTop); 316 | hasPaddingBottom = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_buttonsPaddingBottom); 317 | 318 | groupBackgroundColor = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_backgroundColor, Color.WHITE); 319 | 320 | selectorTop = ta.getBoolean(R.styleable.RadioRealButtonGroup_rrbg_selectorTop, false); 321 | selectorBottom = ta.getBoolean(R.styleable.RadioRealButtonGroup_rrbg_selectorBottom, true); 322 | 323 | borderSize = ta.getDimensionPixelSize(R.styleable.RadioRealButtonGroup_rrbg_borderSize, ConversionHelper.dpToPx(getContext(), 1)); 324 | borderColor = ta.getColor(R.styleable.RadioRealButtonGroup_rrbg_borderColor, Color.BLACK); 325 | 326 | boolean hasBorderSize = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_borderSize); 327 | boolean hasBorderColor = ta.hasValue(R.styleable.RadioRealButtonGroup_rrbg_borderColor); 328 | hasBorder = hasBorderColor || hasBorderSize; 329 | 330 | clickable = ta.getBoolean(R.styleable.RadioRealButtonGroup_android_clickable, true); 331 | hasClickable = ta.hasValue(R.styleable.RadioRealButtonGroup_android_clickable); 332 | enabled = ta.getBoolean(R.styleable.RadioRealButtonGroup_android_enabled, true); 333 | hasEnabled = ta.hasValue(R.styleable.RadioRealButtonGroup_android_enabled); 334 | 335 | animationType = ta.getInt(R.styleable.RadioRealButtonGroup_rrbg_selectorAnimationType, 0); 336 | enableDeselection = ta.getBoolean(R.styleable.RadioRealButtonGroup_rrbg_enableDeselection, false); 337 | 338 | hasAnimation = ta.getBoolean(R.styleable.RadioRealButtonGroup_rrbg_animate, true); 339 | 340 | selectorFullSize = ta.getBoolean(R.styleable.RadioRealButtonGroup_rrbg_selectorFullSize, false); 341 | 342 | ta.recycle(); 343 | } 344 | 345 | private void setButtonPadding(RadioRealButton button) { 346 | if (hasPadding) 347 | button.setPaddings(buttonPadding, buttonPadding, buttonPadding, buttonPadding); 348 | else if (hasPaddingBottom || hasPaddingTop || hasPaddingLeft || hasPaddingRight) 349 | button.setPaddings(buttonPaddingLeft, buttonPaddingTop, buttonPaddingRight, buttonPaddingBottom); 350 | } 351 | 352 | private int numberOfButtons = 0; 353 | 354 | @Override 355 | public void addView(View child, int index, ViewGroup.LayoutParams params) { 356 | if (child instanceof RadioRealButton) { 357 | RadioRealButton button = (RadioRealButton) child; 358 | 359 | int position = buttons.size(); 360 | 361 | int id = button.getId(); 362 | 363 | if (lastPosition == -1) { 364 | if (checkedButtonId != NO_ID && checkedButtonId == id) 365 | lastPosition = initialPosition = position; 366 | else if (checkedButtonId == NO_ID && button.isChecked()) 367 | lastPosition = initialPosition = position; 368 | } 369 | 370 | if (lastPosition == position) { 371 | button.setChecked(true); 372 | 373 | if (hasAnimateDrawables) 374 | button.bounceDrawable(animateDrawablesScale); 375 | if (hasAnimateTexts) 376 | button.bounceText(animateTextsScale); 377 | 378 | if (button.hasTextColorTo()) { 379 | button.setCheckedTextColor(button.getTextColorTo()); 380 | } else if (hasAnimateTextsColor) { 381 | button.setCheckedTextColor(animateTextsColorEnter); 382 | } 383 | 384 | if (button.hasDrawableTintTo()) { 385 | button.setCheckedDrawableTint(button.getDrawableTintTo()); 386 | } else if (hasAnimateDrawablesTint) { 387 | button.setCheckedDrawableTint(animateDrawablesTintEnter); 388 | } 389 | 390 | } else { 391 | button.setChecked(false); 392 | 393 | if (!button.hasTextColor() && hasAnimateTextsColor) 394 | button.setTextColor(animateTextsColorExit); 395 | 396 | if (!button.hasDrawableTint() && hasAnimateDrawablesTint) 397 | button.setDrawableTint(animateDrawablesTintExit); 398 | } 399 | 400 | initButtonListener(button, position); 401 | setButtonPadding(button); 402 | container.addView(button); 403 | createSelectorItem(position, button); 404 | buttons.add(button); 405 | 406 | numberOfButtons = buttons.size(); 407 | } else 408 | super.addView(child, index, params); 409 | } 410 | 411 | private void createSelectorItem(int position, RadioRealButton button) { 412 | BackgroundView view = new BackgroundView(getContext()); 413 | 414 | int height = selectorSize; 415 | if (selectorFullSize) 416 | height = LayoutParams.MATCH_PARENT; 417 | view.setLayoutParams(new LinearLayout.LayoutParams(0, height, 1)); 418 | 419 | int value = 0; 420 | if (position == lastPosition) { 421 | value = 1; 422 | } 423 | 424 | switch (animationType) { 425 | case ANIM_SCALE_X: 426 | view.setScaleX(value); 427 | break; 428 | case ANIM_SCALE_Y: 429 | view.setScaleY(value); 430 | break; 431 | case ANIM_TRANSLATE_X: 432 | if (value == 0) 433 | view.setVisibility(INVISIBLE); 434 | break; 435 | case ANIM_TRANSLATE_Y: 436 | view.setTranslationY(value == 1 ? value : selectorSize); 437 | break; 438 | case ANIM_ALPHA: 439 | view.setAlpha(value); 440 | break; 441 | } 442 | button.setOnSelectorColorChangedListener(this, position); 443 | updateViewSelectorColor(view, button.hasSelectorColor() ? button.getSelectorColor() : selectorColor); 444 | 445 | v_selectors.add(view); 446 | selectorContainer.addView(view); 447 | } 448 | 449 | private void initButtonListener(RadioRealButton button, final int position) { 450 | boolean isClickable = button.isClickable(); 451 | boolean isEnabled = button.isEnabled(); 452 | 453 | button.setOnClickListener(new OnClickListener() { 454 | @Override 455 | public void onClick(View v) { 456 | makeSelection(position, true, hasAnimation); 457 | } 458 | }); 459 | 460 | if (hasEnabled || hasClickable) { 461 | button.setClickable(clickable && enabled); 462 | } else if (button.hasClickable()) { 463 | button.setClickable(isClickable); 464 | } else if (button.hasEnabled()) { 465 | button.setEnabled(isEnabled); 466 | } 467 | } 468 | 469 | public int getNumberOfButtons() { 470 | return numberOfButtons; 471 | } 472 | 473 | public void setPosition(int position) { 474 | makeSelection(position, false, hasAnimation); 475 | } 476 | 477 | public void setPosition(int position, boolean hasAnimation) { 478 | makeSelection(position, false, hasAnimation); 479 | } 480 | 481 | public void deselect() { 482 | deselect(hasAnimation); 483 | } 484 | 485 | public void deselect(boolean hasAnimation) { 486 | if (lastPosition == -1 || !buttons.get(lastPosition).isChecked()) 487 | return; 488 | makeSelection(lastPosition, false, hasAnimation, true); 489 | } 490 | 491 | private boolean isInRange(int value) { 492 | return value >= 0 && value < numberOfButtons; 493 | } 494 | 495 | private void makeSelection(int position, boolean isToggledByTouch, boolean hasAnimation) { 496 | makeSelection(position, isToggledByTouch, hasAnimation, enableDeselection); 497 | } 498 | 499 | private void makeSelection(int position, boolean isToggledByTouch, boolean hasAnimation, boolean enableDeselection) { 500 | if (!enabled && !clickable) 501 | return; 502 | 503 | RadioRealButton buttonIn = isInRange(position) ? buttons.get(position) : null; 504 | RadioRealButton buttonOut = isInRange(lastPosition) ? buttons.get(lastPosition) : null; 505 | 506 | if ((buttonIn == null || !buttonIn.isClickable() || !buttonIn.isEnabled())) 507 | return; 508 | 509 | moveSelector(position, hasAnimation, enableDeselection); 510 | animateTextAndDrawable(position, hasAnimation, buttonIn, buttonOut, enableDeselection); 511 | 512 | if (!enableDeselection) { 513 | buttonIn.setChecked(true); 514 | if (null != buttonOut) 515 | buttonOut.setChecked(false); 516 | } else { 517 | if (lastPosition == position && buttonIn.isChecked()) { 518 | buttonIn.setChecked(false); 519 | position = -1; 520 | } else 521 | buttonIn.setChecked(true); 522 | } 523 | 524 | if (null != onClickedButtonListener && isToggledByTouch) 525 | onClickedButtonListener.onClickedButton(buttonIn, position); 526 | if (null != onPositionChangedListener && (lastPosition != position || enableDeselection)) { 527 | onPositionChangedListener.onPositionChanged(buttonIn, position, lastPosition); 528 | } 529 | 530 | this.lastPosition = position; 531 | } 532 | 533 | public int getPosition() { 534 | return lastPosition; 535 | } 536 | 537 | /* DRAWABLE AND TEXT ANIMATION BEGINS */ 538 | private void animateTextAndDrawable(int toPosition, boolean hasAnimation, RadioRealButton buttonIn, RadioRealButton buttonOut, boolean enableDeselection) { 539 | if (lastPosition == toPosition && enableDeselection) { 540 | if (buttonIn.isChecked()) 541 | animateExit(buttonIn, hasAnimation); 542 | else 543 | animateEnter(buttonIn, hasAnimation); 544 | } else { 545 | if (null != buttonOut) 546 | animateExit(buttonOut, hasAnimation); 547 | if (null != buttonIn) 548 | animateEnter(buttonIn, hasAnimation); 549 | } 550 | } 551 | 552 | private void animateColorTransitions(RadioRealButton button, boolean hasAnimation, boolean onEnter) { 553 | int textDuration = onEnter ? animateTextsColorDurationEnter : animateTextsColorDurationExit; 554 | int drawableDuration = onEnter ? animateDrawablesTintDurationEnter : animateDrawablesTintDurationExit; 555 | 556 | button.colorTransitionText(hasAnimateTextsColor, animateTextsColorExit, animateTextsColorEnter, textDuration, hasAnimation, onEnter); 557 | button.colorTransitionDrawable(hasAnimateDrawablesTint, animateDrawablesTintExit, animateDrawablesTintEnter, drawableDuration, hasAnimation, onEnter); 558 | } 559 | 560 | private void animateExit(RadioRealButton button, boolean hasAnimation) { 561 | if (hasAnimateTexts) 562 | button.bounceText(1, animateTextsExitDuration, interpolatorTextExit, hasAnimation); 563 | if (hasAnimateDrawables) 564 | button.bounceDrawable(1, animateDrawablesExitDuration, interpolatorDrawablesExit, hasAnimation); 565 | animateColorTransitions(button, hasAnimation, false); 566 | } 567 | 568 | private void animateEnter(RadioRealButton button, boolean hasAnimation) { 569 | if (hasAnimateTexts) 570 | button.bounceText(animateTextsScale, animateTextsEnterDuration, interpolatorText, hasAnimation); 571 | if (hasAnimateDrawables) 572 | button.bounceDrawable(animateDrawablesScale, animateDrawablesEnterDuration, interpolatorDrawablesEnter, hasAnimation); 573 | animateColorTransitions(button, hasAnimation, true); 574 | } 575 | /* DRAWABLE AND TEXT ANIMATION ENDS */ 576 | 577 | public final int ANIM_TRANSLATE_X = 0; 578 | public final int ANIM_TRANSLATE_Y = 1; 579 | public final int ANIM_SCALE_X = 2; 580 | public final int ANIM_SCALE_Y = 3; 581 | public final int ANIM_ALPHA = 4; 582 | 583 | private void moveSelector(int toPosition, boolean hasAnimation, boolean enableDeselection) { 584 | if (toPosition == lastPosition && !enableDeselection) 585 | return; 586 | String[] properties = {"translationX", "translationY", "scaleX", "scaleY", "alpha", "translationY"}; 587 | 588 | if (animationType == ANIM_TRANSLATE_X) { 589 | animateSelectorSliding(toPosition, properties[animationType], hasAnimation, enableDeselection); 590 | } else { 591 | animateSelector(toPosition, properties[animationType], hasAnimation, enableDeselection); 592 | } 593 | } 594 | 595 | private void animateSelector(int toPosition, String property, boolean hasAnimation, boolean enableDeselection) { 596 | int value1 = 0, value2 = 1; 597 | if (animationType == ANIM_TRANSLATE_Y) { 598 | value1 = selectorSize; 599 | value2 = 0; 600 | } 601 | 602 | if (enableDeselection && toPosition == lastPosition && !buttons.get(toPosition).isChecked()) { 603 | int temp = value1; 604 | value1 = value2; 605 | value2 = temp; 606 | } 607 | 608 | AnimatorSet set = new AnimatorSet(); 609 | ObjectAnimator to = createAnimator(v_selectors.get(toPosition), property, value2, false, hasAnimation); 610 | 611 | if (lastPosition > -1) { 612 | ObjectAnimator from = createAnimator(v_selectors.get(lastPosition), property, value1, true, hasAnimation); 613 | set.playTogether(to, from); 614 | } else 615 | set.play(to); 616 | 617 | set.start(); 618 | } 619 | 620 | private void animateSelectorSliding(int toPosition, String property, boolean hasAnimation, boolean enableDeselection) { 621 | boolean isViewDrawn = buttons.size() > 0 && buttons.get(0).getWidth() > 0; 622 | if (!isViewDrawn) { 623 | if (initialPosition != -1) 624 | v_selectors.get(initialPosition).setVisibility(INVISIBLE); 625 | v_selectors.get(toPosition).setVisibility(VISIBLE); 626 | initialPosition = toPosition; 627 | return; 628 | } 629 | 630 | if (initialPosition < 0) { 631 | initialPosition = 0; 632 | 633 | View view = v_selectors.get(initialPosition); 634 | view.setTranslationX(-buttons.get(initialPosition).getMeasuredWidth()); 635 | view.setVisibility(VISIBLE); 636 | } 637 | 638 | if (enableDeselection && toPosition == lastPosition && buttons.get(toPosition).isChecked()) { 639 | toPosition = lastPosition > numberOfButtons / 2 ? numberOfButtons : -1; 640 | } 641 | 642 | float position = toPosition - initialPosition; 643 | 644 | float value = buttons.get(initialPosition).getMeasuredWidth() * position + dividerSize * position; 645 | ObjectAnimator animator = createAnimator(v_selectors.get(initialPosition), property, value, false, hasAnimation); 646 | animator.start(); 647 | } 648 | 649 | private ObjectAnimator createAnimator(View view, String property, float value, boolean hasDelay, boolean hasDuration) { 650 | ObjectAnimator animator = ObjectAnimator.ofFloat(view, property, value); 651 | animator.setInterpolator(interpolatorSelector); 652 | if (hasDuration) 653 | animator.setDuration(animateSelectorDuration); 654 | else 655 | animator.setDuration(0); 656 | if (hasDelay) 657 | animator.setStartDelay(animateSelectorDelay); 658 | return animator; 659 | } 660 | 661 | private void setRippleState(boolean state) { 662 | for (RadioRealButton b : buttons) { 663 | b.setClickable(state); 664 | } 665 | } 666 | 667 | private void setState() { 668 | if (hasEnabled) 669 | setEnabled(enabled); 670 | else if (hasClickable) 671 | setClickable(clickable); 672 | } 673 | 674 | private void setEnabledAlpha(boolean enabled) { 675 | float alpha = 1f; 676 | if (!enabled) 677 | alpha = 0.5f; 678 | 679 | setAlpha(alpha); 680 | } 681 | 682 | @Override 683 | public void setEnabled(boolean enabled) { 684 | this.enabled = enabled; 685 | setEnabledAlpha(enabled); 686 | setRippleState(enabled); 687 | } 688 | 689 | @Override 690 | public void setClickable(boolean clickable) { 691 | this.clickable = clickable; 692 | setRippleState(clickable); 693 | } 694 | 695 | /** 696 | * LISTENERS 697 | */ 698 | private OnClickedButtonListener onClickedButtonListener; 699 | 700 | public void setOnClickedButtonListener(OnClickedButtonListener onClickedButtonListener) { 701 | this.onClickedButtonListener = onClickedButtonListener; 702 | } 703 | 704 | public interface OnClickedButtonListener { 705 | void onClickedButton(RadioRealButton button, int position); 706 | } 707 | 708 | private OnPositionChangedListener onPositionChangedListener; 709 | 710 | public void setOnPositionChangedListener(OnPositionChangedListener onPositionChangedListener) { 711 | this.onPositionChangedListener = onPositionChangedListener; 712 | } 713 | 714 | public interface OnPositionChangedListener { 715 | void onPositionChanged(RadioRealButton button, int currentPosition, int lastPosition); 716 | } 717 | 718 | public void setOnLongClickedButtonListener(final OnLongClickedButtonListener onLongClickedButtonListener) { 719 | for (int i = 0; i < numberOfButtons; i++) { 720 | final int buttonPosition = i; 721 | buttons.get(i).setOnLongClickListener(new View.OnLongClickListener() { 722 | @Override 723 | public boolean onLongClick(View v) { 724 | return onLongClickedButtonListener == null || onLongClickedButtonListener.onLongClickedButton((RadioRealButton) v, buttonPosition); 725 | } 726 | }); 727 | } 728 | } 729 | 730 | public interface OnLongClickedButtonListener { 731 | boolean onLongClickedButton(RadioRealButton button, int position); 732 | 733 | } 734 | 735 | /** 736 | * LISTENERS --- ENDS 737 | */ 738 | 739 | 740 | public int getAnimateTextsColorExit() { 741 | return animateTextsColorExit; 742 | } 743 | 744 | public void setAnimateTextsColorExit(int animateTextsColorExit) { 745 | this.animateTextsColorExit = animateTextsColorExit; 746 | } 747 | 748 | public int getAnimateTextsColorEnter() { 749 | return animateTextsColorEnter; 750 | } 751 | 752 | public void setAnimateTextsColorEnter(int animateTextsColorEnter) { 753 | this.animateTextsColorEnter = animateTextsColorEnter; 754 | } 755 | 756 | public int getAnimateTextsColorDuration() { 757 | return animateTextsColorDuration; 758 | } 759 | 760 | public void setAnimateTextsColorDuration(int animateTextsColorDuration) { 761 | this.animateTextsColorDuration = animateTextsColorDuration; 762 | } 763 | 764 | public int getAnimateDrawablesTintExit() { 765 | return animateDrawablesTintExit; 766 | } 767 | 768 | public void setAnimateDrawablesTintExit(int animateDrawablesTintExit) { 769 | this.animateDrawablesTintExit = animateDrawablesTintExit; 770 | } 771 | 772 | public int getAnimateDrawablesTintEnter() { 773 | return animateDrawablesTintEnter; 774 | } 775 | 776 | public void setAnimateDrawablesTintEnter(int animateDrawablesTintEnter) { 777 | this.animateDrawablesTintEnter = animateDrawablesTintEnter; 778 | } 779 | 780 | public int getAnimateDrawablesTintColorDuration() { 781 | return animateDrawablesTintDuration; 782 | } 783 | 784 | public void setAnimateDrawablesTintColorDuration(int animateDrawablesTintColorDuration) { 785 | this.animateDrawablesTintDuration = animateDrawablesTintColorDuration; 786 | } 787 | 788 | public List getButtons() { 789 | return buttons; 790 | } 791 | 792 | public Interpolator getInterpolatorDrawablesEnter() { 793 | return interpolatorDrawablesEnter; 794 | } 795 | 796 | public void setInterpolatorDrawablesEnter(Interpolator interpolatorDrawablesEnter) { 797 | this.interpolatorDrawablesEnter = interpolatorDrawablesEnter; 798 | } 799 | 800 | public Interpolator getInterpolatorText() { 801 | return interpolatorText; 802 | } 803 | 804 | public void setInterpolatorText(Interpolator interpolatorText) { 805 | this.interpolatorText = interpolatorText; 806 | } 807 | 808 | public Interpolator getInterpolatorSelector() { 809 | return interpolatorSelector; 810 | } 811 | 812 | public void setInterpolatorSelector(Interpolator interpolatorSelector) { 813 | this.interpolatorSelector = interpolatorSelector; 814 | } 815 | 816 | public Interpolator getInterpolatorDrawablesExit() { 817 | return interpolatorDrawablesExit; 818 | } 819 | 820 | public void setInterpolatorDrawablesExit(Interpolator interpolatorDrawablesExit) { 821 | this.interpolatorDrawablesExit = interpolatorDrawablesExit; 822 | } 823 | 824 | public Interpolator getInterpolatorTextExit() { 825 | return interpolatorTextExit; 826 | } 827 | 828 | public void setInterpolatorTextExit(Interpolator interpolatorTextExit) { 829 | this.interpolatorTextExit = interpolatorTextExit; 830 | } 831 | 832 | public int getAnimateTextsEnter() { 833 | return animateTextsEnter; 834 | } 835 | 836 | public void setAnimateTextsEnter(int animateTextsEnter) { 837 | this.animateTextsEnter = animateTextsEnter; 838 | } 839 | 840 | public int getAnimationType() { 841 | return animationType; 842 | } 843 | 844 | public void setAnimationType(int animationType) { 845 | this.animationType = animationType; 846 | } 847 | 848 | public int getAnimateDrawablesEnterDuration() { 849 | return animateDrawablesEnterDuration; 850 | } 851 | 852 | public void setAnimateDrawablesEnterDuration(int animateDrawablesEnterDuration) { 853 | this.animateDrawablesEnterDuration = animateDrawablesEnterDuration; 854 | } 855 | 856 | public int getAnimateTextsEnterDuration() { 857 | return animateTextsEnterDuration; 858 | } 859 | 860 | public void setAnimateTextsEnterDuration(int animateTextsEnterDuration) { 861 | this.animateTextsEnterDuration = animateTextsEnterDuration; 862 | } 863 | 864 | public int getAnimateSelector() { 865 | return animateSelector; 866 | } 867 | 868 | public void setAnimateSelector(int animateSelector) { 869 | this.animateSelector = animateSelector; 870 | } 871 | 872 | public int getAnimateSelectorDuration() { 873 | return animateSelectorDuration; 874 | } 875 | 876 | public void setAnimateSelectorDuration(int animateSelectorDuration) { 877 | this.animateSelectorDuration = animateSelectorDuration; 878 | } 879 | 880 | public int getAnimateSelectorDelay() { 881 | return animateSelectorDelay; 882 | } 883 | 884 | public void setAnimateSelectorDelay(int animateSelectorDelay) { 885 | this.animateSelectorDelay = animateSelectorDelay; 886 | } 887 | 888 | public int getAnimateDrawablesExitDuration() { 889 | return animateDrawablesExitDuration; 890 | } 891 | 892 | public void setAnimateDrawablesExitDuration(int animateDrawablesExitDuration) { 893 | this.animateDrawablesExitDuration = animateDrawablesExitDuration; 894 | } 895 | 896 | public int getAnimateTextsExit() { 897 | return animateTextsExit; 898 | } 899 | 900 | public void setAnimateTextsExit(int animateTextsExit) { 901 | this.animateTextsExit = animateTextsExit; 902 | } 903 | 904 | public int getAnimateTextsExitDuration() { 905 | return animateTextsExitDuration; 906 | } 907 | 908 | public void setAnimateTextsExitDuration(int animateTextsExitDuration) { 909 | this.animateTextsExitDuration = animateTextsExitDuration; 910 | } 911 | 912 | private void setButtonsPadding(int left, int top, int right, int bottom){ 913 | buttonPaddingLeft = left; 914 | buttonPaddingTop = top; 915 | buttonPaddingRight = right; 916 | buttonPaddingBottom = bottom; 917 | 918 | for (RadioRealButton button : buttons) { 919 | setButtonPadding(button); 920 | } 921 | } 922 | 923 | public int getButtonsPadding() { 924 | return buttonPadding; 925 | } 926 | 927 | public int getButtonsPaddingLeft() { 928 | return buttonPaddingLeft; 929 | } 930 | 931 | public int getButtonsPaddingRight() { 932 | return buttonPaddingRight; 933 | } 934 | 935 | public int getButtonsPaddingTop() { 936 | return buttonPaddingTop; 937 | } 938 | 939 | public int getButtonsPaddingBottom() { 940 | return buttonPaddingBottom; 941 | } 942 | 943 | public int getDividerPadding() { 944 | return dividerPadding; 945 | } 946 | 947 | public void setDividerPadding(int dividerPadding) { 948 | this.dividerPadding = dividerPadding; 949 | 950 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 951 | container.setDividerPadding(dividerPadding); 952 | } 953 | } 954 | 955 | public int getDividerSize() { 956 | return dividerSize; 957 | } 958 | 959 | public void setDividerSize(int dividerSize) { 960 | this.dividerSize = dividerSize; 961 | RoundHelper.makeDividerRound(container, dividerColor, dividerRadius, dividerSize); 962 | } 963 | 964 | public int getDividerRadius() { 965 | return dividerRadius; 966 | } 967 | 968 | public void setDividerRadius(int dividerRadius) { 969 | this.dividerRadius = dividerRadius; 970 | RoundHelper.makeDividerRound(container, dividerColor, dividerRadius, dividerSize); 971 | } 972 | 973 | public int getBottomLineSize() { 974 | return bottomLineSize; 975 | } 976 | 977 | public void setBottomLineSize(int bottomLineSize) { 978 | this.bottomLineSize = bottomLineSize; 979 | setBottomLineAttrs(); 980 | } 981 | 982 | public int getBottomLineRadius() { 983 | return bottomLineRadius; 984 | } 985 | 986 | public void setBottomLineRadius(int bottomLineRadius) { 987 | this.bottomLineRadius = bottomLineRadius; 988 | updateViewBottomLine(); 989 | } 990 | 991 | public int getBorderSize() { 992 | return borderSize; 993 | } 994 | 995 | public void setBorderSize(int borderSize) { 996 | this.borderSize = borderSize; 997 | setBorderAttrs(); 998 | } 999 | 1000 | public int getBorderColor() { 1001 | return borderColor; 1002 | } 1003 | 1004 | public void setBorderColor(int borderColor) { 1005 | this.borderColor = borderColor; 1006 | setBorderAttrs(); 1007 | } 1008 | 1009 | public int getDividerColor() { 1010 | return dividerColor; 1011 | } 1012 | 1013 | public void setDividerColor(int dividerColor) { 1014 | this.dividerColor = dividerColor; 1015 | RoundHelper.makeDividerRound(container, dividerColor, dividerRadius, dividerSize); 1016 | } 1017 | 1018 | public int getBottomLineColor() { 1019 | return bottomLineColor; 1020 | } 1021 | 1022 | public void setBottomLineColor(int bottomLineColor) { 1023 | this.bottomLineColor = bottomLineColor; 1024 | updateViewBottomLine(); 1025 | } 1026 | 1027 | private void updateViewBottomLine() { 1028 | RoundHelper.makeRound(v_bottomLine, bottomLineColor, bottomLineRadius, bottomLineRadius); 1029 | } 1030 | 1031 | public int getSelectorColor() { 1032 | return selectorColor; 1033 | } 1034 | 1035 | private void updateViewSelectorColor(View view, int color) { 1036 | updateViewSelector(view, color, selectorRadius, selectorSize); 1037 | } 1038 | 1039 | public void setSelectorColor(int selectorColor) { 1040 | this.selectorColor = selectorColor; 1041 | 1042 | for (View selector : v_selectors) { 1043 | updateViewSelectorColor(selector, selectorColor); 1044 | } 1045 | } 1046 | 1047 | @Override 1048 | public void onSelectorColorChanged(int position, int selectorColor) { 1049 | updateViewSelectorColor(v_selectors.get(position), selectorColor); 1050 | } 1051 | 1052 | private void updateViewSelector(View view, int color, int radius, int size) { 1053 | RoundHelper.makeRound( 1054 | view, 1055 | color, 1056 | radius, 1057 | selectorFullSize ? null : size 1058 | ); 1059 | } 1060 | 1061 | private void updateViewSelector(View view) { 1062 | updateViewSelector(view, selectorColor, selectorRadius, selectorSize); 1063 | } 1064 | 1065 | public int getSelectorSize() { 1066 | return selectorSize; 1067 | } 1068 | 1069 | public void setSelectorSize(int selectorSize) { 1070 | this.selectorSize = selectorSize; 1071 | 1072 | selectorContainer.getLayoutParams().height = selectorSize; 1073 | 1074 | for (View selector : v_selectors) { 1075 | updateViewSelector(selector); 1076 | 1077 | selector.getLayoutParams().height = selectorSize; 1078 | selector.requestLayout(); 1079 | } 1080 | } 1081 | 1082 | public int getSelectorRadius() { 1083 | return selectorRadius; 1084 | } 1085 | 1086 | public void setSelectorRadius(int selectorRadius) { 1087 | this.selectorRadius = selectorRadius; 1088 | 1089 | for (View selector : v_selectors) { 1090 | updateViewSelector(selector); 1091 | } 1092 | } 1093 | 1094 | public float getRadius() { 1095 | return radius; 1096 | } 1097 | 1098 | public void setRadius(float radius) { 1099 | this.radius = radius; 1100 | setCornerRadius(radius); 1101 | } 1102 | 1103 | public float getAnimateDrawablesScale() { 1104 | return animateDrawablesScale; 1105 | } 1106 | 1107 | public void setAnimateDrawablesScale(float animateDrawablesScale) { 1108 | this.animateDrawablesScale = animateDrawablesScale; 1109 | } 1110 | 1111 | public float getAnimateTextsScale() { 1112 | return animateTextsScale; 1113 | } 1114 | 1115 | public void setAnimateTextsScale(float animateTextsScale) { 1116 | this.animateTextsScale = animateTextsScale; 1117 | } 1118 | 1119 | public boolean isBottomLineOnFront() { 1120 | return bottomLineBringToFront; 1121 | } 1122 | 1123 | public void setBottomLineToFront(boolean bottomLineBringToFront) { 1124 | this.bottomLineBringToFront = bottomLineBringToFront; 1125 | setBottomLineAttrs(); 1126 | } 1127 | 1128 | public boolean isSelectorOnFront() { 1129 | return selectorBringToFront; 1130 | } 1131 | 1132 | public void setSelectorToFront(boolean selectorBringToFront) { 1133 | this.selectorBringToFront = selectorBringToFront; 1134 | setSelectorAttrs(); 1135 | } 1136 | 1137 | public boolean isSelectorAboveOfBottomLine() { 1138 | return selectorAboveOfBottomLine; 1139 | } 1140 | 1141 | public void setSelectorAboveOfBottomLine(boolean selectorAboveOfBottomLine) { 1142 | this.selectorAboveOfBottomLine = selectorAboveOfBottomLine; 1143 | setSelectorAttrs(); 1144 | } 1145 | 1146 | public boolean isSelectorTop() { 1147 | return selectorTop; 1148 | } 1149 | 1150 | public void setSelectorTop(boolean selectorTop) { 1151 | this.selectorTop = selectorTop; 1152 | } 1153 | 1154 | public boolean isSelectorBottom() { 1155 | return selectorBottom; 1156 | } 1157 | 1158 | public void setSelectorBottom(boolean selectorBottom) { 1159 | this.selectorBottom = selectorBottom; 1160 | } 1161 | 1162 | public boolean hasPadding() { 1163 | return hasPadding; 1164 | } 1165 | 1166 | public boolean hasPaddingLeft() { 1167 | return hasPaddingLeft; 1168 | } 1169 | 1170 | public boolean hasPaddingRight() { 1171 | return hasPaddingRight; 1172 | } 1173 | 1174 | public boolean hasPaddingTop() { 1175 | return hasPaddingTop; 1176 | } 1177 | 1178 | public boolean hasPaddingBottom() { 1179 | return hasPaddingBottom; 1180 | } 1181 | 1182 | @Override 1183 | public boolean isClickable() { 1184 | return clickable; 1185 | } 1186 | 1187 | @Override 1188 | public boolean isEnabled() { 1189 | return enabled; 1190 | } 1191 | 1192 | public boolean hasDeselection() { 1193 | return enableDeselection; 1194 | } 1195 | 1196 | public void setDeselection(boolean deselection) { 1197 | this.enableDeselection = deselection; 1198 | } 1199 | } 1200 | -------------------------------------------------------------------------------- /library/src/main/java/co/ceryle/radiorealbutton/RippleHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 ceryle 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package co.ceryle.radiorealbutton; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.content.res.ColorStateList; 21 | import android.content.res.TypedArray; 22 | import android.graphics.Color; 23 | import android.graphics.drawable.ColorDrawable; 24 | import android.graphics.drawable.Drawable; 25 | import android.graphics.drawable.RippleDrawable; 26 | import android.graphics.drawable.ShapeDrawable; 27 | import android.graphics.drawable.StateListDrawable; 28 | import android.graphics.drawable.shapes.RectShape; 29 | import android.os.Build; 30 | import android.view.View; 31 | 32 | class RippleHelper { 33 | 34 | static void setSelectableItemBackground(Context context, View view) { 35 | int[] attrs = new int[]{android.R.attr.selectableItemBackground}; 36 | TypedArray ta = context.obtainStyledAttributes(attrs); 37 | Drawable drawableFromTheme = ta.getDrawable(0 /* index */); 38 | ta.recycle(); 39 | BackgroundHelper.setBackground(view, drawableFromTheme); 40 | } 41 | 42 | static void setRipple(View view, int pressedColor) { 43 | setRipple(view, pressedColor, null); 44 | } 45 | 46 | static void setRipple(View view, int pressedColor, Integer normalColor) { 47 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 48 | view.setBackground(getRippleDrawable(pressedColor, normalColor)); 49 | } else { 50 | view.setBackgroundDrawable(getStateListDrawable(pressedColor, normalColor)); 51 | } 52 | } 53 | 54 | private static StateListDrawable getStateListDrawable(int pressedColor, Integer normalColor) { 55 | StateListDrawable states = new StateListDrawable(); 56 | states.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(pressedColor)); 57 | states.addState(new int[]{android.R.attr.state_focused}, new ColorDrawable(pressedColor)); 58 | states.addState(new int[]{android.R.attr.state_activated}, new ColorDrawable(pressedColor)); 59 | if (null != normalColor) 60 | states.addState(new int[]{}, new ColorDrawable(normalColor)); 61 | return states; 62 | } 63 | 64 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 65 | private static Drawable getRippleDrawable(int pressedColor, Integer normalColor) { 66 | ColorStateList colorStateList = getPressedColorSelector(pressedColor); 67 | Drawable mask, content = null; 68 | 69 | if (null == normalColor) { 70 | mask = new ShapeDrawable(); 71 | } else { 72 | content = new ColorDrawable(normalColor); 73 | mask = getRippleMask(Color.WHITE); 74 | } 75 | return new RippleDrawable(colorStateList, content, mask); 76 | } 77 | 78 | private static ColorStateList getPressedColorSelector(int pressedColor) { 79 | return new ColorStateList( 80 | new int[][]{ 81 | new int[]{} 82 | }, 83 | new int[]{ 84 | pressedColor 85 | } 86 | ); 87 | } 88 | 89 | private static Drawable getRippleMask(int color) { 90 | ShapeDrawable shapeDrawable = new ShapeDrawable(new RectShape()); 91 | shapeDrawable.getPaint().setColor(color); 92 | return shapeDrawable; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /library/src/main/java/co/ceryle/radiorealbutton/RoundHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 ceryle 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package co.ceryle.radiorealbutton; 17 | 18 | import android.graphics.drawable.GradientDrawable; 19 | import android.view.View; 20 | import android.widget.LinearLayout; 21 | 22 | class RoundHelper { 23 | 24 | static void makeRound(View view, int dividerColor, int dividerRadius, Integer dividerSize) { 25 | GradientDrawable gradient = getGradientDrawable(dividerColor, dividerRadius, dividerSize); 26 | BackgroundHelper.setBackground(view, gradient); 27 | } 28 | 29 | static void makeDividerRound(LinearLayout layout, int dividerColor, int dividerRadius, Integer dividerSize) { 30 | GradientDrawable gradient = getGradientDrawable(dividerColor, dividerRadius, dividerSize); 31 | layout.setDividerDrawable(gradient); 32 | } 33 | 34 | private static GradientDrawable getGradientDrawable(int dividerColor, int dividerRadius, Integer dividerSize) { 35 | GradientDrawable gradient = 36 | new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, new int[]{dividerColor, dividerColor}); 37 | gradient.setShape(GradientDrawable.RECTANGLE); 38 | gradient.setCornerRadius(dividerRadius); 39 | if (null != dividerSize) 40 | gradient.setSize(dividerSize, 0); 41 | return gradient; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /library/src/main/java/co/ceryle/radiorealbutton/RoundedCornerLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This class is used to create a round corner layout. 3 | * I used Sushant's solution which was shared on stackoverflow.com 4 | * Also, in order to fix elevation problem, I used Ed George's solution. 5 | * Thank you both :) 6 | * 7 | * Those solutions can be found below link 8 | * http://stackoverflow.com/questions/26074784/how-to-make-a-view-in-android-with-rounded-corners 9 | * 10 | * I extended this by adding border. 11 | */ 12 | package co.ceryle.radiorealbutton; 13 | 14 | import android.annotation.TargetApi; 15 | import android.content.Context; 16 | import android.graphics.Canvas; 17 | import android.graphics.Color; 18 | import android.graphics.Outline; 19 | import android.graphics.Paint; 20 | import android.graphics.Path; 21 | import android.graphics.PorterDuff; 22 | import android.graphics.PorterDuffXfermode; 23 | import android.graphics.Rect; 24 | import android.graphics.RectF; 25 | import android.graphics.Region; 26 | import android.os.Build; 27 | import android.util.AttributeSet; 28 | import android.view.View; 29 | import android.view.ViewOutlineProvider; 30 | import android.widget.FrameLayout; 31 | 32 | public class RoundedCornerLayout extends FrameLayout { 33 | 34 | public RoundedCornerLayout(Context context) { 35 | super(context); 36 | init(context); 37 | } 38 | 39 | public RoundedCornerLayout(Context context, AttributeSet attrs) { 40 | super(context, attrs); 41 | init(context); 42 | } 43 | 44 | public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) { 45 | super(context, attrs, defStyle); 46 | init(context); 47 | } 48 | 49 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 50 | public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 51 | super(context, attrs, defStyleAttr, defStyleRes); 52 | init(context); 53 | } 54 | 55 | private float cornerRadius; 56 | private int strokeColor = Color.GRAY, strokeSize; 57 | private boolean hasStroke = false; 58 | 59 | private void init(Context context) { 60 | cornerRadius = ConversionHelper.dpToPx(context, 1); 61 | 62 | setLayerType(View.LAYER_TYPE_SOFTWARE, null); 63 | } 64 | 65 | //Fixes incorrect outline drawn by default 66 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 67 | private class ButtonOutlineProvider extends ViewOutlineProvider { 68 | @Override 69 | public void getOutline(View view, Outline outline) { 70 | outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), cornerRadius); 71 | } 72 | } 73 | 74 | @Override 75 | protected void dispatchDraw(Canvas canvas) { 76 | int count = canvas.save(); 77 | 78 | final Path path = new Path(); 79 | path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), cornerRadius, cornerRadius, Path.Direction.CW); 80 | canvas.clipPath(path, Region.Op.REPLACE); 81 | canvas.clipPath(path); 82 | 83 | super.dispatchDraw(canvas); 84 | 85 | canvas.restoreToCount(count); 86 | 87 | if (hasStroke) { 88 | 89 | Rect rect = canvas.getClipBounds(); 90 | 91 | RectF rectF = new RectF(strokeSize, strokeSize, rect.right - strokeSize, rect.bottom - strokeSize); 92 | 93 | Path clipPath = new Path(); 94 | float corner = cornerRadius - strokeSize; 95 | clipPath.addRoundRect(rectF, corner, corner, Path.Direction.CW); 96 | canvas.clipPath(clipPath, Region.Op.DIFFERENCE); 97 | 98 | Paint p_stroke = new Paint(); 99 | p_stroke.setAntiAlias(true); 100 | p_stroke.setColor(strokeColor); 101 | p_stroke.setStyle(Paint.Style.FILL); 102 | 103 | canvas.drawRoundRect(new RectF(rect), cornerRadius, cornerRadius, p_stroke); 104 | } 105 | } 106 | 107 | void setCornerRadius(float radius) { 108 | cornerRadius = radius; 109 | requestLayout(); 110 | 111 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 112 | setOutlineProvider(new ButtonOutlineProvider()); 113 | } 114 | } 115 | 116 | public void setStroke(boolean hasStroke) { 117 | this.hasStroke = hasStroke; 118 | invalidate(); 119 | } 120 | 121 | public void setStrokeColor(int strokeColor) { 122 | this.strokeColor = strokeColor; 123 | invalidate(); 124 | } 125 | 126 | public void setStrokeSize(int strokeSize) { 127 | this.strokeSize = strokeSize; 128 | invalidate(); 129 | } 130 | 131 | } -------------------------------------------------------------------------------- /library/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | 7 | defaultConfig { 8 | applicationId "co.ceryle.radiorealbutton.sample" 9 | minSdkVersion 11 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:25.3.1' 26 | 27 | compile project(":library") 28 | } 29 | -------------------------------------------------------------------------------- /sample/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 C:\Users\egeak\Documents\Programming\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 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /sample/src/main/assets/fonts/aniron.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/assets/fonts/aniron.ttf -------------------------------------------------------------------------------- /sample/src/main/assets/fonts/shaka_pow.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/assets/fonts/shaka_pow.ttf -------------------------------------------------------------------------------- /sample/src/main/java/co/ceryle/radiorealbutton/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 ceryle 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package co.ceryle.radiorealbutton.sample; 17 | 18 | import android.support.v7.app.AppCompatActivity; 19 | import android.os.Bundle; 20 | import android.view.View; 21 | import android.widget.Button; 22 | import android.widget.Toast; 23 | 24 | import co.ceryle.radiorealbutton.RadioRealButton; 25 | import co.ceryle.radiorealbutton.RadioRealButtonGroup; 26 | 27 | public class MainActivity extends AppCompatActivity { 28 | 29 | private Button button; 30 | private RadioRealButtonGroup group1; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_main); 36 | 37 | button = (Button) findViewById(R.id.button); 38 | group1 = (RadioRealButtonGroup) findViewById(R.id.radioRealButtonGroup_1); 39 | 40 | button.setTransformationMethod(null); 41 | updateText(group1.getPosition()); 42 | 43 | group1.setOnPositionChangedListener(new RadioRealButtonGroup.OnPositionChangedListener() { 44 | @Override 45 | public void onPositionChanged(RadioRealButton button, int currentPosition, int lastPosition) { 46 | updateText(currentPosition); 47 | } 48 | }); 49 | 50 | group1.setOnLongClickedButtonListener(new RadioRealButtonGroup.OnLongClickedButtonListener() { 51 | @Override 52 | public boolean onLongClickedButton(RadioRealButton button, int position) { 53 | Toast.makeText(MainActivity.this, "Long Clicked! Position: " + position, Toast.LENGTH_SHORT).show(); 54 | return false; 55 | } 56 | }); 57 | 58 | button.setOnClickListener(new View.OnClickListener() { 59 | @Override 60 | public void onClick(View v) { 61 | int position = group1.getPosition(); 62 | position = ++position % group1.getNumberOfButtons(); 63 | group1.setPosition(position); 64 | } 65 | }); 66 | 67 | RadioRealButtonGroup group2 = (RadioRealButtonGroup) findViewById(R.id.radioRealButtonGroup_2); 68 | group2.setOnClickedButtonListener(new RadioRealButtonGroup.OnClickedButtonListener() { 69 | @Override 70 | public void onClickedButton(RadioRealButton button, int position) { 71 | Toast.makeText(MainActivity.this, "Position: " + position, Toast.LENGTH_SHORT).show(); 72 | } 73 | }); 74 | } 75 | 76 | private void updateText(int position) { 77 | button.setText("Position: " + position); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/aragorn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/aragorn.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b1.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b11.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b12.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b13.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b17.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b2.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b3.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b4.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b5.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b6.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b7.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b8.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/b9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/b9.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/gimli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/gimli.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-nodpi/legolas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/drawable-nodpi/legolas.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable/ic_android_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 45 | 46 | 61 | 62 | 77 | 78 | 94 | 95 | 96 | 97 | 102 | 103 | 111 | 112 | 134 | 135 | 143 | 144 | 152 | 153 | 161 | 162 | 163 | 164 | 192 | 193 | 203 | 204 | 215 | 216 | 226 | 227 | 228 | 229 | 233 | 234 | 248 | 249 | 256 | 257 | 264 | 265 | 266 | 267 | 283 | 284 | 291 | 292 | 299 | 300 | 301 | 302 | 303 | 329 | 330 | 336 | 337 | 343 | 344 | 350 | 351 | 357 | 358 | 364 | 365 | 366 | 367 | 387 | 388 | 396 | 397 | 405 | 406 | 414 | 415 | 423 | 424 | 432 | 433 | 434 | 463 | 464 | 476 | 477 | 489 | 490 | 502 | 503 | 504 | 505 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ceryle/RadioRealButton/921382d97fe613183fb4c33c198236ff34fb1311/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #3F51B5 5 | #303F9F 6 | #FF4081 7 | 8 | 9 | 10 | 11 | 12 | 13 | #FFEBEE 14 | #FFCDD2 15 | #EF9A9A 16 | #E57373 17 | #EF5350 18 | #F44336 19 | #E53935 20 | #D32F2F 21 | #C62828 22 | #B71C1C 23 | #FF8A80 24 | #FF5252 25 | #FF1744 26 | #D50000 27 | 28 | 29 | 30 | #FCE4EC 31 | #F8BBD0 32 | #F48FB1 33 | #F06292 34 | #EC407A 35 | #E91E63 36 | #D81B60 37 | #C2185B 38 | #AD1457 39 | #880E4F 40 | #FF80AB 41 | #FF4081 42 | #F50057 43 | #C51162 44 | 45 | 46 | 47 | #F3E5F5 48 | #E1BEE7 49 | #CE93D8 50 | #BA68C8 51 | #AB47BC 52 | #9C27B0 53 | #8E24AA 54 | #7B1FA2 55 | #6A1B9A 56 | #4A148C 57 | #EA80FC 58 | #E040FB 59 | #D500F9 60 | #AA00FF 61 | 62 | 63 | 64 | #EDE7F6 65 | #D1C4E9 66 | #B39DDB 67 | #9575CD 68 | #7E57C2 69 | #673AB7 70 | #5E35B1 71 | #512DA8 72 | #4527A0 73 | #311B92 74 | #B388FF 75 | #7C4DFF 76 | #651FFF 77 | #6200EA 78 | 79 | 80 | 81 | #E8EAF6 82 | #C5CAE9 83 | #9FA8DA 84 | #7986CB 85 | #5C6BC0 86 | #3F51B5 87 | #3949AB 88 | #303F9F 89 | #283593 90 | #1A237E 91 | #8C9EFF 92 | #536DFE 93 | #3D5AFE 94 | #304FFE 95 | 96 | 97 | 98 | #E3F2FD 99 | #BBDEFB 100 | #90CAF9 101 | #64B5F6 102 | #42A5F5 103 | #2196F3 104 | #1E88E5 105 | #1976D2 106 | #1565C0 107 | #0D47A1 108 | #82B1FF 109 | #448AFF 110 | #2979FF 111 | #2962FF 112 | 113 | 114 | 115 | #E1F5FE 116 | #B3E5FC 117 | #81D4FA 118 | #4FC3F7 119 | #29B6F6 120 | #03A9F4 121 | #039BE5 122 | #0288D1 123 | #0277BD 124 | #01579B 125 | #80D8FF 126 | #40C4FF 127 | #00B0FF 128 | #0091EA 129 | 130 | 131 | 132 | #E0F7FA 133 | #B2EBF2 134 | #80DEEA 135 | #4DD0E1 136 | #26C6DA 137 | #00BCD4 138 | #00ACC1 139 | #0097A7 140 | #00838F 141 | #006064 142 | #84FFFF 143 | #18FFFF 144 | #00E5FF 145 | #00B8D4 146 | 147 | 148 | 149 | #E0F2F1 150 | #B2DFDB 151 | #80CBC4 152 | #4DB6AC 153 | #26A69A 154 | #009688 155 | #00897B 156 | #00796B 157 | #00695C 158 | #004D40 159 | #A7FFEB 160 | #64FFDA 161 | #1DE9B6 162 | #00BFA5 163 | 164 | 165 | 166 | #E8F5E9 167 | #C8E6C9 168 | #A5D6A7 169 | #81C784 170 | #66BB6A 171 | #4CAF50 172 | #43A047 173 | #388E3C 174 | #2E7D32 175 | #1B5E20 176 | #B9F6CA 177 | #69F0AE 178 | #00E676 179 | #00C853 180 | 181 | 182 | 183 | #F1F8E9 184 | #DCEDC8 185 | #C5E1A5 186 | #AED581 187 | #9CCC65 188 | #8BC34A 189 | #7CB342 190 | #689F38 191 | #558B2F 192 | #33691E 193 | #CCFF90 194 | #B2FF59 195 | #76FF03 196 | #64DD17 197 | 198 | 199 | 200 | #F9FBE7 201 | #F0F4C3 202 | #E6EE9C 203 | #DCE775 204 | #D4E157 205 | #CDDC39 206 | #C0CA33 207 | #AFB42B 208 | #9E9D24 209 | #827717 210 | #F4FF81 211 | #EEFF41 212 | #C6FF00 213 | #AEEA00 214 | 215 | 216 | 217 | #FFFDE7 218 | #FFF9C4 219 | #FFF59D 220 | #FFF176 221 | #FFEE58 222 | #FFEB3B 223 | #FDD835 224 | #FBC02D 225 | #F9A825 226 | #F57F17 227 | #FFFF8D 228 | #FFFF00 229 | #FFEA00 230 | #FFD600 231 | 232 | 233 | 234 | #FFF8E1 235 | #FFECB3 236 | #FFE082 237 | #FFD54F 238 | #FFCA28 239 | #FFC107 240 | #FFB300 241 | #FFA000 242 | #FF8F00 243 | #FF6F00 244 | #FFE57F 245 | #FFD740 246 | #FFC400 247 | #FFAB00 248 | 249 | 250 | 251 | #FFF3E0 252 | #FFE0B2 253 | #FFCC80 254 | #FFB74D 255 | #FFA726 256 | #FF9800 257 | #FB8C00 258 | #F57C00 259 | #EF6C00 260 | #E65100 261 | #FFD180 262 | #FFAB40 263 | #FF9100 264 | #FF6D00 265 | 266 | 267 | 268 | #FBE9E7 269 | #FFCCBC 270 | #FFAB91 271 | #FF8A65 272 | #FF7043 273 | #FF5722 274 | #F4511E 275 | #E64A19 276 | #D84315 277 | #BF360C 278 | #FF9E80 279 | #FF6E40 280 | #FF3D00 281 | #DD2C00 282 | 283 | 284 | 285 | #EFEBE9 286 | #D7CCC8 287 | #BCAAA4 288 | #A1887F 289 | #8D6E63 290 | #795548 291 | #6D4C41 292 | #5D4037 293 | #4E342E 294 | #3E2723 295 | 296 | 297 | 298 | #FAFAFA 299 | #F5F5F5 300 | #EEEEEE 301 | #E0E0E0 302 | #BDBDBD 303 | #9E9E9E 304 | #757575 305 | #616161 306 | #424242 307 | #212121 308 | 309 | 310 | 311 | #ECEFF1 312 | #CFD8DC 313 | #B0BEC5 314 | #90A4AE 315 | #78909C 316 | #607D8B 317 | #546E7A 318 | #455A64 319 | #37474F 320 | #263238 321 | 322 | 323 | 324 | #000000 325 | 326 | 327 | 328 | #FFFFFF 329 | 330 | 331 | 332 | #FFFF00 333 | #FF00FF 334 | #FF0000 335 | #C0C0C0 336 | #808080 337 | #808000 338 | #800080 339 | #800000 340 | #00FFFF 341 | #00FF00 342 | #008080 343 | #008000 344 | #0000FF 345 | #000080 346 | #FFFFFF 347 | #FFFFF0 348 | #FFFFE0 349 | #FFFF00 350 | #FFFAFA 351 | #FFFAF0 352 | #FFFACD 353 | #FFF8DC 354 | #FFF5EE 355 | #FFF0F5 356 | #FFEFD5 357 | #FFEBCD 358 | #FFE4E1 359 | #FFE4C4 360 | #FFE4B5 361 | #FFDEAD 362 | #FFDAB9 363 | #FFD700 364 | #FFC0CB 365 | #FFB6C1 366 | #FFA500 367 | #FFA07A 368 | #FF8C00 369 | #FF7F50 370 | #FF69B4 371 | #FF6347 372 | #FF4500 373 | #FF1493 374 | #FF00FF 375 | #FF00FF 376 | #FF0000 377 | #FDF5E6 378 | #FAFAD2 379 | #FAF0E6 380 | #FAEBD7 381 | #FA8072 382 | #F8F8FF 383 | #F5FFFA 384 | #F5F5F5 385 | #F5F5DC 386 | #F5DEB3 387 | #F4A460 388 | #F0FFFF 389 | #F0FFF0 390 | #F0F8FF 391 | #F0E68C 392 | #F08080 393 | #EEE8AA 394 | #EE82EE 395 | #E9967A 396 | #E6E6FA 397 | #E0FFFF 398 | #DEB887 399 | #DDA0DD 400 | #DCDCDC 401 | #DC143C 402 | #DB7093 403 | #DAA520 404 | #DA70D6 405 | #D8BFD8 406 | #D3D3D3 407 | #D2B48C 408 | #D2691E 409 | #CD853F 410 | #CD5C5C 411 | #C71585 412 | #C0C0C0 413 | #BDB76B 414 | #BC8F8F 415 | #BA55D3 416 | #B8860B 417 | #B22222 418 | #B0E0E6 419 | #B0C4DE 420 | #AFEEEE 421 | #ADFF2F 422 | #ADD8E6 423 | #A9A9A9 424 | #A52A2A 425 | #A0522D 426 | #9ACD32 427 | #9932CC 428 | #98FB98 429 | #9400D3 430 | #9370DB 431 | #90EE90 432 | #8FBC8F 433 | #8B4513 434 | #8B008B 435 | #8B0000 436 | #8A2BE2 437 | #87CEFA 438 | #87CEEB 439 | #808080 440 | #808000 441 | #800080 442 | #800000 443 | #7FFFD4 444 | #7FFF00 445 | #7CFC00 446 | #7B68EE 447 | #4B0082 448 | #778899 449 | #708090 450 | #6B8E23 451 | #6A5ACD 452 | #696969 453 | #66CDAA 454 | #6495ED 455 | #5F9EA0 456 | #556B2F 457 | #48D1CC 458 | #483D8B 459 | #4682B4 460 | #4169E1 461 | #40E0D0 462 | #3CB371 463 | #32CD32 464 | #2F4F4F 465 | #2E8B57 466 | #228B22 467 | #20B2AA 468 | #1E90FF 469 | #191970 470 | #00FFFF 471 | #00FFFF 472 | #00FF7F 473 | #00FF00 474 | #00FA9A 475 | #00CED1 476 | #00BFFF 477 | #008B8B 478 | #008080 479 | #008000 480 | #006400 481 | #0000FF 482 | #0000CD 483 | #00008B 484 | #000080 485 | #000000 486 | #0000A0 487 | 488 | 489 | 490 | -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RadioRealButton 3 | 4 | -------------------------------------------------------------------------------- /sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':sample', ':library' 2 | --------------------------------------------------------------------------------