android 圆角边框边框渐变,支持边框、圆角、渐变色、透明度的GradientButton
最近在项目中发现好多Button背景颜色相同,但圆角大小不等的Button,这样就得写一大堆的shape或者selector,不便于管理及后期维护,于是乎变想能不能写一个支持边框、圆角、渐变色、透明度的万用Button呢。为了能够兼容button自带的属性,当然继承自AppCompatButton是最好的,剩下的就需要考虑selector各状态在我们自定义Button中怎么获取与渲染了。最开始想到,自己draw?不过这样有点low,需要我们处理一大堆的状态,譬如:state_pressed、state_enabled...
那有没有更好的实现方式呢?我们把这些状态交由系统管理呢?在一顿寻找后,发现还真有呢,真是踏破铁鞋无觅处,得来全不费工夫--------GradientDrawable,没错就是它,一个Drawable的子类。我们看看它的描叙:
A Drawable with a color gradient for buttons, backgrounds, etc.
并且通过查看它提供的相应方法,它不仅能替我们管理好各种state,也支持边框绘制、圆角设置,渐变色当然更不用说了,看它的名字就知道啦。好了废话就不多说了,下面就是GradientButton的代码实现过程:
const val TOP_BOTTOM = 0
const val TR_BL = 1
const val RIGHT_LEFT = 2
const val BR_TL = 3
const val BOTTOM_TOP = 4
const val BL_TR = 5
const val LEFT_RIGHT = 6
const val TL_BR = 7
class GradientButton(context: Context, attrs: AttributeSet? = null) :
AppCompatButton(context, attrs, android.R.attr.borderlessButtonStyle) {
@IntDef(TOP_BOTTOM, TR_BL, RIGHT_LEFT, BR_TL, BOTTOM_TOP, BL_TR, LEFT_RIGHT, TL_BR)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
annotation class Orientation
private val radii by lazy { FloatArray(8) }
private var mBackgroundDrawable: GradientButtonDrawable? = null
private var mPaddingLeft = 0.0f
private var mPaddingTop = 0.0f
private var mPaddingRight = 0.0f
private var mPaddingBottom = 0.0f
private var mMinWidth = 0
private var mMinHeight = 0
init {
val stateListDrawable = StateListDrawable()
attrs?.also { it ->
context.obtainStyledAttributes(it, R.styleable.GradientButton).apply {
val borderColorStateList = getColorStateList(R.styleable.GradientButton_border_color)
val borderWidth = getDimension(R.styleable.GradientButton_border_width, 0.0f)
val isRadiusAdjustBounds = getBoolean(R.styleable.GradientButton_is_radius_adjust_bounds, false)
val radius = getDimension(R.styleable.GradientButton_all_radius, 0.0f)
val topLeftRadius = getDimension(R.styleable.GradientButton_top_left_radius, 0.0f)
val topRightRadius = getDimension(R.styleable.GradientButton_top_right_radius, 0.0f)
val bottomLeftRadius = getDimension(R.styleable.GradientButton_bottom_left_radius, 0.0f)
val bottomRightRadius = getDimension(R.styleable.GradientButton_bottom_right_radius, 0.0f)
val backgroundColorStateList = getColorStateList(R.styleable.GradientButton_background_color)
val orientation = getInt(R.styleable.GradientButton_orientation, LEFT_RIGHT)
val startBackgroundColorStateList =
getColorStateList(R.styleable.GradientButton_start_background_color)
val centerBackgroundColorStateList =
getColorStateList(R.styleable.GradientButton_center_background_color)
val endBackgroundColorStateList = getColorStateList(R.styleable.GradientButton_end_background_color)
val backgroundAlpha = getFraction(R.styleable.GradientButton_background_alpha, 1, 1, 0.0f)
val padding = getDimension(R.styleable.GradientButton_padding, -1.0f)
mPaddingLeft = (if (padding != -1.0f) {
padding
} else {
getDimension(R.styleable.GradientButton_padding_left, mPaddingLeft)
})
mPaddingTop = (if (padding != -1.0f) {
padding
} else {
getDimension(R.styleable.GradientButton_padding_top, mPaddingTop)
})
mPaddingRight = (if (padding != -1.0f) {
padding
} else {
getDimension(R.styleable.GradientButton_padding_right, mPaddingRight)
})
mPaddingBottom = (if (padding != -1.0f) {
padding
} else {
getDimension(R.styleable.GradientButton_padding_bottom, mPaddingBottom)
})
mMinWidth = getDimensionPixelSize(R.styleable.GradientButton_min_width, 0)
mMinHeight = getDimensionPixelSize(R.styleable.GradientButton_min_height, 0)
mBackgroundDrawable = createBackgroundDrawable(getOrientation(orientation))
if (borderWidth > 0.0f || backgroundColorStateList != null || (startBackgroundColorStateList != null && endBackgroundColorStateList != null)) {
setTopLeftRadius(topLeftRadius)
setTopRightRadius(topRightRadius)
setBottomLeftRadius(bottomLeftRadius)
setBottomRightRadius(bottomRightRadius)
setRadius(radius)
setBorder(borderWidth, borderColorStateList)
setBackgroundColorStateList(backgroundColorStateList)
setGradientBackgroundColorStateList(
startBackgroundColorStateList,
centerBackgroundColorStateList,
endBackgroundColorStateList
)
setBackgroundAlpha(backgroundAlpha)
mBackgroundDrawable?.setRadius(isRadiusAdjustBounds, radii)
}
recycle()
}
} ?: also {
mBackgroundDrawable = createBackgroundDrawable(getOrientation(LEFT_RIGHT))
}
mBackgroundDrawable?.also {
stateListDrawable.addState(it.state, mBackgroundDrawable)
setGradientDrawable(stateListDrawable)
}
setPadding(mPaddingLeft.toInt(), mPaddingTop.toInt(), mPaddingRight.toInt(), mPaddingBottom.toInt())
minWidth = mMinWidth
minimumWidth = mMinWidth
minHeight = mMinHeight
minimumHeight = mMinHeight
}
private fun setGradientDrawable(stateListDrawable: StateListDrawable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
background = stateListDrawable
} else {
setBackgroundDrawable(stateListDrawable)
}
}
/**
* 设置渐变色方向
*/
fun setOrientation(@Orientation orientation: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mBackgroundDrawable?.orientation = getOrientation(orientation)
}
}
fun setBackgroundAlpha(@FloatRange(from = 0.0, to = MAX_VALUE) alpha: Float) {
mBackgroundDrawable?.alpha = ((1.0f - alpha) * 255).toInt()
}
/**
* 渐变色设置
*/
fun setGradientBackgroundColorStateList(
startBackgroundColorStateList: ColorStateList?,
centerBackgroundColorStateList: ColorStateList? = null,
endBackgroundColorStateList: ColorStateList?
) {
mBackgroundDrawable?.setGradientBackgroundColorStateList(
startBackgroundColorStateList,
centerBackgroundColorStateList,
endBackgroundColorStateList
)
}
fun setBackgroundColorStateList(backgroundColorStateList: ColorStateList?) {
mBackgroundDrawable?.setBackgroundColorStateList(backgroundColorStateList)
}
fun setBackgroundColorRes(@ColorRes backgroundColor: Int) {
setBackgroundColorRes(backgroundColor, backgroundColor, backgroundColor)
}
fun setBackgroundColorRes(@ColorRes startBackgroundColor: Int, @ColorRes centerBackgroundColor: Int?, @ColorRes endBackgroundColor: Int) {
val centerBackgroundColorStateList = centerBackgroundColor?.let {
ColorStateList(arrayOf(intArrayOf(android.R.attr.state_enabled)), intArrayOf(context.resources.getColor(it)))
}
mBackgroundDrawable?.setGradientBackgroundColorStateList(ColorStateList(arrayOf(intArrayOf(android.R.attr.state_enabled)),
intArrayOf(context.resources.getColor(startBackgroundColor))),
centerBackgroundColorStateList,
ColorStateList(arrayOf(intArrayOf(android.R.attr.state_enabled)),
intArrayOf(context.resources.getColor(endBackgroundColor))))
}
private fun getOrientation(@Orientation orientation: Int): GradientDrawable.Orientation {
return when (orientation) {
TOP_BOTTOM -> GradientDrawable.Orientation.TOP_BOTTOM
TR_BL -> GradientDrawable.Orientation.TR_BL
RIGHT_LEFT -> GradientDrawable.Orientation.RIGHT_LEFT
BR_TL -> GradientDrawable.Orientation.BR_TL
BOTTOM_TOP -> GradientDrawable.Orientation.BOTTOM_TOP
BL_TR -> GradientDrawable.Orientation.BL_TR
TL_BR -> GradientDrawable.Orientation.TL_BR
else -> GradientDrawable.Orientation.LEFT_RIGHT
}
}
private fun createBackgroundDrawable(orientation: GradientDrawable.Orientation) =
GradientButtonDrawable(orientation, null)
fun setBorder(@FloatRange(from = 0.0, to = MAX_VALUE) borderWidth: Float, borderColorStateList: ColorStateList?) {
mBackgroundDrawable?.setBorder(borderWidth, borderColorStateList)
}
fun setBorder(@FloatRange(from = 0.0, to = MAX_VALUE) borderWidth: Float, @ColorRes borderColorRes: Int){
setBorder(borderWidth, ColorStateList(arrayOf(intArrayOf(android.R.attr.state_enabled)),
intArrayOf(context.resources.getColor(borderColorRes))))
}
/**
* 设置圆角自适应最小边
*/
fun setRadiusAdjustBounds(isRadiusAdjustBounds: Boolean) {
mBackgroundDrawable?.setRadius(isRadiusAdjustBounds, null)
}
fun setRadius(@FloatRange(from = 0.0, to = MAX_VALUE) radius: Float) {
if (radius > 0.0f) {
for (index in radii.indices) {
radii[index] = radius
}
mBackgroundDrawable?.setRadius(radius = radii)
}
}
fun setTopLeftRadius(@FloatRange(from = 0.0, to = MAX_VALUE) topLeftRadius: Float) {
if (topLeftRadius > 0.0f) {
radii[0] = topLeftRadius
radii[1] = topLeftRadius
mBackgroundDrawable?.setRadius(radius = radii)
}
}
fun setTopRightRadius(@FloatRange(from = 0.0, to = MAX_VALUE) topRightRadius: Float) {
if (topRightRadius > 0.0f) {
radii[2] = topRightRadius
radii[3] = topRightRadius
mBackgroundDrawable?.setRadius(radius = radii)
}
}
fun setBottomLeftRadius(@FloatRange(from = 0.0, to = MAX_VALUE) bottomLeftRadius: Float) {
if (bottomLeftRadius > 0.0f) {
radii[6] = bottomLeftRadius
radii[7] = bottomLeftRadius
mBackgroundDrawable?.setRadius(radius = radii)
}
}
fun setBottomRightRadius(@FloatRange(from = 0.0, to = MAX_VALUE) bottomRightRadius: Float) {
if (bottomRightRadius > 0.0f) {
radii[4] = bottomRightRadius
radii[5] = bottomRightRadius
mBackgroundDrawable?.setRadius(radius = radii)
}
}
}
internal class GradientButtonDrawable(orientation: Orientation = Orientation.LEFT_RIGHT, @ColorInt colors: IntArray?) : GradientDrawable(orientation, colors) {
private var mBackgroundColorStateList: ColorStateList? = null
private var mStartBackgroundColorStateList: ColorStateList? = null
private var mCenterBackgroundColorStateList: ColorStateList? = null
private var mEndBackgroundColorStateList: ColorStateList? = null
private var mBorderColorStateList: ColorStateList? = null
private var mBorderWidth = 0.0f
private var mIsRadiusAdjustBounds = false
internal fun setBackgroundColorStateList(backgroundColorStateList: ColorStateList?) {
mBackgroundColorStateList = backgroundColorStateList
mStartBackgroundColorStateList = null
mCenterBackgroundColorStateList = null
mEndBackgroundColorStateList = null
setBackgroundColor()
}
internal fun setGradientBackgroundColorStateList(startBackgroundColorStateList: ColorStateList?, centerBackgroundColorStateList: ColorStateList?, endBackgroundColorStateList: ColorStateList?) {
mBackgroundColorStateList = null
mStartBackgroundColorStateList = startBackgroundColorStateList
mCenterBackgroundColorStateList = centerBackgroundColorStateList
mEndBackgroundColorStateList = endBackgroundColorStateList
setBackgroundColor()
}
internal fun setBorder(@FloatRange(from = 0.0, to = MAX_VALUE) borderWidth: Float = 0.0f, borderColorStateList: ColorStateList?) {
mBorderWidth = borderWidth
mBorderColorStateList = borderColorStateList
setBorderColor()
}
internal fun setRadius(radiusAdjustBounds: Boolean = false, radius: FloatArray?) {
mIsRadiusAdjustBounds = radiusAdjustBounds
if (!mIsRadiusAdjustBounds) {
cornerRadii = radius
}
}
private fun getColorForState(colorStateList: ColorStateList?): Int {
return colorStateList?.getColorForState(state, 0) ?: 0
}
private fun setBackgroundColor() {
mBackgroundColorStateList?.also {
if (hasNativeStateListAPI()) {
color = mBackgroundColorStateList
} else {
setColor(getColorForState(mBackgroundColorStateList))
}
} ?: also {
if (mStartBackgroundColorStateList != null && mEndBackgroundColorStateList != null) {
val colors = IntArray(mCenterBackgroundColorStateList?.let { 3 } ?: let { 2 })
colors[0] = getColorForState(mStartBackgroundColorStateList)
mCenterBackgroundColorStateList?.also {
colors[1] = getColorForState(mCenterBackgroundColorStateList)
colors[2] = getColorForState(mEndBackgroundColorStateList)
} ?: also {
colors[1] = getColorForState(mEndBackgroundColorStateList)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
setColors(colors)
} else {
setColor(colors[0])
}
}
}
}
private fun setBorderColor() {
mBorderColorStateList?.also {
if (mBorderWidth > 0.0f) {
if (hasNativeStateListAPI()) {
setStroke(mBorderWidth.toInt(), mBorderColorStateList)
} else {
setStroke(mBorderWidth.toInt(), getColorForState(mBorderColorStateList))
}
}
}
}
private fun hasNativeStateListAPI() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
override fun onStateChange(stateSet: IntArray?): Boolean {
return super.onStateChange(stateSet).let {
if (mBorderColorStateList != null || mBackgroundColorStateList != null || mStartBackgroundColorStateList != null) {
setBorderColor()
setBackgroundColor()
true
} else {
it
}
}
}
override fun onBoundsChange(r: Rect?) {
super.onBoundsChange(r)
r?.also {
if (mIsRadiusAdjustBounds) {
cornerRadius = min(it.width() / 2.0f, it.height() / 2.0f)
}
}
}
}
就是这么简单,我们只需要提供相应的color选择器,或者背景色值即可完成我们平时需要使用一大堆shape或selector才能实现的效果,最后再看看效果图吧,正所谓无图无真相,嘿嘿
gradientbutton.png
好了,今天的收获就是这么多O(∩_∩)O
android 圆角边框边框渐变,支持边框、圆角、渐变色、透明度的GradientButton相关推荐
- html5 border边框颜色渐变,css边框颜色渐变
在实际开发中,我们经常遇见边框需要背景渐变的实现要求,那么如何去实现呢,今天给大家分享依稀几种情况 1.直角的背景渐变 border渐变 button{ background:transparent; ...
- android 圆角边框边框渐变,Android中用shape做渐变,边框,圆角等效果
以前没接触到shape的时候,做圆角,渐变等效果都是依赖图片效果:如果对PS不熟悉,光是做图就要花去大把时间. 废话不讲了,把总结的内容记录下来,俺们不是在写博客,算是做个云笔记吧. shape用法与 ...
- html圆角边框背景颜色,CSS之圆角边框渐变的实现
注:测试浏览器版本号--chrome 75.0.3770.80:opera 60.0.3255.109:firefox 67.0:ie 11. 对于普通的边框渐变,其作用于圆角边框渐变时会覆盖掉圆角的 ...
- CSS3_01_圆角_边框_渐变_字体
CSS3 是最新的 CSS 标准. 我们的 CSS3 教程向您讲解 CSS3 中的新特性. 手册说明: CSS3使用了层叠样式表技术,可以对网页布局.字体.颜色.背景灯效果做出控制. css3作为cs ...
- java如何设置圆角边框_巧妙实现带圆角的渐变边框
如何实现下面这个渐变的边框效果: 这个问题本身不难,实现的方法也有一些,主要是有一些细节需要注意. border-image border-image 是 CSS 规范 CSS Backgrounds ...
- java button 圆角_UIButton具有渐变边框和圆角
我想要的是一个自定义UIButton,它有一个渐变边框(只是边框是渐变)和圆角 . 我几乎到了我想去的地方,但是角落有问题 . 这是我目前拥有的: 这是我的代码: override func view ...
- (六)Flutter 基础部件 TextView 和TextStyle Flutter 容器 装饰盒子 边框 圆角 阴影 形状 渐变 背景图像
RichText:行内多样式的文字 import 'package:flutter/material.dart';class BasicDemo extends StatelessWidget {@o ...
- 自定义字体样式引入使用方法、文本阴影、边框阴影、(边框)圆角、渐变、理解重绘与回流、渐进增强和优雅降级的区别
目录 1.文本阴影 text-shadow 2.边框阴影 box-shadow 3.自定义字体样式方法 引入与使用方法举例: 4.(边框)圆角 5.渐变 6.过渡 transition 7.理论知识 ...
- Android 对控件设置边框样式(边框颜色,圆角)和图片样式(圆角)
1.设置边框.圆角.背景色案例 在drawable中 新建一个edge.xml文件 <?xml version="1.0" encoding="utf-8" ...
最新文章
- hive lock命令的使用
- Javascript 检查一组 radio 中的哪一个被勾选
- 在商业中,如何与人工智能建立共生关系?
- 清华计算机系上热搜!近 9 成优秀毕业生放弃留学,前 50 名 41 人留校深造......
- 使用 Python 进行稳定可靠的文件操作
- mysql数据库套件_MySQL数据库管理开发套件(EMS SQL Management Studio For MySQL)下载 v1.3.0.46170 官方版 - 比克尔下载...
- linux shell解析1
- C#中的@符号的使用
- 正确的CentOS系统配置
- Drupal 曝出代码执行高危漏洞,数百万网站受影响
- 用FCM函数实现模糊C均值聚类算法
- October cms(数据库-Mutators)
- App crash原因以及解决办法
- GCN学习:Pytorch-Geometric教程(二)
- Openstack Ironic Bare metal 实操
- 失控--阅读笔记群蜂思维
- OID,唯一性的标志
- 首屏优化,减少白屏时间
- linux设置网卡接受组播,linux下双网卡接收组播需要修改的参数
- 一个小点阵图像JPG图片做吗?
热门文章
- pandas无法打开.xlsx文件,xlrd.biffh.XLRDError: Excel xlsx file; not supported
- php 获取 table,php – 获取表对象(App_Model_TableName)作为获取结果(Zend Framework)
- c++实现插入和冒泡排序
- winpe镜像文件iso下载_精品软件:最喜爱的也是最纯净WinPE-微PE工具箱
- php获取页面中的指定内容,php 获取页面中指定内容的实现类
- java md5 密钥_Java 生成16/32位 MD5密钥串
- 面积积分_袁颖妍:用定理积分求平面区域面积(有代表性的9个例题)
- linux安装python2环境_Python基础手册 2 —— Python 环境搭建(Linux)
- mobi格式电子书_进阶能力 | 了解常见的电子书格式
- python expect模块_Python尚学堂高淇|第二季0408P119P123with上常见的异常的解决tryexcept...else结构,...