diff --git a/.github/ISSUE_TEMPLATE/issue_template_bug.md b/.github/ISSUE_TEMPLATE/issue_template_bug.md index e925a0f..feeca7b 100644 --- a/.github/ISSUE_TEMPLATE/issue_template_bug.md +++ b/.github/ISSUE_TEMPLATE/issue_template_bug.md @@ -16,7 +16,9 @@ assignees: getActivity * 是否必现:填是/否 -* 手机信息:例如某米 9 / Android 10 +* 出现问题的手机信息:请填写出现问题的品牌和机型 + +* 出现问题的安卓版本:请填写出现问题的 Android 版本 ## 请回答 @@ -34,7 +36,7 @@ assignees: getActivity ## 其他 -* 提供报错堆栈(如果有报错的话必填) +* 提供报错堆栈(如果有报错的话必填,注意不要拿被混淆过的代码堆栈上来) * 提供截图或视频(根据需要提供,此项不强制) diff --git a/HelpDoc.md b/HelpDoc.md index 920d13b..8328983 100644 --- a/HelpDoc.md +++ b/HelpDoc.md @@ -1,4 +1,6 @@ -#### 常见疑问解答 +## 常见疑问解答 + +#### 框架入侵性太大怎么办? * 框架上线有很多人说框架的侵入性很强?这点我必须承认,我也有看到网上也有用 `LayoutInflater.Factory` 来实现,这样入侵性很低,但是有一个致命的缺点,无法在布局中预览,这样你是不是突然就感觉不香了?入侵强当然有缺点也有优点,我不能光看它坏的一面,那样看待问题就太片面了,不过它的缺点并不是致命的,就好比你使用了一个自定义 View 叫 `XxxTextView`,这种情况下你肯定就没办法再使用 **ShapeTextView** 了,那么这种情况我们该这么办?解决方式大致分为两种: @@ -8,7 +10,17 @@ * 另外有一个需要注意的点,如果你自己单独使用 **GradientDrawable** 还是 **ShapeDrawable** 在 Java 代码动态设置的话,如果涉及到虚线或者阴影的话,经过验证在有些手机上面是无法生效的,必须要先关闭硬件加速才能生效,当然 **ShapeDrawable** 有对外开放 **intoBackground** 方法,这个方法会帮你判断是否需要关闭硬件加速。 -* 另外还有人要框架做裁剪子 View 的功能?在此我表示拒绝,因为我对框架定位很明确,只是为了帮助大家少写 xml,你现在让我加一个裁剪的功能进去,这样合适吗?不,这样不合适,我个人建议裁剪子 View 可以考虑使用 Google 支持库提供的 **CardView** 来实现,有必要时可以搭配 **ShapeDrawable** 来食用。 +* 现在目前关于 Shape 的框架都无法十全十美,看个人怎么抉择了,无关好与坏,在享受框架优点的同时,也要学会忍受框架的缺点。 + +#### 能否加入 Layout 裁剪子 View 功能? + +* 在此我表示拒绝,因为我对框架定位很明确,只是为了帮助大家少写 xml,你现在让我加一个裁剪的功能进去,这样合适吗?不,这样不合适,我个人建议裁剪子 View 可以考虑使用 Google 支持库提供的 **CardView** 来实现,有必要时可以搭配 **ShapeDrawable** 来使用。 + +#### 能否加入 ImageView 圆角裁剪功能? + +* 对于 ImageView 的 src 圆角裁剪,第一个这个属性属于 View 的内容,而框架是针对设置 View 的背景,第二个就算要做裁剪,框架的 Shape 圆角属性是设置给 View 的背景 Drawable 对象,这个时候来了 ImageView 的 src,这两个要怎么区分开?(圆角到底要应用于背景还是 src?如果背景的圆角大,而 src 圆角小 这种情况怎么做?)有人可能会说了,多加几个属性不就 OK 了?可以是可以,但是框架会复杂化,可能会导致用的人大多区分不开,并且我觉得没有太大必要,圆角的功能统一交给 Glide 来实现就可以了,框架再做一次就功能重复了。 + +#### 最后分享一下我的观点 * 最后我来跟大家分享一下我的观点,我认为做好一个框架并不意味着什么功能都要做,并不是我实现不了,而是有没有必要那么做,如果那样做到最后框架很可能会变成一个杂货铺,连作者都会分不清楚这个框架到底是干嘛的,比如我做[标题栏框架](https://github.com/getActivity/TitleBar)的时候,有很多人让我做沉浸式状态栏的功能,我全部给拒绝了,并建议他们单独集成沉浸式框架来实现,首先我要声明一点,我做的是标题栏框架,沉浸式状态栏是沉浸式框架应该有的功能,我要是破格做了沉浸式状态栏的功能,后面就会有人找我做沉浸式底部导航栏的功能,再后面就会有让我做一个状态栏字体变色的功能..............,如果这些我都做到了,那么请问你是否还会使用这样的框架,将标题栏和沉浸式相互捆绑的框架?到底应该叫标题栏框架还是沉浸式框架?后面如果有人说我只想用标题栏的功能不想用沉浸式的功能该怎么办? diff --git a/README.md b/README.md index 42b1ccb..9aea93f 100644 --- a/README.md +++ b/README.md @@ -8,24 +8,33 @@ ![](picture/demo_code.png) +![](picture/dynamic_figure.jpg) + #### 集成步骤 -* 在项目根目录下的 `build.gradle` 文件中加入 +* 如果你的项目 Gradle 配置是在 `7.0 以下`,需要在 `build.gradle` 文件中加入 ```groovy -buildscript { +allprojects { repositories { + // JitPack 远程仓库:https://jitpack.io maven { url 'https://jitpack.io' } } } -allprojects { +``` + +* 如果你的 Gradle 配置是 `7.0 及以上`,则需要在 `settings.gradle` 文件中加入 + +```groovy +dependencyResolutionManagement { repositories { + // JitPack 远程仓库:https://jitpack.io maven { url 'https://jitpack.io' } } } ``` -* 在项目 app 模块下的 `build.gradle` 文件中加入 +* 配置完远程仓库后,在项目 app 模块下的 `build.gradle` 文件中加入远程依赖 ```groovy android { @@ -38,7 +47,7 @@ android { dependencies { // Shape 框架:https://github.com/getActivity/ShapeView - implementation 'com.github.getActivity:ShapeView:6.2' + implementation 'com.github.getActivity:ShapeView:8.0' } ``` @@ -46,7 +55,7 @@ dependencies { * 如果项目是基于 **AndroidX** 包,请在项目 `gradle.properties` 文件中加入 -```groovy +```text # 表示将第三方库迁移到 AndroidX android.enableJetifier = true ``` @@ -101,17 +110,17 @@ shapeButton.setOnClickListener(new View.OnClickListener() { - + - + - + - + - + - + @@ -130,6 +139,14 @@ shapeButton.setOnClickListener(new View.OnClickListener() { + + + + + + + + @@ -151,17 +168,17 @@ shapeButton.setOnClickListener(new View.OnClickListener() { - + - + - + - + - + - + @@ -172,11 +189,11 @@ shapeButton.setOnClickListener(new View.OnClickListener() { - + - + @@ -189,17 +206,17 @@ shapeButton.setOnClickListener(new View.OnClickListener() { - + - + - + - + - + - + @@ -215,6 +232,11 @@ shapeButton.setOnClickListener(new View.OnClickListener() { + + + + + @@ -235,7 +257,7 @@ shapeButton.setOnClickListener(new View.OnClickListener() { * View 的子类:ShapeView、ShapeTextView、ShapeButton、ShapeImageView、ShapeRadioButton、ShapeCheckBox、ShapeEditText - * ViewGroup 的子类:ShapeLinearLayout、ShapeFrameLayout、ShapeRelativeLayout、ShapeConstraintLayout、ShapeRecyclerView + * ViewGroup 的子类:ShapeLinearLayout、ShapeFrameLayout、ShapeRelativeLayout、ShapeConstraintLayout、ShapeRecyclerView、ShapeRadioGroup #### [常见疑问解答](HelpDoc.md) @@ -243,9 +265,11 @@ shapeButton.setOnClickListener(new View.OnClickListener() { #### 框架亮点 +* 功能强大:支持设置阴影、边框渐变色、文本渐变色 + * 更加便捷:无需新增 Xml 文件,直接定义控件属性即可 -* 即时生效:在布局中可实时预览效果,即见所得 +* 即时生效:在布局中可实时预览效果,即见所得,无需运行 * 无学习成本:控件属性和原生 Shape 命名保持一致,无需额外学习 @@ -253,33 +277,45 @@ shapeButton.setOnClickListener(new View.OnClickListener() { * 支持状态选择器:不仅支持设置背景色的状态选择器,还支持设置文本颜色的状态选择器 -* 功能覆盖全面:不仅支持设置背景阴影色,还支持设置文本渐变色 - #### 作者的其他开源项目 -* 安卓技术中台:[AndroidProject](https://github.com/getActivity/AndroidProject) +* 安卓技术中台:[AndroidProject](https://github.com/getActivity/AndroidProject) ![](https://img.shields.io/github/stars/getActivity/AndroidProject.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidProject.svg) + +* 安卓技术中台 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) + +* 权限框架:[XXPermissions](https://github.com/getActivity/XXPermissions) ![](https://img.shields.io/github/stars/getActivity/XXPermissions.svg) ![](https://img.shields.io/github/forks/getActivity/XXPermissions.svg) + +* 吐司框架:[ToastUtils](https://github.com/getActivity/ToastUtils) ![](https://img.shields.io/github/stars/getActivity/ToastUtils.svg) ![](https://img.shields.io/github/forks/getActivity/ToastUtils.svg) + +* 网络框架:[EasyHttp](https://github.com/getActivity/EasyHttp) ![](https://img.shields.io/github/stars/getActivity/EasyHttp.svg) ![](https://img.shields.io/github/forks/getActivity/EasyHttp.svg) + +* 标题栏框架:[TitleBar](https://github.com/getActivity/TitleBar) ![](https://img.shields.io/github/stars/getActivity/TitleBar.svg) ![](https://img.shields.io/github/forks/getActivity/TitleBar.svg) + +* 悬浮窗框架:[XToast](https://github.com/getActivity/XToast) ![](https://img.shields.io/github/stars/getActivity/XToast.svg) ![](https://img.shields.io/github/forks/getActivity/XToast.svg) + +* 语种切换框架:[MultiLanguages](https://github.com/getActivity/MultiLanguages) ![](https://img.shields.io/github/stars/getActivity/MultiLanguages.svg) ![](https://img.shields.io/github/forks/getActivity/MultiLanguages.svg) -* 权限框架:[XXPermissions](https://github.com/getActivity/XXPermissions) +* 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) -* 吐司框架:[ToastUtils](https://github.com/getActivity/ToastUtils) +* 日志查看框架:[Logcat](https://github.com/getActivity/Logcat) ![](https://img.shields.io/github/stars/getActivity/Logcat.svg) ![](https://img.shields.io/github/forks/getActivity/Logcat.svg) -* 网络框架:[EasyHttp](https://github.com/getActivity/EasyHttp) +* 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) -* 标题栏框架:[TitleBar](https://github.com/getActivity/TitleBar) +* 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) -* 国际化框架:[MultiLanguages](https://github.com/getActivity/MultiLanguages) +* 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) -* 悬浮窗框架:[XToast](https://github.com/getActivity/XToast) +* 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) -* Gson 解析容错:[GsonFactory](https://github.com/getActivity/GsonFactory) +* 表情包大集合:[EmojiPackage](https://github.com/getActivity/EmojiPackage) ![](https://img.shields.io/github/stars/getActivity/EmojiPackage.svg) ![](https://img.shields.io/github/forks/getActivity/EmojiPackage.svg) -* 日志查看框架:[Logcat](https://github.com/getActivity/Logcat) +* 省市区 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) #### 微信公众号:Android轮子哥 ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/official_ccount.png) -#### Android 技术分享 QQ 群:78797078 +#### Android 技术 Q 群:10047167 #### 如果您觉得我的开源库帮你节省了大量的开发时间,请扫描下方的二维码随意打赏,要是能打赏个 10.24 :monkey_face:就太:thumbsup:了。您的支持将鼓励我继续创作:octocat: diff --git a/UseDemo.md b/UseDemo.md index a6d1ab5..0b9758b 100644 --- a/UseDemo.md +++ b/UseDemo.md @@ -18,22 +18,6 @@ app:shape_solidColor="#5A8DDF" app:shape_solidPressedColor="#AA5A8DDF" /> - - + + + + +``` + +![](picture/shape_gradient.jpg) + +```xml + + + + + ``` ![](picture/shape_shadow_background.jpg) @@ -116,7 +189,7 @@ android:textSize="14sp" app:shape="rectangle" app:shape_radius="10dp" - app:shape_shadowColor="#5A8DDF" + app:shape_shadowColor="#AA5A8DDF" app:shape_shadowSize="10dp" app:shape_solidColor="#FFFFFF" /> @@ -128,7 +201,7 @@ android:gravity="center" android:paddingTop="30dp" android:paddingBottom="30dp" - android:text="阴影偏移效果" + android:text="阴影偏移效果(右下)" android:textColor="@android:color/black" android:textSize="14sp" app:shape="rectangle" @@ -138,6 +211,82 @@ app:shape_shadowOffsetY="5dp" app:shape_shadowSize="10dp" app:shape_solidColor="#FFFFFF" /> + + + + + + + + ``` ![](picture/shape_select_text_gradient.jpg) @@ -150,7 +299,7 @@ android:gravity="center" android:padding="10dp" android:text="文本水平渐变效果" - android:textSize="14sp" + android:textSize="18sp" app:shape_textEndColor="#ED58FF" app:shape_textGradientOrientation="horizontal" app:shape_textStartColor="#49DAFA" /> @@ -162,10 +311,24 @@ android:gravity="center" android:padding="10dp" android:text="文本垂直渐变效果" - android:textSize="14sp" + android:textSize="18sp" app:shape_textEndColor="#ED58FF" app:shape_textGradientOrientation="vertical" app:shape_textStartColor="#49DAFA" /> + + ``` ![](picture/shape_select_compound_button.jpg) diff --git a/app/build.gradle b/app/build.gradle index 48ef0f7..13581f8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { minSdkVersion 16 // noinspection ExpiredTargetSdkVersion targetSdkVersion 28 - versionCode 62 - versionName "6.2" + versionCode 80 + versionName "8.0" } // 支持 Java JDK 8 @@ -51,15 +51,17 @@ android { } dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') + // 依赖 libs 目录下所有的 jar 和 aar 包 + implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs') + implementation project(':library') implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:design:28.0.0' // 标题栏框架:https://github.com/getActivity/TitleBar - implementation 'com.github.getActivity:TitleBar:9.2' + implementation 'com.github.getActivity:TitleBar:9.3' // 内存泄漏检测:https://github.com/square/leakcanary - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ef3d63a..f66455c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,4 +21,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/hjq/shape/demo/MainActivity.java b/app/src/main/java/com/hjq/shape/demo/MainActivity.java index c51314b..f074fa1 100644 --- a/app/src/main/java/com/hjq/shape/demo/MainActivity.java +++ b/app/src/main/java/com/hjq/shape/demo/MainActivity.java @@ -1,9 +1,13 @@ package com.hjq.shape.demo; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; +import com.hjq.bar.OnTitleBarListener; +import com.hjq.bar.TitleBar; import com.hjq.shape.view.ShapeButton; public class MainActivity extends AppCompatActivity { @@ -13,6 +17,16 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + TitleBar titleBar = findViewById(R.id.tb_main_bar); + titleBar.setOnTitleBarListener(new OnTitleBarListener() { + @Override + public void onTitleClick(TitleBar titleBar) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(titleBar.getTitle().toString())); + startActivity(intent); + } + }); + ShapeButton shapeButton = findViewById(R.id.btn_main_test); shapeButton.setOnClickListener(new View.OnClickListener() { @Override diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 80d8e1c..b5563a3 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -9,6 +9,7 @@ tools:context=".MainActivity"> - - + + + + + + + + + + + + + + + + + + @@ -224,11 +365,25 @@ android:gravity="center" android:padding="10dp" android:text="文本垂直渐变效果" - android:textSize="14sp" + android:textSize="18sp" app:shape_textEndColor="#ED58FF" app:shape_textGradientOrientation="vertical" app:shape_textStartColor="#49DAFA" /> + + @@ -6,7 +7,8 @@ @color/colorPrimary @color/colorPrimaryDark @color/colorAccent - @color/colorPrimary + @android:color/white + true false diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a185b86..8442046 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,4 @@ + ShapeView \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index f46b18a..f43ca09 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,3 +1,4 @@ + diff --git a/library/build.gradle b/library/build.gradle index 23f20bb..4de1869 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -5,8 +5,8 @@ android { defaultConfig { minSdkVersion 16 - versionCode 62 - versionName "6.2" + versionCode 80 + versionName "8.0" } // 支持 Java JDK 8 diff --git a/library/src/main/java/com/hjq/shape/builder/ShapeDrawableBuilder.java b/library/src/main/java/com/hjq/shape/builder/ShapeDrawableBuilder.java index cad8bd5..0fef416 100644 --- a/library/src/main/java/com/hjq/shape/builder/ShapeDrawableBuilder.java +++ b/library/src/main/java/com/hjq/shape/builder/ShapeDrawableBuilder.java @@ -3,13 +3,14 @@ import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Drawable; -import android.graphics.drawable.StateListDrawable; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; import com.hjq.shape.drawable.ShapeDrawable; import com.hjq.shape.drawable.ShapeGradientType; import com.hjq.shape.drawable.ShapeType; +import com.hjq.shape.drawable.ExtendStateListDrawable; import com.hjq.shape.styleable.IShapeDrawableStyleable; /** @@ -40,7 +41,8 @@ public final class ShapeDrawableBuilder { private float mBottomLeftRadius; private float mBottomRightRadius; - private int[] mGradientColors; + private int[] mSolidGradientColors; + private int[] mStrokeGradientColors; private boolean mUseLevel; private int mAngle; private int mGradientType; @@ -98,14 +100,25 @@ public ShapeDrawableBuilder(View view, TypedArray typedArray, IShapeDrawableStyl mBottomLeftRadius = typedArray.getDimensionPixelSize(styleable.getBottomLeftRadiusStyleable(), radius); mBottomRightRadius = typedArray.getDimensionPixelSize(styleable.getBottomRightRadiusStyleable(), radius); - if (typedArray.hasValue(styleable.getStartColorStyleable()) && typedArray.hasValue(styleable.getEndColorStyleable())) { - if (typedArray.hasValue(styleable.getCenterColorStyleable())) { - mGradientColors = new int[] {typedArray.getColor(styleable.getStartColorStyleable(), NO_COLOR), - typedArray.getColor(styleable.getCenterColorStyleable(), NO_COLOR), - typedArray.getColor(styleable.getEndColorStyleable(), NO_COLOR)}; + if (typedArray.hasValue(styleable.getSolidStartColorStyleable()) && typedArray.hasValue(styleable.getSolidEndColorStyleable())) { + if (typedArray.hasValue(styleable.getSolidCenterColorStyleable())) { + mSolidGradientColors = new int[] {typedArray.getColor(styleable.getSolidStartColorStyleable(), NO_COLOR), + typedArray.getColor(styleable.getSolidCenterColorStyleable(), NO_COLOR), + typedArray.getColor(styleable.getSolidEndColorStyleable(), NO_COLOR)}; } else { - mGradientColors = new int[] {typedArray.getColor(styleable.getStartColorStyleable(), NO_COLOR), - typedArray.getColor(styleable.getEndColorStyleable(), NO_COLOR)}; + mSolidGradientColors = new int[] {typedArray.getColor(styleable.getSolidStartColorStyleable(), NO_COLOR), + typedArray.getColor(styleable.getSolidEndColorStyleable(), NO_COLOR)}; + } + } + + if (typedArray.hasValue(styleable.getStrokeStartColorStyleable()) && typedArray.hasValue(styleable.getStrokeEndColorStyleable())) { + if (typedArray.hasValue(styleable.getStrokeCenterColorStyleable())) { + mStrokeGradientColors = new int[] {typedArray.getColor(styleable.getStrokeStartColorStyleable(), NO_COLOR), + typedArray.getColor(styleable.getStrokeCenterColorStyleable(), NO_COLOR), + typedArray.getColor(styleable.getStrokeEndColorStyleable(), NO_COLOR)}; + } else { + mStrokeGradientColors = new int[] {typedArray.getColor(styleable.getStrokeStartColorStyleable(), NO_COLOR), + typedArray.getColor(styleable.getStrokeEndColorStyleable(), NO_COLOR)}; } } @@ -177,7 +190,7 @@ public int getShapeHeight() { public ShapeDrawableBuilder setSolidColor(int color) { mSolidColor = color; - clearGradientColors(); + clearSolidGradientColors(); return this; } @@ -247,47 +260,94 @@ public ShapeDrawableBuilder setRadius(float topLeftRadius, float topRightRadius, return this; } + public ShapeDrawableBuilder setTopLeftRadius(float radius) { + mTopLeftRadius = radius; + return this; + } + public float getTopLeftRadius() { return mTopLeftRadius; } + public ShapeDrawableBuilder setTopRightRadius(float radius) { + mTopRightRadius = radius; + return this; + } + public float getTopRightRadius() { return mTopRightRadius; } + public ShapeDrawableBuilder setBottomLeftRadius(float radius) { + mBottomLeftRadius = radius; + return this; + } + public float getBottomLeftRadius() { return mBottomLeftRadius; } + public ShapeDrawableBuilder setBottomRightRadius(float radius) { + mBottomRightRadius = radius; + return this; + } + public float getBottomRightRadius() { return mBottomRightRadius; } - public ShapeDrawableBuilder setGradientColors(int startColor, int endColor) { - return setGradientColors(new int[]{startColor, endColor}); + public ShapeDrawableBuilder setSolidGradientColors(int startColor, int endColor) { + return setSolidGradientColors(new int[]{startColor, endColor}); + } + + public ShapeDrawableBuilder setSolidGradientColors(int startColor, int centerColor, int endColor) { + return setSolidGradientColors(new int[]{startColor, centerColor, endColor}); + } + + public ShapeDrawableBuilder setSolidGradientColors(int[] colors) { + mSolidGradientColors = colors; + return this; + } + + @Nullable + public int[] getSolidGradientColors() { + return mSolidGradientColors; + } + + public boolean isSolidGradientColors() { + return mSolidGradientColors != null && + mSolidGradientColors.length > 0; + } + + public void clearSolidGradientColors() { + mSolidGradientColors = null; + } + + public ShapeDrawableBuilder setStrokeGradientColors(int startColor, int endColor) { + return setStrokeGradientColors(new int[]{startColor, endColor}); } - public ShapeDrawableBuilder setGradientColors(int startColor, int centerColor, int endColor) { - return setGradientColors(new int[]{startColor, centerColor, endColor}); + public ShapeDrawableBuilder setStrokeGradientColors(int startColor, int centerColor, int endColor) { + return setStrokeGradientColors(new int[]{startColor, centerColor, endColor}); } - public ShapeDrawableBuilder setGradientColors(int[] colors) { - mGradientColors = colors; + public ShapeDrawableBuilder setStrokeGradientColors(int[] colors) { + mStrokeGradientColors = colors; return this; } @Nullable - public int[] getGradientColors() { - return mGradientColors; + public int[] getStrokeGradientColors() { + return mStrokeGradientColors; } - public boolean isGradientColors() { - return mGradientColors != null && - mGradientColors.length > 0; + public boolean isStrokeGradientColors() { + return mStrokeGradientColors != null && + mStrokeGradientColors.length > 0; } - public void clearGradientColors() { - mGradientColors = null; + public void clearStrokeGradientColors() { + mStrokeGradientColors = null; } public ShapeDrawableBuilder setUseLevel(boolean useLevel) { @@ -346,6 +406,7 @@ public int getGradientRadius() { public ShapeDrawableBuilder setStrokeColor(int color) { mStrokeColor = color; + clearStrokeGradientColors(); return this; } @@ -511,65 +572,77 @@ public int getShadowOffsetY() { } public Drawable buildBackgroundDrawable() { - if (!isGradientColors() && mSolidColor == NO_COLOR && mStrokeColor == NO_COLOR) { + boolean hasSolidColorState = mSolidPressedColor != null || mSolidCheckedColor != null || + mSolidDisabledColor != null || mSolidFocusedColor != null || mSolidSelectedColor != null; + + boolean hasStrokeColorState = mStrokePressedColor != null || mStrokeCheckedColor != null || + mStrokeDisabledColor != null || mStrokeFocusedColor != null || mStrokeSelectedColor != null; + + if (!isSolidGradientColors() && !isStrokeGradientColors() && + mSolidColor == NO_COLOR && !hasSolidColorState && mStrokeColor == NO_COLOR && !hasStrokeColorState) { + // 啥都没有设置,直接 return return null; } - ShapeDrawable defaultDrawable = createShapeDrawable(mSolidColor, mStrokeColor); - // 判断是否设置了渐变色 - if (isGradientColors()) { - defaultDrawable.setGradientColors(mGradientColors); + ShapeDrawable defaultDrawable; + + Drawable viewBackground = mView.getBackground(); + if (viewBackground instanceof ExtendStateListDrawable) { + defaultDrawable = convertShapeDrawable(((ExtendStateListDrawable) viewBackground).getDefaultDrawable()); + } else { + defaultDrawable = convertShapeDrawable(viewBackground); } - if (mSolidPressedColor != null && mStrokePressedColor != null && - mSolidCheckedColor != null && mStrokeCheckedColor != null && - mSolidDisabledColor != null && mStrokeDisabledColor != null && - mSolidFocusedColor != null && mStrokeFocusedColor != null && - mSolidSelectedColor != null && mStrokeSelectedColor != null) { + refreshShapeDrawable(defaultDrawable, null, null); + + if (!hasSolidColorState && !hasStrokeColorState) { return defaultDrawable; } - StateListDrawable drawable = new StateListDrawable(); + ExtendStateListDrawable stateListDrawable = new ExtendStateListDrawable(); if (mSolidPressedColor != null || mStrokePressedColor != null) { - drawable.addState(new int[]{android.R.attr.state_pressed}, createShapeDrawable( - mSolidPressedColor != null ? mSolidPressedColor : mSolidColor, - mStrokePressedColor != null ? mStrokePressedColor : mStrokeColor)); + ShapeDrawable drawable = convertShapeDrawable(stateListDrawable.getPressedDrawable()); + refreshShapeDrawable(drawable, mSolidPressedColor, mStrokePressedColor); + stateListDrawable.setPressedDrawable(drawable); } + if (mSolidCheckedColor != null || mStrokeCheckedColor != null) { - drawable.addState(new int[]{android.R.attr.state_checked}, createShapeDrawable( - mSolidCheckedColor != null ? mSolidCheckedColor : mSolidColor, - mStrokeCheckedColor != null ? mStrokeCheckedColor : mStrokeColor)); + ShapeDrawable drawable = convertShapeDrawable(stateListDrawable.getCheckDrawable()); + refreshShapeDrawable(drawable, mSolidCheckedColor, mStrokeCheckedColor); + stateListDrawable.setCheckDrawable(drawable); } + if (mSolidDisabledColor != null || mStrokeDisabledColor != null) { - drawable.addState(new int[]{-android.R.attr.state_enabled}, createShapeDrawable( - mSolidDisabledColor != null ? mSolidDisabledColor : mSolidColor, - mStrokeDisabledColor != null ? mStrokeDisabledColor : mStrokeColor)); + ShapeDrawable drawable = convertShapeDrawable(stateListDrawable.getDisabledDrawable()); + refreshShapeDrawable(drawable, mSolidDisabledColor, mStrokeDisabledColor); + stateListDrawable.setDisabledDrawable(drawable); } + if (mSolidFocusedColor != null || mStrokeFocusedColor != null) { - drawable.addState(new int[]{android.R.attr.state_focused}, createShapeDrawable( - mSolidFocusedColor != null ? mSolidFocusedColor : mSolidColor, - mStrokeFocusedColor != null ? mStrokeFocusedColor : mStrokeColor)); + ShapeDrawable drawable = convertShapeDrawable(stateListDrawable.getFocusedDrawable()); + refreshShapeDrawable(drawable, mSolidFocusedColor, mStrokeFocusedColor); + stateListDrawable.setFocusedDrawable(drawable); } + if (mSolidSelectedColor != null || mStrokeSelectedColor != null) { - drawable.addState(new int[]{android.R.attr.state_selected}, createShapeDrawable( - mSolidSelectedColor != null ? mSolidSelectedColor : mSolidColor, - mStrokeSelectedColor != null ? mStrokeSelectedColor : mStrokeColor)); + ShapeDrawable drawable = convertShapeDrawable(stateListDrawable.getSelectDrawable()); + refreshShapeDrawable(drawable, mSolidSelectedColor, mStrokeSelectedColor); + stateListDrawable.setSelectDrawable(drawable); } - drawable.addState(new int[]{}, defaultDrawable); - return drawable; + stateListDrawable.setDefaultDrawable(defaultDrawable); + return stateListDrawable; } - public ShapeDrawable createShapeDrawable(int solidColor, int strokeColor) { - - ShapeDrawable drawable = new ShapeDrawable(); - + public void refreshShapeDrawable(ShapeDrawable drawable, + @Nullable Integer solidStateColor, + @Nullable Integer strokeStateColor) { drawable.setShape(mShape) .setSize(mShapeWidth, mShapeHeight) .setRadius(mTopLeftRadius, mTopRightRadius, mBottomLeftRadius, mBottomRightRadius) - .setSolidColor(solidColor) .setUseLevel(mUseLevel) - .setStroke(mStrokeWidth, strokeColor, mDashWidth, mDashGap); + .setStrokeWidth(mStrokeWidth) + .setStrokeDash(mDashWidth, mDashGap); drawable.setGradientAngle(mAngle) .setGradientType(mGradientType) @@ -586,7 +659,31 @@ public ShapeDrawable createShapeDrawable(int solidColor, int strokeColor) { .setShadowOffsetX(mShadowOffsetX) .setShadowOffsetY(mShadowOffsetY); - return drawable; + // 填充色设置 + if (solidStateColor != null) { + drawable.setSolidColor(solidStateColor); + } else if (isSolidGradientColors()){ + drawable.setSolidColor(mSolidGradientColors); + } else { + drawable.setSolidColor(mSolidColor); + } + + // 边框色设置 + if (strokeStateColor != null) { + drawable.setStrokeColor(strokeStateColor); + } else if (isStrokeGradientColors()) { + drawable.setStrokeColor(mStrokeGradientColors); + } else { + drawable.setStrokeColor(mStrokeColor); + } + } + + @NonNull + public ShapeDrawable convertShapeDrawable(Drawable drawable) { + if (drawable instanceof ShapeDrawable) { + return (ShapeDrawable) drawable; + } + return new ShapeDrawable(); } public void intoBackground() { diff --git a/library/src/main/java/com/hjq/shape/builder/TextColorBuilder.java b/library/src/main/java/com/hjq/shape/builder/TextColorBuilder.java index e094de8..ae87101 100644 --- a/library/src/main/java/com/hjq/shape/builder/TextColorBuilder.java +++ b/library/src/main/java/com/hjq/shape/builder/TextColorBuilder.java @@ -2,11 +2,15 @@ import android.content.res.ColorStateList; import android.content.res.TypedArray; +import android.graphics.Color; import android.support.annotation.Nullable; import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.widget.TextView; -import com.hjq.shape.other.LinearGradientFontSpan; +import com.hjq.shape.span.LinearGradientFontSpan; +import com.hjq.shape.span.MultiFontSpan; +import com.hjq.shape.span.StrokeFontSpan; import com.hjq.shape.styleable.ITextColorStyleable; /** @@ -29,6 +33,9 @@ public final class TextColorBuilder { private int[] mTextGradientColors; private int mTextGradientOrientation; + private int mTextStrokeColor; + private int mTextStrokeSize; + public TextColorBuilder(TextView textView, TypedArray typedArray, ITextColorStyleable styleable) { mTextView = textView; mTextColor = typedArray.getColor(styleable.getTextColorStyleable(), textView.getTextColors().getDefaultColor()); @@ -61,6 +68,14 @@ public TextColorBuilder(TextView textView, TypedArray typedArray, ITextColorStyl mTextGradientOrientation = typedArray.getColor(styleable.getTextGradientOrientationStyleable(), LinearGradientFontSpan.GRADIENT_ORIENTATION_HORIZONTAL); + + if (typedArray.hasValue(styleable.getTextStrokeColorStyleable())) { + mTextStrokeColor = typedArray.getColor(styleable.getTextStrokeColorStyleable(), 0); + } + + if (typedArray.hasValue(styleable.getTextStrokeSizeStyleable())) { + mTextStrokeSize = typedArray.getDimensionPixelSize(styleable.getTextStrokeSizeStyleable(), 0); + } } public TextColorBuilder setTextColor(int color) { @@ -158,8 +173,60 @@ public int getTextGradientOrientation() { return mTextGradientOrientation; } - public SpannableStringBuilder buildLinearGradientSpannable(CharSequence text) { - return LinearGradientFontSpan.buildLinearGradientSpannable(text, mTextGradientColors, null, mTextGradientOrientation); + public TextColorBuilder setTextStrokeColor(int color) { + mTextStrokeColor = color; + return this; + } + + public TextColorBuilder setTextStrokeSize(int size) { + mTextStrokeSize = size; + return this; + } + + public int getTextStrokeColor() { + return mTextStrokeColor; + } + + public int getTextStrokeSize() { + return mTextStrokeSize; + } + + public boolean isTextStrokeColor() { + return mTextStrokeColor != Color.TRANSPARENT && mTextStrokeSize > 0; + } + + public void clearTextStrokeColor() { + mTextStrokeColor = Color.TRANSPARENT; + mTextStrokeSize = 0; + } + + public SpannableStringBuilder buildTextSpannable(CharSequence text) { + SpannableStringBuilder builder = new SpannableStringBuilder(text); + + LinearGradientFontSpan linearGradientFontSpan = null; + StrokeFontSpan strokeFontSpan = null; + + if (isTextGradientColors()) { + linearGradientFontSpan = new LinearGradientFontSpan() + .setTextGradientColor(mTextGradientColors) + .setTextGradientOrientation(mTextGradientOrientation) + .setTextGradientPositions(null); + } + if (isTextStrokeColor()) { + strokeFontSpan = new StrokeFontSpan() + .setTextStrokeColor(mTextStrokeColor) + .setTextStrokeSize(mTextStrokeSize); + } + + if (linearGradientFontSpan != null && strokeFontSpan != null) { + MultiFontSpan multiFontSpan = new MultiFontSpan(strokeFontSpan, linearGradientFontSpan); + builder.setSpan(multiFontSpan, 0, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else if (linearGradientFontSpan != null) { + builder.setSpan(linearGradientFontSpan, 0, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else if (strokeFontSpan != null) { + builder.setSpan(strokeFontSpan, 0, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + return builder; } public ColorStateList buildColorState() { @@ -222,8 +289,8 @@ public ColorStateList buildColorState() { } public void intoTextColor() { - if (isTextGradientColors()) { - mTextView.setText(buildLinearGradientSpannable(mTextView.getText())); + if (isTextGradientColors() || isTextStrokeColor()) { + mTextView.setText(buildTextSpannable(mTextView.getText())); return; } mTextView.setTextColor(buildColorState()); diff --git a/library/src/main/java/com/hjq/shape/drawable/ExtendStateListDrawable.java b/library/src/main/java/com/hjq/shape/drawable/ExtendStateListDrawable.java new file mode 100644 index 0000000..f085c90 --- /dev/null +++ b/library/src/main/java/com/hjq/shape/drawable/ExtendStateListDrawable.java @@ -0,0 +1,81 @@ +package com.hjq.shape.drawable; + +import android.graphics.drawable.Drawable; +import android.graphics.drawable.StateListDrawable; + +import java.util.HashMap; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ShapeView + * time : 2022/04/23 + * desc : 基于 StateListDrawable 类进行扩展 + */ +public class ExtendStateListDrawable extends StateListDrawable { + + private static final int[] STATE_DEFAULT = new int[]{}; + private static final int[] STATE_PRESSED = new int[]{android.R.attr.state_pressed}; + private static final int[] STATE_CHECKED = new int[]{android.R.attr.state_checked}; + private static final int[] STATE_DISABLED = new int[]{-android.R.attr.state_enabled}; + private static final int[] STATE_FOCUSED = new int[]{android.R.attr.state_focused}; + private static final int[] STATE_SELECTED = new int[]{android.R.attr.state_selected}; + + private final HashMap mDrawableMap = new HashMap<>(); + + @Override + public void addState(int[] stateSet, Drawable drawable) { + super.addState(stateSet, drawable); + if (drawable == null) { + return; + } + mDrawableMap.put(stateSet, drawable); + } + + public void setDefaultDrawable(Drawable drawable) { + addState(STATE_DEFAULT, drawable); + } + + public Drawable getDefaultDrawable() { + return mDrawableMap.get(STATE_DEFAULT); + } + + public void setPressedDrawable(Drawable drawable) { + addState(STATE_PRESSED, drawable); + } + + public Drawable getPressedDrawable() { + return mDrawableMap.get(STATE_PRESSED); + } + + public void setCheckDrawable(Drawable drawable) { + addState(STATE_CHECKED, drawable); + } + + public Drawable getCheckDrawable() { + return mDrawableMap.get(STATE_CHECKED); + } + + public void setDisabledDrawable(Drawable drawable) { + addState(STATE_DISABLED, drawable); + } + + public Drawable getDisabledDrawable() { + return mDrawableMap.get(STATE_DISABLED); + } + + public void setFocusedDrawable(Drawable drawable) { + addState(STATE_FOCUSED, drawable); + } + + public Drawable getFocusedDrawable() { + return mDrawableMap.get(STATE_FOCUSED); + } + + public void setSelectDrawable(Drawable drawable) { + addState(STATE_SELECTED, drawable); + } + + public Drawable getSelectDrawable() { + return mDrawableMap.get(STATE_SELECTED); + } +} \ No newline at end of file diff --git a/library/src/main/java/com/hjq/shape/drawable/ShapeDrawable.java b/library/src/main/java/com/hjq/shape/drawable/ShapeDrawable.java index d92cca5..389d425 100644 --- a/library/src/main/java/com/hjq/shape/drawable/ShapeDrawable.java +++ b/library/src/main/java/com/hjq/shape/drawable/ShapeDrawable.java @@ -16,6 +16,7 @@ import android.graphics.SweepGradient; import android.graphics.drawable.Drawable; import android.os.Build; +import android.support.annotation.NonNull; import android.support.v4.graphics.ColorUtils; import android.view.View; @@ -31,7 +32,7 @@ public class ShapeDrawable extends Drawable { private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Rect mPadding; - private Paint mStrokePaint; // optional, set by the caller + private final Paint mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); // optional, set by the caller private Paint mShadowPaint; private ColorFilter mColorFilter; // optional, set by the caller private int mAlpha = 0xFF; // modified by the caller @@ -40,6 +41,9 @@ public class ShapeDrawable extends Drawable { private final Path mPath = new Path(); private final RectF mRect = new RectF(); + private final RectF mShadowRect = new RectF(); + private final Path mShadowPath = new Path(); + private Paint mLayerPaint; // internal, used if we use saveLayer() private boolean mRectIsDirty; // internal state private boolean mMutated; @@ -55,6 +59,8 @@ public ShapeDrawable(ShapeState state) { initializeWithState(state); mRectIsDirty = true; mMutated = false; + + mStrokePaint.setStyle(Paint.Style.STROKE); } /** @@ -65,17 +71,18 @@ public ShapeState getShapeState() { } @Override - public boolean getPadding(Rect padding) { + public boolean getPadding(@NonNull Rect padding) { if (mPadding != null) { padding.set(mPadding); return true; - } else { - return super.getPadding(padding); } + return super.getPadding(padding); } public ShapeDrawable setPadding(Rect padding) { mPadding = padding; + mPathIsDirty = true; + invalidateSelf(); return this; } @@ -86,8 +93,8 @@ public ShapeDrawable setPadding(Rect padding) { */ public ShapeDrawable setShape(int shape) { mRingPath = null; - mPathIsDirty = true; mShapeState.setShape(shape); + mPathIsDirty = true; invalidateSelf(); return this; } @@ -134,9 +141,24 @@ public ShapeDrawable setRadius(float topLeftRadius, float topRightRadius, float /** * 设置填充颜色 */ - public ShapeDrawable setSolidColor(int color) { - mShapeState.setSolidColor(color); - mFillPaint.setColor(color); + + public ShapeDrawable setSolidColor(int startColor, int endColor) { + return setSolidColor(new int[] {startColor, endColor}); + } + + public ShapeDrawable setSolidColor(int startColor, int centerColor, int endColor) { + return setSolidColor(new int[] {startColor, centerColor, endColor}); + } + + public ShapeDrawable setSolidColor(int... colors) { + mShapeState.setSolidColor(colors); + if (colors == null) { + mFillPaint.setColor(0); + } else if (colors.length == 1) { + mFillPaint.setColor(colors[0]); + mFillPaint.clearShadowLayer(); + } + mRectIsDirty = true; invalidateSelf(); return this; } @@ -144,59 +166,45 @@ public ShapeDrawable setSolidColor(int color) { /** * 设置边框颜色 */ - public ShapeDrawable setStrokeColor(int color) { - setStroke(color, mShapeState.mStrokeWidth, mShapeState.mStrokeDashWidth, mShapeState.mStrokeDashGap); - return this; - } - /** - * 设置边框宽度 - */ - public ShapeDrawable setStrokeWidth(int width) { - setStroke(mShapeState.mStrokeColor, width, mShapeState.mStrokeDashWidth, mShapeState.mStrokeDashGap); - return this; + public ShapeDrawable setStrokeColor(int startColor, int endColor) { + return setStrokeColor(new int[] {startColor, endColor}); } - /** - * 设置边框虚线宽度(为 0 就是实线,大于 0 就是虚线) - */ - public ShapeDrawable setDashWidth(float dashWidth) { - setStroke(mShapeState.mStrokeColor, mShapeState.mStrokeWidth, dashWidth, mShapeState.mStrokeDashGap); - return this; + public ShapeDrawable setStrokeColor(int startColor, int centerColor, int endColor) { + return setStrokeColor(new int[] {startColor, centerColor, endColor}); } - /** - * 设置虚线间隔(虚线与虚线之间的间隔) - */ - public ShapeDrawable setDashGap(float dashGap) { - setStroke(mShapeState.mStrokeColor, mShapeState.mStrokeWidth, mShapeState.mStrokeDashWidth, dashGap); + public ShapeDrawable setStrokeColor(int... colors) { + mShapeState.setStrokeColor(colors); + if (colors == null) { + mStrokePaint.setColor(0); + } else if (colors.length == 1) { + mStrokePaint.setColor(colors[0]); + mStrokePaint.clearShadowLayer(); + } + mRectIsDirty = true; + invalidateSelf(); return this; } /** - * 初始化边框属性 + * 设置边框宽度 */ - public ShapeDrawable setStroke(int width, int color, float dashWidth, float dashGap) { - mShapeState.setStroke(width, color, dashWidth, dashGap); - - if (mStrokePaint == null) { - mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mStrokePaint.setStyle(Paint.Style.STROKE); - } + public ShapeDrawable setStrokeWidth(int width) { + mShapeState.setStrokeWidth(width); mStrokePaint.setStrokeWidth(width); - mStrokePaint.setColor(color); - - mStrokePaint.setPathEffect(dashWidth > 0 ? new DashPathEffect(new float[] {dashWidth, dashGap}, 0) : null); + mRectIsDirty = true; invalidateSelf(); return this; } /** - * 设置渐变颜色 + * 设置边框虚线宽度及间隔(为 0 就是实线,大于 0 就是虚线) */ - public ShapeDrawable setGradientColors(int[] colors) { - mShapeState.setGradientColor(colors); - mRectIsDirty = true; + public ShapeDrawable setStrokeDash(float dashWidth, float dashGap) { + mShapeState.setStrokeDash(dashWidth, dashGap); + mStrokePaint.setPathEffect(dashWidth > 0 ? new DashPathEffect(new float[] {dashWidth, dashGap}, 0) : null); invalidateSelf(); return this; } @@ -393,7 +401,7 @@ public void intoBackground(View view) { @SuppressLint("WrongConstant") @Override - public void draw(Canvas canvas) { + public void draw(@NonNull Canvas canvas) { if (!ensureValidRect()) { // nothing to draw return; @@ -402,18 +410,17 @@ public void draw(Canvas canvas) { // remember the alpha values, in case we temporarily overwrite them // when we modulate them with mAlpha final int prevFillAlpha = mFillPaint.getAlpha(); - final int prevStrokeAlpha = mStrokePaint != null ? mStrokePaint.getAlpha() : 0; + final int prevStrokeAlpha = mStrokePaint.getAlpha(); // compute the modulate alpha values final int currFillAlpha = modulateAlpha(prevFillAlpha); final int currStrokeAlpha = modulateAlpha(prevStrokeAlpha); - final boolean haveStroke = currStrokeAlpha > 0 && mStrokePaint != null && - mStrokePaint.getStrokeWidth() > 0; final boolean haveShadow = mShapeState.mShadowSize > 0; + final boolean haveStroke = currStrokeAlpha > 0 && mStrokePaint.getStrokeWidth() > 0; final boolean haveFill = currFillAlpha > 0; final ShapeState st = mShapeState; /* we need a layer iff we're drawing both a fill and stroke, and the - stroke is non-opaque, and our shapetype actually supports + stroke is non-opaque, and our shape type actually supports fill+stroke. Otherwise we can just draw the stroke (if any) on top of the fill (if any) without worrying about blending artifacts. */ @@ -421,7 +428,7 @@ of the fill (if any) without worrying about blending artifacts. currStrokeAlpha < 255 && (mAlpha < 255 || mColorFilter != null); /* Drawing with a layer is slower than direct drawing, but it - allows us to apply paint effects like alpha and colorfilter to + allows us to apply paint effects like alpha and color filter to the result of multiple separate draws. In our case, if the user asks for a non-opaque alpha value (via setAlpha), and we're stroking, then we need to apply the alpha AFTER we've drawn @@ -487,8 +494,21 @@ of the fill (if any) without worrying about blending artifacts. shadowColor = ColorUtils.setAlphaComponent(mShapeState.mShadowColor, 254); } - mShadowPaint.setShadowLayer(mShapeState.mShadowSize, mShapeState.mShadowOffsetX, - mShapeState.mShadowOffsetY, shadowColor); + float shadowOffsetX = 0; + if (mShapeState.mShadowOffsetX > 0) { + shadowOffsetX = mShapeState.mShadowOffsetX; + } + + float shadowOffsetY = 0; + if (mShapeState.mShadowOffsetY > 0) { + shadowOffsetY = mShapeState.mShadowOffsetY; + } + + mShadowPaint.setShadowLayer(mShapeState.mShadowSize, shadowOffsetX, shadowOffsetY, shadowColor); + + // 这种方式也可以实现阴影效果 + // mShadowPaint.setColor(shadowColor); + // mShadowPaint.setMaskFilter(new BlurMaskFilter(mShapeState.mShadowSize, BlurMaskFilter.Blur.NORMAL)); } else { if (mShadowPaint != null) { @@ -505,7 +525,9 @@ of the fill (if any) without worrying about blending artifacts. mPathIsDirty = mRectIsDirty = false; } if (haveShadow) { - canvas.drawPath(mPath, mShadowPaint); + mShadowPath.reset(); + mShadowPath.addRoundRect(mShadowRect, st.mRadiusArray, Path.Direction.CW); + canvas.drawPath(mShadowPath, mShadowPaint); } canvas.drawPath(mPath, mFillPaint); if (haveStroke) { @@ -523,7 +545,7 @@ of the fill (if any) without worrying about blending artifacts. rad = r; } if (haveShadow) { - canvas.drawRoundRect(mRect, rad, rad, mShadowPaint); + canvas.drawRoundRect(mShadowRect, rad, rad, mShadowPaint); } canvas.drawRoundRect(mRect, rad, rad, mFillPaint); if (haveStroke) { @@ -531,7 +553,7 @@ of the fill (if any) without worrying about blending artifacts. } } else { if (haveShadow) { - canvas.drawRect(mRect, mShadowPaint); + canvas.drawRect(mShadowRect, mShadowPaint); } if (mFillPaint.getColor() != 0 || mColorFilter != null || mFillPaint.getShader() != null) { @@ -544,7 +566,7 @@ of the fill (if any) without worrying about blending artifacts. break; case ShapeType.OVAL: if (haveShadow) { - canvas.drawOval(mRect, mShadowPaint); + canvas.drawOval(mShadowRect, mShadowPaint); } canvas.drawOval(mRect, mFillPaint); if (haveStroke) { @@ -710,19 +732,40 @@ private boolean ensureValidRect() { mRectIsDirty = false; Rect bounds = getBounds(); - float inset = 0; - - if (mStrokePaint != null) { - inset = mStrokePaint.getStrokeWidth() * 0.5f; - } + float inset = mStrokePaint.getStrokeWidth() * 0.5f; final ShapeState st = mShapeState; - mRect.set(bounds.left + inset + mShapeState.mShadowSize, bounds.top + inset + mShapeState.mShadowSize, - bounds.right - inset - mShapeState.mShadowSize, bounds.bottom - inset - mShapeState.mShadowSize); + float let = bounds.left + inset + mShapeState.mShadowSize * 1.2f; + float top = bounds.top + inset + mShapeState.mShadowSize * 1.2f; + float right = bounds.right - inset - mShapeState.mShadowSize * 1.2f; + float bottom = bounds.bottom - inset - mShapeState.mShadowSize * 1.2f; + + mRect.set(let, top, right, bottom); + + float shadowLet; + float shadowTop; + float shadowRight; + float shadowBottom; + if (mShapeState.mShadowOffsetX > 0) { + shadowLet = let + mShapeState.mShadowOffsetX; + shadowRight = right - mShapeState.mShadowOffsetX; + } else { + shadowLet = let; + shadowRight = right + mShapeState.mShadowOffsetX; + } + + if (mShapeState.mShadowOffsetY > 0) { + shadowTop = top + mShapeState.mShadowOffsetY; + shadowBottom = bottom - mShapeState.mShadowOffsetY; + } else { + shadowTop = top; + shadowBottom = bottom + mShapeState.mShadowOffsetY; + } + + mShadowRect.set(shadowLet, shadowTop, shadowRight, shadowBottom); - final int[] colors = st.mGradientColors; - if (colors != null) { + if (st.mSolidColors != null || st.mStrokeColors != null) { RectF r = mRect; float x0, x1, y0, y1; @@ -763,47 +806,96 @@ private boolean ensureValidRect() { break; } - mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1, - colors, st.mPositions, Shader.TileMode.CLAMP)); + if (st.mSolidColors != null) { + mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1, + st.mSolidColors, st.mPositions, Shader.TileMode.CLAMP)); + } + if (st.mStrokeColors != null) { + mStrokePaint.setShader(new LinearGradient(x0, y0, x1, y1, + st.mStrokeColors, st.mPositions, Shader.TileMode.CLAMP)); + } + } else if (st.mGradientType == ShapeGradientType.RADIAL_GRADIENT) { x0 = r.left + (r.right - r.left) * st.mCenterX; y0 = r.top + (r.bottom - r.top) * st.mCenterY; final float level = st.mUseLevel ? (float) getLevel() / 10000.0f : 1.0f; - mFillPaint.setShader(new RadialGradient(x0, y0, - level * st.mGradientRadius, colors, null, - Shader.TileMode.CLAMP)); + if (st.mSolidColors != null) { + mFillPaint.setShader(new RadialGradient(x0, y0, + level * st.mGradientRadius, st.mSolidColors, null, + Shader.TileMode.CLAMP)); + } + if (st.mStrokeColors != null) { + mStrokePaint.setShader(new RadialGradient(x0, y0, + level * st.mGradientRadius, st.mStrokeColors, null, + Shader.TileMode.CLAMP)); + } + } else if (st.mGradientType == ShapeGradientType.SWEEP_GRADIENT) { x0 = r.left + (r.right - r.left) * st.mCenterX; y0 = r.top + (r.bottom - r.top) * st.mCenterY; - int[] tempColors = colors; - float[] tempPositions = null; + if (st.mSolidColors != null) { + + int[] tempSolidColors = st.mSolidColors; + float[] tempSolidPositions = null; + + if (st.mUseLevel) { + tempSolidColors = st.mTempSolidColors; + final int length = st.mSolidColors.length; + if (tempSolidColors == null || tempSolidColors.length != length + 1) { + tempSolidColors = st.mTempSolidColors = new int[length + 1]; + } + System.arraycopy(st.mSolidColors, 0, tempSolidColors, 0, length); + tempSolidColors[length] = st.mSolidColors[length - 1]; - if (st.mUseLevel) { - tempColors = st.mTempColors; - final int length = colors.length; - if (tempColors == null || tempColors.length != length + 1) { - tempColors = st.mTempColors = new int[length + 1]; - } - System.arraycopy(colors, 0, tempColors, 0, length); - tempColors[length] = colors[length - 1]; - tempPositions = st.mTempPositions; - final float fraction = 1.0f / (float) (length - 1); - if (tempPositions == null || tempPositions.length != length + 1) { - tempPositions = st.mTempPositions = new float[length + 1]; + tempSolidPositions = st.mTempSolidPositions; + final float fraction = 1.0f / (float) (length - 1); + if (tempSolidPositions == null || tempSolidPositions.length != length + 1) { + tempSolidPositions = st.mTempSolidPositions = new float[length + 1]; + } + + final float level = (float) getLevel() / 10000.0f; + for (int i = 0; i < length; i++) { + tempSolidPositions[i] = i * fraction * level; + } + tempSolidPositions[length] = 1.0f; } - final float level = (float) getLevel() / 10000.0f; - for (int i = 0; i < length; i++) { - tempPositions[i] = i * fraction * level; + mFillPaint.setShader(new SweepGradient(x0, y0, tempSolidColors, tempSolidPositions)); + } + + + if (st.mStrokeColors != null) { + int[] tempStrokeColors = st.mStrokeColors; + float[] tempStrokePositions = null; + + if (st.mUseLevel) { + tempStrokeColors = st.mTempStrokeColors; + final int length = st.mStrokeColors.length; + if (tempStrokeColors == null || tempStrokeColors.length != length + 1) { + tempStrokeColors = st.mTempStrokeColors = new int[length + 1]; + } + System.arraycopy(st.mStrokeColors, 0, tempStrokeColors, 0, length); + tempStrokeColors[length] = st.mStrokeColors[length - 1]; + + tempStrokePositions = st.mTempStrokePositions; + final float fraction = 1.0f / (float) (length - 1); + if (tempStrokePositions == null || tempStrokePositions.length != length + 1) { + tempStrokePositions = st.mTempStrokePositions = new float[length + 1]; + } + + final float level = (float) getLevel() / 10000.0f; + for (int i = 0; i < length; i++) { + tempStrokePositions[i] = i * fraction * level; + } + tempStrokePositions[length] = 1.0f; } - tempPositions[length] = 1.0f; + mStrokePaint.setShader(new SweepGradient(x0, y0, tempStrokeColors, tempStrokePositions)); } - mFillPaint.setShader(new SweepGradient(x0, y0, tempColors, tempPositions)); } // If we don't have a solid color, the alpha channel must be @@ -811,6 +903,10 @@ private boolean ensureValidRect() { if (!st.mHasSolidColor) { mFillPaint.setColor(Color.BLACK); } + + if (!st.mHasStrokeColor) { + mStrokePaint.setColor(Color.BLACK); + } } } return !mRect.isEmpty(); @@ -832,6 +928,7 @@ public ConstantState getConstantState() { return mShapeState; } + @NonNull @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { @@ -845,7 +942,7 @@ public Drawable mutate() { private void initializeWithState(ShapeState state) { if (state.mHasSolidColor) { mFillPaint.setColor(state.mSolidColor); - } else if (state.mGradientColors == null) { + } else if (state.mSolidColors == null) { // If we don't have a solid color and we don't have a gradient, // the app is stroking the shape, set the color to the default // value of state.mSolidColor @@ -856,7 +953,13 @@ private void initializeWithState(ShapeState state) { } mPadding = state.mPadding; if (state.mStrokeWidth >= 0) { - setStroke(state.mStrokeWidth, state.mStrokeColor, state.mStrokeDashWidth, state.mStrokeDashGap); + if (state.mHasStrokeColor) { + setStrokeColor(state.mStrokeColor); + } else { + setStrokeColor(state.mStrokeColors); + } + setStrokeWidth(state.mStrokeWidth); + setStrokeDash(state.mStrokeDashWidth, state.mStrokeDashGap); } } } \ No newline at end of file diff --git a/library/src/main/java/com/hjq/shape/drawable/ShapeState.java b/library/src/main/java/com/hjq/shape/drawable/ShapeState.java index 6d049c8..8142927 100644 --- a/library/src/main/java/com/hjq/shape/drawable/ShapeState.java +++ b/library/src/main/java/com/hjq/shape/drawable/ShapeState.java @@ -16,11 +16,15 @@ public class ShapeState extends Drawable.ConstantState { public int mShapeType = ShapeType.RECTANGLE; public int mGradientType = ShapeGradientType.LINEAR_GRADIENT; public ShapeGradientOrientation mGradientOrientation = ShapeGradientOrientation.TOP_BOTTOM; - public int[] mGradientColors; - public int[] mTempColors; // no need to copy - public float[] mTempPositions; // no need to copy + public int[] mSolidColors; + public int[] mStrokeColors; + public int[] mTempSolidColors; // no need to copy + public int[] mTempStrokeColors; // no need to copy + public float[] mTempSolidPositions; // no need to copy + public float[] mTempStrokePositions; // no need to copy public float[] mPositions; public boolean mHasSolidColor; + public boolean mHasStrokeColor; public int mSolidColor; public int mStrokeWidth = -1; // if >= 0 use stroking. public int mStrokeColor; @@ -54,13 +58,17 @@ public ShapeState(ShapeState state) { mShapeType = state.mShapeType; mGradientType = state.mGradientType; mGradientOrientation = state.mGradientOrientation; - if (state.mGradientColors != null) { - mGradientColors = state.mGradientColors.clone(); + if (state.mSolidColors != null) { + mSolidColors = state.mSolidColors.clone(); + } + if (state.mStrokeColors != null) { + mStrokeColors = state.mStrokeColors.clone(); } if (state.mPositions != null) { mPositions = state.mPositions.clone(); } mHasSolidColor = state.mHasSolidColor; + mHasStrokeColor = state.mHasStrokeColor; mSolidColor = state.mSolidColor; mStrokeWidth = state.mStrokeWidth; mStrokeColor = state.mStrokeColor; @@ -121,16 +129,30 @@ public void setGradientCenter(float x, float y) { mCenterY = y; } - public void setGradientColor(int[] colors) { - mHasSolidColor = false; - mGradientColors = colors; + public void setSolidColor(int... colors) { + if (colors == null) { + mSolidColor = 0; + mHasSolidColor = true; + computeOpacity(); + return; + } + + if (colors.length == 1) { + mHasSolidColor = true; + mSolidColor = colors[0]; + mSolidColors = null; + } else { + mHasSolidColor = false; + mSolidColor = 0; + mSolidColors = colors; + } computeOpacity(); } public void setSolidColor(int argb) { mHasSolidColor = true; mSolidColor = argb; - mGradientColors = null; + mSolidColors = null; computeOpacity(); } @@ -155,8 +177,22 @@ private void computeOpacity() { return; } - if (mGradientColors != null) { - for (int color : mGradientColors) { + if (mSolidColors != null) { + for (int color : mSolidColors) { + if (!isOpaque(color)) { + mOpaque = false; + return; + } + } + } + + if (mHasStrokeColor) { + mOpaque = isOpaque(mStrokeColor); + return; + } + + if (mStrokeColors != null) { + for (int color : mStrokeColors) { if (!isOpaque(color)) { mOpaque = false; return; @@ -171,15 +207,32 @@ private static boolean isOpaque(int color) { return ((color >> 24) & 0xff) == 0xff; } - public void setStroke(int width, int color) { + public void setStrokeWidth(int width) { mStrokeWidth = width; - mStrokeColor = color; computeOpacity(); } - public void setStroke(int width, int color, float dashWidth, float dashGap) { - mStrokeWidth = width; - mStrokeColor = color; + public void setStrokeColor(int... colors) { + if (colors == null) { + mStrokeColor = 0; + mHasStrokeColor = true; + computeOpacity(); + return; + } + + if (colors.length == 1) { + mHasStrokeColor = true; + mStrokeColor = colors[0]; + mStrokeColors = null; + } else { + mHasStrokeColor = false; + mStrokeColor = 0; + mStrokeColors = colors; + } + computeOpacity(); + } + + public void setStrokeDash(float dashWidth, float dashGap) { mStrokeDashWidth = dashWidth; mStrokeDashGap = dashGap; computeOpacity(); diff --git a/library/src/main/java/com/hjq/shape/span/CommonFontSpan.java b/library/src/main/java/com/hjq/shape/span/CommonFontSpan.java new file mode 100644 index 0000000..28c3f95 --- /dev/null +++ b/library/src/main/java/com/hjq/shape/span/CommonFontSpan.java @@ -0,0 +1,58 @@ +package com.hjq.shape.span; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.support.annotation.IntRange; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.style.ReplacementSpan; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ShapeView + * time : 2022/05/04 + * desc : 通用 Span 类 + */ +public abstract class CommonFontSpan extends ReplacementSpan { + + /** 测量的文本宽度 */ + private float mMeasureTextWidth; + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fontMetricsInt) { + mMeasureTextWidth = onMeasure(paint, fontMetricsInt, text, start, end); + // 这段不可以去掉,字体高度没设置,会出现 draw 方法没有被调用的问题 + // 详情请见:https://stackoverflow.com/questions/20069537/replacementspans-draw-method-isnt-called + Paint.FontMetricsInt metrics = paint.getFontMetricsInt(); + if (fontMetricsInt != null) { + fontMetricsInt.top = metrics.top; + fontMetricsInt.ascent = metrics.ascent; + fontMetricsInt.descent = metrics.descent; + fontMetricsInt.bottom = metrics.bottom; + } + return (int) mMeasureTextWidth; + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + int alpha = paint.getAlpha(); + // 判断是否给画笔设置了透明度 + if (alpha != 255) { + // 如果是则设置不透明 + paint.setAlpha(255); + } + onDraw(canvas, paint, text, start, end, x, top, y, bottom); + // 绘制完成之后将画笔的透明度还原回去 + paint.setAlpha(alpha); + } + + public float onMeasure(@NonNull Paint paint, @Nullable Paint.FontMetricsInt fontMetricsInt, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end) { + return paint.measureText(text, start, end); + } + + public abstract void onDraw(@NonNull Canvas canvas, @NonNull Paint paint, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, float x, int top, int y, int bottom); + + public float getMeasureTextWidth() { + return mMeasureTextWidth; + } +} diff --git a/library/src/main/java/com/hjq/shape/other/LinearGradientFontSpan.java b/library/src/main/java/com/hjq/shape/span/LinearGradientFontSpan.java similarity index 62% rename from library/src/main/java/com/hjq/shape/other/LinearGradientFontSpan.java rename to library/src/main/java/com/hjq/shape/span/LinearGradientFontSpan.java index 0c83bf8..c45052f 100644 --- a/library/src/main/java/com/hjq/shape/other/LinearGradientFontSpan.java +++ b/library/src/main/java/com/hjq/shape/span/LinearGradientFontSpan.java @@ -1,4 +1,4 @@ -package com.hjq.shape.other; +package com.hjq.shape.span; import android.graphics.Canvas; import android.graphics.LinearGradient; @@ -7,7 +7,6 @@ import android.support.annotation.NonNull; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.text.style.ReplacementSpan; import android.widget.LinearLayout; /** @@ -16,7 +15,7 @@ * time : 2021/08/17 * desc : 支持直接定义文本渐变色的 Span */ -public class LinearGradientFontSpan extends ReplacementSpan { +public class LinearGradientFontSpan extends CommonFontSpan { /** 水平渐变方向 */ public static final int GRADIENT_ORIENTATION_HORIZONTAL = LinearLayout.HORIZONTAL; @@ -36,9 +35,6 @@ public static SpannableStringBuilder buildLinearGradientSpannable(CharSequence t return builder; } - /** 测量的文本宽度 */ - private float mMeasureTextWidth; - /** 文字渐变方向 */ private int mTextGradientOrientation; /** 文字渐变颜色组 */ @@ -47,42 +43,17 @@ public static SpannableStringBuilder buildLinearGradientSpannable(CharSequence t private float[] mTextGradientPositions; @Override - public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fontMetricsInt) { - mMeasureTextWidth = paint.measureText(text, start, end); - - // 这段不可以去掉,字体高度没设置,会出现 draw 方法没有被调用的问题 - // 详情请见:https://stackoverflow.com/questions/20069537/replacementspans-draw-method-isnt-called - Paint.FontMetricsInt metrics = paint.getFontMetricsInt(); - if (fontMetricsInt != null) { - fontMetricsInt.top = metrics.top; - fontMetricsInt.ascent = metrics.ascent; - fontMetricsInt.descent = metrics.descent; - fontMetricsInt.bottom = metrics.bottom; - } - return (int) mMeasureTextWidth; - } - - @Override - public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + public void onDraw(@NonNull Canvas canvas, @NonNull Paint paint, CharSequence text, int start, int end, float x, int top, int y, int bottom) { LinearGradient linearGradient; if (mTextGradientOrientation == GRADIENT_ORIENTATION_VERTICAL) { linearGradient = new LinearGradient(0, 0, 0, paint.descent() - paint.ascent(), mTextGradientColor, mTextGradientPositions, Shader.TileMode.REPEAT); } else { - linearGradient = new LinearGradient(x, 0, x + mMeasureTextWidth, 0, + linearGradient = new LinearGradient(x, 0, x + getMeasureTextWidth(), 0, mTextGradientColor, mTextGradientPositions, Shader.TileMode.REPEAT); } paint.setShader(linearGradient); - - int alpha = paint.getAlpha(); - // 判断是否给画笔设置了透明度 - if (alpha != 255) { - // 如果是则设置不透明 - paint.setAlpha(255); - } canvas.drawText(text, start, end, x, y, paint); - // 绘制完成之后将画笔的透明度还原回去 - paint.setAlpha(alpha); } public LinearGradientFontSpan setTextGradientOrientation(int orientation) { diff --git a/library/src/main/java/com/hjq/shape/span/MultiFontSpan.java b/library/src/main/java/com/hjq/shape/span/MultiFontSpan.java new file mode 100644 index 0000000..cdc0ed3 --- /dev/null +++ b/library/src/main/java/com/hjq/shape/span/MultiFontSpan.java @@ -0,0 +1,54 @@ +package com.hjq.shape.span; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.support.annotation.NonNull; +import android.text.TextPaint; +import android.text.style.ReplacementSpan; + +import java.util.Arrays; +import java.util.List; + +public class MultiFontSpan extends ReplacementSpan { + + /** 测量的文本宽度 */ + private float mMeasureTextWidth; + + private final List mReplacementSpans; + + public MultiFontSpan(ReplacementSpan... replacementSpans) { + mReplacementSpans = Arrays.asList(replacementSpans); + } + + @Override + public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + for (ReplacementSpan replacementSpan : mReplacementSpans) { + int size = replacementSpan.getSize(paint, text, start, end, fm); + mMeasureTextWidth = Math.max(mMeasureTextWidth, size); + } + return (int) mMeasureTextWidth; + } + + @Override + public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { + for (ReplacementSpan replacementSpan : mReplacementSpans) { + replacementSpan.draw(canvas, text, start, end, x, top, y, bottom, paint); + } + } + + @Override + public void updateMeasureState(TextPaint p) { + super.updateMeasureState(p); + for (ReplacementSpan replacementSpan : mReplacementSpans) { + replacementSpan.updateMeasureState(p); + } + } + + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + for (ReplacementSpan replacementSpan : mReplacementSpans) { + replacementSpan.updateDrawState(ds); + } + } +} \ No newline at end of file diff --git a/library/src/main/java/com/hjq/shape/span/StrokeFontSpan.java b/library/src/main/java/com/hjq/shape/span/StrokeFontSpan.java new file mode 100644 index 0000000..8d50bdc --- /dev/null +++ b/library/src/main/java/com/hjq/shape/span/StrokeFontSpan.java @@ -0,0 +1,47 @@ +package com.hjq.shape.span; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +public class StrokeFontSpan extends CommonFontSpan { + + /** 描边画笔 */ + private final Paint mStrokePaint = new Paint(); + + private int mTextStrokeColor; + private int mTextStrokeSize; + + @Override + public float onMeasure(@NonNull Paint paint, @Nullable Paint.FontMetricsInt fontMetricsInt, CharSequence text, int start, int end) { + return super.onMeasure(paint, fontMetricsInt, text, start, end); + } + + @Override + public void onDraw(@NonNull Canvas canvas, @NonNull Paint paint, CharSequence text, int start, int end, float x, int top, int y, int bottom) { + mStrokePaint.set(paint); + // 设置抗锯齿 + mStrokePaint.setAntiAlias(true); + // 设置防抖动 + mStrokePaint.setDither(true); + mStrokePaint.setTextSize(paint.getTextSize()); + // 描边宽度 + mStrokePaint.setStrokeWidth(mTextStrokeSize); + mStrokePaint.setStyle(Paint.Style.STROKE); + // 设置粗体 + //mStrokePaint.setFakeBoldText(true); + mStrokePaint.setColor(mTextStrokeColor); + canvas.drawText(text, start, end, x, y, mStrokePaint); + } + + public StrokeFontSpan setTextStrokeColor(int color) { + mTextStrokeColor = color; + return this; + } + + public StrokeFontSpan setTextStrokeSize(int size) { + mTextStrokeSize = size; + return this; + } +} diff --git a/library/src/main/java/com/hjq/shape/styleable/IShapeDrawableStyleable.java b/library/src/main/java/com/hjq/shape/styleable/IShapeDrawableStyleable.java index 34b54a3..af51a87 100644 --- a/library/src/main/java/com/hjq/shape/styleable/IShapeDrawableStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/IShapeDrawableStyleable.java @@ -38,11 +38,17 @@ default int getSolidCheckedColorStyleable() { int getBottomRightRadiusStyleable(); - int getStartColorStyleable(); + int getSolidStartColorStyleable(); - int getCenterColorStyleable(); + int getSolidCenterColorStyleable(); - int getEndColorStyleable(); + int getSolidEndColorStyleable(); + + int getStrokeStartColorStyleable(); + + int getStrokeCenterColorStyleable(); + + int getStrokeEndColorStyleable(); int getUseLevelStyleable(); diff --git a/library/src/main/java/com/hjq/shape/styleable/ITextColorStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ITextColorStyleable.java index ace0b0e..075b906 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ITextColorStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ITextColorStyleable.java @@ -29,4 +29,8 @@ default int getTextCheckedColorStyleable() { int getTextEndColorStyleable(); int getTextGradientOrientationStyleable(); + + int getTextStrokeColorStyleable(); + + int getTextStrokeSizeStyleable(); } \ No newline at end of file diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeButtonStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeButtonStyleable.java index 5a72255..f7c612c 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeButtonStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeButtonStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeButton_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeButton_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeButton_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeButton_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeButton_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeButton_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeButton_shape_useLevel; @@ -252,4 +267,14 @@ public int getTextEndColorStyleable() { public int getTextGradientOrientationStyleable() { return R.styleable.ShapeButton_shape_textGradientOrientation; } + + @Override + public int getTextStrokeColorStyleable() { + return R.styleable.ShapeButton_shape_textStrokeColor; + } + + @Override + public int getTextStrokeSizeStyleable() { + return R.styleable.ShapeButton_shape_textStrokeSize; + } } \ No newline at end of file diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeCheckBoxStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeCheckBoxStyleable.java index e47855d..7f1989d 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeCheckBoxStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeCheckBoxStyleable.java @@ -86,20 +86,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeCheckBox_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeCheckBox_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeCheckBox_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeCheckBox_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeCheckBox_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeCheckBox_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeCheckBox_shape_useLevel; @@ -302,4 +317,14 @@ public int getButtonFocusedDrawableStyleable() { public int getButtonSelectedDrawableStyleable() { return R.styleable.ShapeCheckBox_shape_buttonSelectedDrawable; } + + @Override + public int getTextStrokeColorStyleable() { + return R.styleable.ShapeCheckBox_shape_textStrokeColor; + } + + @Override + public int getTextStrokeSizeStyleable() { + return R.styleable.ShapeCheckBox_shape_textStrokeSize; + } } \ No newline at end of file diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeConstraintLayoutStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeConstraintLayoutStyleable.java index a3c5d47..13be81f 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeConstraintLayoutStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeConstraintLayoutStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeConstraintLayout_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeConstraintLayout_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeConstraintLayout_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeConstraintLayout_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeConstraintLayout_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeConstraintLayout_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeConstraintLayout_shape_useLevel; diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeEditTextStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeEditTextStyleable.java index 9795b74..8650a11 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeEditTextStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeEditTextStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeEditText_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeEditText_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeEditText_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeEditText_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeEditText_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeEditText_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeEditText_shape_useLevel; @@ -252,4 +267,14 @@ public int getTextEndColorStyleable() { public int getTextGradientOrientationStyleable() { return R.styleable.ShapeEditText_shape_textGradientOrientation; } + + @Override + public int getTextStrokeColorStyleable() { + return R.styleable.ShapeEditText_shape_textStrokeColor; + } + + @Override + public int getTextStrokeSizeStyleable() { + return R.styleable.ShapeEditText_shape_textStrokeSize; + } } \ No newline at end of file diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeFrameLayoutStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeFrameLayoutStyleable.java index 0702d39..525062d 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeFrameLayoutStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeFrameLayoutStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeFrameLayout_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeFrameLayout_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeFrameLayout_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeFrameLayout_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeFrameLayout_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeFrameLayout_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeFrameLayout_shape_useLevel; diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeImageViewStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeImageViewStyleable.java index 01d6502..a11b303 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeImageViewStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeImageViewStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeImageView_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeImageView_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeImageView_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeImageView_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeImageView_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeImageView_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeImageView_shape_useLevel; diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeLinearLayoutStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeLinearLayoutStyleable.java index d78af91..2e3b8fc 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeLinearLayoutStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeLinearLayoutStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeLinearLayout_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeLinearLayout_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeLinearLayout_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeLinearLayout_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeLinearLayout_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeLinearLayout_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeLinearLayout_shape_useLevel; diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeRadioButtonStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeRadioButtonStyleable.java index ec5a1c7..b820e5c 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeRadioButtonStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeRadioButtonStyleable.java @@ -86,20 +86,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeRadioButton_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeRadioButton_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeRadioButton_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeRadioButton_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeRadioButton_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeRadioButton_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeRadioButton_shape_useLevel; @@ -301,4 +316,14 @@ public int getButtonFocusedDrawableStyleable() { public int getButtonSelectedDrawableStyleable() { return R.styleable.ShapeRadioButton_shape_buttonSelectedDrawable; } + + @Override + public int getTextStrokeColorStyleable() { + return R.styleable.ShapeRadioButton_shape_textStrokeColor; + } + + @Override + public int getTextStrokeSizeStyleable() { + return R.styleable.ShapeRadioButton_shape_textStrokeSize; + } } \ No newline at end of file diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeRadioGroupStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeRadioGroupStyleable.java index 7cd2482..8da7674 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeRadioGroupStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeRadioGroupStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeRadioGroup_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeRadioGroup_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeRadioGroup_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeRadioGroup_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeRadioGroup_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeRadioGroup_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeRadioGroup_shape_useLevel; diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeRecyclerViewStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeRecyclerViewStyleable.java index 90ba795..a3d0280 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeRecyclerViewStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeRecyclerViewStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeRecyclerView_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeRecyclerView_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeRecyclerView_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeRecyclerView_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeRecyclerView_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeRecyclerView_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeRecyclerView_shape_useLevel; diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeRelativeLayoutStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeRelativeLayoutStyleable.java index 8b8dea4..7bf046a 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeRelativeLayoutStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeRelativeLayoutStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeRelativeLayout_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeRelativeLayout_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeRelativeLayout_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeRelativeLayout_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeRelativeLayout_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeRelativeLayout_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeRelativeLayout_shape_useLevel; diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeTextViewStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeTextViewStyleable.java index 933353d..b0e30ef 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeTextViewStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeTextViewStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeTextView_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeTextView_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeTextView_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeTextView_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeTextView_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeTextView_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeTextView_shape_useLevel; @@ -252,4 +267,14 @@ public int getTextEndColorStyleable() { public int getTextGradientOrientationStyleable() { return R.styleable.ShapeTextView_shape_textGradientOrientation; } + + @Override + public int getTextStrokeColorStyleable() { + return R.styleable.ShapeTextView_shape_textStrokeColor; + } + + @Override + public int getTextStrokeSizeStyleable() { + return R.styleable.ShapeTextView_shape_textStrokeSize; + } } \ No newline at end of file diff --git a/library/src/main/java/com/hjq/shape/styleable/ShapeViewStyleable.java b/library/src/main/java/com/hjq/shape/styleable/ShapeViewStyleable.java index db097c0..14b827c 100644 --- a/library/src/main/java/com/hjq/shape/styleable/ShapeViewStyleable.java +++ b/library/src/main/java/com/hjq/shape/styleable/ShapeViewStyleable.java @@ -80,20 +80,35 @@ public int getBottomRightRadiusStyleable() { } @Override - public int getStartColorStyleable() { + public int getSolidStartColorStyleable() { return R.styleable.ShapeView_shape_startColor; } @Override - public int getCenterColorStyleable() { + public int getSolidCenterColorStyleable() { return R.styleable.ShapeView_shape_centerColor; } @Override - public int getEndColorStyleable() { + public int getSolidEndColorStyleable() { return R.styleable.ShapeView_shape_endColor; } + @Override + public int getStrokeStartColorStyleable() { + return R.styleable.ShapeView_shape_strokeStartColor; + } + + @Override + public int getStrokeCenterColorStyleable() { + return R.styleable.ShapeView_shape_strokeCenterColor; + } + + @Override + public int getStrokeEndColorStyleable() { + return R.styleable.ShapeView_shape_strokeEndColor; + } + @Override public int getUseLevelStyleable() { return R.styleable.ShapeView_shape_useLevel; diff --git a/library/src/main/java/com/hjq/shape/view/ShapeButton.java b/library/src/main/java/com/hjq/shape/view/ShapeButton.java index ea643a9..32d9e5c 100644 --- a/library/src/main/java/com/hjq/shape/view/ShapeButton.java +++ b/library/src/main/java/com/hjq/shape/view/ShapeButton.java @@ -41,7 +41,7 @@ public ShapeButton(Context context, AttributeSet attrs, int defStyleAttr) { mShapeDrawableBuilder.intoBackground(); - if (mTextColorBuilder.isTextGradientColors()) { + if (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor()) { setText(getText()); } else { mTextColorBuilder.intoTextColor(); @@ -56,12 +56,14 @@ public void setTextColor(int color) { } mTextColorBuilder.setTextColor(color); mTextColorBuilder.clearTextGradientColors(); + mTextColorBuilder.clearTextStrokeColor(); } @Override public void setText(CharSequence text, BufferType type) { - if (mTextColorBuilder != null && mTextColorBuilder.isTextGradientColors()) { - super.setText(mTextColorBuilder.buildLinearGradientSpannable(text), type); + if (mTextColorBuilder != null && + (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor())) { + super.setText(mTextColorBuilder.buildTextSpannable(text), type); } else { super.setText(text, type); } diff --git a/library/src/main/java/com/hjq/shape/view/ShapeCheckBox.java b/library/src/main/java/com/hjq/shape/view/ShapeCheckBox.java index 6877a64..d33c19e 100644 --- a/library/src/main/java/com/hjq/shape/view/ShapeCheckBox.java +++ b/library/src/main/java/com/hjq/shape/view/ShapeCheckBox.java @@ -45,7 +45,7 @@ public ShapeCheckBox(Context context, AttributeSet attrs, int defStyleAttr) { mShapeDrawableBuilder.intoBackground(); - if (mTextColorBuilder.isTextGradientColors()) { + if (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor()) { setText(getText()); } else { mTextColorBuilder.intoTextColor(); @@ -66,8 +66,9 @@ public void setTextColor(int color) { @Override public void setText(CharSequence text, BufferType type) { - if (mTextColorBuilder != null && mTextColorBuilder.isTextGradientColors()) { - super.setText(mTextColorBuilder.buildLinearGradientSpannable(text), type); + if (mTextColorBuilder != null && + (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor())) { + super.setText(mTextColorBuilder.buildTextSpannable(text), type); } else { super.setText(text, type); } diff --git a/library/src/main/java/com/hjq/shape/view/ShapeEditText.java b/library/src/main/java/com/hjq/shape/view/ShapeEditText.java index a77064d..b550afb 100644 --- a/library/src/main/java/com/hjq/shape/view/ShapeEditText.java +++ b/library/src/main/java/com/hjq/shape/view/ShapeEditText.java @@ -41,7 +41,7 @@ public ShapeEditText(Context context, AttributeSet attrs, int defStyleAttr) { mShapeDrawableBuilder.intoBackground(); - if (mTextColorBuilder.isTextGradientColors()) { + if (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor()) { setText(getText()); } else { mTextColorBuilder.intoTextColor(); @@ -60,8 +60,9 @@ public void setTextColor(int color) { @Override public void setText(CharSequence text, BufferType type) { - if (mTextColorBuilder != null && mTextColorBuilder.isTextGradientColors()) { - super.setText(mTextColorBuilder.buildLinearGradientSpannable(text), type); + if (mTextColorBuilder != null && + (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor())) { + super.setText(mTextColorBuilder.buildTextSpannable(text), type); } else { super.setText(text, type); } diff --git a/library/src/main/java/com/hjq/shape/view/ShapeRadioButton.java b/library/src/main/java/com/hjq/shape/view/ShapeRadioButton.java index be672b0..deb5863 100644 --- a/library/src/main/java/com/hjq/shape/view/ShapeRadioButton.java +++ b/library/src/main/java/com/hjq/shape/view/ShapeRadioButton.java @@ -45,7 +45,7 @@ public ShapeRadioButton(Context context, AttributeSet attrs, int defStyleAttr) { mShapeDrawableBuilder.intoBackground(); - if (mTextColorBuilder.isTextGradientColors()) { + if (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor()) { setText(getText()); } else { mTextColorBuilder.intoTextColor(); @@ -66,8 +66,9 @@ public void setTextColor(int color) { @Override public void setText(CharSequence text, BufferType type) { - if (mTextColorBuilder != null && mTextColorBuilder.isTextGradientColors()) { - super.setText(mTextColorBuilder.buildLinearGradientSpannable(text), type); + if (mTextColorBuilder != null && + (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor())) { + super.setText(mTextColorBuilder.buildTextSpannable(text), type); } else { super.setText(text, type); } diff --git a/library/src/main/java/com/hjq/shape/view/ShapeTextView.java b/library/src/main/java/com/hjq/shape/view/ShapeTextView.java index 44d68dd..1859727 100644 --- a/library/src/main/java/com/hjq/shape/view/ShapeTextView.java +++ b/library/src/main/java/com/hjq/shape/view/ShapeTextView.java @@ -41,7 +41,7 @@ public ShapeTextView(Context context, AttributeSet attrs, int defStyleAttr) { mShapeDrawableBuilder.intoBackground(); - if (mTextColorBuilder.isTextGradientColors()) { + if (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor()) { setText(getText()); } else { mTextColorBuilder.intoTextColor(); @@ -60,8 +60,9 @@ public void setTextColor(int color) { @Override public void setText(CharSequence text, BufferType type) { - if (mTextColorBuilder != null && mTextColorBuilder.isTextGradientColors()) { - super.setText(mTextColorBuilder.buildLinearGradientSpannable(text), type); + if (mTextColorBuilder != null && + (mTextColorBuilder.isTextGradientColors() || mTextColorBuilder.isTextStrokeColor())) { + super.setText(mTextColorBuilder.buildTextSpannable(text), type); } else { super.setText(text, type); } diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index 4caf863..1cc236c 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -18,17 +18,17 @@ - + - + - + - + - + - + @@ -47,6 +47,14 @@ + + + + + + + + @@ -68,17 +76,17 @@ - + - + - + - + - + - + @@ -106,17 +114,17 @@ - + - + - + - + - + - + @@ -132,6 +140,11 @@ + + + + + @@ -162,6 +175,9 @@ + + + @@ -197,6 +213,9 @@ + + + @@ -216,6 +235,9 @@ + + + @@ -251,6 +273,9 @@ + + + @@ -271,6 +296,9 @@ + + + @@ -309,6 +337,9 @@ + + + @@ -335,6 +366,9 @@ + + + @@ -373,6 +407,9 @@ + + + @@ -398,6 +435,9 @@ + + + @@ -433,6 +473,9 @@ + + + @@ -452,6 +495,9 @@ + + + @@ -495,6 +541,9 @@ + + + @@ -538,6 +587,9 @@ + + + @@ -581,6 +633,9 @@ + + + @@ -624,6 +679,9 @@ + + + @@ -667,6 +725,9 @@ + + + @@ -710,6 +771,9 @@ + + + @@ -753,6 +817,9 @@ + + + diff --git a/picture/dynamic_figure.jpg b/picture/dynamic_figure.jpg new file mode 100644 index 0000000..dbe5a4b Binary files /dev/null and b/picture/dynamic_figure.jpg differ diff --git a/picture/shape_gradient.jpg b/picture/shape_gradient.jpg new file mode 100644 index 0000000..6f0054a Binary files /dev/null and b/picture/shape_gradient.jpg differ diff --git a/picture/shape_select_background.jpg b/picture/shape_select_background.jpg index 129f442..4fb94a9 100644 Binary files a/picture/shape_select_background.jpg and b/picture/shape_select_background.jpg differ diff --git a/picture/shape_select_text_gradient.jpg b/picture/shape_select_text_gradient.jpg index faa2126..42f26b2 100644 Binary files a/picture/shape_select_text_gradient.jpg and b/picture/shape_select_text_gradient.jpg differ diff --git a/picture/shape_shadow_background.jpg b/picture/shape_shadow_background.jpg index 2fd33ba..b31fe4a 100644 Binary files a/picture/shape_shadow_background.jpg and b/picture/shape_shadow_background.jpg differ