个人网站备案后做游戏,如何建设一个电商网站,相亲网站男人拉我做外汇,建设部促进中心网站最近在项目中发现好多Button背景颜色相同#xff0c;但圆角大小不等的Button#xff0c;这样就得写一大堆的shape或者selector#xff0c;不便于管理及后期维护#xff0c;于是乎变想能不能写一个支持边框、圆角、渐变色、透明度的万用Button呢。为了能够兼容button自带的属…最近在项目中发现好多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 0const val TR_BL 1const val RIGHT_LEFT 2const val BR_TL 3const val BOTTOM_TOP 4const val BL_TR 5const val LEFT_RIGHT 6const val TL_BR 7class 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 Orientationprivate val radii by lazy { FloatArray(8) }private var mBackgroundDrawable: GradientButtonDrawable? nullprivate var mPaddingLeft 0.0fprivate var mPaddingTop 0.0fprivate var mPaddingRight 0.0fprivate var mPaddingBottom 0.0fprivate var mMinWidth 0private var mMinHeight 0init {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 mMinWidthminimumWidth mMinWidthminHeight mMinHeightminimumHeight 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_BOTTOMTR_BL - GradientDrawable.Orientation.TR_BLRIGHT_LEFT - GradientDrawable.Orientation.RIGHT_LEFTBR_TL - GradientDrawable.Orientation.BR_TLBOTTOM_TOP - GradientDrawable.Orientation.BOTTOM_TOPBL_TR - GradientDrawable.Orientation.BL_TRTL_BR - GradientDrawable.Orientation.TL_BRelse - 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] topLeftRadiusradii[1] topLeftRadiusmBackgroundDrawable?.setRadius(radius radii)}}fun setTopRightRadius(FloatRange(from 0.0, to MAX_VALUE) topRightRadius: Float) {if (topRightRadius 0.0f) {radii[2] topRightRadiusradii[3] topRightRadiusmBackgroundDrawable?.setRadius(radius radii)}}fun setBottomLeftRadius(FloatRange(from 0.0, to MAX_VALUE) bottomLeftRadius: Float) {if (bottomLeftRadius 0.0f) {radii[6] bottomLeftRadiusradii[7] bottomLeftRadiusmBackgroundDrawable?.setRadius(radius radii)}}fun setBottomRightRadius(FloatRange(from 0.0, to MAX_VALUE) bottomRightRadius: Float) {if (bottomRightRadius 0.0f) {radii[4] bottomRightRadiusradii[5] bottomRightRadiusmBackgroundDrawable?.setRadius(radius radii)}}}internal class GradientButtonDrawable(orientation: Orientation Orientation.LEFT_RIGHT, ColorInt colors: IntArray?) : GradientDrawable(orientation, colors) {private var mBackgroundColorStateList: ColorStateList? nullprivate var mStartBackgroundColorStateList: ColorStateList? nullprivate var mCenterBackgroundColorStateList: ColorStateList? nullprivate var mEndBackgroundColorStateList: ColorStateList? nullprivate var mBorderColorStateList: ColorStateList? nullprivate var mBorderWidth 0.0fprivate var mIsRadiusAdjustBounds falseinternal fun setBackgroundColorStateList(backgroundColorStateList: ColorStateList?) {mBackgroundColorStateList backgroundColorStateListmStartBackgroundColorStateList nullmCenterBackgroundColorStateList nullmEndBackgroundColorStateList nullsetBackgroundColor()}internal fun setGradientBackgroundColorStateList(startBackgroundColorStateList: ColorStateList?, centerBackgroundColorStateList: ColorStateList?, endBackgroundColorStateList: ColorStateList?) {mBackgroundColorStateList nullmStartBackgroundColorStateList startBackgroundColorStateListmCenterBackgroundColorStateList centerBackgroundColorStateListmEndBackgroundColorStateList endBackgroundColorStateListsetBackgroundColor()}internal fun setBorder(FloatRange(from 0.0, to MAX_VALUE) borderWidth: Float 0.0f, borderColorStateList: ColorStateList?) {mBorderWidth borderWidthmBorderColorStateList borderColorStateListsetBorderColor()}internal fun setRadius(radiusAdjustBounds: Boolean false, radius: FloatArray?) {mIsRadiusAdjustBounds radiusAdjustBoundsif (!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.LOLLIPOPoverride 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