/SelectTextHelper

高仿微信聊天消息列表自由复制文字,双击查看文本内容,用法超级简单~Copy the text freely in the high imitation WeChat chat message list, double-click to view the text content.

Primary LanguageKotlin

SelectTextHelper-高仿微信聊天消息列表自由复制文字,双击查看文本内容

SelectTextHelper打造一个全网最逼近微信聊天消息自由复制,双击查看文本内容框架。 支持图片和富文本选中,汇聚底层TextView框架、原理并加以整理得出的一个实用的Helper。 仅用几个类实现便实现如此强大的功能,用法也超级简单,侵入性极低。

项目持续维护中... 您的宝贵意见和建议是技术前进的方向

项目演示

消息页效果 查看内容效果
img_v2_c8287d37-8b53-43b0-abc9-6788d73f50dg.jpg img_v2_0256892e-5ef8-4610-b73f-7ef9e4a9668g.jpg
消息页全选 消息页自由复制放大镜
demo_1.jpg demo_2.jpg
消息页选中文本 查看内容
demo_3.jpg demo_4.jpg

特点功能:

  • 支持自由选择文本
  • 支持富文本选择
  • 支持自定义文本有:游标颜色、游标大小、选中文本颜色
  • 支持默认全选文字或选2个文字
  • 支持滑动依然显示弹窗
  • 支持放大镜功能
  • 支持全选情况下自定义弹窗
  • 支持操作弹窗:每行个数、图片、文字、监听回调、弹窗颜色、箭头图片

Demo

demo.jpg

如何添加

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调用SelectTextHelperreset()即可。
override fun dismiss() {
    mSelectableTextHelper.reset()
    super.dismiss()
}

高仿微信聊天消息列表自由复制方法:

  • recycleView + adapter + 多布局的使用在这里不阐述,请看本项目demo。

  • adapter里text类型ViewHolder中的textView参照步骤2放入SelectTextHelper中,注册SelectTextEventBus

  • SelectTextEventBus类特别说明、原理: SelectTextEventBusEventBus基础上加功能。在register时记录下类和方法,方便在Activity/Fragment Destroyunregister所有SelectTextEventBusEventBus

  • 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表情支持(支持动态表情!!)(#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)