├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── issue_zh_template_bug.yml │ ├── issue_zh_template_question.yml │ └── issue_zh_template_suggest.yml └── workflows │ └── android.yml ├── .gitignore ├── Adaptive.md ├── LICENSE ├── README.md ├── app ├── AppSignature.jks ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── hjq │ │ └── bar │ │ └── demo │ │ ├── AppApplication.java │ │ └── MainActivity.java │ └── res │ ├── drawable-xxhdpi │ └── title_bar_head.jpg │ ├── drawable │ ├── message_ic.png │ ├── qr_code_ic.png │ └── shape_gradient.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── 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 ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── hjq │ │ └── bar │ │ ├── ITitleBarStyle.java │ │ ├── OnTitleBarListener.java │ │ ├── SelectorDrawable.java │ │ ├── TitleBar.java │ │ ├── TitleBarSupport.java │ │ └── style │ │ ├── CommonBarStyle.java │ │ ├── LightBarStyle.java │ │ ├── NightBarStyle.java │ │ └── TransparentBarStyle.java │ └── res │ ├── drawable │ ├── bar_arrows_left_black.xml │ ├── bar_arrows_left_white.xml │ └── bar_drawable_placeholder.xml │ ├── values-v21 │ └── style.xml │ └── values │ ├── attrs.xml │ ├── string.xml │ └── style.xml ├── logo.png ├── picture ├── demo.jpg ├── demo_code.png └── dynamic_figure.gif └── 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_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 -------------------------------------------------------------------------------- /Adaptive.md: -------------------------------------------------------------------------------- 1 | # 关于属性适配的问题 2 | 3 | * 你好,如果你是刚使用这个库的人可以不必理会,如果你之前使用了 `TitleBar` 这个库,也就是 `9.0` 版本以下的,在升级到 `9.0` 版本后需要进行适配,否则 `Android Studio` 会报错`编译不通过`,对于这个问题我表示十分抱歉,低版本的 `xml` 属性命名得并不是很规范,现在在 `5.0` 和 `9.0` 版本进行优化,尽管这次的代价比较大,但是我会义无反顾去做,如果你使用了 `TitleBar` 但是不想进行适配,请不要升级依赖库版本。 4 | 5 | #### 从 10.5 升级到 10.6 版本适配方案 6 | 7 | * 删除 `barStyle` 中的 `ripple` 属性值,请使用 `app:barStyle="transparent"` 和 `style="@style/TitleBarRippleClickStyle"` 这两个属性来代替 8 | 9 | #### 从 10.2 以上的版本升级到 10.3 版本适配方案 10 | 11 | * 修改 `app:titleTextEllipsize` 属性名,请使用 `app:titleOverflowMode` 代替(高版本的 CollapsingToolbarLayout 占用了 titleTextEllipsize 属性) 12 | 13 | * 修改 `app:leftTitleTextEllipsize` 属性名,请使用 `app:leftTitleOverflowMode` 代替 14 | 15 | * 修改 `app:rightTitleTextEllipsize` 属性名,请使用 `app:rightTitleOverflowMode` 代替 16 | 17 | #### 从 9.3 以上的版本升级到 9.5 版本适配方案 18 | 19 | * 修改 `app:childPaddingVertical` 属性名,请使用 `app:childVerticalPadding` 代替 20 | 21 | * 拆分 `android:childPaddingHorizontal` 属性,将原有属性拆分为以下几个属性: 22 | 23 | ```text 24 | app:titleHorizontalPadding 25 | 26 | app:leftHorizontalPadding 27 | 28 | app:rightHorizontalPadding 29 | ``` 30 | 31 | #### 从 5.0 以上的版本升级到 9.0 版本适配方案 32 | 33 | * 删除 `app:backButton` 属性,请使用 `app:leftIcon` 代替,全局替换如下: 34 | 35 | ```text 36 | // 旧版本的用法 37 | app:backButton="false" 38 | // 新版本的用法 39 | app:leftIcon="@null" 40 | ``` 41 | 42 | * 拆分 `android:drawablePadding` 属性,将原有属性拆分为以下几个属性: 43 | 44 | ```text 45 | app:titleIconPadding 46 | 47 | app:leftIconPadding 48 | 49 | app:rightIconPadding 50 | ``` 51 | 52 | * 拆分 `android:drawableSize` 属性,将原有属性拆分为以下几个属性: 53 | 54 | ```text 55 | app:titleIconWidth 56 | app:titleIconHeight 57 | 58 | app:leftIconWidth 59 | app:leftIconHeight 60 | 61 | app:rightIconWidth 62 | app:rightIconHeight 63 | ``` 64 | 65 | * 属性改名一览,只是简单改名,没有做太多修改,大家可以使用全局替换: 66 | 67 | | 5.0 版本 | 9.0 版本 | 68 | | :------------: | :-------------: | 69 | | `app:leftSize` | `app:leftTitleSize` | 70 | | `app:rightSize` | `app:rightTitleSize` | 71 | | `app:leftColor` | `app:leftTitleColor` | 72 | | `app:rightColor` | `app:rightTitleColor` | 73 | | `app:leftTint` | `app:leftIconTint` | 74 | | `app:rightTint` | `app:rightIconTint` | 75 | | `app:lineColor` | `app:lineDrawable` | 76 | 77 | * 命名空间和属性都修改(之前用的是系统属性),在这里不推荐大家使用全局替换,而是在代码中一一检查: 78 | 79 | | 5.0 版本 | 9.0 版本 | 80 | | :------------: | :-------------: | 81 | | `android:paddingVertical` | `app:childPaddingVertical` | 82 | | `android:paddingHorizontal` | `app:childPaddingHorizontal` | 83 | 84 | * 新增左标提和右标题的文本样式设置(之前的版本只有中间标题的): 85 | 86 | ```text 87 | app:leftTitleStyle 88 | app:rightTitleStyle 89 | ``` 90 | 91 | * 新增中间标题图标设置(之前的版本只有左标题和右标题才有): 92 | 93 | ```text 94 | app:titleIcon 95 | app:titleIconPadding 96 | app:titleIconTint 97 | ``` 98 | 99 | * 新增图标的显示重心设置(图标在文字的哪个位置上面绘制): 100 | 101 | ```text 102 | app:titleIconGravity 103 | app:leftIconGravity 104 | app:rightIconGravity 105 | ``` 106 | 107 | #### 从 1.5 以上的版本升级到 5.0 版本适配方案 108 | 109 | * 常规适配:单词反向,不再采用下划线形式,而用单词开头大写的方式代替 110 | 111 | | 3.5 版本 | 5.0 版本 | 112 | | :------------: | :-------------: | 113 | | title_left | leftTitle | 114 | | title_right | rightTitle | 115 | | icon_left | leftIcon | 116 | | icon_right | rightIcon | 117 | | color_title | titleColor | 118 | | color_right | rightColor | 119 | | color_left | leftColor | 120 | | size_title | titleSize | 121 | | size_right | rightSize | 122 | | size_left | leftSize | 123 | | background_left | leftBackground | 124 | | background_right| rightBackground | 125 | 126 | * 特殊适配:去除下划线,并且用单词开头大写的方式代替 127 | 128 | | 3.5 版本 | 5.0 版本 | 129 | | :-------: | :---------: | 130 | | bar_style | barStyle | 131 | | line_visible | lineVisible | 132 | | line_color | lineColor | 133 | | line_size | lineSize | 134 | 135 | * 极端适配:命名和之前完全不同 136 | 137 | | 3.5 版本 | 5.0 版本 | 138 | | :-------: | :-------: | 139 | | icon_back | backButton | 140 | 141 | * 无需适配:这个属性没有任何改动 142 | 143 | | 3.5 版本 | 5.0 版本 | 144 | | :-----: | :-------: | 145 | | title | title | 146 | 147 | #### 不同版本的 XML 属性命名预览 148 | 149 | * 3.5 版本 XML 属性命名 150 | 151 | ```xml 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 | * 5.0 版本 XML 属性命名 187 | 188 | ```xml 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 | * 9.0 版本 XML 属性命名 221 | 222 | ```xml 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | ``` 325 | 326 | 327 | 328 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, August 2018 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 2018 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 | # 标题栏框架 2 | 3 | * 项目地址:[Github](https://github.com/getActivity/TitleBar) 4 | 5 | * 博客地址:[Android标题栏(TitleBar)绝佳解决方案](https://www.jianshu.com/p/617be02dc265) 6 | 7 | * 可以扫码下载 Demo 进行演示或者测试,如果扫码下载不了的,[点击此处可直接下载](https://github.com/getActivity/TitleBar/releases/download/10.6/TitleBar.apk) 8 | 9 | ![](picture/demo_code.png) 10 | 11 | * 想了解实现原理的可以参考文章:[纯手工打造一个通用的标题栏 TitleBar](https://www.jianshu.com/p/ccf6506335e7) 12 | 13 | ![](picture/dynamic_figure.gif) 14 | 15 | #### 集成步骤 16 | 17 | * 如果你的项目 Gradle 配置是在 `7.0 以下`,需要在 `build.gradle` 文件中加入 18 | 19 | ```groovy 20 | allprojects { 21 | repositories { 22 | // JitPack 远程仓库:https://jitpack.io 23 | maven { url 'https://jitpack.io' } 24 | } 25 | } 26 | ``` 27 | 28 | * 如果你的 Gradle 配置是 `7.0 及以上`,则需要在 `settings.gradle` 文件中加入 29 | 30 | ```groovy 31 | dependencyResolutionManagement { 32 | repositories { 33 | // JitPack 远程仓库:https://jitpack.io 34 | maven { url 'https://jitpack.io' } 35 | } 36 | } 37 | ``` 38 | 39 | * 配置完远程仓库后,在项目 app 模块下的 `build.gradle` 文件中加入远程依赖 40 | 41 | ```groovy 42 | android { 43 | // 支持 JDK 1.8 44 | compileOptions { 45 | targetCompatibility JavaVersion.VERSION_1_8 46 | sourceCompatibility JavaVersion.VERSION_1_8 47 | } 48 | } 49 | 50 | dependencies { 51 | // 标题栏框架:https://github.com/getActivity/TitleBar 52 | implementation 'com.github.getActivity:TitleBar:10.6' 53 | } 54 | ``` 55 | 56 | #### 布局属性大全 57 | 58 | * [不同版本的 xml 属性适配请点击这里查看](Adaptive.md) 59 | 60 | ```xml 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 | #### XML示例 192 | 193 | * [点我查看完整的 Demo 示例](app/src/main/res/layout/activity_main.xml) 194 | 195 | ![](picture/demo.jpg) 196 | 197 | #### 设置监听事件 198 | 199 | ```java 200 | titleBar.setOnTitleBarListener(new OnTitleBarListener() { 201 | 202 | @Override 203 | public void onLeftClick(TitleBar titleBar) { 204 | toast("左项 View 被点击"); 205 | } 206 | 207 | @Override 208 | public void onTitleClick(TitleBar titleBar) { 209 | toast("中间 View 被点击"); 210 | } 211 | 212 | @Override 213 | public void onRightClick(TitleBar titleBar) { 214 | toast("右项 View 被点击"); 215 | } 216 | }); 217 | ``` 218 | 219 | #### 统一 TitleBar 样式 220 | 221 | * 如果对 TitleBar 的默认样式或者属性不满意,可以在 Application 初始化的地方进行拦截并修改 222 | 223 | ```java 224 | public class XxxApplication extends Application { 225 | 226 | @Override 227 | public void onCreate() { 228 | super.onCreate(); 229 | 230 | // 初始化 TitleBar 默认样式 231 | TitleBar.setDefaultStyle(new ITitleBarStyle()); 232 | } 233 | } 234 | ``` 235 | 236 | #### 框架混淆规则 237 | 238 | * 在混淆规则文件 `proguard-rules.pro` 中加入 239 | 240 | ```text 241 | -keep class com.hjq.bar.** {*;} 242 | ``` 243 | 244 | #### 框架亮点 245 | 246 | * 性能最佳:不使用 LayoutInflater,而使用代码创建 View 的形式 247 | 248 | * 体验最优:TitleBar 默认样式效果已经非常好,可下载 Demo 测试 249 | 250 | * 支持操控子控件:可以在代码中获取 TitleBar 的子控件进行调用相关的 API 251 | 252 | * 兼容沉浸式状态栏:兼容 Github 的沉浸式状态栏框架,达到完全沉浸的效果 253 | 254 | * 框架兼容性良好:本框架不依赖任何第三方库,支持兼容所有的安卓版本 255 | 256 | * 支持全局配置样式:可以在 Application 中初始化 TitleBar 样式,达到一劳永逸的效果 257 | 258 | #### 注意事项 259 | 260 | * TitleBar 并不是为了满足所有需求而诞生的,我的设计初衷是只针对一些常用的需求,例如左边中间右边各有一个 TextView 做封装,其他情况建议进行自定义布局。 261 | 262 | #### 作者的其他开源项目 263 | 264 | * 安卓技术中台:[AndroidProject](https://github.com/getActivity/AndroidProject) ![](https://img.shields.io/github/stars/getActivity/AndroidProject.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidProject.svg) 265 | 266 | * 安卓技术中台 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) 267 | 268 | * 权限框架:[XXPermissions](https://github.com/getActivity/XXPermissions) ![](https://img.shields.io/github/stars/getActivity/XXPermissions.svg) ![](https://img.shields.io/github/forks/getActivity/XXPermissions.svg) 269 | 270 | * 吐司框架:[Toaster](https://github.com/getActivity/Toaster) ![](https://img.shields.io/github/stars/getActivity/Toaster.svg) ![](https://img.shields.io/github/forks/getActivity/Toaster.svg) 271 | 272 | * 网络框架:[EasyHttp](https://github.com/getActivity/EasyHttp) ![](https://img.shields.io/github/stars/getActivity/EasyHttp.svg) ![](https://img.shields.io/github/forks/getActivity/EasyHttp.svg) 273 | 274 | * 悬浮窗框架:[EasyWindow](https://github.com/getActivity/EasyWindow) ![](https://img.shields.io/github/stars/getActivity/EasyWindow.svg) ![](https://img.shields.io/github/forks/getActivity/EasyWindow.svg) 275 | 276 | * 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) 277 | 278 | * ShapeDrawable 框架:[ShapeDrawable](https://github.com/getActivity/ShapeDrawable) ![](https://img.shields.io/github/stars/getActivity/ShapeDrawable.svg) ![](https://img.shields.io/github/forks/getActivity/ShapeDrawable.svg) 279 | 280 | * 语种切换框架:[MultiLanguages](https://github.com/getActivity/MultiLanguages) ![](https://img.shields.io/github/stars/getActivity/MultiLanguages.svg) ![](https://img.shields.io/github/forks/getActivity/MultiLanguages.svg) 281 | 282 | * 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) 283 | 284 | * 日志查看框架:[Logcat](https://github.com/getActivity/Logcat) ![](https://img.shields.io/github/stars/getActivity/Logcat.svg) ![](https://img.shields.io/github/forks/getActivity/Logcat.svg) 285 | 286 | * 嵌套滚动布局框架:[NestedScrollLayout](https://github.com/getActivity/NestedScrollLayout) ![](https://img.shields.io/github/stars/getActivity/NestedScrollLayout.svg) ![](https://img.shields.io/github/forks/getActivity/NestedScrollLayout.svg) 287 | 288 | * 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) 289 | 290 | * 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) 291 | 292 | * 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) 293 | 294 | * 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) 295 | 296 | * 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) 297 | 298 | * 表情包大集合:[EmojiPackage](https://github.com/getActivity/EmojiPackage) ![](https://img.shields.io/github/stars/getActivity/EmojiPackage.svg) ![](https://img.shields.io/github/forks/getActivity/EmojiPackage.svg) 299 | 300 | * AI 资源大汇总:[AiIndex](https://github.com/getActivity/AiIndex) ![](https://img.shields.io/github/stars/getActivity/AiIndex.svg) ![](https://img.shields.io/github/forks/getActivity/AiIndex.svg) 301 | 302 | * 省市区 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) 303 | 304 | * Markdown 语法文档:[MarkdownDoc](https://github.com/getActivity/MarkdownDoc) ![](https://img.shields.io/github/stars/getActivity/MarkdownDoc.svg) ![](https://img.shields.io/github/forks/getActivity/MarkdownDoc.svg) 305 | 306 | #### 微信公众号:Android轮子哥 307 | 308 | ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/official_ccount.png) 309 | 310 | #### Android 技术 Q 群:10047167 311 | 312 | #### 如果您觉得我的开源库帮你节省了大量的开发时间,请扫描下方的二维码随意打赏,要是能打赏个 10.24 :monkey_face:就太:thumbsup:了。您的支持将鼓励我继续创作:octocat:([点击查看捐赠列表](https://github.com/getActivity/Donate)) 313 | 314 | ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_ali.png) ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_wechat.png) 315 | 316 | ## License 317 | 318 | ```text 319 | Copyright 2018 Huang JinQun 320 | 321 | Licensed under the Apache License, Version 2.0 (the "License"); 322 | you may not use this file except in compliance with the License. 323 | You may obtain a copy of the License at 324 | 325 | http://www.apache.org/licenses/LICENSE-2.0 326 | 327 | Unless required by applicable law or agreed to in writing, software 328 | distributed under the License is distributed on an "AS IS" BASIS, 329 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 330 | See the License for the specific language governing permissions and 331 | limitations under the License. 332 | ``` 333 | -------------------------------------------------------------------------------- /app/AppSignature.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/app/AppSignature.jks -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 34 5 | 6 | defaultConfig { 7 | applicationId "com.hjq.bar.demo" 8 | minSdkVersion 18 9 | targetSdkVersion 34 10 | versionCode 1060 11 | versionName "10.6" 12 | } 13 | 14 | // 支持 JDK 1.8 15 | compileOptions { 16 | targetCompatibility JavaVersion.VERSION_1_8 17 | sourceCompatibility JavaVersion.VERSION_1_8 18 | } 19 | 20 | // Apk 签名的那些事:https://www.jianshu.com/p/a1f8e5896aa2 21 | signingConfigs { 22 | config { 23 | storeFile file(StoreFile) 24 | storePassword StorePassword 25 | keyAlias KeyAlias 26 | keyPassword KeyPassword 27 | } 28 | } 29 | 30 | buildTypes { 31 | debug { 32 | minifyEnabled false 33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 34 | signingConfig signingConfigs.config 35 | } 36 | 37 | release { 38 | minifyEnabled true 39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 40 | signingConfig signingConfigs.config 41 | } 42 | } 43 | 44 | applicationVariants.configureEach { variant -> 45 | // apk 输出文件名配置 46 | variant.outputs.configureEach { output -> 47 | outputFileName = rootProject.getName() + '.apk' 48 | } 49 | } 50 | } 51 | 52 | dependencies { 53 | // 依赖 libs 目录下所有的 jar 和 aar 包 54 | implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') 55 | 56 | implementation project(':library') 57 | 58 | // AndroidX 库:https://github.com/androidx/androidx 59 | implementation 'androidx.appcompat:appcompat:1.4.0' 60 | // Material 库:https://github.com/material-components/material-components-android 61 | implementation 'com.google.android.material:material:1.4.0' 62 | 63 | // 吐司工具类:https://github.com/getActivity/Toaster 64 | implementation 'com.github.getActivity:Toaster:12.5' 65 | 66 | // 内存泄漏捕捉:https://github.com/square/leakcanary 67 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12' 68 | 69 | // 权限请求框架:https://github.com/getActivity/XXPermissions 70 | implementation 'com.github.getActivity:XXPermissions:18.5' 71 | } -------------------------------------------------------------------------------- /app/gradle.properties: -------------------------------------------------------------------------------- 1 | StoreFile = AppSignature.jks 2 | StorePassword = AndroidProject 3 | KeyAlias = AndroidProject 4 | KeyPassword = AndroidProject -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class com.hjq.bar.** {*;} -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/hjq/bar/demo/AppApplication.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar.demo; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.widget.TextView; 6 | 7 | import androidx.appcompat.widget.AppCompatTextView; 8 | 9 | import com.hjq.bar.TitleBar; 10 | import com.hjq.bar.style.LightBarStyle; 11 | import com.hjq.toast.Toaster; 12 | 13 | public final class AppApplication extends Application { 14 | 15 | @Override 16 | public void onCreate() { 17 | super.onCreate(); 18 | 19 | // 初始化 Toast 20 | Toaster.init(this); 21 | 22 | // 初始化 TitleBar 默认样式 23 | TitleBar.setDefaultStyle(new LightBarStyle() { 24 | 25 | @Override 26 | public TextView newTitleView(Context context) { 27 | return new AppCompatTextView(context); 28 | } 29 | 30 | @Override 31 | public TextView newLeftView(Context context) { 32 | return new AppCompatTextView(context); 33 | } 34 | 35 | @Override 36 | public TextView newRightView(Context context) { 37 | return new AppCompatTextView(context); 38 | } 39 | }); 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hjq/bar/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar.demo; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.appcompat.app.AppCompatActivity; 6 | 7 | import com.hjq.bar.OnTitleBarListener; 8 | import com.hjq.bar.TitleBar; 9 | import com.hjq.toast.Toaster; 10 | 11 | /** 12 | * author : Android 轮子哥 13 | * github : https://github.com/getActivity/TitleBar 14 | * time : 2018/08/17 15 | * desc : TitleBar 使用案例 16 | */ 17 | public final class MainActivity extends AppCompatActivity { 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | 24 | TitleBar titleBar = findViewById(R.id.tb_main_bar_click); 25 | titleBar.setOnTitleBarListener(new OnTitleBarListener() { 26 | 27 | @Override 28 | public void onLeftClick(TitleBar titleBar) { 29 | Toaster.show("左项 View 被点击"); 30 | } 31 | 32 | @Override 33 | public void onTitleClick(TitleBar titleBar) { 34 | Toaster.show("中间 View 被点击"); 35 | } 36 | 37 | @Override 38 | public void onRightClick(TitleBar titleBar) { 39 | Toaster.show("右项 View 被点击"); 40 | } 41 | }); 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/title_bar_head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/app/src/main/res/drawable-xxhdpi/title_bar_head.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/message_ic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/app/src/main/res/drawable/message_ic.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/qr_code_ic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/app/src/main/res/drawable/qr_code_ic.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 22 | 23 | 29 | 30 | 35 | 36 | 42 | 43 | 52 | 53 | 64 | 65 | 66 | 67 | 68 | 69 | 73 | 74 | 77 | 78 | 85 | 86 | 90 | 91 | 98 | 99 | 108 | 109 | 115 | 116 | 125 | 126 | 132 | 133 | 152 | 153 | 178 | 179 | 193 | 194 | 205 | 206 | 214 | 215 | 225 | 226 | 232 | 233 | 238 | 239 | 244 | 245 | 250 | 251 | 252 | 253 | 254 | 255 | 261 | 262 | 267 | 268 | 273 | 274 | 280 | 281 | 282 | 283 | 284 | 285 | 289 | 290 | 298 | 299 | 305 | 306 | 313 | 314 | 315 | 316 | 317 | 318 | 326 | 327 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | #000000 5 | #5A8DDF 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | TitleBar 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | // 阿里云云效仓库:https://maven.aliyun.com/mvn/guide 4 | maven { url 'https://maven.aliyun.com/repository/public' } 5 | maven { url 'https://maven.aliyun.com/repository/google' } 6 | // 华为开源镜像:https://mirrors.huaweicloud.com/ 7 | maven { url 'https://repo.huaweicloud.com/repository/maven/' } 8 | // JitPack 远程仓库:https://jitpack.io 9 | maven { url 'https://jitpack.io' } 10 | mavenCentral() 11 | google() 12 | // noinspection JcenterRepositoryObsolete 13 | jcenter() 14 | } 15 | dependencies { 16 | classpath 'com.android.tools.build:gradle:4.1.2' 17 | } 18 | } 19 | 20 | allprojects { 21 | repositories { 22 | maven { url 'https://maven.aliyun.com/repository/public' } 23 | maven { url 'https://maven.aliyun.com/repository/google' } 24 | maven { url 'https://repo.huaweicloud.com/repository/maven/' } 25 | maven { url 'https://jitpack.io' } 26 | mavenCentral() 27 | google() 28 | // noinspection JcenterRepositoryObsolete 29 | jcenter() 30 | } 31 | 32 | // 读取 local.properties 文件配置 33 | def properties = new Properties() 34 | def localPropertiesFile = rootProject.file("local.properties") 35 | if (localPropertiesFile.exists()) { 36 | localPropertiesFile.withInputStream { inputStream -> 37 | properties.load(inputStream) 38 | } 39 | } 40 | 41 | String buildDirPath = properties.getProperty("build.dir") 42 | if (buildDirPath != null && buildDirPath != "") { 43 | // 将构建文件统一输出到指定的目录下 44 | setBuildDir(new File(buildDirPath, rootProject.name + "/build/${path.replaceAll(':', '/')}")) 45 | } else { 46 | // 将构建文件统一输出到项目根目录下的 build 文件夹 47 | setBuildDir(new File(rootDir, "build/${path.replaceAll(':', '/')}")) 48 | } 49 | } 50 | 51 | tasks.register('clean', Delete) { 52 | delete rootProject.buildDir 53 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # 表示使用 AndroidX 20 | android.useAndroidX = true 21 | # 表示将第三方库迁移到 AndroidX 22 | android.enableJetifier = true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | zipStoreBase = GRADLE_USER_HOME 2 | zipStorePath = wrapper/dists 3 | distributionBase = GRADLE_USER_HOME 4 | distributionPath = wrapper/dists 5 | distributionUrl = https\://services.gradle.org/distributions/gradle-6.5-all.zip -------------------------------------------------------------------------------- /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/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 34 5 | 6 | defaultConfig { 7 | minSdkVersion 16 8 | versionCode 1060 9 | versionName "10.6" 10 | } 11 | 12 | // 支持 JDK 1.8 13 | compileOptions { 14 | targetCompatibility JavaVersion.VERSION_1_8 15 | sourceCompatibility JavaVersion.VERSION_1_8 16 | } 17 | 18 | android.libraryVariants.configureEach { variant -> 19 | // aar 输出文件名配置 20 | variant.outputs.configureEach { output -> 21 | outputFileName = "${rootProject.name}-${android.defaultConfig.versionName}.aar" 22 | } 23 | } 24 | } 25 | 26 | afterEvaluate { 27 | // 排除 BuildConfig.class 28 | generateReleaseBuildConfig.enabled = false 29 | generateDebugBuildConfig.enabled = false 30 | } 31 | 32 | tasks.withType(Javadoc).configureEach { 33 | options.addStringOption('Xdoclint:none', '-quiet') 34 | options.addStringOption('encoding', 'UTF-8') 35 | options.addStringOption('charSet', 'UTF-8') 36 | } 37 | 38 | tasks.register('sourcesJar', Jar) { 39 | from android.sourceSets.main.java.srcDirs 40 | classifier = 'sources' 41 | } 42 | 43 | tasks.register('javadoc', Javadoc) { 44 | source = android.sourceSets.main.java.srcDirs 45 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 46 | } 47 | 48 | tasks.register('javadocJar', Jar) { 49 | dependsOn javadoc 50 | classifier = 'javadoc' 51 | from javadoc.destinationDir 52 | } 53 | 54 | artifacts { 55 | archives javadocJar 56 | archives sourcesJar 57 | } -------------------------------------------------------------------------------- /library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\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 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /library/src/main/java/com/hjq/bar/ITitleBarStyle.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar; 2 | 3 | import android.content.Context; 4 | import android.content.res.ColorStateList; 5 | import android.graphics.Typeface; 6 | import android.graphics.drawable.Drawable; 7 | import android.text.TextUtils; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | 11 | /** 12 | * author : Android 轮子哥 13 | * github : https://github.com/getActivity/TitleBar 14 | * time : 2020/08/16 15 | * desc : 标题栏样式接口 16 | */ 17 | public interface ITitleBarStyle { 18 | 19 | /** 20 | * 创建标题 View 21 | */ 22 | TextView createTitleView(Context context); 23 | 24 | /** 25 | * 创建左标题 View 26 | */ 27 | TextView createLeftView(Context context); 28 | 29 | /** 30 | * 获取右标题 View 31 | */ 32 | TextView createRightView(Context context); 33 | 34 | /** 35 | * 获取分割线 View 36 | */ 37 | View createLineView(Context context); 38 | 39 | /** 40 | * 获取标题栏背景 41 | */ 42 | Drawable getTitleBarBackground(Context context); 43 | 44 | /** 45 | * 获取左标题的按钮背景 46 | */ 47 | Drawable getLeftTitleBackground(Context context); 48 | 49 | /** 50 | * 获取右标题的按钮背景 51 | */ 52 | Drawable getRightTitleBackground(Context context); 53 | 54 | /** 55 | * 获取左标题的按钮前景 56 | */ 57 | Drawable getLeftTitleForeground(Context context); 58 | 59 | /** 60 | * 获取右标题的按钮前景 61 | */ 62 | Drawable getRightTitleForeground(Context context); 63 | 64 | /** 65 | * 获取默认按钮图片 66 | */ 67 | Drawable getBackButtonDrawable(Context context); 68 | 69 | /** 70 | * 获取左标题子控件的水平内间距 71 | */ 72 | int getLeftHorizontalPadding(Context context); 73 | 74 | /** 75 | * 获取标题子控件的水平内间距 76 | */ 77 | int getTitleHorizontalPadding(Context context); 78 | 79 | /** 80 | * 获取右标题子控件的水平内间距 81 | */ 82 | int getRightHorizontalPadding(Context context); 83 | 84 | /** 85 | * 获取子控件的垂直内间距 86 | */ 87 | int getChildVerticalPadding(Context context); 88 | 89 | /** 90 | * 获取标题的默认文本 91 | */ 92 | CharSequence getTitle(Context context); 93 | 94 | /** 95 | * 获取左标题的默认文本 96 | */ 97 | CharSequence getLeftTitle(Context context); 98 | 99 | /** 100 | * 获取右边标题的默认文本 101 | */ 102 | CharSequence getRightTitle(Context context); 103 | 104 | /** 105 | * 获取标题的默认字体颜色 106 | */ 107 | ColorStateList getTitleColor(Context context); 108 | 109 | /** 110 | * 获取左标题的默认字体颜色 111 | */ 112 | ColorStateList getLeftTitleColor(Context context); 113 | 114 | /** 115 | * 获取右边标题的默认字体颜色 116 | */ 117 | ColorStateList getRightTitleColor(Context context); 118 | 119 | /** 120 | * 获取中间标题的默认字体大小 121 | */ 122 | float getTitleSize(Context context); 123 | 124 | /** 125 | * 获取左标题的默认字体大小 126 | */ 127 | float getLeftTitleSize(Context context); 128 | 129 | /** 130 | * 获取右标题的默认字体大小 131 | */ 132 | float getRightTitleSize(Context context); 133 | 134 | /** 135 | * 获取标题的字体样式 136 | * 137 | * @param style 文字样式 138 | * 常规:{@link Typeface#NORMAL} 139 | * 粗体:{@link Typeface#BOLD} 140 | * 斜体:{@link Typeface#ITALIC} 141 | * 粗斜体:{@link Typeface#BOLD_ITALIC} 142 | */ 143 | Typeface getTitleTypeface(Context context, int style); 144 | 145 | /** 146 | * 获取左标题的的字体样式 147 | * 148 | * @param style 文字样式 149 | * 常规:{@link Typeface#NORMAL} 150 | * 粗体:{@link Typeface#BOLD} 151 | * 斜体:{@link Typeface#ITALIC} 152 | * 粗斜体:{@link Typeface#BOLD_ITALIC} 153 | */ 154 | Typeface getLeftTitleTypeface(Context context, int style); 155 | 156 | /** 157 | * 获取右标题的的字体样式 158 | * 159 | * @param style 文字样式 160 | * 常规:{@link Typeface#NORMAL} 161 | * 粗体:{@link Typeface#BOLD} 162 | * 斜体:{@link Typeface#ITALIC} 163 | * 粗斜体:{@link Typeface#BOLD_ITALIC} 164 | */ 165 | Typeface getRightTitleTypeface(Context context, int style); 166 | 167 | /** 168 | * 获取标题的默认样式 169 | */ 170 | int getTitleStyle(Context context); 171 | 172 | /** 173 | * 获取左标题的默认样式 174 | */ 175 | int getLeftTitleStyle(Context context); 176 | 177 | /** 178 | * 获取右标题的默认样式 179 | */ 180 | int getRightTitleStyle(Context context); 181 | 182 | /** 183 | * 获取标题的图标默认重心 184 | */ 185 | int getTitleIconGravity(Context context); 186 | 187 | /** 188 | * 获取左标题的图标默认重心 189 | */ 190 | int getLeftIconGravity(Context context); 191 | 192 | /** 193 | * 获取右标题的图标默认重心 194 | */ 195 | int getRightIconGravity(Context context); 196 | 197 | /** 198 | * 获取标题的图标默认间距 199 | */ 200 | int getTitleIconPadding(Context context); 201 | 202 | /** 203 | * 获取左标题的图标默认间距 204 | */ 205 | int getLeftIconPadding(Context context); 206 | 207 | /** 208 | * 获取右标题的图标默认间距 209 | */ 210 | int getRightIconPadding(Context context); 211 | 212 | /** 213 | * 获取标题的图标默认宽度 214 | */ 215 | int getTitleIconWidth(Context context); 216 | 217 | /** 218 | * 获取左标题的图标默认宽度 219 | */ 220 | int getLeftIconWidth(Context context); 221 | 222 | /** 223 | * 获取右标题的图标默认宽度 224 | */ 225 | int getRightIconWidth(Context context); 226 | 227 | /** 228 | * 获取标题的图标默认高度 229 | */ 230 | int getTitleIconHeight(Context context); 231 | 232 | /** 233 | * 获取左标题的图标默认高度 234 | */ 235 | int getLeftIconHeight(Context context); 236 | 237 | /** 238 | * 获取右标题的图标默认高度 239 | */ 240 | int getRightIconHeight(Context context); 241 | 242 | /** 243 | * 获取标题文本溢出的处理方式 244 | */ 245 | TextUtils.TruncateAt getTitleOverflowMode(Context context); 246 | 247 | /** 248 | * 获取左标题文本溢出的处理方式 249 | */ 250 | TextUtils.TruncateAt getLeftTitleOverflowMode(Context context); 251 | 252 | /** 253 | * 获取右标题文本溢出的处理方式 254 | */ 255 | TextUtils.TruncateAt getRightTitleOverflowMode(Context context); 256 | 257 | /** 258 | * 分割线是否显示 259 | */ 260 | boolean isLineVisible(Context context); 261 | 262 | /** 263 | * 获取分割线默认大小 264 | */ 265 | int getLineSize(Context context); 266 | 267 | /** 268 | * 获取分割线默认背景 269 | */ 270 | Drawable getLineDrawable(Context context); 271 | } -------------------------------------------------------------------------------- /library/src/main/java/com/hjq/bar/OnTitleBarListener.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar; 2 | 3 | /** 4 | * author : Android 轮子哥 5 | * github : https://github.com/getActivity/TitleBar 6 | * time : 2018/08/20 7 | * desc : 标题栏点击监听接口 8 | */ 9 | public interface OnTitleBarListener { 10 | 11 | /** 12 | * 左边的标题被点击 13 | * 14 | * @param titleBar 标题栏对象(非空) 15 | */ 16 | default void onLeftClick(TitleBar titleBar) {} 17 | 18 | /** 19 | * 中间的标题被点击 20 | * 21 | * @param titleBar 标题栏对象(非空) 22 | */ 23 | default void onTitleClick(TitleBar titleBar) {} 24 | 25 | /** 26 | * 右边的标题被点击 27 | * 28 | * @param titleBar 标题栏对象(非空) 29 | */ 30 | default void onRightClick(TitleBar titleBar) {} 31 | } -------------------------------------------------------------------------------- /library/src/main/java/com/hjq/bar/SelectorDrawable.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.graphics.drawable.StateListDrawable; 5 | 6 | /** 7 | * author : Android 轮子哥 8 | * github : https://github.com/getActivity/TitleBar 9 | * time : 2019/03/10 10 | * desc : 状态选择器构建器 11 | */ 12 | @SuppressWarnings("unused") 13 | public final class SelectorDrawable extends StateListDrawable { 14 | 15 | public final static class Builder { 16 | 17 | /** 默认状态 */ 18 | private Drawable mDefault; 19 | /** 焦点状态 */ 20 | private Drawable mFocused; 21 | /** 按下状态 */ 22 | private Drawable mPressed; 23 | /** 选中状态 */ 24 | private Drawable mChecked; 25 | /** 启用状态 */ 26 | private Drawable mEnabled; 27 | /** 选择状态 */ 28 | private Drawable mSelected; 29 | /** 光标悬浮状态(4.0新特性) */ 30 | private Drawable mHovered; 31 | 32 | public Builder setDefault(Drawable drawable) { 33 | mDefault = drawable; 34 | return this; 35 | } 36 | 37 | public Builder setFocused(Drawable drawable) { 38 | mFocused = drawable; 39 | return this; 40 | } 41 | 42 | public Builder setPressed(Drawable drawable) { 43 | mPressed = drawable; 44 | return this; 45 | } 46 | 47 | public Builder setChecked(Drawable drawable) { 48 | mChecked = drawable; 49 | return this; 50 | } 51 | 52 | public Builder setEnabled(Drawable drawable) { 53 | mEnabled = drawable; 54 | return this; 55 | } 56 | 57 | public Builder setSelected(Drawable drawable) { 58 | mSelected = drawable; 59 | return this; 60 | } 61 | 62 | public Builder setHovered(Drawable drawable) { 63 | mHovered = drawable; 64 | return this; 65 | } 66 | 67 | public SelectorDrawable build() { 68 | SelectorDrawable selector = new SelectorDrawable(); 69 | if (mPressed != null) { 70 | selector.addState(new int[]{android.R.attr.state_pressed}, mPressed); 71 | } 72 | if (mFocused != null) { 73 | selector.addState(new int[]{android.R.attr.state_focused}, mFocused); 74 | } 75 | if (mChecked != null) { 76 | selector.addState(new int[]{android.R.attr.state_checked}, mChecked); 77 | } 78 | if (mEnabled != null) { 79 | selector.addState(new int[]{android.R.attr.state_enabled}, mEnabled); 80 | } 81 | if (mSelected != null) { 82 | selector.addState(new int[]{android.R.attr.state_selected}, mSelected); 83 | } 84 | if (mHovered != null) { 85 | selector.addState(new int[]{android.R.attr.state_hovered}, mHovered); 86 | } 87 | if (mDefault != null) { 88 | selector.addState(new int[]{}, mDefault); 89 | } 90 | return selector; 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /library/src/main/java/com/hjq/bar/TitleBar.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.res.ColorStateList; 6 | import android.content.res.TypedArray; 7 | import android.graphics.Typeface; 8 | import android.graphics.drawable.ColorDrawable; 9 | import android.graphics.drawable.Drawable; 10 | import android.text.TextUtils; 11 | import android.util.AttributeSet; 12 | import android.util.Log; 13 | import android.util.TypedValue; 14 | import android.view.Gravity; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.FrameLayout; 18 | import android.widget.TextView; 19 | import com.hjq.bar.style.LightBarStyle; 20 | import com.hjq.bar.style.NightBarStyle; 21 | import com.hjq.bar.style.TransparentBarStyle; 22 | 23 | /** 24 | * author : Android 轮子哥 25 | * github : https://github.com/getActivity/TitleBar 26 | * time : 2018/08/17 27 | * desc : 标题栏框架 28 | */ 29 | @SuppressWarnings({"unused", "UnusedReturnValue"}) 30 | public class TitleBar extends FrameLayout 31 | implements View.OnClickListener, 32 | View.OnLayoutChangeListener { 33 | 34 | private static final String LOG_TAG = "TitleBar"; 35 | 36 | /** 默认初始化器 */ 37 | private static ITitleBarStyle sGlobalStyle; 38 | /** 当前初始化器 */ 39 | private final ITitleBarStyle mCurrentStyle; 40 | 41 | /** 监听器对象 */ 42 | private OnTitleBarListener mListener; 43 | 44 | /** 标题栏子控件 */ 45 | private final TextView mLeftView, mTitleView, mRightView; 46 | private final View mLineView; 47 | 48 | /** 控件水平间距 */ 49 | private int mLeftHorizontalPadding, mTitleHorizontalPadding, mRightHorizontalPadding; 50 | 51 | /** 控件垂直间距 */ 52 | private int mVerticalPadding; 53 | 54 | /** 图标显示大小 */ 55 | private int mLeftIconWidth, mLeftIconHeight; 56 | private int mTitleIconWidth, mTitleIconHeight; 57 | private int mRightIconWidth, mRightIconHeight; 58 | 59 | /** 图标显示重心 */ 60 | private int mLeftIconGravity, mTitleIconGravity, mRightIconGravity; 61 | 62 | /** 图标着色器 */ 63 | private int mLeftIconTint, mTitleIconTint, mRightIconTint = TitleBarSupport.NO_COLOR; 64 | 65 | public TitleBar(Context context) { 66 | this(context, null); 67 | } 68 | 69 | public TitleBar(Context context, AttributeSet attrs) { 70 | this(context, attrs, 0); 71 | } 72 | 73 | public TitleBar(Context context, AttributeSet attrs, int defStyleAttr) { 74 | super(context, attrs, defStyleAttr); 75 | 76 | if (sGlobalStyle == null) { 77 | sGlobalStyle = new LightBarStyle(); 78 | } 79 | 80 | final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TitleBar, 0, R.style.TitleBarDefaultStyle); 81 | 82 | // 标题栏样式设置 83 | switch (array.getInt(R.styleable.TitleBar_barStyle, 0)) { 84 | case 0x10: 85 | mCurrentStyle = new LightBarStyle(); 86 | break; 87 | case 0x20: 88 | mCurrentStyle = new NightBarStyle(); 89 | break; 90 | case 0x30: 91 | mCurrentStyle = new TransparentBarStyle(); 92 | break; 93 | default: 94 | mCurrentStyle = TitleBar.sGlobalStyle; 95 | break; 96 | } 97 | 98 | mTitleView = mCurrentStyle.createTitleView(context); 99 | mLeftView = mCurrentStyle.createLeftView(context); 100 | mRightView = mCurrentStyle.createRightView(context); 101 | mLineView = mCurrentStyle.createLineView(context); 102 | 103 | mTitleView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 104 | ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER)); 105 | mLeftView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 106 | ViewGroup.LayoutParams.MATCH_PARENT, Gravity.START | Gravity.CENTER_VERTICAL)); 107 | mRightView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 108 | ViewGroup.LayoutParams.MATCH_PARENT, Gravity.END | Gravity.CENTER_VERTICAL)); 109 | mLineView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 110 | mCurrentStyle.getLineSize(context), Gravity.BOTTOM)); 111 | 112 | // 设置图标显示的重心 113 | setTitleIconGravity(array.getInt(R.styleable.TitleBar_titleIconGravity, mCurrentStyle.getTitleIconGravity(context))); 114 | setLeftIconGravity(array.getInt(R.styleable.TitleBar_leftIconGravity, mCurrentStyle.getLeftIconGravity(context))); 115 | setRightIconGravity(array.getInt(R.styleable.TitleBar_rightIconGravity, mCurrentStyle.getRightIconGravity(context))); 116 | 117 | // 设置图标显示的大小 118 | setTitleIconSize(array.getDimensionPixelSize(R.styleable.TitleBar_titleIconWidth, mCurrentStyle.getTitleIconWidth(context)), 119 | array.getDimensionPixelSize(R.styleable.TitleBar_titleIconHeight, mCurrentStyle.getTitleIconHeight(context))); 120 | setLeftIconSize(array.getDimensionPixelSize(R.styleable.TitleBar_leftIconWidth, mCurrentStyle.getLeftIconWidth(context)), 121 | array.getDimensionPixelSize(R.styleable.TitleBar_leftIconHeight, mCurrentStyle.getLeftIconHeight(context))); 122 | setRightIconSize(array.getDimensionPixelSize(R.styleable.TitleBar_rightIconWidth, mCurrentStyle.getRightIconWidth(context)), 123 | array.getDimensionPixelSize(R.styleable.TitleBar_rightIconHeight, mCurrentStyle.getRightIconHeight(context))); 124 | 125 | // 设置文字和图标之间的间距 126 | setTitleIconPadding(array.getDimensionPixelSize(R.styleable.TitleBar_titleIconPadding, mCurrentStyle.getTitleIconPadding(context))); 127 | setLeftIconPadding(array.getDimensionPixelSize(R.styleable.TitleBar_leftIconPadding, mCurrentStyle.getLeftIconPadding(context))); 128 | setRightIconPadding(array.getDimensionPixelSize(R.styleable.TitleBar_rightIconPadding, mCurrentStyle.getRightIconPadding(context))); 129 | 130 | // 标题设置 131 | if (array.hasValue(R.styleable.TitleBar_title)) { 132 | setTitle(array.getResourceId(R.styleable.TitleBar_title, 0) != R.string.bar_string_placeholder ? 133 | array.getString(R.styleable.TitleBar_title) : mCurrentStyle.getTitle(context)); 134 | } 135 | 136 | if (array.hasValue(R.styleable.TitleBar_leftTitle)) { 137 | setLeftTitle(array.getResourceId(R.styleable.TitleBar_leftTitle, 0) != R.string.bar_string_placeholder ? 138 | array.getString(R.styleable.TitleBar_leftTitle) : mCurrentStyle.getLeftTitle(context)); 139 | } 140 | 141 | if (array.hasValue(R.styleable.TitleBar_rightTitle)) { 142 | setRightTitle(array.getResourceId(R.styleable.TitleBar_rightTitle, 0) != R.string.bar_string_placeholder ? 143 | array.getString(R.styleable.TitleBar_rightTitle) : mCurrentStyle.getRightTitle(context)); 144 | } 145 | 146 | // 图标着色设置 147 | if (array.hasValue(R.styleable.TitleBar_titleIconTint)) { 148 | setTitleIconTint(array.getColor(R.styleable.TitleBar_titleIconTint, 0)); 149 | } 150 | 151 | if (array.hasValue(R.styleable.TitleBar_leftIconTint)) { 152 | setLeftIconTint(array.getColor(R.styleable.TitleBar_leftIconTint, 0)); 153 | } 154 | 155 | if (array.hasValue(R.styleable.TitleBar_rightIconTint)) { 156 | setRightIconTint(array.getColor(R.styleable.TitleBar_rightIconTint, 0)); 157 | } 158 | 159 | // 图标设置 160 | if (array.hasValue(R.styleable.TitleBar_titleIcon)) { 161 | setTitleIcon(TitleBarSupport.getDrawable(context, array.getResourceId(R.styleable.TitleBar_titleIcon, 0))); 162 | } 163 | 164 | if (array.hasValue(R.styleable.TitleBar_leftIcon)) { 165 | setLeftIcon(array.getResourceId(R.styleable.TitleBar_leftIcon, 0) != R.drawable.bar_drawable_placeholder ? 166 | TitleBarSupport.getDrawable(context, array.getResourceId(R.styleable.TitleBar_leftIcon, 0)) : 167 | mCurrentStyle.getBackButtonDrawable(context)); 168 | } 169 | 170 | if (array.hasValue(R.styleable.TitleBar_rightIcon)) { 171 | setRightIcon(TitleBarSupport.getDrawable(context, array.getResourceId(R.styleable.TitleBar_rightIcon, 0))); 172 | } 173 | 174 | // 文字颜色设置 175 | setTitleColor(array.hasValue(R.styleable.TitleBar_titleColor) ? 176 | array.getColorStateList(R.styleable.TitleBar_titleColor) : 177 | mCurrentStyle.getTitleColor(context)); 178 | setLeftTitleColor(array.hasValue(R.styleable.TitleBar_leftTitleColor) ? 179 | array.getColorStateList(R.styleable.TitleBar_leftTitleColor) : 180 | mCurrentStyle.getLeftTitleColor(context)); 181 | setRightTitleColor(array.hasValue(R.styleable.TitleBar_rightTitleColor) ? 182 | array.getColorStateList(R.styleable.TitleBar_rightTitleColor) : 183 | mCurrentStyle.getRightTitleColor(context)); 184 | 185 | // 文字大小设置 186 | setTitleSize(TypedValue.COMPLEX_UNIT_PX, array.hasValue(R.styleable.TitleBar_titleSize) ? 187 | array.getDimensionPixelSize(R.styleable.TitleBar_titleSize, 0) : 188 | mCurrentStyle.getTitleSize(context)); 189 | setLeftTitleSize(TypedValue.COMPLEX_UNIT_PX, array.hasValue(R.styleable.TitleBar_leftTitleSize) ? 190 | array.getDimensionPixelSize(R.styleable.TitleBar_leftTitleSize, 0) : 191 | mCurrentStyle.getLeftTitleSize(context)); 192 | setRightTitleSize(TypedValue.COMPLEX_UNIT_PX, array.hasValue(R.styleable.TitleBar_rightTitleSize) ? 193 | array.getDimensionPixelSize(R.styleable.TitleBar_rightTitleSize, 0) : 194 | mCurrentStyle.getRightTitleSize(context)); 195 | 196 | // 文字样式设置 197 | int titleStyle = array.hasValue(R.styleable.TitleBar_titleStyle) ? 198 | array.getInt(R.styleable.TitleBar_titleStyle, Typeface.NORMAL) : 199 | mCurrentStyle.getTitleStyle(context); 200 | setTitleStyle(mCurrentStyle.getTitleTypeface(context, titleStyle), titleStyle); 201 | 202 | int leftTitleStyle = array.hasValue(R.styleable.TitleBar_leftTitleStyle) ? 203 | array.getInt(R.styleable.TitleBar_leftTitleStyle, Typeface.NORMAL) : 204 | mCurrentStyle.getLeftTitleStyle(context); 205 | setLeftTitleStyle(mCurrentStyle.getLeftTitleTypeface(context, leftTitleStyle), leftTitleStyle); 206 | 207 | int rightTitleStyle = array.hasValue(R.styleable.TitleBar_rightTitleStyle) ? 208 | array.getInt(R.styleable.TitleBar_rightTitleStyle, Typeface.NORMAL) : 209 | mCurrentStyle.getRightTitleStyle(context); 210 | setRightTitleStyle(mCurrentStyle.getRightTitleTypeface(context, rightTitleStyle), rightTitleStyle); 211 | 212 | TextUtils.TruncateAt titleOverflowMode = array.hasValue(R.styleable.TitleBar_titleOverflowMode) ? 213 | TitleBarSupport.convertIntToTruncateAtEnum(array.getInt(R.styleable.TitleBar_titleOverflowMode, TitleBarSupport.ELLIPSIZE_NONE)) : 214 | mCurrentStyle.getTitleOverflowMode(context); 215 | setTitleOverflowMode(titleOverflowMode); 216 | 217 | TextUtils.TruncateAt leftTitleOverflowMode = array.hasValue(R.styleable.TitleBar_leftTitleOverflowMode) ? 218 | TitleBarSupport.convertIntToTruncateAtEnum(array.getInt(R.styleable.TitleBar_leftTitleOverflowMode, TitleBarSupport.ELLIPSIZE_NONE)) : 219 | mCurrentStyle.getLeftTitleOverflowMode(context); 220 | setLeftTitleOverflowMode(leftTitleOverflowMode); 221 | 222 | TextUtils.TruncateAt rightTitleOverflowMode = array.hasValue(R.styleable.TitleBar_rightTitleOverflowMode) ? 223 | TitleBarSupport.convertIntToTruncateAtEnum(array.getInt(R.styleable.TitleBar_rightTitleOverflowMode, TitleBarSupport.ELLIPSIZE_NONE)) : 224 | mCurrentStyle.getRightTitleOverflowMode(context); 225 | setRightTitleOverflowMode(rightTitleOverflowMode); 226 | 227 | // 标题重心设置 228 | if (array.hasValue(R.styleable.TitleBar_titleGravity)) { 229 | setTitleGravity(array.getInt(R.styleable.TitleBar_titleGravity, Gravity.NO_GRAVITY)); 230 | } 231 | 232 | // 设置背景 233 | if (array.hasValue(R.styleable.TitleBar_android_background)) { 234 | if (array.getResourceId(R.styleable.TitleBar_android_background, 0) == R.drawable.bar_drawable_placeholder) { 235 | TitleBarSupport.setBackground(this, mCurrentStyle.getTitleBarBackground(context)); 236 | } 237 | } 238 | 239 | if (array.hasValue(R.styleable.TitleBar_leftBackground)) { 240 | setLeftBackground(array.getResourceId(R.styleable.TitleBar_leftBackground, 0) != R.drawable.bar_drawable_placeholder ? 241 | array.getDrawable(R.styleable.TitleBar_leftBackground) : mCurrentStyle.getLeftTitleBackground(context)); 242 | } 243 | 244 | if (array.hasValue(R.styleable.TitleBar_rightBackground)) { 245 | setRightBackground(array.getResourceId(R.styleable.TitleBar_rightBackground, 0) != R.drawable.bar_drawable_placeholder ? 246 | array.getDrawable(R.styleable.TitleBar_rightBackground) : mCurrentStyle.getRightTitleBackground(context)); 247 | } 248 | 249 | // 设置前景 250 | if (array.hasValue(R.styleable.TitleBar_leftForeground)) { 251 | setLeftForeground(array.getResourceId(R.styleable.TitleBar_leftForeground, 0) != R.drawable.bar_drawable_placeholder ? 252 | array.getDrawable(R.styleable.TitleBar_leftForeground) : mCurrentStyle.getLeftTitleForeground(context)); 253 | } 254 | 255 | if (array.hasValue(R.styleable.TitleBar_rightForeground)) { 256 | setRightForeground(array.getResourceId(R.styleable.TitleBar_rightForeground, 0) != R.drawable.bar_drawable_placeholder ? 257 | array.getDrawable(R.styleable.TitleBar_rightForeground) : mCurrentStyle.getRightTitleForeground(context)); 258 | } 259 | 260 | // 分割线设置 261 | setLineVisible(array.getBoolean(R.styleable.TitleBar_lineVisible, mCurrentStyle.isLineVisible(context))); 262 | 263 | if (array.hasValue(R.styleable.TitleBar_lineDrawable)) { 264 | setLineDrawable(array.getResourceId(R.styleable.TitleBar_lineDrawable, 0) != R.drawable.bar_drawable_placeholder ? 265 | array.getDrawable(R.styleable.TitleBar_lineDrawable) : mCurrentStyle.getLineDrawable(context)); 266 | } 267 | 268 | if (array.hasValue(R.styleable.TitleBar_lineSize)) { 269 | setLineSize(array.getDimensionPixelSize(R.styleable.TitleBar_lineSize, 0)); 270 | } 271 | 272 | // 设置子控件的内间距 273 | mLeftHorizontalPadding = array.getDimensionPixelSize(R.styleable.TitleBar_leftHorizontalPadding, mCurrentStyle.getLeftHorizontalPadding(context)); 274 | mTitleHorizontalPadding = array.getDimensionPixelSize(R.styleable.TitleBar_titleHorizontalPadding, mCurrentStyle.getTitleHorizontalPadding(context)); 275 | mRightHorizontalPadding = array.getDimensionPixelSize(R.styleable.TitleBar_rightHorizontalPadding, mCurrentStyle.getRightHorizontalPadding(context)); 276 | setChildHorizontalPadding(mLeftHorizontalPadding, mTitleHorizontalPadding, mRightHorizontalPadding); 277 | 278 | mVerticalPadding = array.getDimensionPixelSize(R.styleable.TitleBar_childVerticalPadding, mCurrentStyle.getChildVerticalPadding(context)); 279 | setChildVerticalPadding(mVerticalPadding); 280 | 281 | // 回收 TypedArray 对象 282 | array.recycle(); 283 | 284 | addView(mTitleView, 0); 285 | addView(mLeftView, 1); 286 | addView(mRightView, 2); 287 | addView(mLineView, 3); 288 | 289 | addOnLayoutChangeListener(this); 290 | 291 | // 如果当前是布局预览模式 292 | if (isInEditMode()) { 293 | measure(0, 0); 294 | mTitleView.measure(0, 0); 295 | mLeftView.measure(0, 0); 296 | mRightView.measure(0, 0); 297 | int horizontalMargin = Math.max( 298 | mLeftView.getMeasuredWidth() + mLeftHorizontalPadding * 2, 299 | mRightView.getMeasuredWidth() + mRightHorizontalPadding * 2); 300 | MarginLayoutParams layoutParams = (MarginLayoutParams) mTitleView.getLayoutParams(); 301 | layoutParams.setMargins(horizontalMargin, 0, horizontalMargin, 0); 302 | } 303 | } 304 | 305 | @Override 306 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 307 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 308 | 309 | int titleBarWidth = this.getMeasuredWidth(); 310 | int titleBarHeight = this.getMeasuredHeight(); 311 | 312 | int leftViewMeasuredWidth = mLeftView.getMeasuredWidth(); 313 | int leftViewMeasuredHeight = mLeftView.getMeasuredHeight(); 314 | 315 | int titleViewMeasuredWidth = mTitleView.getMeasuredWidth(); 316 | int titleViewMeasuredHeight = mTitleView.getMeasuredHeight(); 317 | 318 | int rightViewMeasuredWidth = mRightView.getMeasuredWidth(); 319 | int rightViewMeasuredHeight = mRightView.getMeasuredHeight(); 320 | 321 | int maxEdgeWidth = Math.max(leftViewMeasuredWidth, rightViewMeasuredWidth); 322 | int calculateTotalWidth = maxEdgeWidth * 2 + titleViewMeasuredWidth; 323 | // 算出来总宽度是否小于标题栏的宽度 324 | if (calculateTotalWidth <= titleBarWidth) { 325 | measureTitleBar((TitleBarSupport.containContent(mLeftView) ? leftViewMeasuredWidth : 0), titleViewMeasuredWidth, 326 | (TitleBarSupport.containContent(mRightView) ? rightViewMeasuredWidth : 0), heightMeasureSpec); 327 | return; 328 | } 329 | 330 | int leftViewWidth; 331 | int titleViewWidth; 332 | int rightViewWidth; 333 | 334 | // 判断是左右项太长还是标题项太长 335 | if (maxEdgeWidth > titleBarWidth / 3) { 336 | // 如果是左右项太长,那么就进行动态计算 337 | leftViewWidth = titleBarWidth / 4; 338 | titleViewWidth = titleBarWidth / 2; 339 | rightViewWidth = titleBarWidth / 4; 340 | } else { 341 | // 如果是标题项太长,那么就进行动态计算 342 | leftViewWidth = maxEdgeWidth; 343 | titleViewWidth = titleBarWidth - maxEdgeWidth * 2; 344 | rightViewWidth = maxEdgeWidth; 345 | } 346 | 347 | measureTitleBar((TitleBarSupport.containContent(mLeftView) ? leftViewWidth : 0), titleViewWidth, 348 | (TitleBarSupport.containContent(mRightView) ? rightViewWidth : 0), heightMeasureSpec); 349 | } 350 | 351 | private void measureTitleBar(int leftViewWidth, int titleViewWidth, int rightViewWidth, int titleBarHeightMeasureSpec) { 352 | // 这里解释一下这里要为什么要用 TitleBar 的 heightMeasureSpec 作为子 View 测量的 heightMeasureSpec 353 | // 而不是直接用子 View 的测量高度 MeasureSpec.makeMeasureSpec(xxxViewHeight, MeasureSpec.EXACTLY) 354 | // 这是直接用子 View 的测量高度是理想化的,万一 TitleBar 写死高度了呢?还不是得跟随父 View 的高度来走? 355 | // 另外如果那样做还会出现一个 bug,就是当 TitleBar 设置了 padding = 30dp 的,并且中间标题的 View 开启了跑马灯模式 356 | // 会导致子 View 的空间会被再一次压缩,具体表现为子 View 的高度会再减去 30 dp,具体原因没有去深究 357 | // 但是对比了 FrameLayout,确实人家在 measureChild 子 View 的时候就是直接用的父 View 的 heightMeasureSpec 358 | int leftWidthMeasureSpec = MeasureSpec.makeMeasureSpec(leftViewWidth, MeasureSpec.EXACTLY); 359 | int titleWidthMeasureSpec = MeasureSpec.makeMeasureSpec(titleViewWidth, MeasureSpec.EXACTLY); 360 | int rightWidthMeasureSpec = MeasureSpec.makeMeasureSpec(rightViewWidth, MeasureSpec.EXACTLY); 361 | measureChildWithMargins(mLeftView, leftWidthMeasureSpec, 0, titleBarHeightMeasureSpec, 0); 362 | measureChildWithMargins(mTitleView, titleWidthMeasureSpec, 0, titleBarHeightMeasureSpec, 0); 363 | measureChildWithMargins(mRightView, rightWidthMeasureSpec, 0, titleBarHeightMeasureSpec, 0); 364 | 365 | // 这里解释一下为什么那么做,这是因为不同子 View 测量出来的高度不一样 366 | // 由于我们的子 LeftView、TitleView、RightView、都是设置的 match_parent 367 | // 如果有子 View 高度有不一致的问题,则必须让它调整到和 TitleBar 布局的高度保持一致才可以 368 | // 主要是为了解决在 TitleView 在开启跑马灯的情况下,LeftView 和 RightView 高度没有占满 TitleBar 的问题 369 | // 解决方案是我参考了 FrameLayout 源码中,有看到对设置 match_parent 宽度和高度的子 View 大小进行了二次调整 370 | int titleBarMeasuredHeight = this.getMeasuredHeight(); 371 | if (titleBarMeasuredHeight != mLeftView.getMeasuredHeight()) { 372 | mLeftView.measure(leftWidthMeasureSpec, MeasureSpec.makeMeasureSpec(titleBarMeasuredHeight, MeasureSpec.EXACTLY)); 373 | } 374 | 375 | if (titleBarMeasuredHeight != mTitleView.getMeasuredHeight()) { 376 | mTitleView.measure(titleWidthMeasureSpec, MeasureSpec.makeMeasureSpec(titleBarMeasuredHeight, MeasureSpec.EXACTLY)); 377 | } 378 | 379 | if (titleBarMeasuredHeight != mRightView.getMeasuredHeight()) { 380 | mRightView.measure(rightWidthMeasureSpec, MeasureSpec.makeMeasureSpec(titleBarMeasuredHeight, MeasureSpec.EXACTLY)); 381 | } 382 | } 383 | 384 | @Override 385 | public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 386 | // 解决在外部触摸时触发点击效果的问题 387 | if (!mLeftView.isClickable()) { 388 | mLeftView.setClickable(true); 389 | } 390 | if (!mTitleView.isClickable()) { 391 | mTitleView.setClickable(true); 392 | } 393 | if (!mRightView.isClickable()) { 394 | mRightView.setClickable(true); 395 | } 396 | 397 | // TextView 里面必须有东西才能被点击 398 | mLeftView.setEnabled(TitleBarSupport.containContent(mLeftView)); 399 | mTitleView.setEnabled(TitleBarSupport.containContent(mTitleView)); 400 | mRightView.setEnabled(TitleBarSupport.containContent(mRightView)); 401 | } 402 | 403 | /** 404 | * {@link View.OnClickListener} 405 | */ 406 | 407 | @Override 408 | public void onClick(View view) { 409 | if (mListener == null) { 410 | return; 411 | } 412 | 413 | if (view == mLeftView) { 414 | mListener.onLeftClick(this); 415 | } else if (view == mRightView) { 416 | mListener.onRightClick(this); 417 | } else if (view == mTitleView) { 418 | mListener.onTitleClick(this); 419 | } 420 | } 421 | 422 | @Override 423 | public void setLayoutParams(ViewGroup.LayoutParams params) { 424 | if (params.width == LayoutParams.WRAP_CONTENT) { 425 | // 如果当前宽度是自适应则转换成占满父布局 426 | params.width = LayoutParams.MATCH_PARENT; 427 | } 428 | 429 | int verticalPadding = 0; 430 | // 如果当前高度是自适应则设置默认的内间距 431 | if (params.height == ViewGroup.LayoutParams.WRAP_CONTENT) { 432 | verticalPadding = mVerticalPadding; 433 | } 434 | 435 | setChildVerticalPadding(verticalPadding); 436 | super.setLayoutParams(params); 437 | } 438 | 439 | @Override 440 | protected LayoutParams generateDefaultLayoutParams() { 441 | return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 442 | } 443 | 444 | /** 445 | * 设置标题栏的点击监听器 446 | */ 447 | public TitleBar setOnTitleBarListener(OnTitleBarListener listener) { 448 | mListener = listener; 449 | // 设置监听 450 | mTitleView.setOnClickListener(this); 451 | mLeftView.setOnClickListener(this); 452 | mRightView.setOnClickListener(this); 453 | return this; 454 | } 455 | 456 | /** 457 | * 设置标题的文本 458 | */ 459 | public TitleBar setTitle(int id) { 460 | return setTitle(getResources().getString(id)); 461 | } 462 | 463 | public TitleBar setTitle(CharSequence text) { 464 | mTitleView.setText(text); 465 | return this; 466 | } 467 | 468 | public CharSequence getTitle() { 469 | return mTitleView.getText(); 470 | } 471 | 472 | /** 473 | * 设置左标题的文本 474 | */ 475 | public TitleBar setLeftTitle(int id) { 476 | return setLeftTitle(getResources().getString(id)); 477 | } 478 | 479 | public TitleBar setLeftTitle(CharSequence text) { 480 | mLeftView.setText(text); 481 | return this; 482 | } 483 | 484 | public CharSequence getLeftTitle() { 485 | return mLeftView.getText(); 486 | } 487 | 488 | /** 489 | * 设置右标题的文本 490 | */ 491 | public TitleBar setRightTitle(int id) { 492 | return setRightTitle(getResources().getString(id)); 493 | } 494 | 495 | public TitleBar setRightTitle(CharSequence text) { 496 | mRightView.setText(text); 497 | return this; 498 | } 499 | 500 | public CharSequence getRightTitle() { 501 | return mRightView.getText(); 502 | } 503 | 504 | public TitleBar setTitleStyle(int style) { 505 | return setTitleStyle(TitleBarSupport.getTextTypeface(style), style); 506 | } 507 | 508 | /** 509 | * 设置标题样式 510 | * 511 | * @param typeface 字体样式 512 | * @param style 文字样式 513 | */ 514 | public TitleBar setTitleStyle(Typeface typeface, int style) { 515 | mTitleView.setTypeface(typeface, style); 516 | return this; 517 | } 518 | 519 | public TitleBar setLeftTitleStyle(int style) { 520 | return setLeftTitleStyle(TitleBarSupport.getTextTypeface(style), style); 521 | } 522 | 523 | /** 524 | * 设置左标题样式 525 | * 526 | * @param typeface 字体样式 527 | * @param style 文字样式 528 | */ 529 | public TitleBar setLeftTitleStyle(Typeface typeface, int style) { 530 | mLeftView.setTypeface(typeface, style); 531 | return this; 532 | } 533 | 534 | public TitleBar setRightTitleStyle(int style) { 535 | return setRightTitleStyle(TitleBarSupport.getTextTypeface(style), style); 536 | } 537 | 538 | /** 539 | * 设置右边标题样式 540 | * 541 | * @param typeface 字体样式 542 | * @param style 文字样式 543 | */ 544 | public TitleBar setRightTitleStyle(Typeface typeface, int style) { 545 | mRightView.setTypeface(typeface, style); 546 | return this; 547 | } 548 | 549 | /** 550 | * 设置标题的文本溢出处理方式 551 | */ 552 | public TitleBar setTitleOverflowMode(TextUtils.TruncateAt where) { 553 | TitleBarSupport.setTextViewEllipsize(mTitleView, where); 554 | return this; 555 | } 556 | 557 | /** 558 | * 设置左边标题的文本溢出处理方式 559 | */ 560 | public TitleBar setLeftTitleOverflowMode(TextUtils.TruncateAt where) { 561 | TitleBarSupport.setTextViewEllipsize(mLeftView, where); 562 | return this; 563 | } 564 | 565 | /** 566 | * 设置右边标题的文本溢出处理方式 567 | */ 568 | public TitleBar setRightTitleOverflowMode(TextUtils.TruncateAt where) { 569 | TitleBarSupport.setTextViewEllipsize(mRightView, where); 570 | return this; 571 | } 572 | 573 | /** 574 | * 设置标题的字体颜色 575 | */ 576 | public TitleBar setTitleColor(int color) { 577 | return setTitleColor(ColorStateList.valueOf(color)); 578 | } 579 | 580 | public TitleBar setTitleColor(ColorStateList color) { 581 | if (color != null) { 582 | mTitleView.setTextColor(color); 583 | } 584 | return this; 585 | } 586 | 587 | /** 588 | * 设置左标题的字体颜色 589 | */ 590 | public TitleBar setLeftTitleColor(int color) { 591 | return setLeftTitleColor(ColorStateList.valueOf(color)); 592 | } 593 | 594 | public TitleBar setLeftTitleColor(ColorStateList color) { 595 | if (color != null) { 596 | mLeftView.setTextColor(color); 597 | } 598 | return this; 599 | } 600 | 601 | /** 602 | * 设置右标题的字体颜色 603 | */ 604 | public TitleBar setRightTitleColor(int color) { 605 | return setRightTitleColor(ColorStateList.valueOf(color)); 606 | } 607 | 608 | public TitleBar setRightTitleColor(ColorStateList color) { 609 | if (color != null) { 610 | mRightView.setTextColor(color); 611 | } 612 | return this; 613 | } 614 | 615 | /** 616 | * 设置标题的字体大小 617 | */ 618 | public TitleBar setTitleSize(float size) { 619 | return setTitleSize(TypedValue.COMPLEX_UNIT_SP, size); 620 | } 621 | 622 | public TitleBar setTitleSize(int unit, float size) { 623 | mTitleView.setTextSize(unit, size); 624 | return this; 625 | } 626 | 627 | /** 628 | * 设置左标题的字体大小 629 | */ 630 | public TitleBar setLeftTitleSize(float size) { 631 | return setLeftTitleSize(TypedValue.COMPLEX_UNIT_SP, size); 632 | } 633 | 634 | public TitleBar setLeftTitleSize(int unit, float size) { 635 | mLeftView.setTextSize(unit, size); 636 | return this; 637 | } 638 | 639 | /** 640 | * 设置右标题的字体大小 641 | */ 642 | public TitleBar setRightTitleSize(float size) { 643 | return setRightTitleSize(TypedValue.COMPLEX_UNIT_SP, size); 644 | } 645 | 646 | public TitleBar setRightTitleSize(int unit, float size) { 647 | mRightView.setTextSize(unit, size); 648 | return this; 649 | } 650 | 651 | /** 652 | * 设置标题的图标 653 | */ 654 | public TitleBar setTitleIcon(int id) { 655 | return setTitleIcon(TitleBarSupport.getDrawable(getContext(), id)); 656 | } 657 | 658 | public TitleBar setTitleIcon(Drawable drawable) { 659 | TitleBarSupport.setDrawableTint(drawable, mTitleIconTint); 660 | TitleBarSupport.setDrawableSize(drawable, mTitleIconWidth, mTitleIconHeight); 661 | TitleBarSupport.setTextCompoundDrawable(mTitleView, drawable, mTitleIconGravity); 662 | return this; 663 | } 664 | 665 | public Drawable getTitleIcon() { 666 | return TitleBarSupport.getTextCompoundDrawable(mTitleView, mTitleIconGravity); 667 | } 668 | 669 | /** 670 | * 设置左标题的图标 671 | */ 672 | public TitleBar setLeftIcon(int id) { 673 | return setLeftIcon(TitleBarSupport.getDrawable(getContext(), id)); 674 | } 675 | 676 | public TitleBar setLeftIcon(Drawable drawable) { 677 | TitleBarSupport.setDrawableTint(drawable, mLeftIconTint); 678 | TitleBarSupport.setDrawableSize(drawable, mLeftIconWidth, mLeftIconHeight); 679 | TitleBarSupport.setTextCompoundDrawable(mLeftView, drawable, mLeftIconGravity); 680 | return this; 681 | } 682 | 683 | public Drawable getLeftIcon() { 684 | return TitleBarSupport.getTextCompoundDrawable(mLeftView, mLeftIconGravity); 685 | } 686 | 687 | /** 688 | * 设置右标题的图标 689 | */ 690 | public TitleBar setRightIcon(int id) { 691 | return setRightIcon(TitleBarSupport.getDrawable(getContext(), id)); 692 | } 693 | 694 | public TitleBar setRightIcon(Drawable drawable) { 695 | TitleBarSupport.setDrawableTint(drawable, mRightIconTint); 696 | TitleBarSupport.setDrawableSize(drawable, mRightIconWidth, mRightIconHeight); 697 | TitleBarSupport.setTextCompoundDrawable(mRightView, drawable, mRightIconGravity); 698 | return this; 699 | } 700 | 701 | public Drawable getRightIcon() { 702 | return TitleBarSupport.getTextCompoundDrawable(mRightView, mRightIconGravity); 703 | } 704 | 705 | /** 706 | * 设置标题的图标大小 707 | */ 708 | public TitleBar setTitleIconSize(int width, int height) { 709 | mTitleIconWidth = width; 710 | mTitleIconHeight = height; 711 | TitleBarSupport.setDrawableSize(getTitleIcon(), width, height); 712 | return this; 713 | } 714 | 715 | /** 716 | * 设置左标题的图标大小 717 | */ 718 | public TitleBar setLeftIconSize(int width, int height) { 719 | mLeftIconWidth = width; 720 | mLeftIconHeight = height; 721 | TitleBarSupport.setDrawableSize(getLeftIcon(), width, height); 722 | return this; 723 | } 724 | 725 | /** 726 | * 设置右标题的图标大小 727 | */ 728 | public TitleBar setRightIconSize(int width, int height) { 729 | mRightIconWidth = width; 730 | mRightIconHeight = height; 731 | TitleBarSupport.setDrawableSize(getRightIcon(), width, height); 732 | return this; 733 | } 734 | 735 | /** 736 | * 设置标题的文字和图标间距 737 | */ 738 | public TitleBar setTitleIconPadding(int padding) { 739 | mTitleView.setCompoundDrawablePadding(padding); 740 | return this; 741 | } 742 | 743 | /** 744 | * 设置左标题的文字和图标间距 745 | */ 746 | public TitleBar setLeftIconPadding(int padding) { 747 | mLeftView.setCompoundDrawablePadding(padding); 748 | return this; 749 | } 750 | 751 | /** 752 | * 设置右标题的文字和图标间距 753 | */ 754 | public TitleBar setRightIconPadding(int padding) { 755 | mRightView.setCompoundDrawablePadding(padding); 756 | return this; 757 | } 758 | 759 | /** 760 | * 设置标题的图标着色器 761 | */ 762 | public TitleBar setTitleIconTint(int color) { 763 | mTitleIconTint = color; 764 | TitleBarSupport.setDrawableTint(getTitleIcon(), color); 765 | return this; 766 | } 767 | 768 | /** 769 | * 设置左标题的图标着色器 770 | */ 771 | public TitleBar setLeftIconTint(int color) { 772 | mLeftIconTint = color; 773 | TitleBarSupport.setDrawableTint(getLeftIcon(), color); 774 | return this; 775 | } 776 | 777 | /** 778 | * 设置右标题的图标着色器 779 | */ 780 | public TitleBar setRightIconTint(int color) { 781 | mRightIconTint = color; 782 | TitleBarSupport.setDrawableTint(getRightIcon(), color); 783 | return this; 784 | } 785 | 786 | /** 787 | * 清除标题的图标着色器 788 | */ 789 | public TitleBar clearTitleIconTint() { 790 | mTitleIconTint = TitleBarSupport.NO_COLOR; 791 | TitleBarSupport.clearDrawableTint(getTitleIcon()); 792 | return this; 793 | } 794 | 795 | /** 796 | * 清除左标题的图标着色器 797 | */ 798 | public TitleBar clearLeftIconTint() { 799 | mLeftIconTint = TitleBarSupport.NO_COLOR; 800 | TitleBarSupport.clearDrawableTint(getLeftIcon()); 801 | return this; 802 | } 803 | 804 | /** 805 | * 清除右标题的图标着色器 806 | */ 807 | public TitleBar clearRightIconTint() { 808 | mRightIconTint = TitleBarSupport.NO_COLOR; 809 | TitleBarSupport.clearDrawableTint(getRightIcon()); 810 | return this; 811 | } 812 | 813 | /** 814 | * 设置标题的图标显示重心 815 | */ 816 | public TitleBar setTitleIconGravity(int gravity) { 817 | Drawable drawable = getTitleIcon(); 818 | mTitleIconGravity = gravity; 819 | if (drawable != null) { 820 | TitleBarSupport.setTextCompoundDrawable(mTitleView, drawable, gravity); 821 | } 822 | return this; 823 | } 824 | 825 | /** 826 | * 设置左标题的图标显示重心 827 | */ 828 | public TitleBar setLeftIconGravity(int gravity) { 829 | Drawable drawable = getLeftIcon(); 830 | mLeftIconGravity = gravity; 831 | if (drawable != null) { 832 | TitleBarSupport.setTextCompoundDrawable(mLeftView, drawable, gravity); 833 | } 834 | return this; 835 | } 836 | 837 | /** 838 | * 设置右标题的图标显示重心 839 | */ 840 | public TitleBar setRightIconGravity(int gravity) { 841 | Drawable drawable = getRightIcon(); 842 | mRightIconGravity = gravity; 843 | if (drawable != null) { 844 | TitleBarSupport.setTextCompoundDrawable(mRightView, drawable, gravity); 845 | } 846 | return this; 847 | } 848 | 849 | /** 850 | * 设置左标题的背景状态选择器 851 | */ 852 | public TitleBar setLeftBackground(int id) { 853 | return setLeftBackground(TitleBarSupport.getDrawable(getContext(), id)); 854 | } 855 | 856 | public TitleBar setLeftBackground(Drawable drawable) { 857 | TitleBarSupport.setBackground(mLeftView, drawable); 858 | return this; 859 | } 860 | 861 | /** 862 | * 设置右标题的背景状态选择器 863 | */ 864 | public TitleBar setRightBackground(int id) { 865 | return setRightBackground(TitleBarSupport.getDrawable(getContext(), id)); 866 | } 867 | 868 | public TitleBar setRightBackground(Drawable drawable) { 869 | TitleBarSupport.setBackground(mRightView, drawable); 870 | return this; 871 | } 872 | 873 | /** 874 | * 设置左标题的前景状态选择器 875 | */ 876 | public TitleBar setLeftForeground(int id) { 877 | return setLeftForeground(TitleBarSupport.getDrawable(getContext(), id)); 878 | } 879 | 880 | public TitleBar setLeftForeground(Drawable drawable) { 881 | TitleBarSupport.setForeground(mLeftView, drawable); 882 | return this; 883 | } 884 | 885 | /** 886 | * 设置右标题的前景状态选择器 887 | */ 888 | public TitleBar setRightForeground(int id) { 889 | return setRightForeground(TitleBarSupport.getDrawable(getContext(), id)); 890 | } 891 | 892 | public TitleBar setRightForeground(Drawable drawable) { 893 | TitleBarSupport.setForeground(mRightView, drawable); 894 | return this; 895 | } 896 | 897 | /** 898 | * 设置分割线是否显示 899 | */ 900 | public TitleBar setLineVisible(boolean visible) { 901 | mLineView.setVisibility(visible ? VISIBLE : INVISIBLE); 902 | return this; 903 | } 904 | 905 | /** 906 | * 设置分割线的颜色 907 | */ 908 | public TitleBar setLineColor(int color) { 909 | return setLineDrawable(new ColorDrawable(color)); 910 | } 911 | 912 | public TitleBar setLineDrawable(Drawable drawable) { 913 | TitleBarSupport.setBackground(mLineView, drawable); 914 | return this; 915 | } 916 | 917 | /** 918 | * 设置分割线的大小 919 | */ 920 | public TitleBar setLineSize(int px) { 921 | ViewGroup.LayoutParams layoutParams = mLineView.getLayoutParams(); 922 | layoutParams.height = px; 923 | mLineView.setLayoutParams(layoutParams); 924 | return this; 925 | } 926 | 927 | /** 928 | * 设置标题重心 929 | */ 930 | @SuppressLint("RtlHardcoded") 931 | public TitleBar setTitleGravity(int gravity) { 932 | gravity = TitleBarSupport.getAbsoluteGravity(this, gravity); 933 | 934 | // 如果标题的重心为左,那么左边就不能有内容 935 | if (gravity == Gravity.LEFT && 936 | TitleBarSupport.containContent(TitleBarSupport.isLayoutRtl(getContext()) ? mRightView : mLeftView)) { 937 | Log.e(LOG_TAG, "Title center of gravity for the left, the left title can not have content"); 938 | return this; 939 | } 940 | 941 | // 如果标题的重心为右,那么右边就不能有内容 942 | if (gravity == Gravity.RIGHT && 943 | TitleBarSupport.containContent(TitleBarSupport.isLayoutRtl(getContext()) ? mLeftView : mRightView)) { 944 | Log.e(LOG_TAG, "Title center of gravity for the right, the right title can not have content"); 945 | return this; 946 | } 947 | 948 | LayoutParams params = (LayoutParams) mTitleView.getLayoutParams(); 949 | params.gravity = gravity; 950 | mTitleView.setLayoutParams(params); 951 | return this; 952 | } 953 | 954 | /** 955 | * 设置子 View 内间距 956 | */ 957 | public TitleBar setChildVerticalPadding(int verticalPadding) { 958 | mVerticalPadding = verticalPadding; 959 | mLeftView.setPadding(mLeftHorizontalPadding, mVerticalPadding, mLeftHorizontalPadding, mVerticalPadding); 960 | mTitleView.setPadding(mTitleHorizontalPadding, mVerticalPadding, mTitleHorizontalPadding, mVerticalPadding); 961 | mRightView.setPadding(mRightHorizontalPadding, mVerticalPadding, mRightHorizontalPadding, mVerticalPadding); 962 | return this; 963 | } 964 | 965 | public TitleBar setChildHorizontalPadding(int leftHorizontalPadding, int titleHorizontalPadding, int rightHorizontalPadding) { 966 | mLeftHorizontalPadding = leftHorizontalPadding; 967 | mTitleHorizontalPadding = titleHorizontalPadding; 968 | mRightHorizontalPadding = rightHorizontalPadding; 969 | mLeftView.setPadding(mLeftHorizontalPadding, mVerticalPadding, mLeftHorizontalPadding, mVerticalPadding); 970 | mTitleView.setPadding(mTitleHorizontalPadding, mVerticalPadding, mTitleHorizontalPadding, mVerticalPadding); 971 | mRightView.setPadding(mRightHorizontalPadding, mVerticalPadding, mRightHorizontalPadding, mVerticalPadding); 972 | return this; 973 | } 974 | 975 | /** 976 | * 获取左标题View对象 977 | */ 978 | public TextView getLeftView() { 979 | return mLeftView; 980 | } 981 | 982 | /** 983 | * 获取标题View对象 984 | */ 985 | public TextView getTitleView() { 986 | return mTitleView; 987 | } 988 | 989 | /** 990 | * 获取右标题View对象 991 | */ 992 | public TextView getRightView() { 993 | return mRightView; 994 | } 995 | 996 | /** 997 | * 获取分割线View对象 998 | */ 999 | public View getLineView() { 1000 | return mLineView; 1001 | } 1002 | 1003 | /** 1004 | * 获取当前的初始化器 1005 | */ 1006 | public ITitleBarStyle getCurrentStyle() { 1007 | return mCurrentStyle; 1008 | } 1009 | 1010 | /** 1011 | * 设置默认初始化器 1012 | */ 1013 | public static void setDefaultStyle(ITitleBarStyle style) { 1014 | sGlobalStyle = style; 1015 | } 1016 | } -------------------------------------------------------------------------------- /library/src/main/java/com/hjq/bar/TitleBarSupport.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar; 2 | 3 | import android.content.Context; 4 | import android.graphics.BlendMode; 5 | import android.graphics.BlendModeColorFilter; 6 | import android.graphics.Color; 7 | import android.graphics.PorterDuff; 8 | import android.graphics.Typeface; 9 | import android.graphics.drawable.Drawable; 10 | import android.os.Build; 11 | import android.text.TextUtils; 12 | import android.view.Gravity; 13 | import android.view.View; 14 | import android.widget.TextView; 15 | 16 | /** 17 | * author : Android 轮子哥 18 | * github : https://github.com/getActivity/TitleBar 19 | * time : 2021/08/21 20 | * desc : 标题栏支持类 21 | */ 22 | public final class TitleBarSupport { 23 | 24 | /** 无色值 */ 25 | static final int NO_COLOR = Color.TRANSPARENT; 26 | 27 | public static final int ELLIPSIZE_NONE = 0; 28 | public static final int ELLIPSIZE_START = 1; 29 | public static final int ELLIPSIZE_MIDDLE = 2; 30 | public static final int ELLIPSIZE_END = 3; 31 | public static final int ELLIPSIZE_MARQUEE = 4; 32 | 33 | /** 34 | * 获取图片资源 35 | */ 36 | public static Drawable getDrawable(Context context, int id) { 37 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 38 | return context.getResources().getDrawable(id, context.getTheme()); 39 | } else { 40 | return context.getResources().getDrawable(id); 41 | } 42 | } 43 | 44 | /** 45 | * 设置 View 背景 46 | */ 47 | public static void setBackground(View view, Drawable drawable) { 48 | view.setBackground(drawable); 49 | } 50 | 51 | /** 52 | * 设置 View 前景 53 | */ 54 | public static void setForeground(View view, Drawable drawable) { 55 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 56 | view.setForeground(drawable); 57 | } 58 | } 59 | 60 | /** 61 | * 获取绝对重心 62 | */ 63 | public static int getAbsoluteGravity(View view, int gravity) { 64 | // 适配布局反方向 65 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { 66 | return gravity; 67 | } 68 | return Gravity.getAbsoluteGravity(gravity, view.getResources().getConfiguration().getLayoutDirection()); 69 | } 70 | 71 | /** 72 | * 是否启用了布局反方向特性 73 | */ 74 | public static boolean isLayoutRtl(Context context) { 75 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { 76 | return false; 77 | } 78 | 79 | return context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; 80 | } 81 | 82 | /** 83 | * TextView 是否存在内容 84 | */ 85 | public static boolean containContent(TextView textView) { 86 | CharSequence text = textView.getText(); 87 | if (!TextUtils.isEmpty(text)) { 88 | return true; 89 | } 90 | Drawable[] drawables = textView.getCompoundDrawables(); 91 | for (Drawable drawable : drawables) { 92 | if (drawable != null) { 93 | return true; 94 | } 95 | } 96 | return false; 97 | } 98 | 99 | /** 100 | * 给图片设置着色器 101 | */ 102 | public static void setDrawableTint(Drawable drawable, int color) { 103 | if (drawable == null) { 104 | return; 105 | } 106 | if (color == NO_COLOR) { 107 | return; 108 | } 109 | drawable.mutate(); 110 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { 111 | drawable.setColorFilter(new BlendModeColorFilter(color, BlendMode.SRC_IN)); 112 | } else { 113 | drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); 114 | } 115 | } 116 | 117 | /** 118 | * 清除图片设置着色器 119 | */ 120 | public static void clearDrawableTint(Drawable drawable) { 121 | if (drawable == null) { 122 | return; 123 | } 124 | drawable.mutate(); 125 | drawable.clearColorFilter(); 126 | } 127 | 128 | /** 129 | * 根据给定的大小限制 Drawable 宽高 130 | */ 131 | public static void setDrawableSize(Drawable drawable, int width, int height) { 132 | if (drawable == null ) { 133 | return; 134 | } 135 | 136 | if (width <= 0 && height <= 0) { 137 | drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); 138 | return; 139 | } 140 | 141 | if (width > 0 && height > 0) { 142 | drawable.setBounds(0, 0, width, height); 143 | return; 144 | } 145 | 146 | int drawableWidth = drawable.getIntrinsicWidth(); 147 | int drawableHeight = drawable.getIntrinsicHeight(); 148 | if (drawableWidth <= 0) { 149 | drawableWidth = width; 150 | } 151 | if (drawableHeight <= 0) { 152 | drawableHeight = height; 153 | } 154 | 155 | // 将 Drawable 等比缩放 156 | if (width > 0) { 157 | drawable.setBounds(0, 0, width, width * drawableHeight / drawableWidth); 158 | } else { 159 | drawable.setBounds(0, 0, drawableWidth * height / drawableHeight, height); 160 | } 161 | } 162 | 163 | /** 164 | * 根据图片重心获取在 TextView 的 Drawable 对象 165 | */ 166 | public static Drawable getTextCompoundDrawable(TextView textView, int gravity) { 167 | Drawable[] drawables = textView.getCompoundDrawables(); 168 | switch (getAbsoluteGravity(textView, gravity)) { 169 | case Gravity.LEFT: 170 | return drawables[0]; 171 | case Gravity.TOP: 172 | return drawables[1]; 173 | case Gravity.RIGHT: 174 | return drawables[2]; 175 | case Gravity.BOTTOM: 176 | return drawables[3]; 177 | default: 178 | return null; 179 | } 180 | } 181 | 182 | /** 183 | * 根据图标重心设置 TextView 某个位置的 Drawable 184 | */ 185 | public static void setTextCompoundDrawable(TextView textView, Drawable drawable, int gravity) { 186 | switch (getAbsoluteGravity(textView, gravity)) { 187 | case Gravity.LEFT: 188 | textView.setCompoundDrawables(drawable, null, null, null); 189 | break; 190 | case Gravity.TOP: 191 | textView.setCompoundDrawables(null, drawable, null, null); 192 | break; 193 | case Gravity.RIGHT: 194 | textView.setCompoundDrawables(null, null, drawable, null); 195 | break; 196 | case Gravity.BOTTOM: 197 | textView.setCompoundDrawables(null, null, null, drawable); 198 | break; 199 | default: 200 | textView.setCompoundDrawables(null, null, null, null); 201 | break; 202 | } 203 | } 204 | 205 | /** 206 | * 根据文字样式返回不同的字体样式 207 | */ 208 | public static Typeface getTextTypeface(int style) { 209 | switch (style) { 210 | case Typeface.BOLD: 211 | return Typeface.DEFAULT_BOLD; 212 | case Typeface.ITALIC: 213 | case Typeface.BOLD_ITALIC: 214 | return Typeface.MONOSPACE; 215 | case Typeface.NORMAL: 216 | default: 217 | return Typeface.DEFAULT; 218 | } 219 | } 220 | 221 | /** 222 | * int 转 TruncateAt 枚举 223 | */ 224 | public static TextUtils.TruncateAt convertIntToTruncateAtEnum(int ellipsize) { 225 | switch (ellipsize) { 226 | case ELLIPSIZE_START: 227 | return TextUtils.TruncateAt.START; 228 | case ELLIPSIZE_MIDDLE: 229 | return TextUtils.TruncateAt.MIDDLE; 230 | case ELLIPSIZE_END: 231 | return TextUtils.TruncateAt.END; 232 | case ELLIPSIZE_MARQUEE: 233 | return TextUtils.TruncateAt.MARQUEE; 234 | default: 235 | return null; 236 | } 237 | } 238 | 239 | /** 240 | * 设置 TextView 文本溢出处理方式 241 | */ 242 | public static void setTextViewEllipsize(TextView textView, TextUtils.TruncateAt where) { 243 | if (textView.getEllipsize() == where) { 244 | return; 245 | } 246 | textView.setEllipsize(where); 247 | if (where != TextUtils.TruncateAt.MARQUEE) { 248 | return; 249 | } 250 | if (!textView.isSelected()) { 251 | // 设置跑马灯之后需要设置选中才能有效果 252 | textView.setSelected(true); 253 | } 254 | if (!textView.isFocusable()) { 255 | // 设置跑马灯需要先获取焦点 256 | textView.setFocusable(true); 257 | } 258 | // 设置跑马灯的循环次数 259 | textView.setMarqueeRepeatLimit(-1); 260 | } 261 | } -------------------------------------------------------------------------------- /library/src/main/java/com/hjq/bar/style/CommonBarStyle.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar.style; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.pm.PackageInfo; 6 | import android.content.pm.PackageManager; 7 | import android.graphics.Typeface; 8 | import android.graphics.drawable.Drawable; 9 | import android.text.TextUtils; 10 | import android.util.TypedValue; 11 | import android.view.Gravity; 12 | import android.view.View; 13 | import android.widget.TextView; 14 | 15 | import com.hjq.bar.ITitleBarStyle; 16 | import com.hjq.bar.TitleBarSupport; 17 | 18 | /** 19 | * author : Android 轮子哥 20 | * github : https://github.com/getActivity/TitleBar 21 | * time : 2020/09/19 22 | * desc : 默认初始化器基类 23 | */ 24 | public abstract class CommonBarStyle implements ITitleBarStyle { 25 | 26 | @Override 27 | public TextView createTitleView(Context context) { 28 | TextView titleView = newTitleView(context); 29 | titleView.setGravity(Gravity.CENTER_VERTICAL); 30 | titleView.setFocusable(true); 31 | titleView.setSingleLine(); 32 | return titleView; 33 | } 34 | 35 | public TextView newTitleView(Context context) { 36 | return new TextView(context); 37 | } 38 | 39 | @Override 40 | public TextView createLeftView(Context context) { 41 | TextView leftView = newLeftView(context); 42 | leftView.setGravity(Gravity.CENTER_VERTICAL); 43 | leftView.setFocusable(true); 44 | leftView.setSingleLine(); 45 | return leftView; 46 | } 47 | 48 | public TextView newLeftView(Context context) { 49 | return new TextView(context); 50 | } 51 | 52 | @Override 53 | public TextView createRightView(Context context) { 54 | TextView rightView = newRightView(context); 55 | rightView.setGravity(Gravity.CENTER_VERTICAL); 56 | rightView.setFocusable(true); 57 | rightView.setSingleLine(); 58 | return rightView; 59 | } 60 | 61 | public TextView newRightView(Context context) { 62 | return new TextView(context); 63 | } 64 | 65 | @Override 66 | public View createLineView(Context context) { 67 | return new View(context); 68 | } 69 | 70 | @Override 71 | public Drawable getLeftTitleForeground(Context context) { 72 | return null; 73 | } 74 | 75 | @Override 76 | public Drawable getRightTitleForeground(Context context) { 77 | return null; 78 | } 79 | 80 | @Override 81 | public int getLeftHorizontalPadding(Context context) { 82 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics()); 83 | } 84 | 85 | @Override 86 | public int getTitleHorizontalPadding(Context context) { 87 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0, context.getResources().getDisplayMetrics()); 88 | } 89 | 90 | @Override 91 | public int getRightHorizontalPadding(Context context) { 92 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics()); 93 | } 94 | 95 | @Override 96 | public int getChildVerticalPadding(Context context) { 97 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, context.getResources().getDisplayMetrics()); 98 | } 99 | 100 | @Override 101 | public CharSequence getTitle(Context context) { 102 | // 如果当前上下文对象是 Activity,就获取 Activity 的 label 属性作为标题栏的标题 103 | if (!(context instanceof Activity)) { 104 | return ""; 105 | } 106 | 107 | // 获取清单文件中的 android:label 属性值 108 | CharSequence label = ((Activity) context).getTitle(); 109 | if (TextUtils.isEmpty(label)) { 110 | return ""; 111 | } 112 | 113 | try { 114 | PackageManager packageManager = context.getPackageManager(); 115 | PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); 116 | // 如果当前 Activity 没有设置 android:label 属性,则默认会返回 App 名称,则需要过滤掉 117 | if (!label.toString().equals(packageInfo.applicationInfo.loadLabel(packageManager).toString())) { 118 | // 设置标题 119 | return label; 120 | } 121 | } catch (PackageManager.NameNotFoundException ignored) {} 122 | 123 | return ""; 124 | } 125 | 126 | @Override 127 | public CharSequence getLeftTitle(Context context) { 128 | return ""; 129 | } 130 | 131 | @Override 132 | public CharSequence getRightTitle(Context context) { 133 | return ""; 134 | } 135 | 136 | @Override 137 | public float getTitleSize(Context context) { 138 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, context.getResources().getDisplayMetrics()); 139 | } 140 | 141 | @Override 142 | public float getLeftTitleSize(Context context) { 143 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics()); 144 | } 145 | 146 | @Override 147 | public float getRightTitleSize(Context context) { 148 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics()); 149 | } 150 | 151 | @Override 152 | public Typeface getTitleTypeface(Context context, int style) { 153 | return TitleBarSupport.getTextTypeface(style); 154 | } 155 | 156 | @Override 157 | public Typeface getLeftTitleTypeface(Context context, int style) { 158 | return TitleBarSupport.getTextTypeface(style); 159 | } 160 | 161 | @Override 162 | public Typeface getRightTitleTypeface(Context context, int style) { 163 | return TitleBarSupport.getTextTypeface(style); 164 | } 165 | 166 | @Override 167 | public int getTitleStyle(Context context) { 168 | return Typeface.NORMAL; 169 | } 170 | 171 | @Override 172 | public int getLeftTitleStyle(Context context) { 173 | return Typeface.NORMAL; 174 | } 175 | 176 | @Override 177 | public int getRightTitleStyle(Context context) { 178 | return Typeface.NORMAL; 179 | } 180 | 181 | @Override 182 | public int getTitleIconGravity(Context context) { 183 | return Gravity.END; 184 | } 185 | 186 | @Override 187 | public int getLeftIconGravity(Context context) { 188 | return Gravity.START; 189 | } 190 | 191 | @Override 192 | public int getRightIconGravity(Context context) { 193 | return Gravity.END; 194 | } 195 | 196 | @Override 197 | public int getTitleIconPadding(Context context) { 198 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics()); 199 | } 200 | 201 | @Override 202 | public int getLeftIconPadding(Context context) { 203 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics()); 204 | } 205 | 206 | @Override 207 | public int getRightIconPadding(Context context) { 208 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics()); 209 | } 210 | 211 | @Override 212 | public int getTitleIconWidth(Context context) { 213 | return 0; 214 | } 215 | 216 | @Override 217 | public int getLeftIconWidth(Context context) { 218 | return 0; 219 | } 220 | 221 | @Override 222 | public int getRightIconWidth(Context context) { 223 | return 0; 224 | } 225 | 226 | @Override 227 | public int getTitleIconHeight(Context context) { 228 | return 0; 229 | } 230 | 231 | @Override 232 | public int getLeftIconHeight(Context context) { 233 | return 0; 234 | } 235 | 236 | @Override 237 | public int getRightIconHeight(Context context) { 238 | return 0; 239 | } 240 | 241 | @Override 242 | public TextUtils.TruncateAt getTitleOverflowMode(Context context) { 243 | return TextUtils.TruncateAt.MARQUEE; 244 | } 245 | 246 | @Override 247 | public TextUtils.TruncateAt getLeftTitleOverflowMode(Context context) { 248 | return null; 249 | } 250 | 251 | @Override 252 | public TextUtils.TruncateAt getRightTitleOverflowMode(Context context) { 253 | return null; 254 | } 255 | 256 | @Override 257 | public boolean isLineVisible(Context context) { 258 | return true; 259 | } 260 | 261 | @Override 262 | public int getLineSize(Context context) { 263 | return 1; 264 | } 265 | } -------------------------------------------------------------------------------- /library/src/main/java/com/hjq/bar/style/LightBarStyle.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar.style; 2 | 3 | import android.content.Context; 4 | import android.content.res.ColorStateList; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | 8 | import com.hjq.bar.R; 9 | import com.hjq.bar.SelectorDrawable; 10 | import com.hjq.bar.TitleBarSupport; 11 | 12 | /** 13 | * author : Android 轮子哥 14 | * github : https://github.com/getActivity/TitleBar 15 | * time : 2020/09/19 16 | * desc : 日间主题样式实现(对应布局属性:app:barStyle="light") 17 | */ 18 | public class LightBarStyle extends CommonBarStyle { 19 | 20 | @Override 21 | public Drawable getTitleBarBackground(Context context) { 22 | return new ColorDrawable(0xFFFFFFFF); 23 | } 24 | 25 | @Override 26 | public Drawable getLeftTitleBackground(Context context) { 27 | return new SelectorDrawable.Builder() 28 | .setDefault(new ColorDrawable(0x00000000)) 29 | .setFocused(new ColorDrawable(0x0C000000)) 30 | .setPressed(new ColorDrawable(0x0C000000)) 31 | .build(); 32 | } 33 | 34 | @Override 35 | public Drawable getRightTitleBackground(Context context) { 36 | return new SelectorDrawable.Builder() 37 | .setDefault(new ColorDrawable(0x00000000)) 38 | .setFocused(new ColorDrawable(0x0C000000)) 39 | .setPressed(new ColorDrawable(0x0C000000)) 40 | .build(); 41 | } 42 | 43 | @Override 44 | public Drawable getBackButtonDrawable(Context context) { 45 | return TitleBarSupport.getDrawable(context, R.drawable.bar_arrows_left_black); 46 | } 47 | 48 | @Override 49 | public ColorStateList getTitleColor(Context context) { 50 | return ColorStateList.valueOf(0xFF222222); 51 | } 52 | 53 | @Override 54 | public ColorStateList getLeftTitleColor(Context context) { 55 | return ColorStateList.valueOf(0xFF666666); 56 | } 57 | 58 | @Override 59 | public ColorStateList getRightTitleColor(Context context) { 60 | return ColorStateList.valueOf(0xFFA4A4A4); 61 | } 62 | 63 | @Override 64 | public Drawable getLineDrawable(Context context) { 65 | return new ColorDrawable(0xFFECECEC); 66 | } 67 | } -------------------------------------------------------------------------------- /library/src/main/java/com/hjq/bar/style/NightBarStyle.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar.style; 2 | 3 | import android.content.Context; 4 | import android.content.res.ColorStateList; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | 8 | import com.hjq.bar.R; 9 | import com.hjq.bar.SelectorDrawable; 10 | import com.hjq.bar.TitleBarSupport; 11 | 12 | /** 13 | * author : Android 轮子哥 14 | * github : https://github.com/getActivity/TitleBar 15 | * time : 2020/09/19 16 | * desc : 夜间主题样式实现(对应布局属性:app:barStyle="night") 17 | */ 18 | public class NightBarStyle extends CommonBarStyle { 19 | 20 | @Override 21 | public Drawable getBackButtonDrawable(Context context) { 22 | return TitleBarSupport.getDrawable(context, R.drawable.bar_arrows_left_white); 23 | } 24 | 25 | @Override 26 | public Drawable getLeftTitleBackground(Context context) { 27 | return new SelectorDrawable.Builder() 28 | .setDefault(new ColorDrawable(0x00000000)) 29 | .setFocused(new ColorDrawable(0x66FFFFFF)) 30 | .setPressed(new ColorDrawable(0x66FFFFFF)) 31 | .build(); 32 | } 33 | 34 | @Override 35 | public Drawable getRightTitleBackground(Context context) { 36 | return new SelectorDrawable.Builder() 37 | .setDefault(new ColorDrawable(0x00000000)) 38 | .setFocused(new ColorDrawable(0x66FFFFFF)) 39 | .setPressed(new ColorDrawable(0x66FFFFFF)) 40 | .build(); 41 | } 42 | 43 | @Override 44 | public Drawable getTitleBarBackground(Context context) { 45 | return new ColorDrawable(0xFF000000); 46 | } 47 | 48 | @Override 49 | public ColorStateList getTitleColor(Context context) { 50 | return ColorStateList.valueOf(0xEEFFFFFF); 51 | } 52 | 53 | @Override 54 | public ColorStateList getLeftTitleColor(Context context) { 55 | return ColorStateList.valueOf(0xCCFFFFFF); 56 | } 57 | 58 | @Override 59 | public ColorStateList getRightTitleColor(Context context) { 60 | return ColorStateList.valueOf(0xCCFFFFFF); 61 | } 62 | 63 | @Override 64 | public Drawable getLineDrawable(Context context) { 65 | return new ColorDrawable(0xFFFFFFFF); 66 | } 67 | } -------------------------------------------------------------------------------- /library/src/main/java/com/hjq/bar/style/TransparentBarStyle.java: -------------------------------------------------------------------------------- 1 | package com.hjq.bar.style; 2 | 3 | import android.content.Context; 4 | import android.content.res.ColorStateList; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | 8 | import com.hjq.bar.R; 9 | import com.hjq.bar.SelectorDrawable; 10 | import com.hjq.bar.TitleBarSupport; 11 | 12 | /** 13 | * author : Android 轮子哥 14 | * github : https://github.com/getActivity/TitleBar 15 | * time : 2020/09/19 16 | * desc : 透明主题样式实现(对应布局属性:app:barStyle="transparent") 17 | */ 18 | public class TransparentBarStyle extends CommonBarStyle { 19 | 20 | @Override 21 | public Drawable getBackButtonDrawable(Context context) { 22 | return TitleBarSupport.getDrawable(context, R.drawable.bar_arrows_left_white); 23 | } 24 | 25 | @Override 26 | public Drawable getLeftTitleBackground(Context context) { 27 | return new SelectorDrawable.Builder() 28 | .setDefault(new ColorDrawable(0x00000000)) 29 | .setFocused(new ColorDrawable(0x22000000)) 30 | .setPressed(new ColorDrawable(0x22000000)) 31 | .build(); 32 | } 33 | 34 | @Override 35 | public Drawable getRightTitleBackground(Context context) { 36 | return new SelectorDrawable.Builder() 37 | .setDefault(new ColorDrawable(0x00000000)) 38 | .setFocused(new ColorDrawable(0x22000000)) 39 | .setPressed(new ColorDrawable(0x22000000)) 40 | .build(); 41 | } 42 | 43 | @Override 44 | public Drawable getTitleBarBackground(Context context) { 45 | return new ColorDrawable(0x00000000); 46 | } 47 | 48 | @Override 49 | public ColorStateList getTitleColor(Context context) { 50 | return ColorStateList.valueOf(0xFFFFFFFF); 51 | } 52 | 53 | @Override 54 | public ColorStateList getLeftTitleColor(Context context) { 55 | return ColorStateList.valueOf(0xFFFFFFFF); 56 | } 57 | 58 | @Override 59 | public ColorStateList getRightTitleColor(Context context) { 60 | return ColorStateList.valueOf(0xFFFFFFFF); 61 | } 62 | 63 | @Override 64 | public Drawable getLineDrawable(Context context) { 65 | return new ColorDrawable(0x00000000); 66 | } 67 | } -------------------------------------------------------------------------------- /library/src/main/res/drawable/bar_arrows_left_black.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/bar_arrows_left_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/bar_drawable_placeholder.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /library/src/main/res/values-v21/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /library/src/main/res/values/string.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | "" 4 | -------------------------------------------------------------------------------- /library/src/main/res/values/style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | 20 | 22 | 23 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/logo.png -------------------------------------------------------------------------------- /picture/demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/picture/demo.jpg -------------------------------------------------------------------------------- /picture/demo_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/picture/demo_code.png -------------------------------------------------------------------------------- /picture/dynamic_figure.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getActivity/TitleBar/fcb4cf2d07db757c966ddd399d73d659c4142ba9/picture/dynamic_figure.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':library' 2 | --------------------------------------------------------------------------------