Giter Site home page Giter Site logo

chinalwb / android-rich-text-editor Goto Github PK

View Code? Open in Web Editor NEW
830.0 37.0 170.0 42.65 MB

Android Rich Text Editor With customized spans - 富文本编辑器 - Don't miss this one :)

License: Apache License 2.0

Java 98.63% Kotlin 1.37%
android rich-text-editor ordered-list emoji-picker youdaonote superscript subscript font-size quotes video

android-rich-text-editor's People

Contributors

chinalwb avatar kant avatar lfork avatar linxueyuanstdio avatar starshipcoder avatar tejnote avatar vishalx4 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

android-rich-text-editor's Issues

Force closed ARE app

Some time, ARE app was forced close.
Below is error log I got:
08-06 14:57:07.079 6261 6261 E AndroidRuntime: FATAL EXCEPTION: main 08-06 14:57:07.079 6261 6261 E AndroidRuntime: Process: com.chinalwb.are.demo, PID: 6261 08-06 14:57:07.079 6261 6261 E AndroidRuntime: java.lang.IndexOutOfBoundsException: setSpan (-1 ... -1) starts before 0 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1314) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:680) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:672) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at com.chinalwb.are.styles.ARE_ListBullet.changeListNumberSpanToListBulletSpan(ARE_ListBullet.java:462) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at com.chinalwb.are.styles.ARE_ListBullet.access$000(ARE_ListBullet.java:22) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at com.chinalwb.are.styles.ARE_ListBullet$1.onClick(ARE_ListBullet.java:68) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at android.view.View.performClick(View.java:6897) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at android.view.View$PerformClick.run(View.java:26100) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:789) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:98) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at android.os.Looper.loop(Looper.java:164) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6944) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) 08-06 14:57:07.079 6261 6261 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

I don't know exactly when error occur. However, for example, you can reproduce the issue as following:
1> Build ARE app -> run on real device
2> Select all -> remove
3> Use ListNumber to write some list
4> Click ListBullet -> app FC

More features for Default Toolbar

I think AREditText + Default Toolbar are very flexibility. However, Default Toolbar now have less feature than full AREditor. I really want to you add more features. I know you are busy now but I hope you can complete these in the near future. I also try to custom own my toolbar but that seem quite difficult for me :)

希望能够加入再次编辑功能

作为富文本编辑器,肯定需要有对文本进行二次展示和编辑的需求,目前虽然能够通过edittext简单展示,但是基本上不能再次编辑,希望可以加入这个功能。
我个人目前的想法是通过解析HTML然后在根据相应的标签调用不同控件实现(想法),不知道还有没有更好的方案。
富文本编辑器看了好多都是基于webview实现的。还有不少需要选中文本才能实现更改样式,这个非常不错,希望能够保持更新。

theme color change

After using your library in my app, my app theme color colour changing. so,what should i do for not changing the colour?

feature request

  1. AREToolbarAREditext 分开,它们耦合太严重了。现在编辑器的布局是写死的,如果想移动 toolbar 到别的位置 或者 自定义键盘操作会很麻烦。
  2. emoji键盘里引用的图片资源会静态打包到apk里,但是像表情包这些,应该通过网络或其他途径加载。现在引入项目的话导致apk太大。
  3. 还是emoiji键盘的问题,我想抽象一下,可以绑定其他自定义键盘。参考time cat里的做法:
    /**
     * 设置软键盘和选择面板的平滑交互
     */
    private void setKeyboardManager() {
        mSmartKeyboardManager = new SmartKeyboardManager.Builder(this)
                .setContentView(dialog_add_task_ll_content)
                .setEditText(dialog_add_task_et_content)
                .addKeyboard(dialog_add_task_tv_important_urgent, dialog_add_task_select_ll_important_urgent)
                .addKeyboard(dialog_add_task_tv_date, dialog_add_task_select_gv_date)
                .addKeyboard(dialog_add_task_tv_time, dialog_add_task_select_ll_time)
                .addKeyboard(dialog_add_task_tv_remind, dialog_add_task_select_sv_container)
                .addKeyboard(dialog_add_task_tv_tag, dialog_add_task_select_ll_tag)
                .addKeyboard(dialog_add_task_tv_notebook, dialog_add_task_select_ll_notebook)
                .addKeyboard(dialog_add_task_tv_plan, dialog_add_task_select_ll_plan)
                .create();
    }

