**FlycoRoundView
一个扩展原生控件支持圆角矩形框背景的库,可以减少相关shape资源文件使用
支持TextView,FrameLayout,LinearLayout,RelativeLayout,更多使用也可以自己扩展**
1.使用方法
实现以上的效果只需要如下,几个简单的自定义属性,
<com.flyco.roundview.RoundTextView
android:id="@+id/rtv_3"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:ellipsize="end"
android:gravity="center"
android:paddingBottom="10dp"
android:paddingLeft="18dp"
android:paddingRight="18dp"
android:paddingTop="10dp"
android:singleLine="true"
android:text="TextView Radius 10dpTextView Radius 10dp"
android:textColor="#383838"
rv:rv_backgroundColor="#F6CE59"
rv:rv_cornerRadius="10dp" />
自定义xml属性的意思
<!-- 圆角矩形背景色 -->
<attr name="rv_backgroundColor" format="color"/>
<!-- 圆角矩形背景色press -->
<attr name="rv_backgroundPressColor" format="color"/>
<!-- 圆角弧度,单位dp-->
<attr name="rv_cornerRadius" format="dimension"/>
<!-- 圆角弧度,单位dp-->
<attr name="rv_strokeWidth" format="dimension"/>
<!-- 圆角边框颜色-->
<attr name="rv_strokeColor" format="color"/>
<!-- 圆角边框颜色press -->
<attr name="rv_strokePressColor" format="color"/>
<!-- 文字颜色press-->
<attr name="rv_textPressColor" format="color"/>
<!-- 圆角弧度是高度一半-->
<attr name="rv_isRadiusHalfHeight" format="boolean"/>
<!-- 圆角矩形宽高相等,取较宽高中大值-->
<attr name="rv_isWidthHeightEqual" format="boolean"/>
<!-- 圆角弧度,单位dp,TopLeft-->
<attr name="rv_cornerRadius_TL" format="dimension"/>
<!-- 圆角弧度,单位dp,TopRight-->
<attr name="rv_cornerRadius_TR" format="dimension"/>
<!-- 圆角弧度,单位dp,BottomLeft-->
<attr name="rv_cornerRadius_BL" format="dimension"/>
<!-- 圆角弧度,单位dp,BottomRight-->
<attr name="rv_cornerRadius_BR" format="dimension"/>
<!-- 是否有Ripple效果,api21+有效-->
<attr name="rv_isRippleEnable" format="boolean"/>
代码解析
通过观察源码,主要有如下几个类
- RoundFrameLayout
- RoundLinearLayout
- RoundRelativeLayout
- RoundTextView
- RoundViewDelegate
其中所有的自定义View的代码大致全都是这样
public RoundRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
//主要逻辑在这里面初始化
delegate = new RoundViewDelegate(this, context, attrs);
}
/** use delegate to set attr */
public RoundViewDelegate getDelegate() {
return delegate;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//判断是否设置为是宽高相同
if (delegate.isWidthHeightEqual() && getWidth() > 0 && getHeight() > 0) {
int max = Math.max(getWidth(), getHeight());
int measureSpec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY);
super.onMeasure(measureSpec, measureSpec);
return;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//判断是否圆角取高的一半
if (delegate.isRadiusHalfHeight()) {
delegate.setCornerRadius(getHeight() / 2);
}else {
delegate.setBgSelector();
}
}
主要代码集中在RoundViewDelegate里面,进去看看
取出xml中的属性 ,如果对自定义xml属性不熟悉–>戳这里Android 深入理解Android中的自定义属性
//取出xml中的属性
private void obtainAttributes(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundTextView);
backgroundColor = ta.getColor(R.styleable.RoundTextView_rv_backgroundColor, Color.TRANSPARENT);
//~~~省略代码
isRippleEnable = ta.getBoolean(R.styleable.RoundTextView_rv_isRippleEnable, true);
ta.recycle();
}
在各个自定义View中看到,在onLayout中会调用setBgSelector()方法,进去看看
public void setBgSelector() {
//StateListDrawable类对应<selector>这个xml标签
StateListDrawable bg = new StateListDrawable();
//如果是5.0以上的系统,可以设置水波纹的效果
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && isRippleEnable) {
setDrawable(gd_background, backgroundColor, strokeColor);
//对应<ripple>标签
RippleDrawable rippleDrawable = new RippleDrawable(
getPressedColorSelector(backgroundColor, backgroundPressColor), gd_background, null);
//设置为View背景
view.setBackground(rippleDrawable);
} else {
//设置四个角的圆角弧度,背景颜色
setDrawable(gd_background, backgroundColor, strokeColor);
//前面加个‘-’,相当于xml中的 state_pressed属性为false的时候,
bg.addState(new int[]{-android.R.attr.state_pressed}, gd_background);
if (backgroundPressColor != Integer.MAX_VALUE || strokePressColor != Integer.MAX_VALUE) {
//设置按下去的背景色
setDrawable(gd_background_press, backgroundPressColor == Integer.MAX_VALUE ? backgroundColor : backgroundPressColor,
strokePressColor == Integer.MAX_VALUE ? strokeColor : strokePressColor);
bg.addState(new int[]{android.R.attr.state_pressed}, gd_background_press);
}
//设置背景
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {//16
view.setBackground(bg);
} else {
//noinspection deprecation
view.setBackgroundDrawable(bg);
}
}
//如果是TextView,设置字体的颜色,按下去的颜色
if (view instanceof TextView) {
if (textPressColor != Integer.MAX_VALUE) {
ColorStateList textColors = ((TextView) view).getTextColors();
// Log.d("AAA", textColors.getColorForState(new int[]{-android.R.attr.state_pressed}, -1) + "");
ColorStateList colorStateList = new ColorStateList(
new int[][]{new int[]{-android.R.attr.state_pressed}, new int[]{android.R.attr.state_pressed}},
new int[]{textColors.getDefaultColor(), textPressColor});
((TextView) view).setTextColor(colorStateList);
}
}
}
设置背景的方法全都在这里了~比较简单,基本就是把以前只能用xml写死的selector等等标签,用java代码变灵活了!
private void setDrawable(GradientDrawable gd, int color, int strokeColor) {
//设置Drawable的背景色
gd.setColor(color);
//四个角设置圆角
if (cornerRadius_TL > 0 || cornerRadius_TR > 0 || cornerRadius_BR > 0 || cornerRadius_BL > 0) {
/**The corners are ordered top-left, top-right, bottom-right, bottom-left*/
radiusArr[0] = cornerRadius_TL;
radiusArr[1] = cornerRadius_TL;
radiusArr[2] = cornerRadius_TR;
radiusArr[3] = cornerRadius_TR;
radiusArr[4] = cornerRadius_BR;
radiusArr[5] = cornerRadius_BR;
radiusArr[6] = cornerRadius_BL;
radiusArr[7] = cornerRadius_BL;
gd.setCornerRadii(radiusArr);
} else {
//全都设置成cornerRadius
gd.setCornerRadius(cornerRadius);
}
//设置边框
gd.setStroke(strokeWidth, strokeColor);
}
以下是Drawable Xml对应的的class类
GradientDrawable
<shape> 对应 GradientDrawable
//设置背景颜色
setColor(@ColorInt int argb)
//设置各个角的弧度
setCornerRadii(float[] radii)
//左上角 右上角 右下角 左下角 这里数组长度必须是8位 如下
gradientDrawable1.setCornerRadii(new float[]{0,0,8,8,16,16,32,32});
//设置四个角的弧度
setCornerRadius(float radius)
//设置边框 宽度,和颜色
setStroke(int width, @ColorInt int color)
StateListDrawable
<selector> 对应 StateListDrawable类
主要方法有以下
//对应xml的属性,当前状态下的显示背景
addState(new int[]{-android.R.attr.state_pressed}, gd_background);
这里可以同时设置多个状态比如
stateListDrawable.addState(
new int[]{-android.R.attr.state_pressed,
-android.R.attr.state_checked,
-android.R.attr.state_selected,gradientDrawable1);
主要用到的就是这两个类了~~