├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── issue_en_template_bug.yml │ ├── issue_en_template_question.yml │ ├── issue_en_template_suggest.yml │ ├── issue_zh_template_bug.yml │ ├── issue_zh_template_question.yml │ └── issue_zh_template_suggest.yml └── workflows │ └── android.yml ├── .gitignore ├── LICENSE ├── README.md ├── app ├── AppSignature.jks ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── hjq │ │ └── shape │ │ └── drawable │ │ └── demo │ │ ├── AppApplication.java │ │ └── MainActivity.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values-v23 │ └── styles.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── hjq │ └── shape │ └── drawable │ ├── ShapeDrawable.java │ ├── ShapeDrawableUtils.java │ ├── ShapeGradientOrientation.java │ ├── ShapeGradientType.java │ ├── ShapeGradientTypeLimit.java │ ├── ShapeState.java │ ├── ShapeType.java │ └── ShapeTypeLimit.java ├── picture ├── demo_code.png └── long_screenshots.jpg └── settings.gradle /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_ali.png 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_en_template_bug.yml: -------------------------------------------------------------------------------- 1 | name: Submit Bug 2 | description: Please let me know the issues with the framework, and I will assist you in resolving them! 3 | title: "[Bug]:" 4 | labels: ["bug"] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | ## [Warning: Please make sure to fill in the issue template accurately. If an issue is found to be filled incorrectly, it will be closed without further notice.](https://github.com/getActivity/IssueTemplateGuide) 11 | - type: input 12 | id: input_id_1 13 | attributes: 14 | label: Framework Version [Required] 15 | description: Please enter the version of the framework you are using. 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: input_id_2 20 | attributes: 21 | label: Issue Description [Required] 22 | description: Please describe the issue you are facing. 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: input_id_3 27 | attributes: 28 | label: Steps to Reproduce [Required] 29 | description: Please provide steps to reproduce the issue. 30 | validations: 31 | required: true 32 | - type: dropdown 33 | id: input_id_4 34 | attributes: 35 | label: Is the Issue Reproducible? [Required] 36 | multiple: false 37 | options: 38 | - "Not Selected" 39 | - "Yes" 40 | - "No" 41 | validations: 42 | required: true 43 | - type: input 44 | id: input_id_5 45 | attributes: 46 | label: Project targetSdkVersion [Required] 47 | validations: 48 | required: true 49 | - type: input 50 | id: input_id_6 51 | attributes: 52 | label: Device Information [Required] 53 | description: Please provide the brand and model of the device where the issue occurred. 54 | validations: 55 | required: true 56 | - type: input 57 | id: input_id_7 58 | attributes: 59 | label: Android Version [Required] 60 | description: Please provide the Android version where the issue occurred. 61 | validations: 62 | required: true 63 | - type: dropdown 64 | id: input_id_8 65 | attributes: 66 | label: Issue Source Channel [Required] 67 | multiple: true 68 | options: 69 | - Encountered by myself 70 | - Identified in Bugly 71 | - User feedback 72 | - Other channels 73 | - type: input 74 | id: input_id_9 75 | attributes: 76 | label: Is it specific to certain device models? [Required] 77 | description: Specify whether the issue is specific to certain devices (e.g., specific brand or Android version). 78 | validations: 79 | required: true 80 | - type: dropdown 81 | id: input_id_10 82 | attributes: 83 | label: Does the latest version of the framework have this issue? [Required] 84 | description: If you are using an older version, it is recommended to upgrade and check if the issue still persists. 85 | multiple: false 86 | options: 87 | - "Not Selected" 88 | - "Yes" 89 | - "No" 90 | validations: 91 | required: true 92 | - type: dropdown 93 | id: input_id_11 94 | attributes: 95 | label: Is the issue mentioned in the framework documentation? [Required] 96 | description: The documentation provides answers to frequently asked questions. Please check if the information you are looking for is already provided. 97 | multiple: false 98 | options: 99 | - "Not Selected" 100 | - "Yes" 101 | - "No" 102 | validations: 103 | required: true 104 | - type: dropdown 105 | id: input_id_12 106 | attributes: 107 | label: Did you consult the framework documentation but couldn't find a solution? [Required] 108 | description: If you have consulted the documentation but still couldn't find a solution, you can select "Yes." 109 | multiple: false 110 | options: 111 | - "Not Selected" 112 | - "Yes" 113 | - "No" 114 | validations: 115 | required: true 116 | - type: dropdown 117 | id: input_id_13 118 | attributes: 119 | label: Has a similar issue been reported in the issue list? [Required] 120 | description: You can search the issue list for keywords related to your problem and refer to the solutions provided by others. 121 | multiple: false 122 | options: 123 | - "Not Selected" 124 | - "Yes" 125 | - "No" 126 | validations: 127 | required: true 128 | - type: dropdown 129 | id: input_id_14 130 | attributes: 131 | label: Have you searched the issue list but couldn't find a solution? [Required] 132 | description: If you have searched the issue list and couldn't find a solution, you can select "Yes." 133 | multiple: false 134 | options: 135 | - "Not Selected" 136 | - "Yes" 137 | - "No" 138 | validations: 139 | required: true 140 | - type: dropdown 141 | id: input_id_15 142 | attributes: 143 | label: Can the issue be reproduced with a demo project? [Required] 144 | description: Check if the issue can be reproduced in a minimal demo project to isolate potential issues in your own code. 145 | multiple: false 146 | options: 147 | - "Not Selected" 148 | - "Yes" 149 | - "No" 150 | validations: 151 | required: true 152 | - type: textarea 153 | id: input_id_16 154 | attributes: 155 | label: Provide Error Stack Trace 156 | description: If there is an error, please provide the stack trace. Note, Do not include obfuscated code in the stack trace. 157 | render: text 158 | validations: 159 | required: false 160 | - type: textarea 161 | id: input_id_17 162 | attributes: 163 | label: Provide Screenshots or Videos 164 | description: Provide screenshots or videos if necessary. This field is optional. 165 | validations: 166 | required: false 167 | - type: textarea 168 | id: input_id_18 169 | attributes: 170 | label: Provide a Solution 171 | description: If you have already found a solution, this field is optional. 172 | validations: 173 | required: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_en_template_question.yml: -------------------------------------------------------------------------------- 1 | name: Ask a Question 2 | description: Ask your questions, and I will provide you with answers. 3 | title: "[Question]:" 4 | labels: ["question"] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | ## [Warning: Please make sure to fill in the issue template accurately. If an issue is found to be filled incorrectly, it will be closed without further notice.](https://github.com/getActivity/IssueTemplateGuide) 11 | - type: textarea 12 | id: input_id_1 13 | attributes: 14 | label: Question Description [Required] 15 | description: Please describe your question (Note, If it is a framework bug, please do not raise it here, as it will not be accepted). 16 | validations: 17 | required: true 18 | - type: dropdown 19 | id: input_id_2 20 | attributes: 21 | label: Is the issue mentioned in the framework documentation? [Required] 22 | description: The documentation provides answers to frequently asked questions. Please check if the information you are looking for is already provided. 23 | multiple: false 24 | options: 25 | - "Not Selected" 26 | - "Yes" 27 | - "No" 28 | validations: 29 | required: true 30 | - type: dropdown 31 | id: input_id_3 32 | attributes: 33 | label: Did you consult the framework documentation but couldn't find a solution? [Required] 34 | description: If you have consulted the documentation but still couldn't find a solution, you can select "Yes." 35 | multiple: false 36 | options: 37 | - "Not Selected" 38 | - "Yes" 39 | - "No" 40 | validations: 41 | required: true 42 | - type: dropdown 43 | id: input_id_4 44 | attributes: 45 | label: Has a similar issue been reported in the issue list? [Required] 46 | description: You can search the issue list for keywords related to your problem and refer to the solutions provided by others. 47 | multiple: false 48 | options: 49 | - "Not Selected" 50 | - "Yes" 51 | - "No" 52 | validations: 53 | required: true 54 | - type: dropdown 55 | id: input_id_5 56 | attributes: 57 | label: Have you searched the issue list but couldn't find a solution? [Required] 58 | description: If you have searched the issue list and couldn't find a solution, you can select "Yes." 59 | multiple: false 60 | options: 61 | - "Not Selected" 62 | - "Yes" 63 | - "No" 64 | validations: 65 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_en_template_suggest.yml: -------------------------------------------------------------------------------- 1 | name: Submit Suggestion 2 | description: Please let me know the shortcomings of the framework, so that I can improve it! 3 | title: "[Suggestion]:" 4 | labels: ["help wanted"] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | ## [Warning: Please make sure to fill in the issue template accurately. If an issue is found to be filled incorrectly, it will be closed without further notice.](https://github.com/getActivity/IssueTemplateGuide) 11 | - type: textarea 12 | id: input_id_1 13 | attributes: 14 | label: What are the shortcomings you have noticed in the framework? [Required] 15 | description: You can describe any aspects of the framework that you are not satisfied with. 16 | validations: 17 | required: true 18 | - type: dropdown 19 | id: input_id_2 20 | attributes: 21 | label: Has a similar suggestion been made in the issue list? [Required] 22 | description: If a similar suggestion has already been made, I will not address it again. 23 | multiple: false 24 | options: 25 | - "Not Selected" 26 | - "Yes" 27 | - "No" 28 | validations: 29 | required: true 30 | - type: dropdown 31 | id: input_id_3 32 | attributes: 33 | label: Is the suggestion mentioned in the framework documentation? [Required] 34 | description: The documentation provides answers to frequently asked questions. Please check if the information you are looking for is already provided. 35 | multiple: false 36 | options: 37 | - "Not Selected" 38 | - "Yes" 39 | - "No" 40 | validations: 41 | required: true 42 | - type: dropdown 43 | id: input_id_4 44 | attributes: 45 | label: Did you consult the framework documentation but couldn't find a solution? [Required] 46 | description: If you have consulted the documentation but still couldn't find a solution, you can select "Yes." 47 | multiple: false 48 | options: 49 | - "Not Selected" 50 | - "Yes" 51 | - "No" 52 | validations: 53 | required: true 54 | - type: textarea 55 | id: input_id_5 56 | attributes: 57 | label: How do you suggest improving it? [Optional] 58 | description: You can provide your ideas or approaches for the author's reference. 59 | validations: 60 | required: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_zh_template_bug.yml: -------------------------------------------------------------------------------- 1 | name: 提交 Bug 2 | description: 请告诉我框架存在的问题,我会协助你解决此问题! 3 | title: "[Bug]:" 4 | labels: ["bug"] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | ## [【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】](https://github.com/getActivity/IssueTemplateGuide) 11 | - type: input 12 | id: input_id_1 13 | attributes: 14 | label: 框架版本【必填】 15 | description: 请输入你使用的框架版本 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: input_id_2 20 | attributes: 21 | label: 问题描述【必填】 22 | description: 请输入你对这个问题的描述 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: input_id_3 27 | attributes: 28 | label: 复现步骤【必填】 29 | description: 请输入问题的复现步骤 30 | validations: 31 | required: true 32 | - type: dropdown 33 | id: input_id_4 34 | attributes: 35 | label: 是否必现【必填】 36 | multiple: false 37 | options: 38 | - "未选择" 39 | - "是" 40 | - "否" 41 | validations: 42 | required: true 43 | - type: input 44 | id: input_id_5 45 | attributes: 46 | label: 项目 targetSdkVersion【必填】 47 | validations: 48 | required: true 49 | - type: input 50 | id: input_id_6 51 | attributes: 52 | label: 出现问题的手机信息【必填】 53 | description: 请填写出现问题的品牌和机型 54 | validations: 55 | required: true 56 | - type: input 57 | id: input_id_7 58 | attributes: 59 | label: 出现问题的安卓版本【必填】 60 | description: 请填写出现问题的 Android 版本 61 | validations: 62 | required: true 63 | - type: dropdown 64 | id: input_id_8 65 | attributes: 66 | label: 问题信息的来源渠道【必填】 67 | multiple: true 68 | options: 69 | - 自己遇到的 70 | - Bugly 看到的 71 | - 用户反馈 72 | - 其他渠道 73 | - type: input 74 | id: input_id_9 75 | attributes: 76 | label: 是部分机型还是所有机型都会出现【必答】 77 | description: 部分/全部(例如:某为,某 Android 版本会出现) 78 | validations: 79 | required: true 80 | - type: dropdown 81 | id: input_id_10 82 | attributes: 83 | label: 框架最新的版本是否存在这个问题【必答】 84 | description: 如果用的是旧版本的话,建议升级看问题是否还存在 85 | multiple: false 86 | options: 87 | - "未选择" 88 | - "是" 89 | - "否" 90 | validations: 91 | required: true 92 | - type: dropdown 93 | id: input_id_11 94 | attributes: 95 | label: 框架文档是否提及了该问题【必答】 96 | description: 文档会提供最常见的问题解答,可以先看看是否有自己想要的 97 | multiple: false 98 | options: 99 | - "未选择" 100 | - "是" 101 | - "否" 102 | validations: 103 | required: true 104 | - type: dropdown 105 | id: input_id_12 106 | attributes: 107 | label: 是否已经查阅框架文档但还未能解决的【必答】 108 | description: 如果查阅了文档但还是没有解决的话,可以选择是 109 | multiple: false 110 | options: 111 | - "未选择" 112 | - "是" 113 | - "否" 114 | validations: 115 | required: true 116 | - type: dropdown 117 | id: input_id_13 118 | attributes: 119 | label: issue 列表中是否有人曾提过类似的问题【必答】 120 | description: 可以在 issue 列表在搜索问题关键字,参考一下别人的解决方案 121 | multiple: false 122 | options: 123 | - "未选择" 124 | - "是" 125 | - "否" 126 | validations: 127 | required: true 128 | - type: dropdown 129 | id: input_id_14 130 | attributes: 131 | label: 是否已经搜索过了 issue 列表但还未能解决的【必答】 132 | description: 如果搜索过了 issue 列表但是问题没有解决的话,可以选择是 133 | multiple: false 134 | options: 135 | - "未选择" 136 | - "是" 137 | - "否" 138 | validations: 139 | required: true 140 | - type: dropdown 141 | id: input_id_15 142 | attributes: 143 | label: 是否可以通过 Demo 来复现该问题【必答】 144 | description: 排查一下是不是自己的项目代码写得有问题导致的 145 | multiple: false 146 | options: 147 | - "未选择" 148 | - "是" 149 | - "否" 150 | validations: 151 | required: true 152 | - type: textarea 153 | id: input_id_16 154 | attributes: 155 | label: 提供报错堆栈 156 | description: 如果有报错的话必填,注意不要拿被混淆过的代码堆栈上来 157 | render: text 158 | validations: 159 | required: false 160 | - type: textarea 161 | id: input_id_17 162 | attributes: 163 | label: 提供截图或视频 164 | description: 根据需要提供,此项不强制 165 | validations: 166 | required: false 167 | - type: textarea 168 | id: input_id_18 169 | attributes: 170 | label: 提供解决方案 171 | description: 如果已经解决了的话,此项不强制 172 | validations: 173 | required: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_zh_template_question.yml: -------------------------------------------------------------------------------- 1 | name: 提出疑问 2 | description: 提出你的困惑,我会给你解答 3 | title: "[疑惑]:" 4 | labels: ["question"] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | ## [【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】](https://github.com/getActivity/IssueTemplateGuide) 11 | - type: textarea 12 | id: input_id_1 13 | attributes: 14 | label: 问题描述【必填】 15 | description: 请描述一下你的问题(注意:如果确定是框架 bug 请不要在这里提,否则一概不受理) 16 | validations: 17 | required: true 18 | - type: dropdown 19 | id: input_id_2 20 | attributes: 21 | label: 框架文档是否提及了该问题【必答】 22 | description: 文档会提供最常见的问题解答,可以先看看是否有自己想要的 23 | multiple: false 24 | options: 25 | - "未选择" 26 | - "是" 27 | - "否" 28 | validations: 29 | required: true 30 | - type: dropdown 31 | id: input_id_3 32 | attributes: 33 | label: 是否已经查阅框架文档但还未能解决的【必答】 34 | description: 如果查阅了文档但还是没有解决的话,可以选择是 35 | multiple: false 36 | options: 37 | - "未选择" 38 | - "是" 39 | - "否" 40 | validations: 41 | required: true 42 | - type: dropdown 43 | id: input_id_4 44 | attributes: 45 | label: issue 列表中是否有人曾提过类似的问题【必答】 46 | description: 可以在 issue 列表在搜索问题关键字,参考一下别人的解决方案 47 | multiple: false 48 | options: 49 | - "未选择" 50 | - "是" 51 | - "否" 52 | validations: 53 | required: true 54 | - type: dropdown 55 | id: input_id_5 56 | attributes: 57 | label: 是否已经搜索过了 issue 列表但还未能解决的【必答】 58 | description: 如果搜索过了 issue 列表但是问题没有解决的话,可以选择是 59 | multiple: false 60 | options: 61 | - "未选择" 62 | - "是" 63 | - "否" 64 | validations: 65 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_zh_template_suggest.yml: -------------------------------------------------------------------------------- 1 | name: 提交建议 2 | description: 请告诉我框架的不足之处,让我做得更好! 3 | title: "[建议]:" 4 | labels: ["help wanted"] 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | ## [【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】](https://github.com/getActivity/IssueTemplateGuide) 11 | - type: textarea 12 | id: input_id_1 13 | attributes: 14 | label: 你觉得框架有什么不足之处?【必答】 15 | description: 你可以描述框架有什么令你不满意的地方 16 | validations: 17 | required: true 18 | - type: dropdown 19 | id: input_id_2 20 | attributes: 21 | label: issue 是否有人曾提过类似的建议?【必答】 22 | description: 一旦出现重复提问我将不会再次解答 23 | multiple: false 24 | options: 25 | - "未选择" 26 | - "是" 27 | - "否" 28 | validations: 29 | required: true 30 | - type: dropdown 31 | id: input_id_3 32 | attributes: 33 | label: 框架文档是否提及了该问题【必答】 34 | description: 文档会提供最常见的问题解答,可以先看看是否有自己想要的 35 | multiple: false 36 | options: 37 | - "未选择" 38 | - "是" 39 | - "否" 40 | validations: 41 | required: true 42 | - type: dropdown 43 | id: input_id_4 44 | attributes: 45 | label: 是否已经查阅框架文档但还未能解决的【必答】 46 | description: 如果查阅了文档但还是没有解决的话,可以选择是 47 | multiple: false 48 | options: 49 | - "未选择" 50 | - "是" 51 | - "否" 52 | validations: 53 | required: true 54 | - type: textarea 55 | id: input_id_5 56 | attributes: 57 | label: 你觉得该怎么去完善会比较好?【非必答】 58 | description: 你可以提供一下自己的想法或者做法供作者参考 59 | validations: 60 | required: false -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: set up JDK 1.8 13 | uses: actions/setup-java@v1 14 | with: 15 | java-version: 1.8 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | .cxx 4 | .externalNativeBuild 5 | build 6 | captures 7 | 8 | ._* 9 | *.iml 10 | .DS_Store 11 | local.properties -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, October 2023 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2023 Huang JinQun 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ShapeDrawable 框架 2 | 3 | * 项目地址:[Github](https://github.com/getActivity/ShapeDrawable) 4 | 5 | * 可以扫码下载 Demo 进行演示或者测试,如果扫码下载不了的,[点击此处可直接下载](https://github.com/getActivity/ShapeDrawable/releases/download/3.3/ShapeDrawable.apk) 6 | 7 | ![](picture/demo_code.png) 8 | 9 | ![](picture/long_screenshots.jpg) 10 | 11 | #### 集成步骤 12 | 13 | * 如果你的项目 Gradle 配置是在 `7.0 以下`,需要在 `build.gradle` 文件中加入 14 | 15 | ```groovy 16 | allprojects { 17 | repositories { 18 | // JitPack 远程仓库:https://jitpack.io 19 | maven { url 'https://jitpack.io' } 20 | } 21 | } 22 | ``` 23 | 24 | * 如果你的 Gradle 配置是 `7.0 及以上`,则需要在 `settings.gradle` 文件中加入 25 | 26 | ```groovy 27 | dependencyResolutionManagement { 28 | repositories { 29 | // JitPack 远程仓库:https://jitpack.io 30 | maven { url 'https://jitpack.io' } 31 | } 32 | } 33 | ``` 34 | 35 | * 配置完远程仓库后,在项目 app 模块下的 `build.gradle` 文件中加入远程依赖 36 | 37 | ```groovy 38 | android { 39 | // 支持 JDK 1.8 40 | compileOptions { 41 | targetCompatibility JavaVersion.VERSION_1_8 42 | sourceCompatibility JavaVersion.VERSION_1_8 43 | } 44 | } 45 | 46 | dependencies { 47 | // ShapeDrawable:https://github.com/getActivity/ShapeDrawable 48 | implementation 'com.github.getActivity:ShapeDrawable:3.3' 49 | } 50 | ``` 51 | 52 | #### 框架文档 53 | 54 | * 通用属性 55 | 56 | ```java 57 | // 设置 Shape 形状 58 | setType(@ShapeTypeLimit int shape) 59 | 60 | // 设置 Shape 宽度 61 | setWidth(int width) 62 | 63 | // 设置 Shape 高度 64 | setHeight(int height) 65 | 66 | // 设置矩形的圆角大小 67 | setRadius(float radius) 68 | setRadius(float topLeftRadius, float topRightRadius, float bottomLeftRadius, float bottomRightRadius) 69 | ``` 70 | 71 | * 填充色相关 72 | 73 | ```java 74 | // 设置填充色 75 | setSolidColor(@ColorInt int startColor, @ColorInt int endColor) 76 | setSolidColor(@ColorInt int startColor, @ColorInt int centerColor, @ColorInt int endColor) 77 | setSolidColor(@ColorInt int... colors) 78 | 79 | // 设置填充色渐变类型 80 | setSolidGradientType(@ShapeGradientTypeLimit int type) 81 | 82 | // 设置填充色渐变方向 83 | setSolidGradientOrientation(ShapeGradientOrientation orientation) 84 | 85 | // 设置填充色渐变中心 X 点坐标的相对位置(默认值为 0.5) 86 | setSolidGradientCenterX(float centerX) 87 | // 设置填充色渐变中心 Y 点坐标的相对位置(默认值为 0.5) 88 | setSolidGradientCenterY(float centerY) 89 | 90 | // 设置填充色渐变半径大小 91 | setSolidGradientRadius(float radius) 92 | ``` 93 | 94 | * 边框色相关 95 | 96 | ```java 97 | // 设置边框色 98 | setStrokeColor(@ColorInt int startColor, @ColorInt int endColor) 99 | setStrokeColor(@ColorInt int startColor, @ColorInt int centerColor, @ColorInt int endColor) 100 | setStrokeColor(@ColorInt int... colors) 101 | 102 | // 设置边框色渐变方向 103 | setStrokeGradientOrientation(ShapeGradientOrientation orientation) 104 | 105 | // 设置边框大小 106 | setStrokeSize(int size) 107 | 108 | // 设置边框每一节虚线宽度 109 | setStrokeDashSize(float dashSize) 110 | // 设置边框虚线每一节间隔 111 | setStrokeDashGap(float dashGap) 112 | ``` 113 | 114 | * 阴影相关 115 | 116 | ```java 117 | // 设置阴影颜色 118 | setShadowColor(@ColorInt int color) 119 | 120 | // 设置阴影大小 121 | setShadowSize(int size) 122 | 123 | // 设置阴影水平偏移 124 | setShadowOffsetX(int offsetX) 125 | 126 | // 设置阴影垂直偏移 127 | setShadowOffsetY(int offsetY) 128 | ``` 129 | 130 | * 圆环相关 131 | 132 | ```java 133 | // 设置内环的半径大小 134 | setRingInnerRadiusSize(int size) 135 | // 设置内环的半径比率 136 | setRingInnerRadiusRatio(float ratio) 137 | 138 | // 设置外环的厚度大小 139 | setRingThicknessSize(int size) 140 | // 设置外环的厚度比率 141 | setRingThicknessRatio(float ratio) 142 | ``` 143 | 144 | * 线条相关 145 | 146 | ```java 147 | // 设置线条重心 148 | setLineGravity(int lineGravity) 149 | ``` 150 | 151 | * 其他的 152 | 153 | ```java 154 | // 将当前 Drawable 对象应用到 View 背景,需要调用此 API 设置到 View 背景,否则可能会导致虚线或者阴影无法生效 155 | intoBackground(View view) 156 | ``` 157 | 158 | #### 框架亮点 159 | 160 | * 相比系统提供的 GradientDrawable 更强大,ShapeDrawable 支持设置阴影(颜色、大小、偏移量) 161 | 162 | * 相比系统提供的 GradientDrawable 更强大,ShapeDrawable 支持单独给边框设置渐变色(渐变色色值、渐变色方向) 163 | 164 | * 相比系统提供的 GradientDrawable 更强大,ShapeDrawable 支持单独给线条设置方向(top、bottom、left、right、start、end 方向都支持) 165 | 166 | #### 作者的其他开源项目 167 | 168 | * 安卓技术中台:[AndroidProject](https://github.com/getActivity/AndroidProject) ![](https://img.shields.io/github/stars/getActivity/AndroidProject.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidProject.svg) 169 | 170 | * 安卓技术中台 Kt 版:[AndroidProject-Kotlin](https://github.com/getActivity/AndroidProject-Kotlin) ![](https://img.shields.io/github/stars/getActivity/AndroidProject-Kotlin.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidProject-Kotlin.svg) 171 | 172 | * 权限框架:[XXPermissions](https://github.com/getActivity/XXPermissions) ![](https://img.shields.io/github/stars/getActivity/XXPermissions.svg) ![](https://img.shields.io/github/forks/getActivity/XXPermissions.svg) 173 | 174 | * 吐司框架:[Toaster](https://github.com/getActivity/Toaster) ![](https://img.shields.io/github/stars/getActivity/Toaster.svg) ![](https://img.shields.io/github/forks/getActivity/Toaster.svg) 175 | 176 | * 网络框架:[EasyHttp](https://github.com/getActivity/EasyHttp) ![](https://img.shields.io/github/stars/getActivity/EasyHttp.svg) ![](https://img.shields.io/github/forks/getActivity/EasyHttp.svg) 177 | 178 | * 标题栏框架:[TitleBar](https://github.com/getActivity/TitleBar) ![](https://img.shields.io/github/stars/getActivity/TitleBar.svg) ![](https://img.shields.io/github/forks/getActivity/TitleBar.svg) 179 | 180 | * 悬浮窗框架:[EasyWindow](https://github.com/getActivity/EasyWindow) ![](https://img.shields.io/github/stars/getActivity/EasyWindow.svg) ![](https://img.shields.io/github/forks/getActivity/EasyWindow.svg) 181 | 182 | * ShapeView 框架:[ShapeView](https://github.com/getActivity/ShapeView) ![](https://img.shields.io/github/stars/getActivity/ShapeView.svg) ![](https://img.shields.io/github/forks/getActivity/ShapeView.svg) 183 | 184 | * 语种切换框架:[MultiLanguages](https://github.com/getActivity/MultiLanguages) ![](https://img.shields.io/github/stars/getActivity/MultiLanguages.svg) ![](https://img.shields.io/github/forks/getActivity/MultiLanguages.svg) 185 | 186 | * Gson 解析容错:[GsonFactory](https://github.com/getActivity/GsonFactory) ![](https://img.shields.io/github/stars/getActivity/GsonFactory.svg) ![](https://img.shields.io/github/forks/getActivity/GsonFactory.svg) 187 | 188 | * 日志查看框架:[Logcat](https://github.com/getActivity/Logcat) ![](https://img.shields.io/github/stars/getActivity/Logcat.svg) ![](https://img.shields.io/github/forks/getActivity/Logcat.svg) 189 | 190 | * 嵌套滚动布局框架:[NestedScrollLayout](https://github.com/getActivity/NestedScrollLayout) ![](https://img.shields.io/github/stars/getActivity/NestedScrollLayout.svg) ![](https://img.shields.io/github/forks/getActivity/NestedScrollLayout.svg) 191 | 192 | * Android 版本适配:[AndroidVersionAdapter](https://github.com/getActivity/AndroidVersionAdapter) ![](https://img.shields.io/github/stars/getActivity/AndroidVersionAdapter.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidVersionAdapter.svg) 193 | 194 | * Android 代码规范:[AndroidCodeStandard](https://github.com/getActivity/AndroidCodeStandard) ![](https://img.shields.io/github/stars/getActivity/AndroidCodeStandard.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidCodeStandard.svg) 195 | 196 | * Android 资源大汇总:[AndroidIndex](https://github.com/getActivity/AndroidIndex) ![](https://img.shields.io/github/stars/getActivity/AndroidIndex.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidIndex.svg) 197 | 198 | * Android 开源排行榜:[AndroidGithubBoss](https://github.com/getActivity/AndroidGithubBoss) ![](https://img.shields.io/github/stars/getActivity/AndroidGithubBoss.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidGithubBoss.svg) 199 | 200 | * Studio 精品插件:[StudioPlugins](https://github.com/getActivity/StudioPlugins) ![](https://img.shields.io/github/stars/getActivity/StudioPlugins.svg) ![](https://img.shields.io/github/forks/getActivity/StudioPlugins.svg) 201 | 202 | * 表情包大集合:[EmojiPackage](https://github.com/getActivity/EmojiPackage) ![](https://img.shields.io/github/stars/getActivity/EmojiPackage.svg) ![](https://img.shields.io/github/forks/getActivity/EmojiPackage.svg) 203 | 204 | * 省市区 Json 数据:[ProvinceJson](https://github.com/getActivity/ProvinceJson) ![](https://img.shields.io/github/stars/getActivity/ProvinceJson.svg) ![](https://img.shields.io/github/forks/getActivity/ProvinceJson.svg) 205 | 206 | #### 微信公众号:Android轮子哥 207 | 208 | ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/official_ccount.png) 209 | 210 | #### Android 技术 Q 群:10047167 211 | 212 | #### 如果您觉得我的开源库帮你节省了大量的开发时间,请扫描下方的二维码随意打赏,要是能打赏个 10.24 :monkey_face:就太:thumbsup:了。您的支持将鼓励我继续创作:octocat: 213 | 214 | ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_ali.png) ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_wechat.png) 215 | 216 | #### [点击查看捐赠列表](https://github.com/getActivity/Donate) 217 | 218 | ## License 219 | 220 | ```text 221 | Copyright 2023 Huang JinQun 222 | 223 | Licensed under the Apache License, Version 2.0 (the "License"); 224 | you may not use this file except in compliance with the License. 225 | You may obtain a copy of the License at 226 | 227 | http://www.apache.org/licenses/LICENSE-2.0 228 | 229 | Unless required by applicable law or agreed to in writing, software 230 | distributed under the License is distributed on an "AS IS" BASIS, 231 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 232 | See the License for the specific language governing permissions and 233 | limitations under the License. 234 | ``` -------------------------------------------------------------------------------- /app/AppSignature.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/ShapeDrawable/caa59f8408a7d6f121b0ffaab0fedd4febe2d3e8/app/AppSignature.jks -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | 6 | defaultConfig { 7 | applicationId "com.hjq.shape.drawable.demo" 8 | minSdkVersion 16 9 | targetSdkVersion 28 10 | versionCode 33 11 | versionName "3.3" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | 15 | // Apk 签名的那些事:https://www.jianshu.com/p/a1f8e5896aa2 16 | signingConfigs { 17 | config { 18 | storeFile file(StoreFile) 19 | storePassword StorePassword 20 | keyAlias KeyAlias 21 | keyPassword KeyPassword 22 | } 23 | } 24 | 25 | // 支持 Java JDK 8 26 | compileOptions { 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | sourceCompatibility JavaVersion.VERSION_1_8 29 | } 30 | 31 | buildTypes { 32 | debug { 33 | minifyEnabled false 34 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 35 | signingConfig signingConfigs.config 36 | } 37 | 38 | release { 39 | minifyEnabled true 40 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 41 | signingConfig signingConfigs.config 42 | } 43 | } 44 | 45 | applicationVariants.configureEach { variant -> 46 | // apk 输出文件名配置 47 | variant.outputs.configureEach { output -> 48 | outputFileName = rootProject.getName() + '.apk' 49 | } 50 | } 51 | } 52 | 53 | dependencies { 54 | // 依赖 libs 目录下所有的 jar 和 aar 包 55 | implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') 56 | 57 | implementation project(':library') 58 | 59 | implementation 'com.android.support:appcompat-v7:28.0.0' 60 | implementation 'com.android.support:design:28.0.0' 61 | 62 | // 标题栏框架:https://github.com/getActivity/TitleBar 63 | implementation 'com.github.getActivity:TitleBar:10.5' 64 | 65 | // 吐司框架:https://github.com/getActivity/Toaster 66 | implementation 'com.github.getActivity:Toaster:12.5' 67 | } -------------------------------------------------------------------------------- /app/gradle.properties: -------------------------------------------------------------------------------- 1 | StoreFile = AppSignature.jks 2 | StorePassword = AndroidProject 3 | KeyAlias = AndroidProject 4 | KeyPassword = AndroidProject -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\SDK\Studio\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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/hjq/shape/drawable/demo/AppApplication.java: -------------------------------------------------------------------------------- 1 | package com.hjq.shape.drawable.demo; 2 | 3 | import android.app.Application; 4 | 5 | import com.hjq.toast.Toaster; 6 | 7 | public class AppApplication extends Application { 8 | 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | 13 | // 初始化吐司工具类 14 | Toaster.init(this); 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hjq/shape/drawable/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.hjq.shape.drawable.demo; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.support.v4.content.ContextCompat; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.util.TypedValue; 10 | import android.view.Gravity; 11 | import android.view.View; 12 | 13 | import com.hjq.bar.OnTitleBarListener; 14 | import com.hjq.bar.TitleBar; 15 | import com.hjq.shape.drawable.ShapeDrawable; 16 | import com.hjq.shape.drawable.ShapeGradientOrientation; 17 | import com.hjq.shape.drawable.ShapeGradientType; 18 | import com.hjq.shape.drawable.ShapeType; 19 | 20 | public class MainActivity extends AppCompatActivity { 21 | 22 | private float mRadiusSize; 23 | 24 | private ShapeDrawable mShapeDrawable; 25 | 26 | private View mExampleView; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_main); 32 | 33 | TitleBar titleBar = findViewById(R.id.tb_main_bar); 34 | titleBar.setOnTitleBarListener(new OnTitleBarListener() { 35 | @Override 36 | public void onTitleClick(TitleBar titleBar) { 37 | Intent intent = new Intent(Intent.ACTION_VIEW); 38 | intent.setData(Uri.parse(titleBar.getTitle().toString())); 39 | startActivity(intent); 40 | } 41 | }); 42 | 43 | mExampleView = findViewById(R.id.v_main_example); 44 | 45 | mRadiusSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics()); 46 | 47 | int shapeSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, getResources().getDisplayMetrics()); 48 | 49 | mShapeDrawable = new ShapeDrawable() 50 | .setWidth(shapeSize) 51 | .setHeight(shapeSize) 52 | .setSolidColor(ContextCompat.getColor(this, android.R.color.black)); 53 | mShapeDrawable.intoBackground(mExampleView); 54 | 55 | findViewById(R.id.btn_main_shape_type_rectangle).setOnClickListener(mShapeTypeClickListener); 56 | findViewById(R.id.btn_main_shape_type_oval).setOnClickListener(mShapeTypeClickListener); 57 | findViewById(R.id.btn_main_shape_type_line).setOnClickListener(mShapeTypeClickListener); 58 | findViewById(R.id.btn_main_shape_type_ring).setOnClickListener(mShapeTypeClickListener); 59 | 60 | findViewById(R.id.btn_main_shape_rectangle_radius_top_left).setOnClickListener(mRectangleRadiusClickListener); 61 | findViewById(R.id.btn_main_shape_rectangle_radius_top_right).setOnClickListener(mRectangleRadiusClickListener); 62 | findViewById(R.id.btn_main_shape_rectangle_radius_bottom_left).setOnClickListener(mRectangleRadiusClickListener); 63 | findViewById(R.id.btn_main_shape_rectangle_radius_bottom_right).setOnClickListener(mRectangleRadiusClickListener); 64 | findViewById(R.id.btn_main_shape_rectangle_radius_all).setOnClickListener(mRectangleRadiusClickListener); 65 | findViewById(R.id.btn_main_shape_rectangle_radius_not).setOnClickListener(mRectangleRadiusClickListener); 66 | 67 | findViewById(R.id.btn_main_shape_width).setOnClickListener(mCommonPropertyClickListener); 68 | findViewById(R.id.btn_main_shape_height).setOnClickListener(mCommonPropertyClickListener); 69 | 70 | findViewById(R.id.btn_main_shape_solid_color).setOnClickListener(mSolidPropertyClickListener); 71 | findViewById(R.id.btn_main_shape_solid_gradient_color).setOnClickListener(mSolidPropertyClickListener); 72 | findViewById(R.id.btn_main_shape_solid_gradient_orientation).setOnClickListener(mSolidPropertyClickListener); 73 | findViewById(R.id.btn_main_shape_solid_gradient_type_linear).setOnClickListener(mSolidPropertyClickListener); 74 | findViewById(R.id.btn_main_shape_solid_gradient_type_radial).setOnClickListener(mSolidPropertyClickListener); 75 | findViewById(R.id.btn_main_shape_solid_gradient_type_sweep).setOnClickListener(mSolidPropertyClickListener); 76 | findViewById(R.id.btn_main_shape_solid_gradient_center_x).setOnClickListener(mSolidPropertyClickListener); 77 | findViewById(R.id.btn_main_shape_solid_gradient_center_y).setOnClickListener(mSolidPropertyClickListener); 78 | findViewById(R.id.btn_main_shape_solid_gradient_radius).setOnClickListener(mSolidPropertyClickListener); 79 | 80 | findViewById(R.id.btn_main_shape_stroke_color).setOnClickListener(mStrokePropertyClickListener); 81 | findViewById(R.id.btn_main_shape_stroke_gradient_color).setOnClickListener(mStrokePropertyClickListener); 82 | findViewById(R.id.btn_main_shape_stroke_gradient_orientation).setOnClickListener(mStrokePropertyClickListener); 83 | findViewById(R.id.btn_main_shape_stroke_size).setOnClickListener(mStrokePropertyClickListener); 84 | findViewById(R.id.btn_main_shape_stroke_dash_gap).setOnClickListener(mStrokePropertyClickListener); 85 | 86 | findViewById(R.id.btn_main_shape_shadow_size).setOnClickListener(mShadowPropertyClickListener); 87 | findViewById(R.id.btn_main_shape_shadow_color).setOnClickListener(mShadowPropertyClickListener); 88 | findViewById(R.id.btn_main_shape_shadow_offset_x).setOnClickListener(mShadowPropertyClickListener); 89 | findViewById(R.id.btn_main_shape_shadow_offset_y).setOnClickListener(mShadowPropertyClickListener); 90 | 91 | findViewById(R.id.btn_main_shape_ring_inner_radius_size).setOnClickListener(mRingPropertyClickListener); 92 | findViewById(R.id.btn_main_shape_ring_inner_radius_ratio).setOnClickListener(mRingPropertyClickListener); 93 | findViewById(R.id.btn_main_shape_ring_thickness_size).setOnClickListener(mRingPropertyClickListener); 94 | findViewById(R.id.btn_main_shape_ring_thickness_ratio).setOnClickListener(mRingPropertyClickListener); 95 | 96 | findViewById(R.id.btn_main_shape_line_gravity_left).setOnClickListener(mLineGravityPropertyClickListener); 97 | findViewById(R.id.btn_main_shape_line_gravity_top).setOnClickListener(mLineGravityPropertyClickListener); 98 | findViewById(R.id.btn_main_shape_line_gravity_right).setOnClickListener(mLineGravityPropertyClickListener); 99 | findViewById(R.id.btn_main_shape_line_gravity_bottom).setOnClickListener(mLineGravityPropertyClickListener); 100 | findViewById(R.id.btn_main_shape_line_gravity_start).setOnClickListener(mLineGravityPropertyClickListener); 101 | findViewById(R.id.btn_main_shape_line_gravity_center).setOnClickListener(mLineGravityPropertyClickListener); 102 | findViewById(R.id.btn_main_shape_line_gravity_end).setOnClickListener(mLineGravityPropertyClickListener); 103 | } 104 | 105 | private final View.OnClickListener mShapeTypeClickListener = new View.OnClickListener() { 106 | 107 | @Override 108 | public void onClick(View v) { 109 | int viewId = v.getId(); 110 | if (viewId == R.id.btn_main_shape_type_rectangle) { 111 | mShapeDrawable.setType(ShapeType.RECTANGLE); 112 | } else if (viewId == R.id.btn_main_shape_type_oval) { 113 | mShapeDrawable.setType(ShapeType.OVAL); 114 | } else if (viewId == R.id.btn_main_shape_type_line) { 115 | mShapeDrawable.setType(ShapeType.LINE) 116 | .setStrokeSize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 117 | 2, getResources().getDisplayMetrics())) 118 | .setStrokeColor(ContextCompat.getColor(MainActivity.this, android.R.color.black)); 119 | } else if (viewId == R.id.btn_main_shape_type_ring) { 120 | mShapeDrawable.setType(ShapeType.RING) 121 | .setRingInnerRadiusRatio(4) 122 | .setRingThicknessRatio(4); 123 | } 124 | } 125 | }; 126 | 127 | private final View.OnClickListener mCommonPropertyClickListener = new View.OnClickListener() { 128 | 129 | @Override 130 | public void onClick(View v) { 131 | int viewId = v.getId(); 132 | if (viewId == R.id.btn_main_shape_width) { 133 | mShapeDrawable.setWidth((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 134 | 200, getResources().getDisplayMetrics())); 135 | // 这次修改需要重新测量 View,所以要调用 requestLayout 136 | mExampleView.requestLayout(); 137 | } else if (viewId == R.id.btn_main_shape_height) { 138 | mShapeDrawable.setHeight((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 139 | 200, getResources().getDisplayMetrics())); 140 | // 这次修改需要重新测量 View,所以要调用 requestLayout 141 | mExampleView.requestLayout(); 142 | } 143 | } 144 | }; 145 | 146 | private final View.OnClickListener mSolidPropertyClickListener = new View.OnClickListener() { 147 | 148 | @Override 149 | public void onClick(View v) { 150 | int viewId = v.getId(); 151 | if (viewId == R.id.btn_main_shape_solid_color) { 152 | mShapeDrawable.setSolidColor(ContextCompat.getColor(MainActivity.this, android.R.color.darker_gray)); 153 | } else if (viewId == R.id.btn_main_shape_solid_gradient_color) { 154 | mShapeDrawable.setSolidColor(0xFF49DAFA, 0xFFED58FF); 155 | } else if (viewId == R.id.btn_main_shape_solid_gradient_orientation) { 156 | mShapeDrawable.setSolidGradientOrientation(ShapeGradientOrientation.RIGHT_TO_LEFT); 157 | } else if (viewId == R.id.btn_main_shape_solid_gradient_type_linear) { 158 | mShapeDrawable.setSolidGradientType(ShapeGradientType.LINEAR_GRADIENT); 159 | } else if (viewId == R.id.btn_main_shape_solid_gradient_type_radial) { 160 | // 设置径向渐变前需要先设置渐变色和渐变半径大小才能有效果 161 | mShapeDrawable.setSolidColor(0xFF49DAFA, 0xFFED58FF); 162 | mShapeDrawable.setSolidGradientRadius((int) TypedValue.applyDimension( 163 | TypedValue.COMPLEX_UNIT_DIP, 80, getResources().getDisplayMetrics())); 164 | mShapeDrawable.setSolidGradientType(ShapeGradientType.RADIAL_GRADIENT); 165 | } else if (viewId == R.id.btn_main_shape_solid_gradient_type_sweep) { 166 | mShapeDrawable.setSolidGradientType(ShapeGradientType.SWEEP_GRADIENT); 167 | } else if (viewId == R.id.btn_main_shape_solid_gradient_center_x) { 168 | mShapeDrawable.setSolidGradientCenterX(0.7f); 169 | mShapeDrawable.setSolidGradientCenterY(0.5f); 170 | } else if (viewId == R.id.btn_main_shape_solid_gradient_center_y) { 171 | mShapeDrawable.setSolidGradientCenterX(0.5f); 172 | mShapeDrawable.setSolidGradientCenterY(0.7f); 173 | } else if (viewId == R.id.btn_main_shape_solid_gradient_radius) { 174 | mShapeDrawable.setSolidGradientRadius((int) TypedValue.applyDimension( 175 | TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics())); 176 | } 177 | } 178 | }; 179 | 180 | private final View.OnClickListener mStrokePropertyClickListener = new View.OnClickListener() { 181 | 182 | @Override 183 | public void onClick(View v) { 184 | int viewId = v.getId(); 185 | if (viewId == R.id.btn_main_shape_stroke_color) { 186 | // 设置边框色之前需要先设置边框大小 187 | mShapeDrawable.setStrokeSize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics())); 188 | mShapeDrawable.setStrokeColor(ContextCompat.getColor(MainActivity.this, android.R.color.holo_blue_bright)); 189 | } else if (viewId == R.id.btn_main_shape_stroke_gradient_color) { 190 | // 设置边框色之前需要先设置边框大小才能有效果 191 | mShapeDrawable.setStrokeSize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics())); 192 | mShapeDrawable.setStrokeColor(0xFFFEFA54, 0xFFF08833); 193 | } else if (viewId == R.id.btn_main_shape_stroke_gradient_orientation) { 194 | mShapeDrawable.setStrokeGradientOrientation(ShapeGradientOrientation.BOTTOM_TO_TOP); 195 | } else if (viewId == R.id.btn_main_shape_stroke_size) { 196 | mShapeDrawable.setStrokeSize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics())); 197 | } else if (viewId == R.id.btn_main_shape_stroke_dash_gap) { 198 | mShapeDrawable.setStrokeDashSize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics())); 199 | mShapeDrawable.setStrokeDashGap((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics())); 200 | } 201 | } 202 | }; 203 | 204 | 205 | private final View.OnClickListener mShadowPropertyClickListener = new View.OnClickListener() { 206 | 207 | @Override 208 | public void onClick(View v) { 209 | int viewId = v.getId(); 210 | if (viewId == R.id.btn_main_shape_shadow_color) { 211 | // 设置阴影颜色需要先设置阴影大小才能生效 212 | mShapeDrawable.setShadowSize((int) TypedValue.applyDimension( 213 | TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics())); 214 | mShapeDrawable.setShadowColor(0xAA5A8DDF); 215 | } else if (viewId == R.id.btn_main_shape_shadow_size) { 216 | mShapeDrawable.setShadowSize((int) TypedValue.applyDimension( 217 | TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics())); 218 | } else if (viewId == R.id.btn_main_shape_shadow_offset_x) { 219 | mShapeDrawable.setShadowOffsetY(0); 220 | mShapeDrawable.setShadowOffsetX((int) TypedValue.applyDimension( 221 | TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics())); 222 | } else if (viewId == R.id.btn_main_shape_shadow_offset_y) { 223 | mShapeDrawable.setShadowOffsetX(0); 224 | mShapeDrawable.setShadowOffsetY((int) TypedValue.applyDimension( 225 | TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics())); 226 | } 227 | } 228 | }; 229 | 230 | private final View.OnClickListener mRectangleRadiusClickListener = new View.OnClickListener() { 231 | 232 | @Override 233 | public void onClick(View v) { 234 | mShapeTypeClickListener.onClick(findViewById(R.id.btn_main_shape_type_rectangle)); 235 | int viewId = v.getId(); 236 | if (viewId == R.id.btn_main_shape_rectangle_radius_top_left) { 237 | mShapeDrawable.setRadius(mRadiusSize, 0, 0, 0); 238 | } else if (viewId == R.id.btn_main_shape_rectangle_radius_top_right) { 239 | mShapeDrawable.setRadius(0, mRadiusSize, 0, 0); 240 | } else if (viewId == R.id.btn_main_shape_rectangle_radius_bottom_left) { 241 | mShapeDrawable.setRadius(0, 0, mRadiusSize, 0); 242 | } else if (viewId == R.id.btn_main_shape_rectangle_radius_bottom_right) { 243 | mShapeDrawable.setRadius(0, 0, 0, mRadiusSize); 244 | } else if (viewId == R.id.btn_main_shape_rectangle_radius_all) { 245 | mShapeDrawable.setRadius(mRadiusSize); 246 | } else if (viewId == R.id.btn_main_shape_rectangle_radius_not) { 247 | mShapeDrawable.setRadius(0); 248 | } 249 | } 250 | }; 251 | 252 | private final View.OnClickListener mRingPropertyClickListener = new View.OnClickListener() { 253 | 254 | @Override 255 | public void onClick(View v) { 256 | mShapeTypeClickListener.onClick(findViewById(R.id.btn_main_shape_type_ring)); 257 | 258 | int viewId = v.getId(); 259 | if (viewId == R.id.btn_main_shape_ring_inner_radius_size) { 260 | mShapeDrawable.setRingInnerRadiusSize((int) TypedValue.applyDimension( 261 | TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics())); 262 | // 这次修改需要重新测量 View,所以要调用 requestLayout 263 | mExampleView.requestLayout(); 264 | } else if (viewId == R.id.btn_main_shape_ring_inner_radius_ratio) { 265 | mShapeDrawable.setRingInnerRadiusRatio(6); 266 | // 这次修改需要重新测量 View,所以要调用 requestLayout 267 | mExampleView.requestLayout(); 268 | } else if (viewId == R.id.btn_main_shape_ring_thickness_size) { 269 | mShapeDrawable.setRingThicknessSize((int) TypedValue.applyDimension( 270 | TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics())); 271 | // 这次修改需要重新测量 View,所以要调用 requestLayout 272 | mExampleView.requestLayout(); 273 | } else if (viewId == R.id.btn_main_shape_ring_thickness_ratio) { 274 | mShapeDrawable.setRingThicknessRatio(6); 275 | // 这次修改需要重新测量 View,所以要调用 requestLayout 276 | mExampleView.requestLayout(); 277 | } 278 | } 279 | }; 280 | 281 | private final View.OnClickListener mLineGravityPropertyClickListener = new View.OnClickListener() { 282 | 283 | @SuppressLint("RtlHardcoded") 284 | @Override 285 | public void onClick(View v) { 286 | mShapeTypeClickListener.onClick(findViewById(R.id.btn_main_shape_type_line)); 287 | int viewId = v.getId(); 288 | if (viewId == R.id.btn_main_shape_line_gravity_left) { 289 | mShapeDrawable.setLineGravity(Gravity.LEFT); 290 | } else if (viewId == R.id.btn_main_shape_line_gravity_top) { 291 | mShapeDrawable.setLineGravity(Gravity.TOP); 292 | } else if (viewId == R.id.btn_main_shape_line_gravity_right) { 293 | mShapeDrawable.setLineGravity(Gravity.RIGHT); 294 | } else if (viewId == R.id.btn_main_shape_line_gravity_bottom) { 295 | mShapeDrawable.setLineGravity(Gravity.BOTTOM); 296 | } else if (viewId == R.id.btn_main_shape_line_gravity_start) { 297 | mShapeDrawable.setLineGravity(Gravity.START); 298 | } else if (viewId == R.id.btn_main_shape_line_gravity_center) { 299 | mShapeDrawable.setLineGravity(Gravity.CENTER); 300 | } else if (viewId == R.id.btn_main_shape_line_gravity_end) { 301 | mShapeDrawable.setLineGravity(Gravity.END); 302 | } 303 | } 304 | }; 305 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 28 | 29 | 33 | 34 | 37 | 38 | 43 | 44 | 51 | 52 | 60 | 61 |