让toolbar暴露类似void addTriggerButton(View view)的接口,允许自定义添加按钮

Copy Paste removes formatting

Hi

I added some bullet text in the editor and then tried to cut all the content and then paste it, now pasted content doesn't show bulleted list. Can you guide me where to fix this?

Thanks

Callback for image upload

I like this rte. One thing that is stopping me from fully trying this out is the image upload functionality. Such that, if I upload an image to the server I get an image url(server location), then I want to insert the image using this server image url. Do you have any way to achieve this functionality? Currently there doesn't seem to be any callback/method to achieve this.

隐藏不需要的按钮

如题 想隐藏不需要的功能按钮 只能修改源码了吗 或许有开放api会灵活一点?

Bold Italic and underline not working

Hello,
First of all amazing efforts on the tool.

I am trying to use the tool and it works fine for my requirement. The issue is when I select either bold/italic/underline, there is not change in the text I select or the the text I type after selecting these options. Rest all of the stylings work fine. Do I need to add something else to it?

新功能,视频上传

你好,您能否支持和知乎一样的添加视频上传功能,我想这会是个很强大的编辑器

怎么解决java.lang.RuntimeException: Unable to start activity ComponentInfo{}

我的project原本就有使用glide了, 但是implemented 你的library 后就有这个package 不一样导致的问题。请问怎么解决?
java.lang.RuntimeException: Unable to start activity ComponentInfo{}: java.lang.ClassCastException: com.chinalwb.are.glidesupport.GlideRequests cannot be cast to com.xxxx.xxx.xxx.GlideRequests

find the image button id

when I clicked on image button, it redirects to radio button. but i have to find onclicklistener of image button

Not update repo in my project

implementation 'com.github.bumptech.glide:glide:4.3.1'
implementation 'com.github.chinalwb:are:0.1.2'

I am used this, but you have done the update of color is not working in my app(project).So what I have to do for that.

问个简单问题

在哪里可以修改默认的字体大小?当是纯文字时,在哪里设置fontsize 属性。我知道在html.java中,怕改错里面逻辑了

这个库很棒

发现严重的闪退BUG

文字在使用多种格式(例如:下划线,删除线,颜色)之后,在不换行情况下,直接导入图片,再次输入文字会闪退。
FULL TOP模式下

image

另外。添加图片之后,添加第二张或者第三张偶尔会出现闪退。

最后希望大神能出个保存草稿箱的功能,即点击按钮后,退出依然可以看到该文章

图片URI问题

在高版本系统中直接读 URI 会崩溃
比如这样的 URI

content://media/external/images/media/846589
content://com.android.providers.media.documents/document/image%3A283030

事实上用 Glide 是可以在 AreImageGetter 读到图片并加载成功的,但是插入ImageSpan 的时候又不用 Glide 了,搞成直接加载 Uri:

// Html.java
package com.chinalwb.are.android.inner;
...
// 1309 行 startImg(Editable text, Attributes attributes, Html.ImageGetter img)方法片段
        String src = attributes.getValue("", "src");
        Drawable d = null;
        ImageSpan imageSpan = null;
        if (img != null) {
            d = img.getDrawable(src);
            if (src.startsWith(Constants.EMOJI)) {
                String resIdStr = src.substring(6);
                int resId = Integer.parseInt(resIdStr);
                imageSpan = new AreImageSpan(sContext, resId);
            } else if (src.startsWith("http")) {
                imageSpan = new AreImageSpan(sContext, d, src);
            } else {
                // content://com.android.providers.media.documents/document/image%3A33
                // Such uri cannot be loaded from AreImageGetter.
                imageSpan = new AreImageSpan(sContext, Uri.parse(src));
            }
        }

