关于项目中圆角及特殊圆角的实际使用问题
小知识,大挑战!本文正在参与「程序员必备小知识」创作活动
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。
目前我们日常使用的APP中大部分控件已经赋予了圆角的特性,圆角实际上的视觉体验也比较好,不像默认那么锋利,给人一种舒适的感觉.
以前我对控件使用圆角无非就三种方式.
- xml文件中shape的方式 ````
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:background="@drawable/shape_circle"
/>
```` shape_circle
````
<corners android:radius="8dp" />
<solid android:color="@color/teal_200"/>
````
- cardview ```
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
app:cardCornerRadius="10dp"
app:cardElevation="10dp">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/ic_launcher_background"/>
</androidx.cardview.widget.CardView>
```
这种方式使用起来更为简单,而且CardView还自带阴影效果,直接设置属性即可,相较于xml减少了包体大小(聊胜于无). 3. 自定义View
```` /* * 自定义圆角view / public class RoundImageView extends AppCompatImageView {
private float width, height;
// 全部角度
private float radius, leftRadius, rightRadius;
// 是否是半圆
private boolean isRound = false;
// 底部圆角
private boolean isBottomRound = false;
public RoundImageView(Context context) {
this(context, null);
}
public RoundImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
/**
* 初始化
*
* @param context
* @param attrs
*/
private void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
radius = array.getDimensionPixelOffset(R.styleable.RoundImageView_radius, 0);
leftRadius = array.getDimensionPixelOffset(R.styleable.RoundImageView_left_radius, 0);
rightRadius = array.getDimensionPixelOffset(R.styleable.RoundImageView_right_radius, 0);
if (radius == 0 && leftRadius == 0 && rightRadius == 0) {
isRound = true;
}
if (leftRadius != 0 && rightRadius != 0) {
isBottomRound = true;
}
array.recycle();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
width = getWidth();
height = getHeight();
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
// 抗锯齿
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
Path path = new Path();
if (isRound) {
radius = Math.min(width, height) / 2;
}
// 设置背景颜色透明
canvas.drawColor(Color.TRANSPARENT);
Drawable drawable = getDrawable();
int w = this.getWidth();
int h = this.getHeight();
if (null != drawable && w > 0 && h > 0) {
float[] rids;
// 圆角的半径,依次为左上角xy半径,右上角,右下角,左下角
if (isBottomRound) {
rids = new float[]{0, 0, 0, 0,
rightRadius, rightRadius, leftRadius, leftRadius};
} else {
rids = new float[]{radius, radius, radius, radius,
radius, radius, radius, radius};
}
path.addRoundRect(new RectF(0, 0, w, h), rids, Path.Direction.CW);
canvas.clipPath(path);
}
super.onDraw(canvas);
}
public void setRadius(int radius) {
this.radius = radius;
invalidate();
}
} ```` attrs
```
使用 ```
<com.jsxr.kotlintest.RoundImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/ic_launcher_background"
app:radius="10dp"
android:layout_centerInParent="true"/>
``` 效果
这种方式实用性上和第二种差不多,就是一开始麻烦点,你要么自己写,要么去百度复制,但是相较于官方提供的View,这种方式自定义性比较强,你个别角圆都行.
上面三种是我以前用过的方式,最近项目重构,为了简化代码,降低系统复杂度,就另外寻找了一个功能强大的View.
GradientDrawable
这是官方对于它的解释.在实际的使用上十分得劲,少了好多跟UI扯皮,自己做重复性工作的时间,下面请看代码
工具类
``` public class MyShape {
private static final ConcurrentHashMap<String, GradientDrawable> hashMap = new ConcurrentHashMap();
/**
* 设置圆角
* @param context
* @param radius
* @return
*/
public static GradientDrawable setMyShape(Context context, int radius) {
int realRadius = ImageUtil.dp2px(context, radius);
String radiusKey = String.valueOf(radius);
if (hashMap.contains(radiusKey)) {
return hashMap.get(radiusKey);
} else {
GradientDrawable drawable = new GradientDrawable();
if (radius != 0) {
drawable.setCornerRadius(realRadius);
}
hashMap.put(radiusKey, drawable);
return drawable;
}
}
/**
* @param context
* @param radius
* @param bg
* @return 自定义圆角、背景图形
*/
public static GradientDrawable setMyShape(Context context, int radius, int bg) {
int realRadius = ImageUtil.dp2px(context, radius);
String key = String.valueOf(realRadius + bg);
if (hashMap.contains(key)) {
return hashMap.get(key);
} else {
GradientDrawable drawable = new GradientDrawable();
if (radius != 0) {
drawable.setCornerRadius(realRadius);
}
if (bg != 0) {
drawable.setColor(bg);
}
hashMap.put(key, drawable);
return drawable;
}
}
/**
* 设置圆角、背景、透明度
*
* @param radius
* @param bg
* @param alpha
* @return
*/
public static GradientDrawable setMyShapeWithAlpha(Context activity,int radius, int bg, int alpha) {
int realRadius = ImageUtil.dp2px(activity, radius);
String key = String.valueOf(realRadius + bg + alpha);
if (hashMap.containsKey(key)) {
return hashMap.get(key);
} else {
GradientDrawable drawable = new GradientDrawable();
drawable.setCornerRadius(radius);
drawable.setColor(bg);
drawable.setAlpha(alpha);
hashMap.put(key, drawable);
return drawable;
}
}
/**
* @param activity
* @param topLeft,topRight,bottomLeft,bottomRight
* @param bg
* @return 自定义圆角、背景布局
*/
public static GradientDrawable setMyShapeRadiusWithBg(Context activity, int topLeft, int topRight, int bottomLeft, int bottomRight, int bg) {
topLeft = ImageUtil.dp2px(activity, topLeft);
topRight = ImageUtil.dp2px(activity, topRight);
bottomLeft = ImageUtil.dp2px(activity, bottomLeft);
bottomRight = ImageUtil.dp2px(activity, bottomRight);
String key = String.valueOf(topLeft + topRight + bottomLeft + bottomRight + bg);
if (hashMap.containsKey(key)) {
return hashMap.get(key);
} else {
GradientDrawable drawable = new GradientDrawable();
drawable.setCornerRadii(new float[]{topLeft, topLeft,
topRight, topRight,
bottomLeft, bottomLeft,
bottomRight, bottomRight});
if (bg != 0) {
drawable.setColor(bg);
}
hashMap.put(key, drawable);
return drawable;
}
}
/**
* @param activity
* @param radius
* @param width
* @param bg
* @return 设置带边框的椭圆+圆角+自定义边框颜色
*/
public static GradientDrawable setMyShapeStroke(Context activity, int radius, int width, int bg) {
int realRadius = ImageUtil.dp2px(activity, radius);
int realWidth = ImageUtil.dp2px(activity, width);
String key = String.valueOf(realRadius + realWidth + bg);
if (hashMap.containsKey(key)) {
return hashMap.get(key);
} else {
GradientDrawable drawable = new GradientDrawable();
if (radius != 0) {
drawable.setCornerRadius(realRadius);
}
if (width != 0 && bg != 0) {
drawable.setStroke(realWidth, bg);
}
hashMap.put(key, drawable);
return drawable;
}
}
/**
* @param activity
* @param radius
* @param width
* @param strokeBg
* @param bg
* @return 设置带边框的椭圆,自定义内部颜色+自定义边框颜色
*/
public static GradientDrawable setMyshapeStroke(Context activity, int radius, int width, int strokeBg, int bg) {
int realRadius = ImageUtil.dp2px(activity, radius);
int realWidth = ImageUtil.dp2px(activity, width);
String key = String.valueOf(realRadius + realRadius + strokeBg);
if (hashMap.containsKey(key)) {
return hashMap.get(key);
} else {
GradientDrawable drawable = new GradientDrawable();
if (radius != 0) {
drawable.setCornerRadius(realRadius);
}
if (width != 0 && strokeBg != 0) {
drawable.setStroke(realWidth, strokeBg);
}
if (bg != 0) {
drawable.setColor(bg);
}
hashMap.put(key, drawable);
return drawable;
}
}
/**
* @param activity
* @param topLeftRadius
* @param topRightRadius
* @param bottomRightRadius
* @param bottomLeftRadius
* @return 设置椭圆,并可以自定义内部颜色
*/
public static GradientDrawable setMyShapeRadius(Context activity, int bgColor, int topLeftRadius, int topRightRadius,
int bottomRightRadius, int bottomLeftRadius) {
GradientDrawable drawable = new GradientDrawable();
if (bgColor != 0) {
drawable.setColor(bgColor);
}
drawable.setCornerRadii(new float[]{ImageUtil.dp2px(activity, topLeftRadius), ImageUtil.dp2px(activity, topLeftRadius),
ImageUtil.dp2px(activity, topRightRadius), ImageUtil.dp2px(activity, topRightRadius),
ImageUtil.dp2px(activity, bottomRightRadius), ImageUtil.dp2px(activity, bottomRightRadius),
ImageUtil.dp2px(activity, bottomLeftRadius), ImageUtil.dp2px(activity, bottomLeftRadius)});
return drawable;
}
/**
* @param startColor
* @param endColor
* @param angle
* @return 设置渐变色
*/
@SuppressLint("WrongConstant")
public static GradientDrawable setGradient(Context activity, int startColor, int endColor, int topLeftRadius, int topRightRadius,
int bottomRightRadius, int bottomLeftRadius, int angle) {
int[] colors = {startColor, endColor};
topLeftRadius = ImageUtil.dp2px(activity, topLeftRadius);
topRightRadius = ImageUtil.dp2px(activity, topRightRadius);
bottomLeftRadius = ImageUtil.dp2px(activity, bottomLeftRadius);
bottomRightRadius = ImageUtil.dp2px(activity, bottomRightRadius);
String key = String.valueOf(topLeftRadius + topRightRadius + bottomLeftRadius + bottomRightRadius + angle);
if (hashMap.containsKey(key)) {
return hashMap.get(key);
} else {
GradientDrawable drawable = null;
if (angle == 0) {
drawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
} else if (angle == 90) {
drawable = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, colors);
} else if (angle == 180) {
drawable = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, colors);
} else if (angle == 270) {
drawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors);
} else if (angle == 315) {
drawable = new GradientDrawable(GradientDrawable.Orientation.TL_BR, colors);
} else {
drawable = new GradientDrawable();
}
drawable.setCornerRadii(new float[]{topLeftRadius, topLeftRadius,
topRightRadius, topRightRadius,
bottomRightRadius, bottomRightRadius,
bottomLeftRadius, bottomLeftRadius});
drawable.setGradientType(GradientDrawable.RECTANGLE);
hashMap.put(key, drawable);
return drawable;
}
}
} ```
简单用哈希表存了下参数,这个应该叫享元模式,我觉得意义不是很大
适配器
```
class TestAdapter(val context: Context, val list: MutableList
class ViewHolder(item: View) : RecyclerView.ViewHolder(item) {
val layout: ConstraintLayout = item.findViewById(R.id.item_layout)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflate = LayoutInflater.from(context).inflate(R.layout.item, parent, false)
return ViewHolder(inflate)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (position) {
1 -> holder.layout.background = MyShape.setMyShape(context,
10,
ContextCompat.getColor(context, R.color.design_default_color_error)
)
2 -> holder.layout.background = MyShape.setMyShapeStroke(context,
15,
3,
ContextCompat.getColor(context, R.color.design_default_color_primary_dark)
)
3 -> holder.layout.background = MyShape.setMyShapeRadius(context,
ContextCompat.getColor(context, R.color.design_default_color_secondary_variant),
0,
10,
0,
10
)
4 -> holder.layout.background = MyShape.setMyShapeWithAlpha(context,
10,
ContextCompat.getColor(context, android.R.color.holo_green_dark),
50
)
5 -> holder.layout.background = MyShape.setMyShapeRadiusWithBg(context,
15,
0,
15,
0,
ContextCompat.getColor(context,
android.R.color.holo_red_light))
6 -> holder.layout.background = MyShape.setGradient(context,
ContextCompat.getColor(context, android.R.color.holo_purple),
ContextCompat.getColor(context, R.color.black),
15,
15,
15,
15,
180)
}
}
override fun getItemCount(): Int {
return list.size
}
} ```
item ```
```
最终效果
上面的工具类是我在我们公司实际项目中经常使用的,实际上你们可以根据官方提供的API进行更多的创作.
这里面有一个坑,我不修改,我只在这里说哈 就是工具类中
setCornerRadii
他的圆角顺序应该是 左上,右上,右下,左下,里面有一个搞错了,你们使用的时候应该会发现,我就不修了,锻炼下你们的小脑瓜,哈哈哈哈哈.
我这里随便介绍一下API ``` setCornerRadius 设置圆角 setColor 设置背景颜色 setAlpha 设置透明度 setCornerRadii 设置多角度圆角 setStroke 设置边框+边框颜色 setGradientType 设置渐变风格 有四种
GradientDrawable.RECTANGLE 矩形 GradientDrawable.LINE 线 GradientDrawable.RING 圆环 GradientDrawable.OVAL 圆 ```
好啦!常用的大概就是这么多,其实工具类中我也写了点注释,大家不明白的直接评论区提问就好了,如果有时间的话我会尽量回复给大家.
下班!回家!!!
- 学习Android的第十七天
- 这是一个吸猫文章的标题,甚至可以有两行这么多哦
- 学习Android的第四天
- 学习Android的第一天
- 含有边框的TextView-Android
- 电池-Android
- 倒计时封装-Android
- 标题和状态栏滑动渐变(2)-Android
- 标题和状态栏滑动渐变(1)-Android
- 关于选项卡三方库FlycoTabLayout的使用及修改
- 关于第三方库SmartTabLayout的一点小修改
- 关于递归反转链表的思路
- 搜索历史记录的实现-Android
- 感觉让人耳目一新的动画库Lottie
- Android-关于设备唯一ID的奇技淫巧
- 稍微巧妙的双模块联动-ViewPager
- 动画库NineOldAndroids实战自定义悬浮窗
- 关于项目中圆角及特殊圆角的实际使用问题
- 自定义TextView可控制Drawable大小