SelectTextHelper
 Introduction:  高仿微信聊天消息列表自由复制文字,双击查看文本内容,用法超级简单~
 Tags:  
掘金地址 github 地址
SelectTextHelper打造一个全网最逼近微信聊天消息自由复制,双击查看文本内容框架。 支持图片和富文本选中,汇聚底层TextView框架、原理并加以整理得出的一个实用的Helper。
仅用几个类实现便实现如此强大的功能,用法也超级简单,侵入性极低。
项目持续维护中... 您的宝贵意见和建议是技术前进的方向
项目演示
| 消息页效果 | 查看内容效果 | 
|---|---|
| 消息页全选 | 消息页自由复制放大镜 | 
|---|---|
| 消息页选中文本 | 查看内容 | 
|---|---|
特点功能:
- 支持自由选择文本
 - 支持
富文本选择 - 支持自定义文本有:游标颜色、游标大小、选中文本颜色
 - 支持默认全选文字或选 2 个文字
 - 支持滑动依然显示弹窗
 - 支持放大镜功能
 - 支持全选情况下自定义弹窗
 - 支持操作弹窗:每行个数、图片、文字、监听回调、弹窗颜色、箭头图片
 
Demo
如何添加
Gradle 添加:
1.在 Project 的build.gradle中添加仓库地址
allprojects {
  repositories {
     ...
     maven { url "https://jitpack.io" }
  }
}
2.在 Module 目录下的build.gradle中添加依赖
dependencies {
       implementation 'com.github.ITxiaoguang:SelectTextHelper:1.1.0'
}
传送门
主要实现
通过 仿照的例子 并改进弹窗坐标位置、加对 ImageSpan 支持、大小加上EventBus实现
简单用例
1.导入代码
把该项目里的selecttext Module放入你的项目里面 或者 按照Gradle添加的步骤导入依赖。
2.给你的TextView创建Helper和加监听
val mSelectableTextHelper = SelectTextHelper.Builder(textView) // 放你的 textView 到这里!!
    .setCursorHandleColor(ContextCompat.getColor(mContext, R.color.colorAccent)) // 游标颜色
    .setCursorHandleSizeInDp(22f) // 游标大小 单位 dp
    .setSelectedColor(ContextCompat.getColor(mContext, R.color.colorAccentTransparent)) // 选中文本的颜色
    .setSelectAll(true) // 初次选中是否全选 default true
    .setScrollShow(true) // 滚动时是否继续显示 default true
    .setSelectedAllNoPop(true) // 已经全选无弹窗,设置了监听会回调 onSelectAllShowCustomPop 方法
    .setMagnifierShow(true) // 放大镜 default true
    .setSelectTextLength(2)// 首次选中文本的长度 default 2
    .setPopDelay(100)// 弹窗延迟时间 default 100 毫秒
    .setPopAnimationStyle(R.style.Base_Animation_AppCompat_Dialog)// 弹窗动画 default 无动画
    .addItem(0/*item 的图标*/,"复制"/*item 的描述*/, {Log.i("SelectTextHelper","复制")/*item 的回调*/}// 操作弹窗的每个 item
    .setPopSpanCount(5) // 设置操作弹窗每行个数 default 5
    .setPopStyle(
        R.drawable.shape_color_4c4c4c_radius_8 /*操作弹窗背*/,
        R.drawable.ic_arrow /*箭头图片*/
    ) // 设置操作弹窗背景色、箭头图片
    .build()
mSelectableTextHelper!!.setSelectListener(object : OnSelectListener {
    /**
     * 点击回调
     */
    override fun onClick(v: View?, originalContent: CharSequence?) {
        // 拿原始文本方式
        // clickTextView(msgBean.content!!) // 推荐
        // clickTextView(originalContent!!) // 不推荐 富文本可能被修改值 导致 gif 动不了
    }
    /**
     * 长按回调
     */
    override fun onLongClick(v: View?) {
    }
    /**
     * 选中文本回调
     */
    override fun onTextSelected(content: CharSequence?) {
    }
    /**
     * 弹窗关闭回调
     */
    override fun onDismiss() {}
    /**
     * 点击 TextView 里的 url 回调
     *
     * 已被下面重写
     * textView.setMovementMethod(new LinkMovementMethodInterceptor());
     */
    override fun onClickUrl(url: String?) {
    }
    /**
     * 全选显示自定义弹窗回调
     */
    override fun onSelectAllShowCustomPop() {
    }
    /**
     * 重置回调
     */
    override fun onReset() {
      // SelectTextEventBus.instance.dispatch(SelectTextEvent("dismissOperatePop"))
    }
    /**
     * 解除自定义弹窗回调
     */
    override fun onDismissCustomPop() {
      // SelectTextEventBus.instance.dispatch(SelectTextEvent("dismissOperatePop"))
    }
    /**
     * 是否正在滚动回调
     */
    override fun onScrolling() {
        // removeShowSelectView()
    }
})
3.demo 中提供了查看文本内容的SelectTextDialog和 消息列表自由复制MainActivity
查看文本内容方法:
- 该方法比较简单,将
textView参照步骤 2 放入SelectTextHelper中,在dismiss调用SelectTextHelper的reset()即可。 
override fun dismiss() {
    mSelectableTextHelper.reset()
    super.dismiss()
}
高仿微信聊天消息列表自由复制方法:
recycleView+adapter+ 多布局的使用在这里不阐述,请看本项目 demo。为
adapter里 text 类型ViewHolder中的textView参照步骤 2 放入SelectTextHelper中,注册SelectTextEventBus。SelectTextEventBus类特别说明、原理:SelectTextEventBus在EventBus基础上加功能。在register时记录下类和方法,方便在Activity/Fragment Destroy时unregister所有SelectTextEventBus的EventBus。text 类型
ViewHolder添加EventBus监听
/**
 * 自定义 SelectTextEvent 隐藏 光标
 */
@Subscribe(threadMode = ThreadMode.MAIN)
fun handleSelector(event: SelectTextEvent) {
    if (null == mSelectableTextHelper) {
        return
    }
    val type = event.type
    if (TextUtils.isEmpty(type)) {
        return
    }
    when (type) {
        "dismissAllPop" -> mSelectableTextHelper!!.reset()
        "dismissAllPopDelayed" -> postReset(Companion.RESET_DELAY)
    }
}
- 重写
adapter里的onViewRecycled方法,该方法在回收View时调用 
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
    super.onViewRecycled(holder)
    if (holder is ViewHolderText) {
        // 注销
        SelectTextEventBus.instance.unregister(holder)
    }
}
- 对 ImageSpan 表情支持(支持动态表情!!)(https://github.com/ITxiaoguang/SelectTextHelper/issues/4 )
 
val emojiMap: MutableMap<String, Int> = HashMap()
emojiMap["\\[笑脸\\]"] = R.drawable.emoji_00
emojiMap["\\[瘪嘴\\]"] = R.drawable.emoji_01
emojiMap["\\[色\\]"] = R.drawable.emoji_02
emojiMap["\\[瞪大眼\\]"] = R.drawable.emoji_03
emojiMap["\\[酷\\]"] = R.drawable.emoji_04
emojiMap["\\[Android\\]"] = R.mipmap.ic_launcher_round
emojiMap["\\[好的\\]"] = R.drawable.emoji_gif
emojiMap["\\[羊驼\\]"] = R.drawable.emoji_gif2
`
- 富文本支持 富文本用法点这里
 
// todo 方法一:富文本  需要转行成富文本形式
RichText.initCacheDir(holder.textView.context.applicationContext) // 项目里初始化一次即可
RichText.from(msgBean.content)
    .autoFix(false) // 是否自动修复宽高,默认 true
    .autoPlay(true) // gif 自动播放
    .singleLoad(false) // RecyclerView 里设为 false 若同时启动了多个 RichText,会并发解析,类似于 AsyncTask 的 executeOnExecutor
    .done { // 在成功回调处理
        // 演示消息列表选择文本
        holder.selectText(msgBean)
    }
    .into(holder.textView)
// todo 方法二:普通文本
holder.textView.text = msgBean.content
// 演示消息列表选择文本
holder.selectText(msgBean)