这里是直接搞进 Uri 了 imageSpan = new AreImageSpan(sContext, Uri.parse(src));
很奇怪为什么要这样做。。。
然后 AreImageGetter 成功读到的 Drawable 转成 Bitmap 又会出错。。。
所以我不得不自己修改了 Html.java

    static ImageSpan imageSpan = null;

    private static void startImg(Editable text, Attributes attributes, Html.ImageGetter img) {
        String src = attributes.getValue("", "src");
        Drawable d = null;
        if (img != null) {
            d = img.getDrawable(src);
            if (src.startsWith(Constants.EMOJI)) {
                String resIdStr = src.substring(6);
                int resId = Integer.parseInt(resIdStr);
                imageSpan = new AreImageSpan(sContext, resId);
            } else if (src.startsWith("http")) {
                imageSpan = new AreImageSpan(sContext, d, src);
            } else {
                // content://com.android.providers.media.documents/document/image%3A33
                // Such uri cannot be loaded from AreImageGetter.
                Uri uri = Uri.parse(src);
                String path = PictureHelper.getPath(sContext, uri);
                if (path != null) {
                    File file = new File(path);
                    Glide.with(sContext)
                            .asBitmap()
                            .load(file)
                            .into(new SimpleTarget<Bitmap>() {
                                @Override
                                public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
                                    Bitmap bitmap = scaleBitmapToFitWidth(resource,
                                            (int) (0.8 * ScreenUtil.getScreenWidth(sContext)));
                                    imageSpan = new ImageSpan(sContext, bitmap);
                                }
                            });
                }
            }
        }

        if (d == null) {
            if (sContext == null) {
                d = Resources.getSystem().getDrawable(R.drawable.ic_launcher);
            } else {
                d = sContext.getResources().getDrawable(R.drawable.ic_launcher);
            }

            d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
        }

        int len = text.length();
        text.append("\uFFFC");

        text.setSpan(imageSpan, len, text.length(),
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    public static Bitmap scaleBitmapToFitWidth(Bitmap bitmap, int maxWidth) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        int newWidth = maxWidth;
        int newHeight = maxWidth * h / w;
        Matrix matrix = new Matrix();
        float scaleWidth = ((float) newWidth / w);
        float scaleHeight = ((float) newHeight / h);
        if (w < maxWidth * 0.2) {
            return bitmap;
        }
        matrix.postScale(scaleWidth, scaleHeight);
        return Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
    }

    /**
     * 获取屏幕宽度 单位:像素
     *
     * @return 屏幕宽度
     */
    public static int getScreenWidth(Context context) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        return displayMetrics.widthPixels;
    }
//  PictureHelper .java
// 解析 Uri 成 filepath 字符串
public class PictureHelper {

    // get the absolute path from the uri
    @SuppressLint("NewApi")
    public static String getPath(final Context context, final Uri uri) {
        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/"
                            + split[1];
                }
                // TODO handle non-primary volumes
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {
                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(id));
                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }
                final String selection = "_id=?";
                final String[] selectionArgs = new String[] { split[1] };
                return getDataColumn(context, contentUri, selection,
                        selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }
        return null;
    }


    public static String getDataColumn(Context context, Uri uri,
                                       String selection, String[] selectionArgs) {
        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = { column };
        try {
            cursor = context.getContentResolver().query(uri, projection,
                    selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }


    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri
                .getAuthority());
    }


    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri
                .getAuthority());
    }


    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri
                .getAuthority());
    }


    private static boolean isGooglePhotosUri(Uri uri) {
        return "com.google.android.apps.photos.content".equals(uri
                .getAuthority());
    }

}

