Need help with RichEditor?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

yuruiyin
224 Stars 29 Forks MIT License 50 Commits 10 Opened issues

Description

基于原生EditText+span实现的Android富文本编辑器

Services available

!
?

Need anything else?

Contributors list

# 68,034
Java
Android
dagger2
appbarl...
48 commits

RichEditor

基于原生EditText+span实现的Android富文本编辑器

组件描述

该组件是基于原生EditText+span的方式实现的,旨在提供一个功能齐全且使用方便的Android富文本编辑器。主要支持了加粗斜体等行内样式、标题引用等段内样式以及插入图片视频甚至自定义View等。

功能演示

Demo

功能列表

  • [x] 支持加粗、斜体、删除线、下划线行内样式
  • [x] 支持插入标题、引用段内样式
  • [x] 支持插入段落图片、视频
  • [x] 支持插入段落自定义布局
  • [x] 支持视频、gif和长图标记
  • [x] 支持图片圆角
  • [x] 支持图片视频及自定义View的点击事件
  • [x] undo redo
  • [ ] 支持行内ImageSpan,如类似微博@xxx,#话题名#
  • [ ] 支持清除样式
  • [ ] 编辑器内部复制粘贴ImageSpan(任意以ImageSpan方式插入的的类型,如图片、视频、自定义view等)

如何使用

gradle

Step 1. Add the JitPack repository in your root build.gradle at the end of repositories:

groovy
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
Step 2. Add the dependency in your app build.gradle:
groovy
dependencies {
    implementation 'com.github.yuruiyin:RichEditor:latest-version'
}

参数定义

自定义属性名字 参数含义
editor_show_video_mark 是否显示视频标识图标
editor_video_mark_resource_id 视频图标资源id
editor_show_gif_mark 是否显示gif标识图标
editor_show_long_image_mark 是否显示长图标识
editor_image_radius 图片和视频圆角大小
editor_headline_text_size 标题字体大小

代码演示

说明:各个样式按钮的layout由调用方自行完成

1) 首先在xml中引用RichEditText:


2) 针对加粗、斜体、标题等需要修改图标样式的按钮(不包括插入图片按钮),处理如下:

    // 加粗, 仅包含图标(见demo)
    val styleBtnVm = StyleBtnVm.Builder()
            .setType(RichTypeEnum.BOLD)
            .setIvIcon(ivBold)
            .setIconNormalResId(R.mipmap.icon_bold_normal)
            .setIconLightResId(R.mipmap.icon_bold_light)
            .setClickedView(ivBold)
            .build()

richEditText.initStyleButton(styleBtnVm)

// 标题,包含图标和文字(图标高亮的同时文字也要高亮)
val styleBtnVm = StyleBtnVm.Builder()
        .setType(RichTypeEnum.BLOCK_HEADLINE)  // 指定为段落标题类型
        .setIvIcon(ivHeadline)       // 图标ImageView,用于修改高亮状态
        .setIconNormalResId(R.mipmap.icon_headline_normal)  // 正常图标资源id
        .setIconLightResId(R.mipmap.icon_headline_light)    // 高亮图标资源id
        .setClickedView(vgHeadline)  // 指定被点击的view
        .setTvTitle(tvHeadline)      // 按钮标题文字
        .setTitleNormalColor(ContextCompat.getColor([email protected], R.color.headline_normal_text_color)) // 正常标题文字颜色
        .setTitleLightColor(ContextCompat.getColor([email protected], R.color.headline_light_text_color))   // 高亮标题文字颜色
        .build()

richEditText.initStyleButton(styleBtnVm)

3)插入图片或视频

    /**
     * 处理插入图片
     */
    private fun handleAddImage() {
        val intent = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
        startActivityForResult(intent, GET_PHOTO_REQUEST_CODE)
    }

