最近写一个自定义控件,发现 MaterialButton 相关的问题颇多,在此记录
1. MaterialButton 文字与 Icon 的BUG
- MaterialButton width match_parent, 设置 Gravity 为 START,IconGravity 为 textEnd
结果按钮与文字之间有一定距离,后来在GitHub上发现这是一个BUG,升级版本修复
- MaterialButton width wrap_content,IconGravity 为 textEnd
结果 Icon跑到文字前边,后来发现只能设置 IconGravity 为 end
2. 如何让 MaterialButton 的大小变小,或者说看起来像TextView
结合使用minWidth/minHeight
,minimalWidth/minimalHeight
,insetTop/...
,leftPadding/...
3. OutlinedButton 宽度问题
设置三个View,分别为 MaterialButton、TextView、View
统一设置背景、文字颜色、文字大小,比较各长度
View 是通过测量出数字然后设置宽度
文字 | 打印 |
---|---|
My Application | 295,292, 292 |
My ApplicationApplication | 519,514, 514 |
另外一台手机居然三个数字都不同
发现跟背景、圆角都没关系,代码里设置 background 为 null 也不行
跟上面第二点的最小宽度也没关系
甚至 IconSize 和 IconPadding 我也尝试了,没有关系
然后看显示效果,发现 Button 的文字粗一些,难道跟 fontWeight 有关系?
显示效果确实是,修改 TypeFace 之后宽度一样了
继续研究,发现
MaterialButton 默认的是TypeFace@20046,style为0,weight为500
MaterialTextView 默认的是TypeFace@20087,style为0,weight为400
TextView使用的是默认字体,这个每个手机都可以自己设置,我这里是TypefaceCompat.create(it.context, Typeface.SANS_SERIF, Typeface.NORMAL)
而 MaterialButton 是 style 为Widget.MaterialComponents.Button
下的<item name="android:textAppearance">?attr/textAppearanceButton</item>
指定的
继续找,发现textAppearance
是在style为Widget.Material.Button
下的<item name="textAppearance">?attr/textAppearanceButton</item>
指定的。
也就是说,取决于我们项目中使用的主题里面的这个属性
而我的测试Demo是Theme.MaterialComponents.DayNight.DarkActionBar
,继续看一下。
Base.V14.Theme.MaterialComponents.Light.Bridge
=> <item name="textAppearanceButton">@style/TextAppearance.MaterialComponents.Button</item>
最终找到
<style name="TextAppearance.MaterialComponents.Button" parent="Base.TextAppearance.MaterialComponents.Button">
<!-- Roboto Medium was added in this api level -->
<item name="fontFamily">sans-serif-medium</item>
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textStyle">normal</item>
结论:
Button、TextView等即使去除所有影响布局的因素仍然可能大小不同,本质是字体不同,MaterialButton 默认使用 FontWeight 为500的字体,而 FontWeight 在API28才被添加。
TextPaint 也有个 TypeFace,所以很可能出现三个不一样的值。
测试代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:insetTop="0dp"
android:insetBottom="0dp"
android:letterSpacing="0"
android:minWidth="0dp"
android:minHeight="0dp"
android:padding="0dp"
android:text="@string/app_name"
android:textAllCaps="false"
android:textColor="@android:color/holo_red_dark"
android:textSize="16dp"
app:backgroundTint="@color/black"
app:cornerRadius="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:strokeWidth="0dp" />
<TextView
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:background="@color/black"
android:text="@string/app_name"
android:textColor="@android:color/holo_red_dark"
android:textSize="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn" />
<View
android:id="@+id/test"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginTop="2dp"
android:background="@color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn2" />
</androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {
private lateinit var mBinding: ActivityMainBinding
private var itemCount = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(mBinding.root)
val paint = TextPaint(Paint.ANTI_ALIAS_FLAG)
paint.textSize = 16.dp
mBinding.test.doOnPreDraw {
val w = paint.measureText(it.context.getString(R.string.app_name)).toInt()
it.layoutParams.width = w
Log.d("lq","${mBinding.btn.measuredWidth},${mBinding.btn2.measuredWidth}, $w")
}
}
}
网友评论