貌似在 Android 5.0 以后是要 ACTION_OPEN_DOCUMENT 这些才能从 Uri 拿图片,很麻烦。
我建议不要搞 Uri 了,直接面向文件多好,统一管理资源文件,像图片、视频这些,如果不是 url ,备份起来很麻烦了。

然后还有一些问题。
比如插入录音等等,希望有一个统一的 API 去做这些事

  1. 插入 Bitmap 的大小宽高
  2. 点击插入的 span 回调

GlideSupport

Where are the GlideApp and GlideRequests class ?

image not save

try to insert image, in edit mode, image is show. but when it save. no image url in html.

Change font size incorrect

I see that you are setting default font size is 18.
When I change the font size to other value (for example 24) and write some text. If I back to font size 18, all of the text before also change the font size to 18

How to Add Toolbar Item Emoji and Font Foregound/Background Color in ARE_ToolbarDefault

Hello guys,
This library is very cool, but how to apply add Toolbar Item Emoji and Font Foregound/Background Color in ARE_ToolbarDefault ?


    private void initToolbar() {
        IARE_ToolItem bold = new ARE_ToolItem_Bold();
        IARE_ToolItem italic = new ARE_ToolItem_Italic();
        IARE_ToolItem underline = new ARE_ToolItem_Underline();
        IARE_ToolItem strikethrough = new ARE_ToolItem_Strikethrough();
        ARE_ToolItem_FontSize fontSize = new ARE_ToolItem_FontSize();
        IARE_ToolItem quote = new ARE_ToolItem_Quote();
        IARE_ToolItem listNumber = new ARE_ToolItem_ListNumber();
        IARE_ToolItem listBullet = new ARE_ToolItem_ListBullet();
        IARE_ToolItem hr = new ARE_ToolItem_Hr();
        IARE_ToolItem link = new ARE_ToolItem_Link();
        IARE_ToolItem subscript = new ARE_ToolItem_Subscript();
        IARE_ToolItem superscript = new ARE_ToolItem_Superscript();
        IARE_ToolItem left = new ARE_ToolItem_AlignmentLeft();
        IARE_ToolItem center = new ARE_ToolItem_AlignmentCenter();
        IARE_ToolItem right = new ARE_ToolItem_AlignmentRight();
        IARE_ToolItem image = new ARE_ToolItem_Image();
        areToolbar.addToolbarItem(bold);
        areToolbar.addToolbarItem(italic);
        areToolbar.addToolbarItem(underline);
        areToolbar.addToolbarItem(strikethrough);
        areToolbar.addToolbarItem(quote);
        areToolbar.addToolbarItem(fontSize);
        areToolbar.addToolbarItem(listNumber);
        areToolbar.addToolbarItem(listBullet);
        areToolbar.addToolbarItem(hr);
        areToolbar.addToolbarItem(link);
        areToolbar.addToolbarItem(subscript);
        areToolbar.addToolbarItem(superscript);
        areToolbar.addToolbarItem(left);
        areToolbar.addToolbarItem(center);
        areToolbar.addToolbarItem(right);
        areToolbar.addToolbarItem(image);

        arEditText.setToolbar(areToolbar);

        setHtml();

        initToolbarArrow();
    }

Above code just implement some toolbar item , i cant find how to add Toolbar Item Emoji and Font Foregound/Background Color.
Please Advice ..
Thanks

New Design

android rich text

Hi,

I have studied your work and I think a new design will make you more visible. I designed for you, I hope you like it and you want to use it. If you want to reach me, you can look at the my profile. I can give you all the formats of the design free. If you want a change please specify.

Andorid in A and Fountain Pen combine

0.1.2 版 glide 冲突...

AGPBI: {"kind":"error","text":"Program type already present: com.bumptech.glide.GeneratedRequestManagerFactory","sources":[{}],"tool":"D8"}

有一个闪退bug

在选中图片后有闪退,第一张没问题,加载第二或第三张就闪退了。我觉得是不是控件内存消耗太大导致内存溢出

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.