private fun doAddBlockImageSpan(
        realImagePath: String, blockImageSpanObtainObject: IBlockImageSpanObtainObject, isFromDraft: Boolean = false
) {
    val blockImageSpanVm = BlockImageSpanVm(blockImageSpanObtainObject) // 不指定宽高,使用图片原始大小(但组件内对最大宽和最大高还是有约束的)
//        val blockImageSpanVm = BlockImageSpanVm(blockImageSpanObtainObject, imageWidth, imageMaxHeight) // 指定宽高
    blockImageSpanVm.isFromDraft = isFromDraft
    richEditText.insertBlockImage(realImagePath, blockImageSpanVm) { blockImageSpan ->
        val spanObtainObject = blockImageSpan.blockImageSpanVm.spanObject
        when (spanObtainObject) {
            is ImageVm -> {
                Toast.makeText(this, "短按了图片-当前图片路径:${spanObtainObject.path}", Toast.LENGTH_SHORT).show()
            }
            is VideoVm -> {
                Toast.makeText(this, "短按了视频-当前视频路径:${spanObtainObject.path}", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == GET_PHOTO_REQUEST_CODE && resultCode == RESULT_OK && data != null) {
        // 相册图片返回
        val selectedImageUri = data.data ?: return
        val realImagePath = FileUtil.getFileRealPath(this, selectedImageUri) ?: return
        val fileType = FileUtil.getFileType(realImagePath) ?: return
        when (fileType) {
            FileTypeEnum.STATIC_IMAGE, FileTypeEnum.GIF -> {
                val imageVm = ImageVm(realImagePath, "2")
                doAddBlockImageSpan(realImagePath, imageVm)
            }
            FileTypeEnum.VIDEO -> {
                // 插入视频封面
                val videoVm = VideoVm(realImagePath, "3")
                doAddBlockImageSpan(realImagePath, videoVm)
            }
        }
    }
}

4) 插入自定义布局

    /**
     * 插入游戏
     */
    private fun handleAddGame() {
        val gameVm = GameVm(1, "一起来捉妖")
        doAddGame(gameVm)
    }

private fun doAddGame(gameVm: GameVm, isFromDraft: Boolean = false) {
    val gameItemView = layoutInflater.inflate(R.layout.editor_game_item, null)
    val ivGameIcon = gameItemView.findViewById<imageview>(R.id.ivGameIcon)
    val tvGameName = gameItemView.findViewById<textview>(R.id.tvGameName)
    ivGameIcon.setImageResource(R.mipmap.icon_game_zhuoyao)
    tvGameName.text = gameVm.name

    ivGameIcon.layoutParams.width = gameIconSize
    ivGameIcon.layoutParams.height = gameIconSize

    val gameItemWidth = getEditTextWidthWithoutPadding()
    ViewUtil.layoutView(gameItemView, gameItemWidth, gameItemHeight)

    val blockImageSpanVm = BlockImageSpanVm(gameVm, gameItemWidth, imageMaxHeight)
    blockImageSpanVm.isFromDraft = isFromDraft
    richEditText.insertBlockImage(ViewUtil.getBitmap(gameItemView), blockImageSpanVm) { blockImageSpan -&gt;
        val retGameVm = blockImageSpan.blockImageSpanVm.spanObject as GameVm
        // 点击游戏item
        Toast.makeText(this, "短按了游戏:${retGameVm.name}", Toast.LENGTH_SHORT).show()
    }
}    

说明:插入自定义布局最终也是通过bitmap以ImageSpan的形式插入到编辑器中的。

5)获取数据

    // 返回的编辑器实体是一个list,list中每个元素代表一个段落block,具体block参数可以参考RichEditorBlock, 
    // 但是若需要保存草稿功能,则需要对该list进行转换成自己的实体,否则List序列化后反序列化会丢失数据,可以参考demo
    val content: List = richEditText.content

具体使用请参考demo

相关引用

1) 设置EditText的光标高度: LineHeightEditText 2) 设置图片圆角: RoundedImageView 3) undo redo: AndroidEdit

最后

您的star是我把组件做到完美的动力~

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.