自定义控件中drawableStart、drawableEnd属性不生效问题

在项目中遇到一个问题,在自定义的EditTextWithDel控件中,drawableLeft设置正常,但drawableStart无法正常生效,按正常理解在常规的左右布局中,这俩应该效果是一样的。

​ 先说结论:其实是该自定义控件中的一个设置不完善,但如果你在网上拷贝代码的话,大家基本上都未对这个添加特别处理。

关键代码:

setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], rightDrawable, getCompoundDrawables()[3]);
复制代码

解决方案也容易,添加处理如下:

Drawable leftDrawable = null == getCompoundDrawables()[0] ? getCompoundDrawablesRelative()[0] : getCompoundDrawables()[0];
setCompoundDrawables(leftDrawable, getCompoundDrawables()[1], rightDrawable, getCompoundDrawables()[3]);
复制代码

​ 在android sdk版本17之后,安卓新增了supportsRtl属性,在设置-开发者选项中有一个“强制使用从右到左布局方向”的选项,如果supportsRtl属性为true时,可使布局从右到左排列,其主要作用是在国际化项目中,当手机在诸如阿拉伯语、希伯来语等环境中,会自动修改为从右往左的布局。

<Application
     android:label="DT示例demo"
     android:supportsRtl="true">
	<activity />
</Application>
复制代码

​ 由此安卓中新增了诸如marginStart/End、paddingStart/End、drawableStart/End等属性及***其它一些相关设置方法***,而在Android Studio等IDE的默认inspection中也会标黄提示建议用Start、End代替。也正是因此导致本人这种强迫症患者在日常开发中也喜欢用Start/End这种设置方式,即便不是国际化项目。

​ 回到上面提到的问题,我的代码是这样的:

<com.xxx.view.EditTextWithDel
            android:id="@+id/search_et"
            android:layout_width="0dp"
            android:layout_height="36dp"
            android:layout_weight="5"
            android:background="@null"
            android:drawableLeft="@drawable/search_icon"
            android:gravity="center_vertical"
            android:hint="搜索"
            android:imeOptions="actionDone"
            android:singleLine="true"
            android:textColorHint="@color/light_text_color"
            android:textSize="16sp" />
复制代码

按常规理解,drawableLeft和drawableStart应该效果是等同的,但工程运行后的效果是,如果用drawableLeft显示正常,但用drawableStart就无效。

因为EditText是TextView子类,看TextView源码中有以下四个方法(***WithIntrinsicBounds方法类似):

/**
 * ...
 * Calling this method will overwrite any Drawables previously set using
 * {@link #setCompoundDrawablesRelative} or related methods.
*/
public void setCompoundDrawables(@Nullable Drawable left, @Nullable Drawable top,
            @Nullable Drawable right, @Nullable Drawable bottom){
            //...
}//方法1

/**
 * ...
 * Calling this method will overwrite any Drawables previously set using
 * {@link #setCompoundDrawables} or related methods.
*/
public void setCompoundDrawablesRelative(@Nullable Drawable start, @Nullable Drawable top,
            @Nullable Drawable end, @Nullable Drawable bottom) {
            //...
}//方法2

/**
 * Returns drawables for the left, top, right, and bottom borders.
 *
 * @attr ref android.R.styleable#TextView_drawableLeft
 * @attr ref android.R.styleable#TextView_drawableTop
 * @attr ref android.R.styleable#TextView_drawableRight
 * @attr ref android.R.styleable#TextView_drawableBottom
*/
public Drawable[] getCompoundDrawables() {
    //...
}//方法3

/**
 * Returns drawables for the start, top, end, and bottom borders.
 *
 * @attr ref android.R.styleable#TextView_drawableStart
 * @attr ref android.R.styleable#TextView_drawableTop
 * @attr ref android.R.styleable#TextView_drawableEnd
 * @attr ref android.R.styleable#TextView_drawableBottom
*/
public Drawable[] getCompoundDrawablesRelative() {
		//...
}//方法4
复制代码

网上找到的类似自定义EditTextWithDel控件都是上述方法1和方法3的结合,即默认都走left/right这一套。

