移动端强大的富文本编辑器richeditor-android
通常我们使用富文本编辑器都是在H5端实现,但是如果你遇到在移动端发表文章的功能,那么richeditor-android这套框架可以轻松为你实现,不需要再使用大量的控件进行拼凑!
- 功能表如下图所示:

- 引入richeditor-android
 richeditor-android需要的jar:
implementation 'jp.wasabeef:richeditor-android:1.2.2'
 这是一个Dialog框架,demo中不想自己去写,所以就使用了第三方
implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
- 引入控件RichEditor
   <jp.wasabeef.richeditor.RichEditor
        android:id="@+id/editor"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />- 使用到的权限
如果拍照需要相机权限,选择图片需要SD卡权限,插入网络图片需要网络权限
 <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />- 初始化RichEditor
       mEditor = (RichEditor) findViewById(R.id.editor);
        //初始化编辑高度
        mEditor.setEditorHeight(200);
        //初始化字体大小
        mEditor.setEditorFontSize(22);
        //初始化字体颜色
        mEditor.setEditorFontColor(Color.BLACK);
        //mEditor.setEditorBackgroundColor(Color.BLUE);
        //初始化内边距
        mEditor.setPadding(10, 10, 10, 10);
        //设置编辑框背景,可以是网络图片
        // mEditor.setBackground("https://raw.githubusercontent.com/wasabeef/art/master/chip.jpg");
        // mEditor.setBackgroundColor(Color.BLUE);
        mEditor.setBackgroundResource(R.drawable.bg);
        //设置默认显示语句
        mEditor.setPlaceholder("Insert text here...");
        //设置编辑器是否可用
        mEditor.setInputEnabled(true);
- 实时监听Editor输入内容
   mPreview = (TextView) findViewById(R.id.preview);
        mEditor.setOnTextChangeListener(new RichEditor.OnTextChangeListener() {
@Override
public void onTextChange(String text) {
                mPreview.setText(text);
            }
        });- 功能方法
        /**
         * 撤销当前标签状态下所有内容
         */
        findViewById(R.id.action_undo).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.undo();
            }
        });
/**
         * 恢复撤销的内容
         */
        findViewById(R.id.action_redo).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.redo();
            }
        });
/**
         * 加粗
         */
        findViewById(R.id.action_bold).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
                mEditor.setBold();
            }
        });
/**
         * 斜体
         */
        findViewById(R.id.action_italic).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
                mEditor.setItalic();
            }
        });
/**
         * 下角表
         */
        findViewById(R.id.action_subscript).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
if (mEditor.getHtml() == null) {
return;
                }
                mEditor.setSubscript();
            }
        });
/**
         * 上角标
         */
        findViewById(R.id.action_superscript).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
if (mEditor.getHtml() == null) {
return;
                }
                mEditor.setSuperscript();
            }
        });
/**
         * 删除线
         */
        findViewById(R.id.action_strikethrough).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
                mEditor.setStrikeThrough();
            }
        });
/**
         *下划线
         */
        findViewById(R.id.action_underline).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
                mEditor.setUnderline();
            }
        });
/**
         * 设置标题(1到6)
         */
        findViewById(R.id.action_heading1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setHeading(1);
            }
        });
        findViewById(R.id.action_heading2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setHeading(2);
            }
        });
        findViewById(R.id.action_heading3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setHeading(3);
            }
        });
        findViewById(R.id.action_heading4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setHeading(4);
            }
        });
        findViewById(R.id.action_heading5).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setHeading(5);
            }
        });
        findViewById(R.id.action_heading6).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setHeading(6);
            }
        });
/**
         * 设置字体颜色
         */
        findViewById(R.id.action_txt_color).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
new MaterialDialog.Builder(MainActivity.this)
                        .title("选择字体颜色")
                        .items(R.array.color_items)
                        .itemsCallbackSingleChoice(-1, new MaterialDialog.ListCallbackSingleChoice() {
@Override
public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
                                dialog.dismiss();
switch (which) {
case 0://红
                                        mEditor.setTextColor(Color.RED);
break;
case 1://黄
                                        mEditor.setTextColor(Color.YELLOW);
break;
case 2://蓝
                                        mEditor.setTextColor(Color.GREEN);
break;
case 3://绿
                                        mEditor.setTextColor(Color.BLUE);
break;
case 4://黑
                                        mEditor.setTextColor(Color.BLACK);
break;
                                }
return false;
                            }
                        }).show();
            }
        });
        findViewById(R.id.action_bg_color).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
