1. xml裏寫shape
這種大家比較熟了,最基礎的使用了
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="25dp" />
<solid android:color="#ff0000" />
</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. 自定義形狀
我們就是參考系統的這個來寫
代碼如下
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:menu="@menu/menu_nav_bottom"
app:backgroundTint="#673AB7"
app:fabAlignmentMode="end"
app:fabAnimationMode="slide"
app:fabCradleVerticalOffset="0dp"
app:fabCradleMargin="5dp"
app:fabCradleRoundedCornerRadius="10dp"
app:navigationIcon="@drawable/iv_leaf_1"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/iv_leaf_3"
app:layout_anchor="@id/bar"/>
看了下源碼,實現如下
跟我們參數有關主要就是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個圓角半徑,
相關代碼,都是系統原生的
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomView"
android:layout_width="300dp"
android:layout_height="60dp"
android:layout_marginTop="100dp"
app:menu="@menu/menu_nav_bottom2" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/iv_leaf_3"
app:layout_anchor="@id/bottomView" />
menu
menu_nav_bottom2.xml 中間那個隱藏了,不可用,就佔位用
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/settings_fragment"
android:icon="@drawable/iv_leaf_1"
android:title="settings"
app:showAsAction="always" />
<item
android:id="@+id/second_fragment"
android:enabled="false"
android:icon="@null"
android:title="@null" />
<item
android:id="@+id/third_fragment"
android:icon="@drawable/iv_leaf_3"
android:title="third"
app:showAsAction="always" />
</menu>
效果圖
學完這個,以後複雜形狀自己也能模仿這裏的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個圓角一樣
<com.google.android.material.card.MaterialCardView
app:cardCornerRadius="10dp"
實際上可以設置4個不同的圓角的,另外上邊那個cardCornerRadius優先級比較高
<com.google.android.material.card.MaterialCardView
app:shapeAppearance="@style/cornerCustom"
app:shapeAppearance如下
<style name="cornerCustom">
<item name="cornerSizeTopRight">20dp</item>
<item name="cornerSizeBottomRight">20dp</item>
</style>
至於完整的屬性可以參考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,如下
<style name="cornerCustom">
<item name="cornerSizeTopRight">40dp</item>
<item name="cornerSizeBottomRight">40dp</item>
<item name="cornerFamilyTopRight">cut</item>
</style>
- Chip
系統默認的是兩邊半圓,提供了一個屬性可以修改圓角,不過圓角都一樣的
要是想讓圓角不一樣,那麼也可以通過設置app:shapeAppearance來實現
<com.google.android.material.chip.Chip
後記
對於不支持ShapeAppearanceModel的控件,那麼用MaterialShapeDrawable也可以,給它設置個ShapeAppearanceModel就行了