而通过源码中的注释可知,方法1和方法2可以覆盖彼此。所以单调其中任一个其实没什么影响,但方法3和方法4就不同了

仔细查阅源码可知,在TextView中有一个内部类Drawables,它包含若干个Drawable如: mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight, mDrawableStart, mDrawableEnd, mDrawableError, mDrawableTemp, mDrawableLeftInitial, mDrawableRightInitial等,

getCompoundDrawables()取到的数组是new Drawable[] {dr.mDrawableLeft, dr.mDrawableTop, dr.mDrawableRight, dr.mDrawableBottom}

getCompoundDrawablesRelative()取到的数组是new Drawable[] {dr.mDrawableStart, dr.mDrawableTop, dr.mDrawableEnd, dr.mDrawableBottom}

所以getCompoundDrawables()只能取到left位的drawable,这也是drawableStart未生效的原因,实际上

setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], rightDrawable, getCompoundDrawables()[3]);方法中第一个参数取到的是null,将drawableStart设置的图片替换掉了,所以运行结果是drawableStart看似未生效。

那么为什么正常设置drawableStart属性没有问题呢?查源码可知,在TextView的onResolveDrawables周期方法中有调用Drawables的**resolveWithLayoutDirection()**方法,正是在这个方法中将mDrawableStart(!=null)赋值给mDrawableLeft的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Cannot initialize RTSP codec context: " << av_err2str(ret) << endl; return 1; } ret = av好的,这是一个关于自定义控件属性问题。在 Android ,我们可以通过自定义属性为自定义codec_open2(rtsp_codec_ctx, rtsp_codec, NULL); if (ret < 0) { cout << "Cannot控件提供一些可配置的属性值。想要调用自定义控件并设置其属性值,可以按照 open RTSP codec: " << av_err2str(ret) << endl; return 1; } // 打开HTTP-以下步骤进行: 1. 在 res/values/attrs.xml 定义自定义属性,例如: ```xml <resources> <declare-styleable name="CustomView"> <attr name="customAttr" format="string" /> </declare-styleable> </resourcesFLV地址 avformat_alloc_output_context2(&http_flv_ctx, NULL, "flv", http_flv_url); > ``` 这里定义了一个名为 CustomView 的自定义属性集合,其包含一个名为 customAttr 的属性 if (http_flv_ctx == NULL) { cout << "Cannot allocate HTTP-FLV output context" << endl; return,格式为字符串。 2. 在自定义控件的构造函数,通过 AttributeSet 获取自定义属性的值,例如: 1; } // 查找HTTP-FLV编码器 http_flv_codec = avcodec_find_encoder_by_name```java public class CustomView extends View { private String customAttrValue; public CustomView(Context context, AttributeSet attrs) { ("libx264"); if (http_flv_codec == NULL) { cout << "Cannot find encoder for codec libx264 super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView); customAttrValue = a" << endl; return 1; } // 添加HTTP-FLV流 AVStream* stream = avformat_new.getString(R.styleable.CustomView_customAttr); a.recycle(); } } ``` 这里通过 TypedArray 获取自定义属性值,注意_stream(http_flv_ctx, NULL); if (stream == NULL) { cout << "Cannot create new stream for HTTP-FL需要使用 R.styleable.CustomView 来获取自定义属性集合,并使用 a.recycle() 回收 TypedArray。 3. 在布局文件V output" << endl; return 1; } // 设置HTTP-FLV编码器上下文参数 使用自定义控件,并设置自定义属性值,例如: ```xml <com.example.CustomView android:layout_width http_flv_codec_ctx = avcodec_alloc_context3(http_flv_codec); if (http_flv_codec_ctx == NULL) { ="wrap_content" android:layout_height="wrap_content" app:customAttr="someValue" /> ``` 这里通过 app cout << "Cannot allocate codec context for encoder libx264" << endl; return 1; } http_flv_codec:customAttr 设置自定义属性的值。 希望这个回答能够解决你的问题。如果还有疑问,请随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tried Not Tired

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值