new MaterialDialog.Builder(MainActivity.this)
                        .title("选择字体背景颜色")
                        .items(R.array.text_back_color_items)
                        .itemsCallbackSingleChoice(-1, new MaterialDialog.ListCallbackSingleChoice() {
@Override
public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
                                dialog.dismiss();
switch (which) {
case 0://红
                                        mEditor.setTextBackgroundColor(Color.RED);
break;
case 1://黄
                                        mEditor.setTextBackgroundColor(Color.YELLOW);
break;
case 2://蓝
                                        mEditor.setTextBackgroundColor(Color.GREEN);
break;
case 3://绿
                                        mEditor.setTextBackgroundColor(Color.BLUE);
break;
case 4://黑
                                        mEditor.setTextBackgroundColor(Color.BLACK);
break;
case 5://透明
                                        mEditor.setTextBackgroundColor(R.color.transparent);
break;
                                }
return false;
                            }
                        }).show();
            }
        });
/**
         * 向右缩进
         */
        findViewById(R.id.action_indent).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
                mEditor.setIndent();
            }
        });
/**
         * 向左缩进
         */
        findViewById(R.id.action_outdent).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
                mEditor.setOutdent();
            }
        });
/**
         *文章左对齐
         */
        findViewById(R.id.action_align_left).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
                mEditor.setAlignLeft();
            }
        });
/**
         * 文章居中对齐
         */
        findViewById(R.id.action_align_center).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setAlignCenter();
            }
        });
/**
         * 文章右对齐
         */
        findViewById(R.id.action_align_right).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setAlignRight();
            }
        });
/**
         * 无序排列
         */
        findViewById(R.id.action_insert_bullets).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setBullets();
            }
        });
/**
         * 有序排列
         */
        findViewById(R.id.action_insert_numbers).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setNumbers();
            }
        });
/**
         * 引用
         */
        findViewById(R.id.action_blockquote).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.setBlockquote();
            }
        });
/**
         * 插入图片
         */
        findViewById(R.id.action_insert_image).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
                ActivityCompat.requestPermissions(MainActivity.this, mPermissionList, 100);
            }
        });
/**
         * 插入连接
         */
        findViewById(R.id.action_insert_link).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MaterialDialog.Builder(MainActivity.this)
                        .title("将输入连接地址")
                        .items("http://blog.csdn.net/huangxiaoguo1")
                        .itemsCallbackSingleChoice(-1, new MaterialDialog.ListCallbackSingleChoice() {
@Override
public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
                                dialog.dismiss();
                                mEditor.focusEditor();
                                mEditor.insertLink("http://blog.csdn.net/huangxiaoguo1",
"http://blog.csdn.net/huangxiaoguo1");
return false;
                            }
                        }).show();
            }
        });
/**
         * 选择框
         */
        findViewById(R.id.action_insert_checkbox).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                mEditor.focusEditor();
                mEditor.insertTodo();
            }
        });
/**
         * 获取并显示Html
         */
        findViewById(R.id.tv_showhtml).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                Intent intent = new Intent(v.getContext(), WebViewActivity.class);
                intent.putExtra("contextURL", mEditor.getHtml());
                startActivity(intent);
            }
        });- 插入图片并使用屏幕宽度


权限,我这里只是选着图片,关于拍照的自己可以去实现
  String[] mPermissionList = new String[]{
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE};
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 100:
boolean writeExternalStorage = grantResults[0] == PackageManager.PERMISSION_GRANTED;
boolean readExternalStorage = grantResults[1] == PackageManager.PERMISSION_GRANTED;
if (grantResults.length > 0 && writeExternalStorage && readExternalStorage) {
                    getImage();
                } else {
                    Toast.makeText(this, "请设置必要权限", Toast.LENGTH_SHORT).show();
                }
break;
        }
    }
private void getImage() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT).setType("image/*"),
                    REQUEST_PICK_IMAGE);
        } else {
            Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("image/*");
            startActivityForResult(intent, REQUEST_PICK_IMAGE);
        }
    }
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case REQUEST_PICK_IMAGE:
if (data != null) {
                        String realPathFromUri = RealPathFromUriUtils.getRealPathFromUri(this, data.getData());
                        mEditor.insertImage("https://unsplash.it/2000/2000?random&58",
"huangxiaoguo\" style=\"max-width:100%");
                        mEditor.insertImage(realPathFromUri, realPathFromUri + "\" style=\"max-width:100%");
//                        mEditor.insertImage(realPathFromUri, realPathFromUri + "\" style=\"max-width:100%;max-height:100%");
                    } else {
                        Toast.makeText(this, "图片损坏,请重新选择", Toast.LENGTH_SHORT).show();
                    }
break;
            }
        }
    }
注意这里 “\” style=\”max-width:100%”是让我们从手机选择的图片和网络加载的图片适配屏幕宽高,解决图片太大显示不全问题!
关于如何获得手机图片真正地址(realPathFromUri )请看http://blog.csdn.net/huangxiaoguo1/article/details/78983582
richeditor-android github地址:https://github.com/wasabeef/richeditor-android
demo地址:http://download.csdn.net/download/huangxiaoguo1/10205773
 
			