主要介绍通过自定义 View 实现 View 所有边都有圆角及某一边有圆角的功能,替代在 xml 中写 shape;
首先看效果图
1587479574658.jpg1、加一个自定义的属性,某个边是圆角还是都是圆角以及圆角的大小
<declare-styleable name="viewOutLineStrategy">
<!-- 圆角大小 -->
<attr name="clip_radius" format="dimension" />
<attr name="clip_side" format="enum">
<enum name="all" value="0" />
<!-- 左边 -->
<enum name="left" value="1" />
<!-- 上边 -->
<enum name="top" value="2" />
<!-- 右边 -->
<enum name="right" value="3" />
<!-- 下边 -->
<enum name="bottom" value="4" />
</attr>
</declare-styleable>
布局不仅由 FrameLayout 还有 LinearLayout 和 RelativeLayout,都有可能通过这种方式实现圆角,所以自定义属性的解析,我们单独写个类来解析。
下面创建 ViewHelper 类来解析自定义属性:
import android.annotation.TargetApi;
import android.content.res.TypedArray;
import android.graphics.Outline;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
/**
* @desciption: View 帮助类,自定义属性解析
*/
public class ViewHelper {
public static final int RADIUS_ALL = 0;
public static final int RADIUS_LEFT = 1;
public static final int RADIUS_TOP = 2;
public static final int RADIUS_RIGHT = 3;
public static final int RADIUS_BOTTOM = 4;
public static void setViewOutline(View view, AttributeSet attributes, int defStyleAttr, int defStyleRes) {
TypedArray array = view.getContext().obtainStyledAttributes(attributes, R.styleable.viewOutLineStrategy, defStyleAttr, defStyleRes);
int radius = array.getDimensionPixelSize(R.styleable.viewOutLineStrategy_clip_radius, 0);
int hideSide = array.getInt(R.styleable.viewOutLineStrategy_clip_side, 0);
array.recycle();
setViewOutline(view, radius, hideSide);
}
/**
* 设置 view 带有边角的边线
* @param owner view
* @param radius 半径
* @param radiusSide view 的边角
*/
public static void setViewOutline(View owner, final int radius, final int radiusSide) {
owner.setOutlineProvider(new ViewOutlineProvider() {
@Override
@TargetApi(21)
public void getOutline(View view, Outline outline) {
int w = view.getWidth(), h = view.getHeight();
if (w == 0 || h == 0) {
return;
}
//某一边需要圆角
if (radiusSide != RADIUS_ALL) {
int left = 0, top = 0, right = w, bottom = h;
if (radiusSide == RADIUS_LEFT) {
right += radius;
} else if (radiusSide == RADIUS_TOP) {
bottom += radius;
} else if (radiusSide == RADIUS_RIGHT) {
left -= radius;
} else if (radiusSide == RADIUS_BOTTOM) {
top -= radius;
}
outline.setRoundRect(left, top, right, bottom, radius);
return;
}
//所有边需要圆角
int top = 0, bottom = h, left = 0, right = w;
if (radius <= 0) {
outline.setRect(left, top, right, bottom);
} else {
outline.setRoundRect(left, top, right, bottom, radius);
}
}
});
owner.setClipToOutline(radius > 0);
owner.invalidate();
}
}
ViewHelper 类中裁剪代码分析如下:
1587481083065.jpg
红色区域左边被裁剪为圆角,右上角和右下角圆角没有被裁剪掉,因为右边的裁剪区域已经超过了 VIew 的大小。同理其它几边圆角裁剪原理一样。
接下来实现自定义带有 Corner 的 FrameLayout 和 LinearLayout
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* @desciption: 自定义带有 Corner 的 FrameLayout
*/
public class CornerFrameLayout extends FrameLayout {
public CornerFrameLayout(@NonNull Context context) {
this(context, null);
}
public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
ViewHelper.setViewOutline(this, attrs, defStyleAttr, defStyleRes);
}
public void setViewOutline(int radius, int radiusSide) {
ViewHelper.setViewOutline(this, radius, radiusSide);
}
}
接下来实现自定义带有 Corner 的 FrameLayout
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
/**
* @desciption: 自定义带有 Corner 的 LinearLayout
*/
public class CornerLinearLayout extends LinearLayout {
public CornerLinearLayout(Context context) {
this(context, null);
}
public CornerLinearLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CornerLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public CornerLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
ViewHelper.setViewOutline(this, attrs, defStyleAttr, defStyleRes);
}
}
使用方式
和正常使用 View 方式一样,加上自定义的属性即可:
<com.....libcommon.view.CornerFrameLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_16"
android:layout_marginRight="@dimen/dp_16"
android:background="@color/color_gray"
android:paddingLeft="@dimen/dp_10"
android:paddingRight="@dimen/dp_10"
android:paddingBottom="@dimen/dp_10"
app:clip_radius="6dp"
app:clip_side="all"/>
网友评论