TextView/EditText显示GIF图片富文本

TextView/EditText显示GIF图片富文本

由于产品要求,app的对话页面中,需要让对话页面中显示动态的gif表情

我查询了一些资料,已找到了很好的解决方案,并编写了GifEmoticonHelper工具类.

具体Demo项目我已上传github,地址: https://github.com/shuihuadx/GifEmoticonDemo
欢迎各位提出意见,相互探讨,共同进步.

效果图

https://github.com/shuihuadx/GifEmoticonDemo/tree/master/img/gifEmoticonListDemo.gif

解决方案

首先在build.gradle引入android-gif-drawable依赖:

implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.19'

然后,将 GifEmoticonHelper.java 类复制到你的项目中( GifEmoticonHelper.java 是我写的一个单例类,根据 android-gif-drawable开源库进行了简单封装,方便gif表情的展示),这里先贴一下 GifEmoticonHelper.java 类的主要方法:

public static GifEmoticonHelper getInstance() {
    // 代码略...
}
/**
 * 根据gif表情路径获取GifDrawable对象
 * 注意点:
 * 返回的GifDrawable默认没有自动刷新,需要调用GifEmoticonHelper的playTextViewGifEmoticon(TextView)方法播放;
 * @param emoticonAssetPath 表情的assets/路径,如"emoticon-res/e1.gif"
 * @return 实际的GifDrawable对象, 默认尺寸为30x30dp, 默认情况下是停止播放的
 */
public GifDrawable getGifDrawable(Context context, String emoticonAssetPath) {
    // 代码略...
}

/**
 * 开始播放TextView富文本中的gif表情,通常在TextView可见的时候调用
 * @param tv 由于EditText属于TextView的子类,所以也可以传入EditText
 */
public void playGifEmoticon(TextView tv) {
    // 代码略...
}

/**
 * 停止播放TextView富文本中的gif表情,以节省cpu资源
 * 通常在TextView不可见的时候调用当前方法,例如RecyclerView#onViewRecycled()方法被调用时
 * @param tv 由于EditText属于TextView的子类,所以也可以传入EditText
 */
public void stopGifEmoticon(TextView tv) {
    // 代码略...
}

GifEmoticonHelper的完整代码: https://github.com/shuihuadx/UtilProject/blob/master/app/src/main/java/com/example/dx/utilproject/pic/GifEmoticonHelper.java

为了便于理解,这里我写了一个TextView展示gif富文本表情的demo:

public class MainActivity extends AppCompatActivity {
    private TextView gifEmoticonTv;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        gifEmoticonTv = findViewById(R.id.gif_emoticon_tv);

        // 我将gif表情资源放在了assets/emoticon-res/目录下
        GifDrawable gifDrawable = GifEmoticonHelper.getInstance()
                .getGifDrawable(MainActivity.this, "emoticon-res/e1.gif");
        // 设置gif表情的长宽各为30dp
        int emoticonSize = dp2px(MainActivity.this, 30);
        gifDrawable.setBounds(0, 0, emoticonSize, emoticonSize);
        // 创建一个图片富文本对象
        ImageSpan gifImageSpan = new ImageSpan(gifDrawable);

        SpannableStringBuilder ssBuilder = new SpannableStringBuilder("123456789");
        // 将ssBuilder中的第4个字符设为图片富文本
        ssBuilder.setSpan(gifImageSpan, 3, 4, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
        gifEmoticonTv.setText(ssBuilder);
    }

    private int dp2px(Context context, int dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // 开始播放gif表情
        GifEmoticonHelper.getInstance().playGifEmoticon(gifEmoticonTv);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 停止播放gif表情,以节省系统资源
        GifEmoticonHelper.getInstance().stopGifEmoticon(gifEmoticonTv);
    }
}

运行效果如下效果如下:

gifEmoticonDemo

GifEmoticonHelper解决的问题

一. gif表情在播放一段时间以后,自己会停住
查看Drawable#setCallback(Callback cb)方法的源码如下:

/**
* Bind a {@link Callback} object to this Drawable.  Required for clients
* that want to support animated drawables.
*
* @param cb The client's Callback implementation.
*
* @see #getCallback()
*/
public final void setCallback(@Nullable Callback cb) {
    mCallback = cb != null ? new WeakReference<>(cb) : null;
}

我们看到,Drawable内部持有的是一个Callback弱引用,当Callback被回收以后,gif图片的播放也就停止了

解决方法: 外部再持有一次Callback的强引用,阻止Android系统对Callback的回收。

二. 每次创建GifDrawable对象时,都会读取一次硬盘,导致列表滑动时卡顿

解决办法:

  1. 使用LruCache对GifDrawable加个缓存,当检测到缓存中存在目标GifDrawable时,就使用缓存;
  2. 一个GifDrawable对象与多个TextView关联,当GifDrawable刷新下一帧时,将其关联的所有可见的TextView都刷新.

三. 显示gif富文本的TextView被回收以后,后台的GifDrawable仍然在进行gif图片播放,导致资源浪费

解决办法: 当页面不可见时,暂停gif图片的播放.例如:

  1. Activity#onStop()方法被调用时;
  2. RecyclerView#onViewRecycled()方法被调用时;
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Android 中,TextViewEditText 都是常用的用户界面元素,用于显示文本和接收用户输入。layout_constraintEnd_toEndOf 属性是用于约束布局的属性,用于指定视图的右侧边缘与另一个视图的右侧边缘对齐。 下面是对 TextViewEditText 的 layout_constraintEnd_toEndOf 属性的使用方法的说明: 1. 布局文件中添加 TextViewEditText 元素: ```xml <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is a TextView" /> <EditText android:id="@+id/editText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="Enter text here" /> ``` 2. 使用 layout_constraintEnd_toEndOf 属性约束 TextViewEditText: ```xml <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is a TextView" app:layout_constraintEnd_toEndOf="@id/editText" /> <EditText android:id="@+id/editText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="Enter text here" /> ``` 在上述代码中,TextView 的 layout_constraintEnd_toEndOf 属性被设置为 @id/editText,表示 TextView 的右侧边缘与 EditText 的右侧边缘对齐。 这样,当布局被渲染时,TextView 的右侧边缘将与 EditText 的右侧边缘对齐,从而实现了视图之间的约束关系。 希望这个回答对你有帮助!如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值