如何为自定义RelativeLayout内的子View通过代码设置各自样式
为自定义View的子View编程设置自定义样式方案
嘿,我来帮你搞定这个问题!要给自定义View里的子TextView、ImageView设置专属样式,其实可以通过预定义样式资源+代码解析应用的方式来实现,下面给你两种实用的方案:
第一步:先定义好子View的专属样式
首先在res/values/styles.xml里把每个子View的样式写好,比如:
<!-- 自定义TextView样式 --> <style name="CustomTextViewStyle" parent="Widget.AppCompat.TextView"> <item name="android:textColor">#FF4081</item> <item name="android:textSize">16sp</item> <item name="android:padding">8dp</item> </style> <!-- 自定义ImageView样式 --> <style name="CustomImageViewStyle" parent="Widget.AppCompat.ImageView"> <item name="android:scaleType">centerCrop</item> <item name="android:background">#ECEFF1</item> </style>
方案一:直接在自定义View初始化时应用样式
如果你的样式是固定的,不需要外部配置,直接在自定义View的初始化方法里给子View套样式就行:
public class MyCustomView extends RelativeLayout { public MyCustomView(Context context) { super(context); init(context, null); } public MyCustomView(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context context, AttributeSet attrs) { // 加载你的自定义布局 LayoutInflater.from(context).inflate(R.layout.your_custom_view_layout, this, true); // 找到子View TextView infoText = findViewById(R.id.your_text_view_id); ImageView infoImg = findViewById(R.id.your_image_view_id); // 给TextView应用样式 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { infoText.setTextAppearance(R.style.CustomTextViewStyle); } else { // 兼容Android 6.0以下的版本 infoText.setTextAppearance(context, R.style.CustomTextViewStyle); } // 给ImageView应用样式(ImageView没有直接的setStyle方法,得解析样式属性) TypedArray imgStyleArray = context.obtainStyledAttributes( R.style.CustomImageViewStyle, new int[]{android.R.attr.scaleType, android.R.attr.background} ); // 获取scaleType属性 int scaleTypeOrdinal = imgStyleArray.getInt(0, ImageView.ScaleType.CENTER_CROP.ordinal()); infoImg.setScaleType(ImageView.ScaleType.values()[scaleTypeOrdinal]); // 获取背景属性 Drawable bg = imgStyleArray.getDrawable(1); if (bg != null) infoImg.setBackground(bg); // 记得回收TypedArray,避免内存泄漏 imgStyleArray.recycle(); } }
方案二:通过自定义属性让样式可配置
如果想让自定义View更灵活,允许在布局xml里指定子View的样式,可以先定义自定义属性:
在res/values/attrs.xml里添加:
<declare-styleable name="MyCustomView"> <attr name="textViewStyle" format="reference" /> <attr name="imageViewStyle" format="reference" /> </declare-styleable>
然后在自定义View里解析这些属性并应用:
private void init(Context context, AttributeSet attrs) { LayoutInflater.from(context).inflate(R.layout.your_custom_view_layout, this, true); TextView infoText = findViewById(R.id.your_text_view_id); ImageView infoImg = findViewById(R.id.your_image_view_id); // 解析自定义属性 TypedArray customAttrs = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView); // 获取TextView样式,默认用我们预定义的 int textStyleRes = customAttrs.getResourceId( R.styleable.MyCustomView_textViewStyle, R.style.CustomTextViewStyle ); // 获取ImageView样式,默认用预定义的 int imgStyleRes = customAttrs.getResourceId( R.styleable.MyCustomView_imageViewStyle, R.style.CustomImageViewStyle ); customAttrs.recycle(); // 应用TextView样式 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { infoText.setTextAppearance(textStyleRes); } else { infoText.setTextAppearance(context, textStyleRes); } // 应用ImageView样式 applyImageViewStyle(context, infoImg, imgStyleRes); } // 封装一个ImageView样式应用的方法,复用代码 private void applyImageViewStyle(Context context, ImageView imgView, int styleRes) { TypedArray imgStyleArray = context.obtainStyledAttributes( styleRes, new int[]{android.R.attr.scaleType, android.R.attr.background} ); try { int scaleTypeOrdinal = imgStyleArray.getInt(0, ImageView.ScaleType.CENTER_CROP.ordinal()); imgView.setScaleType(ImageView.ScaleType.values()[scaleTypeOrdinal]); Drawable bg = imgStyleArray.getDrawable(1); if (bg != null) imgView.setBackground(bg); } finally { imgStyleArray.recycle(); } }
之后你就可以在布局里这样灵活配置样式了:
<com.yourpackage.MyCustomView android:layout_width="wrap_content" android:layout_height="wrap_content" app:textViewStyle="@style/YourCustomTextStyle" app:imageViewStyle="@style/YourCustomImageStyle" />
小提醒
- 一定要记得回收
TypedArray,不然会造成内存泄漏哦 - 低版本系统(API <23)的
setTextAppearance需要传入Context,不能直接传样式ID - 像ImageView这类没有直接
setStyle方法的View,就得通过TypedArray把样式里的属性逐个解析出来设置
内容的提问来源于stack exchange,提问作者Aman Jain
相关产品推荐
相关产品推荐

