1. xml里写shape
这种大家比较熟了,最基础的使用了
2. java代码生成drawable
如下一个简单的圆角矩形,
var shape=RoundRectShape(floatArrayOf(10f,10f,10f,10f,10f,10f,10f,10f),null,null);
var drawble=ShapeDrawable(shape).apply { setColorFilter(Color.RED,PorterDuff.Mode.SRC_IN) }
tv_test.background=drawble
var pD=PaintDrawable(Color.RED);
pD.setCornerRadius(20f);
tv_test2.background=pD;
其实xml里能有的drawalbe,java代码都有对应的,我们这里只看圆角矩形
没找到stroke咋设置,等有空再看看
3 outline
对于21以上 的版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
findViewById(R.id.iv_temp).setClipToOutline(true);
findViewById(R.id.iv_temp).setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0,0,view.getWidth(),view.getHeight(),20);
}
});
}
4. 自定义形状
我们就是参考系统的这个来写
代碼如下
看了下源码,实现如下
跟我们参数有关主要就是BottomAppBarTopEdgeTreatment类了,不过看了下这类如下两个设置fab直径以及凹槽偏移量的方法不是公用的。瞅了眼这个类也没几行代码,那就复制下这个类,把下边两个方法弄成公共的就完事了
@RestrictTo(LIBRARY_GROUP)
public void setFabDiameter(float fabDiameter) {
this.fabDiameter = fabDiameter;
}
/** Sets the horizontal offset, in pixels, of the cradle from center. */
void setHorizontalOffset(float horizontalOffset) {
this.horizontalOffset = horizontalOffset;
}
最终代码如下
BottomNavViewTopEdgeTreatment类 就是修改的系统类
private val materialShapeDrawable = MaterialShapeDrawable()
val topEdgeTreatment: EdgeTreatment = BottomNavViewTopEdgeTreatment(10f, 5f, 0f)
val shapeAppearanceModel = ShapeAppearanceModel.builder().setTopEdge(topEdgeTreatment)
.setAllCornerSizes(30f)
.build()
materialShapeDrawable.shapeAppearanceModel = shapeAppearanceModel
materialShapeDrawable.shadowCompatibilityMode = MaterialShapeDrawable.SHADOW_COMPAT_MODE_ALWAYS
materialShapeDrawable.paintStyle = Paint.Style.FILL
materialShapeDrawable.interpolation=1f
materialShapeDrawable.initializeElevationOverlay(this)
DrawableCompat.setTintList(materialShapeDrawable, ColorStateList.valueOf(Color.GREEN));
getTopEdgeTreatment()?.horizontalOffset=0f;//默认凹槽在正中心,这里可以左右偏移
getTopEdgeTreatment()?.fabDiameter=60f//就是那个floatingActionBar的直径
ViewCompat.setBackground(bottomView, materialShapeDrawable)
ShapeAppearanceModel这个类可以简单看下,可以设置四条边的path,我们这里就设置的是top,完事还可以设置4个圆角半径,
相关代码,都是系统原生的
menu
menu_nav_bottom2.xml 中间那个隐藏了,不可用,就占位用
效果图
学完这个,以后复杂形状自己也能模仿这里的path自己弄出来了
其他字段的解释,以前有篇帖子研究过BottomAppBar,这几个属性有说明
fabMargin :就是fab和凹槽之间的间隔距离
roundedCornerRadius :这个是凹槽那个圆弧和横线之间还有个圆弧的,就是那个圆弧的半径
cradleVerticalOffset :凹槽的偏移量,为0的话凹槽刚好是个半圆,为正的话凹槽上移,为负抛出异常
/**
* @param fabMargin the margin in pixels between the cutout and the fab.
* @param roundedCornerRadius the radius, in pixels, of the rounded corners created by the cutout.
* A value of 0 will produce a sharp cutout.
* @param cradleVerticalOffset vertical offset, in pixels, of the {@link FloatingActionButton}
* being cradled. An offset of 0 indicates the vertical center of the {@link
* FloatingActionButton} is positioned on the top edge.
*/
public BottomAppBarTopEdgeTreatment(
float fabMargin, float roundedCornerRadius, float cradleVerticalOffset)
参考:
https://www.jianshu.com/p/8cd6add34f19
写不了太复杂的path,一会就晕了,所以就偷懒用系统写好的,修修补补就可以用了。
看下一些系统控件的使用:
- MaterialButton
ShapeAppearanceModel shapeAppearanceModel =
ShapeAppearanceModel.builder(context, attrs, defStyleAttr, DEF_STYLE_RES).build();
private void updateButtonShape(@NonNull ShapeAppearanceModel shapeAppearanceModel) {
if (getMaterialShapeDrawable() != null) {
getMaterialShapeDrawable().setShapeAppearanceModel(shapeAppearanceModel);
}
if (getSurfaceColorStrokeDrawable() != null) {
getSurfaceColorStrokeDrawable().setShapeAppearanceModel(shapeAppearanceModel);
}
if (getMaskDrawable() != null) {
getMaskDrawable().setShapeAppearanceModel(shapeAppearanceModel);
}
}
- CardView
这里用的是RoundRectDrawable
public void initialize(CardViewDelegate cardView, Context context,
ColorStateList backgroundColor, float radius, float elevation, float maxElevation) {
final RoundRectDrawable background = new RoundRectDrawable(backgroundColor, radius);
cardView.setCardBackground(background);
View view = cardView.getCardView();
view.setClipToOutline(true);
view.setElevation(elevation);
setMaxElevation(cardView, maxElevation);
}
- MaterialCardView
//MaterialCardViewHelper
bgDrawable = new MaterialShapeDrawable(card.getContext(), attrs, defStyleAttr, defStyleRes);
bgDrawable.initializeElevationOverlay(card.getContext());
bgDrawable.setShadowColor(Color.DKGRAY);
ShapeAppearanceModel.Builder shapeAppearanceModelBuilder =
bgDrawable.getShapeAppearanceModel().toBuilder();
另外我们使用这个控件的时候发现它只提供了一个radius的设置,也就是只能4个圆角一样
实际上可以设置4个不同的圆角的,另外上边那个cardCornerRadius优先级比较高
app:shapeAppearance如下
至于完整的属性可以参考ShapeAppearanceModel
int cornerFamily = a.getInt(R.styleable.ShapeAppearance_cornerFamily, CornerFamily.ROUNDED);
int cornerFamilyTopLeft =
a.getInt(R.styleable.ShapeAppearance_cornerFamilyTopLeft, cornerFamily);
int cornerFamilyTopRight =
a.getInt(R.styleable.ShapeAppearance_cornerFamilyTopRight, cornerFamily);
int cornerFamilyBottomRight =
a.getInt(R.styleable.ShapeAppearance_cornerFamilyBottomRight, cornerFamily);
int cornerFamilyBottomLeft =
a.getInt(R.styleable.ShapeAppearance_cornerFamilyBottomLeft, cornerFamily);
CornerSize cornerSize =
getCornerSize(a, R.styleable.ShapeAppearance_cornerSize, defaultCornerSize);
CornerSize cornerSizeTopLeft =
getCornerSize(a, R.styleable.ShapeAppearance_cornerSizeTopLeft, cornerSize);
CornerSize cornerSizeTopRight =
getCornerSize(a, R.styleable.ShapeAppearance_cornerSizeTopRight, cornerSize);
CornerSize cornerSizeBottomRight =
getCornerSize(a, R.styleable.ShapeAppearance_cornerSizeBottomRight, cornerSize);
CornerSize cornerSizeBottomLeft =
getCornerSize(a, R.styleable.ShapeAppearance_cornerSizeBottomLeft, cornerSize);
另外看下CornerFamily的效果,默认就是Rounded圆角,还有一种是Cut,如下
- Chip
系统默认的是两边半圆,提供了一个属性可以修改圆角,不过圆角都一样的
要是想让圆角不一样,那么也可以通过设置app:shapeAppearance来实现