Android 布局圆角方案总结 | 您所在的位置:网站首页 › ps照片变圆角四个小圆角消除不了 › Android 布局圆角方案总结 |
一.遇到的问题
最近在开发中会遇到Android布局切圆角的需求,大多数是对一个layout布局切下圆角。这里和图片切圆角有一些雷同的地方,可以相互借鉴,但是也不全一样。图片切圆角的一些总结和实践准备下次有空再写出来。 假设我们要对一种LinearLayout布局切圆角,不知道你能想出来哪些办法。我这里先提供下我的思路,亲自实践过的主要包括下面五种: 1.利用xml背景文件配置shape属性实现切圆角 2.利用GradientDrawable实现切圆角 3.利用clipPath实现切圆角 4.利用CardView实现切圆角 5.利用ViewOutlineProvider实现切圆角 下面分别对这几种方式进行实践与优缺点分析,原理讲解较少,感兴趣可以自己再深入了解下。 二.利用xml背景文件配置shape属性实现 2.1方案实现 这种方式相比大家都比较熟悉了,就是在drawable文件夹下新建一个App Action XML File,然后作为background属性添加到Layout XML File中。 如果要生成四个角都为10dp圆角的形状我们可以在drawable文件夹下新建如下shape_10dp_corners.xml文件 如果仅要生成上方两个10dp圆角的形状我们可以在drawable文件夹下新建如下shape_10dp_top_corners.xml文件 如果仅要生成上方两个10dp圆角的形状我们可以在drawable文件夹下新建如下shape_10dp_bottom_right_corners.xml文件 然后在XmlShapeActivity的布局XML文件中为对应的三个LinearLayout分别设置background属性如下 然后勉为其难地贴一下打酱油的XmlShapeActivity代码 package com.openld.roundcornerdemmo.xmlshape; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import com.openld.roundcornerdemmo.R; public class XmlShapeActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_xml_shape); } } 2.1运行效果 2.3优缺点 优点:1.最简单 2.四个圆角可以单独定制,也可以统一处理 3.还可以一并设置背景颜色等属性 4.圆角无锯齿 缺点: 1.圆角属性是提前确定的并写在客户端本地的drawable中,如果是动态下发再去配置的话这种方式无法支持。 2.如果子View长宽都match_parent并且设置一个有色background属性的话,圆角就消失了。 三.利用GradientDrawable实现切圆角 3.1 方案实现 有没有想过动态地在Java代码中为layout设置圆角,那就想到了GradientDrawable。其实是和第一种XML方式呼应的,只不过没有办法让你你动态去配置XML,那就用GradientDrawable吧,XML shape中能设置的属性这里也能哦! 这里先贴一下GradientDrawableActivity的布局XML 再贴一下GradientDrawableActivity的代码 package com.openld.roundcornerdemmo.gradientdrawable; import android.graphics.drawable.GradientDrawable; import android.os.Bundle; import android.widget.LinearLayout; import androidx.appcompat.app.AppCompatActivity; import com.openld.roundcornerdemmo.R; import com.openld.roundcornerdemmo.utils.DisplayUtils; public class GradientDrawableActivity extends AppCompatActivity { private LinearLayout mLly1; private LinearLayout mLly2; private LinearLayout mLly3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_gradient_drawable); initWidgets(); } private void initWidgets() { mLly1 = findViewById(R.id.lly1); GradientDrawable gradientDrawable1 = new GradientDrawable(); gradientDrawable1.setShape(GradientDrawable.RECTANGLE); gradientDrawable1.setCornerRadius(DisplayUtils.dp2px(this, 10F)); gradientDrawable1.setColor(getResources().getColor(R.color.colorPrimary)); mLly1.setBackground(gradientDrawable1); mLly2 = findViewById(R.id.lly2); GradientDrawable gradientDrawable2 = new GradientDrawable(); gradientDrawable2.setShape(GradientDrawable.RECTANGLE); gradientDrawable2.setColor(getResources().getColor(R.color.colorAccent)); float[] radii = new float[]{ DisplayUtils.dp2px(this, 10F), DisplayUtils.dp2px(this, 10F), 0F, 0F, 0F, 0F, DisplayUtils.dp2px(this, 10F), DisplayUtils.dp2px(this, 10F) }; gradientDrawable2.setCornerRadii(radii); mLly2.setBackground(gradientDrawable2); mLly3 = findViewById(R.id.lly3); GradientDrawable gradientDrawable3 = new GradientDrawable(); gradientDrawable3.setShape(GradientDrawable.RECTANGLE); gradientDrawable3.setColor(getResources().getColor(R.color.colorPrimary)); float[] radii1 = new float[]{ DisplayUtils.dp2px(this, 10F), DisplayUtils.dp2px(this, 10F), 0F, 0F, 0F, 0F, 0F, 0F }; gradientDrawable3.setCornerRadii(radii1); mLly3.setBackground(gradientDrawable3); } }核心代码都在initWidgets()方法中,里面实例化一个GradientDrawable对象,设置一下对应的属性。setCornerRadii()或者se'tCornerRadius()方法即为设置圆角,具体可以看下API,这里不再赘述。 3.2 运行效果 3.3 优缺点 优点: 1.支持动态配置啊 2.四个圆角可以单独定制,也可以统一处理 3.还可以一并设置背景颜色等属性 4.圆角无锯齿 缺点 1.如果子View长宽都match_parent并且设置一个有色background属性的话,圆角就消失了。 四. 利用clipPath实现切圆角 4.1 方案实现 继承现有的布局,在draw()方法中使用clipPath()方法切割你想要的形状,只要切割出一个圆角矩形即可。 比如新建一个继承LinearLayout的CornersLinearLayout package com.openld.roundcornerdemmo.clippath; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Path; import android.graphics.RectF; import android.util.AttributeSet; import android.widget.LinearLayout; import androidx.annotation.Nullable; import com.openld.roundcornerdemmo.R; /** * author: lllddd * created on: 2020/6/9 10:55 * description: */ public class CornersLinearLayout extends LinearLayout { private Context mContext; private float mCorners; private float mLeftTopCorner; private float mRightTopCorner; private float mLeftBottomCorner; private float mRightBottomCorner; private int mWidth; private int mHeight; public CornersLinearLayout(Context context) { this(context, null); } public CornersLinearLayout(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public CornersLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CornersLinearLayout); mCorners = typedArray.getDimension(R.styleable.CornersLinearLayout_corner, 0F); mLeftTopCorner = typedArray.getDimension(R.styleable.CornersLinearLayout_leftTopCorner, 0F); mRightTopCorner = typedArray.getDimension(R.styleable.CornersLinearLayout_rightTopCorner, 0F); mRightBottomCorner = typedArray.getDimension(R.styleable.CornersLinearLayout_rightBottomCorner, 0F); mLeftBottomCorner = typedArray.getDimension(R.styleable.CornersLinearLayout_leftBottomCorner, 0F); typedArray.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); setMeasuredDimension(mWidth, mHeight); } @Override public void draw(Canvas canvas) { canvas.save(); Path path = new Path(); RectF rectF = new RectF(0, 0, mWidth, mHeight); if (mCorners > 0F) { path.addRoundRect(rectF, mCorners, mCorners, Path.Direction.CCW); } else { float[] radii = new float[]{ mLeftTopCorner, mLeftTopCorner, mRightTopCorner, mRightTopCorner, mRightBottomCorner, mRightBottomCorner, mLeftBottomCorner, mLeftBottomCorner }; path.addRoundRect(rectF, radii, Path.Direction.CCW); } canvas.clipPath(path); super.draw(canvas); } }相关的属性声明在style.xml文件中配置,这里不涉及。draw()方法是在onDraw()之前的一个方法,在这里可以使用clipPath()裁剪出一个圆角矩形轮廓。调用canvas.clipPath(path)生效,之后再执行super方法即可。 4.2 运行效果 4.3 优缺点 优点: 1.整个外层轮廓都切成圆角矩形,子View的background不会影响到圆角 2.四个角可以单独配置也可以统一配置 缺点: 1.无法抗锯齿,在一些老的手机上面效果可能差强人意 2.需要实现自己的自定义布局 五.利用CardView实现切圆角 5.1 方案实现 CardView是v7包中的组件(ViewGroup),主要用来设置布局的边框为圆角、z轴的偏移量(这个是5.0以后才有的概念,也就是阴影的效果)。这里我们仅仅使用圆角功能。 实现一个带CardView的布局 对应activity的代码就没必要贴了,XML布局中 app:cardCornerRadius="10dp"即配置四个角为10dp的圆角 5.2 运行效果 5.3 优缺点 优点: 1.Google的控件,效果和稳定性都是杠杠的,还支持阴影等其他的配置 2.抗锯齿 缺点: 1.四个角要一起配置,不支持其中若干个角单独配置 2.使用时外层要嵌套CardView 六.利用ViewOutlineProvider实现切圆角 6.1 方案实现 利用ViewOutlineProvider设置轮廓切圆角。 对应ViewOutlineProviderActivity的布局XML如下 ViewOutlineProviderActivity代码如下 package com.openld.roundcornerdemmo.viewoutlineprovider; import android.graphics.Outline; import android.os.Build; import android.os.Bundle; import android.view.View; import android.view.ViewOutlineProvider; import android.widget.LinearLayout; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import com.openld.roundcornerdemmo.R; import com.openld.roundcornerdemmo.utils.DisplayUtils; public class ViewOutlineProviderActivity extends AppCompatActivity { private LinearLayout mLly; @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view_outline_provider); initWidgets(); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void initWidgets() { mLly = findViewById(R.id.lly); mLly.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), DisplayUtils.dp2px(ViewOutlineProviderActivity.this, 10F)); } }); mLly.setClipToOutline(true); } }关键就是mLly.setOutlineProvider()与mLly.setClipToOutline()两个方法的使用。 6.2 运行效果 6.3 优缺点 优点: 1.支持动态下发与配置 缺点: 1.只能四个角同时配置不支持每个角单独配置 七.源码位置 链接地址
|
CopyRight 2018-2019 实验室设备网 版权所有 |