美文网首页
Android用过觉得最满意的富文本编辑器(自定义方便),基于w

Android用过觉得最满意的富文本编辑器(自定义方便),基于w

作者: yefuliu | 来源:发表于2019-02-27 15:58 被阅读0次

    最要类代码:
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Bitmap;
    import android.graphics.drawable.Drawable;
    import android.os.Build;
    import android.text.TextUtils;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.Gravity;
    import android.webkit.CookieManager;
    import android.webkit.CookieSyncManager;
    import android.webkit.WebChromeClient;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;

    import com.urun.media.util.Utils;

    import java.io.UnsupportedEncodingException;
    import java.net.URLDecoder;
    import java.net.URLEncoder;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Locale;

    /**

    • Copyright (C) 2017 Wasabeef
    • <p>
    • Licensed under the Apache License, Version 2.0 (the "License");
    • you may not use this file except in compliance with the License.
    • You may obtain a copy of the License at
    • <p>
    • http://www.apache.org/licenses/LICENSE-2.0
    • <p>
    • Unless required by applicable law or agreed to in writing, software
    • distributed under the License is distributed on an "AS IS" BASIS,
    • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    • See the License for the specific language governing permissions and
    • limitations under the License.
      */

    public class RichEditor extends WebView {

    public enum Type {
        BOLD,
        ITALIC,
        SUBSCRIPT,
        SUPERSCRIPT,
        STRIKETHROUGH,
        UNDERLINE,
        H1,
        H2,
        H3,
        H4,
        H5,
        H6,
        ORDEREDLIST,
        UNORDEREDLIST,
        JUSTIFYCENTER,
        JUSTIFYFULL,
        JUSTUFYLEFT,
        JUSTIFYRIGHT
    }
    
    public interface OnTextChangeListener {
        void onTextChange(String text);
    }
    
    public interface OnDecorationStateListener {
        void onStateChangeListener(String text, List<RichEditor.Type> types);
    }
    
    public interface AfterInitialLoadListener {
        void onAfterInitialLoad(boolean isReady);
    }
    
    private static final String SETUP_HTML = "file:///android_asset/editor.html";
    private static final String CALLBACK_SCHEME = "re-callback://";
    private static final String STATE_SCHEME = "re-state://";
    private boolean isReady = false;
    private String mContents;
    private OnTextChangeListener mTextChangeListener;
    private OnDecorationStateListener mDecorationStateListener;
    private AfterInitialLoadListener mLoadListener;
    private Context mContext;
    
    public RichEditor(Context context) {
        this(context, null);
        mContext = context;
    }
    
    public RichEditor(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.webViewStyle);
        mContext = context;
    }
    
    @SuppressLint("SetJavaScriptEnabled")
    public RichEditor(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    
        setVerticalScrollBarEnabled(false);
        setHorizontalScrollBarEnabled(false);
        getSettings().setJavaScriptEnabled(true);
        getSettings().setDomStorageEnabled(true);
        setWebChromeClient(createWebChromeClient());
        setWebViewClient(createWebviewClient());
        loadUrl(SETUP_HTML);
    
        applyAttributes(context, attrs);
    }
    
    protected EditorWebViewClient createWebviewClient() {
        return new EditorWebViewClient();
    }
    
    protected EditorWebChromeClient createWebChromeClient() {
        return new EditorWebChromeClient();
    }
    
    public void clearCookie() {
        CookieSyncManager.createInstance(mContext);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.removeAllCookie();
        CookieSyncManager.getInstance().sync();
    
        setWebChromeClient(null);
        setWebViewClient(null);
        getSettings().setJavaScriptEnabled(false);
        clearCache(true);
    }
    
    public void setOnTextChangeListener(OnTextChangeListener listener) {
        mTextChangeListener = listener;
    }
    
    public void setOnDecorationChangeListener(OnDecorationStateListener listener) {
        mDecorationStateListener = listener;
    }
    
    public void setOnInitialLoadListener(AfterInitialLoadListener listener) {
        mLoadListener = listener;
    }
    
    private void callback(String text) {
        mContents = text.replaceFirst(CALLBACK_SCHEME, "");
        if (mTextChangeListener != null) {
            mTextChangeListener.onTextChange(mContents);
        }
    }
    
    private void stateCheck(String text) {
        String state = text.replaceFirst(STATE_SCHEME, "").toUpperCase(Locale.ENGLISH);
        List<RichEditor.Type> types = new ArrayList<>();
        for (RichEditor.Type type : RichEditor.Type.values()) {
            if (TextUtils.indexOf(state, type.name()) != -1) {
                types.add(type);
            }
        }
    
        if (mDecorationStateListener != null) {
            mDecorationStateListener.onStateChangeListener(state, types);
        }
    }
    
    private void applyAttributes(Context context, AttributeSet attrs) {
        final int[] attrsArray = new int[]{
                android.R.attr.gravity
        };
        TypedArray ta = context.obtainStyledAttributes(attrs, attrsArray);
    
        int gravity = ta.getInt(0, NO_ID);
        switch (gravity) {
            case Gravity.LEFT:
                exec("javascript:RE.setTextAlign(\"left\")");
                break;
            case Gravity.RIGHT:
                exec("javascript:RE.setTextAlign(\"right\")");
                break;
            case Gravity.TOP:
                exec("javascript:RE.setVerticalAlign(\"top\")");
                break;
            case Gravity.BOTTOM:
                exec("javascript:RE.setVerticalAlign(\"bottom\")");
                break;
            case Gravity.CENTER_VERTICAL:
                exec("javascript:RE.setVerticalAlign(\"middle\")");
                break;
            case Gravity.CENTER_HORIZONTAL:
                exec("javascript:RE.setTextAlign(\"center\")");
                break;
            case Gravity.CENTER:
                exec("javascript:RE.setVerticalAlign(\"middle\")");
                exec("javascript:RE.setTextAlign(\"center\")");
                break;
        }
    
        ta.recycle();
    }
    
    public void setHtml(String contents) {
        if (contents == null) {
            contents = "";
        }
        try {
            exec("javascript:RE.setHtml('" + URLEncoder.encode(contents, "UTF-8") + "');");
        } catch (UnsupportedEncodingException e) {
            // No handling
        }
        mContents = contents;
    }
    
    public String getHtml() {
        return mContents;
    }
    
    public void setEditorFontColor(int color) {
        String hex = convertHexColorString(color);
        exec("javascript:RE.setBaseTextColor('" + hex + "');");
    }
    
    public void setEditorFontSize(int px) {
        exec("javascript:RE.setBaseFontSize('" + px + "px');");
    }
    
    @Override
    public void setPadding(int left, int top, int right, int bottom) {
        super.setPadding(left, top, right, bottom);
        exec("javascript:RE.setPadding('" + left + "px', '" + top + "px', '" + right + "px', '" + bottom
                + "px');");
    }
    
    @Override
    public void setPaddingRelative(int start, int top, int end, int bottom) {
        // still not support RTL.
        setPadding(start, top, end, bottom);
    }
    
    public void setEditorBackgroundColor(int color) {
        setBackgroundColor(color);
    }
    
    @Override
    public void setBackgroundColor(int color) {
        super.setBackgroundColor(color);
    }
    
    @Override
    public void setBackgroundResource(int resid) {
        Bitmap bitmap = Utils.decodeResource(getContext(), resid);
        String base64 = Utils.toBase64(bitmap);
        bitmap.recycle();
    
        exec("javascript:RE.setBackgroundImage('url(data:image/png;base64," + base64 + ")');");
    }
    
    @Override
    public void setBackground(Drawable background) {
        Bitmap bitmap = Utils.toBitmap(background);
        String base64 = Utils.toBase64(bitmap);
        bitmap.recycle();
    
        exec("javascript:RE.setBackgroundImage('url(data:image/png;base64," + base64 + ")');");
    }
    
    public void setBackground(String url) {
        exec("javascript:RE.setBackgroundImage('url(" + url + ")');");
    }
    
    public void setEditorWidth(int px) {
        exec("javascript:RE.setWidth('" + px + "px');");
    }
    
    public void setEditorHeight(int px) {
        exec("javascript:RE.setHeight('" + px + "px');");
    }
    
    public void setPlaceholder(String placeholder) {
        exec("javascript:RE.setPlaceholder('" + placeholder + "');");
    }
    
    public void setInputEnabled(Boolean inputEnabled) {
        exec("javascript:RE.setInputEnabled(" + inputEnabled + ")");
    }
    
    public void loadCSS(String cssFile) {
        String jsCSSImport = "(function() {" +
                "    var head  = document.getElementsByTagName(\"head\")[0];" +
                "    var link  = document.createElement(\"link\");" +
                "    link.rel  = \"stylesheet\";" +
                "    link.type = \"text/css\";" +
                "    link.href = \"" + cssFile + "\";" +
                "    link.media = \"all\";" +
                "    head.appendChild(link);" +
                "}) ();";
        exec("javascript:" + jsCSSImport + "");
    }
    
    public void undo() {
        exec("javascript:RE.undo();");
    }
    
    public void redo() {
        exec("javascript:RE.redo();");
    }
    
    public void setBold() {
        exec("javascript:RE.setBold();");
    }
    
    public void setItalic() {
        exec("javascript:RE.setItalic();");
    }
    
    public void setSubscript() {
        exec("javascript:RE.setSubscript();");
    }
    
    public void setSuperscript() {
        exec("javascript:RE.setSuperscript();");
    }
    
    public void setStrikeThrough() {
        exec("javascript:RE.setStrikeThrough();");
    }
    
    public void setUnderline() {
        exec("javascript:RE.setUnderline();");
    }
    
    public void setTextColor(int color) {
        exec("javascript:RE.prepareInsert();");
    
        String hex = convertHexColorString(color);
        exec("javascript:RE.setTextColor('" + hex + "');");
    }
    
    public void setTextBackgroundColor(int color) {
        exec("javascript:RE.prepareInsert();");
    
        String hex = convertHexColorString(color);
        exec("javascript:RE.setTextBackgroundColor('" + hex + "');");
    }
    
    public void setFontSize(int fontSize) {
        if (fontSize > 7 || fontSize < 1) {
            Log.e("RichEditor", "Font size should have a value between 1-7");
        }
        exec("javascript:RE.setFontSize('" + fontSize + "');");
    }
    
    public void removeFormat() {
        exec("javascript:RE.removeFormat();");
    }
    
    public void setHeading(int heading) {
        exec("javascript:RE.setHeading('" + heading + "');");
    }
    
    public void setIndent() {
        exec("javascript:RE.setIndent();");
    }
    
    public void setOutdent() {
        exec("javascript:RE.setOutdent();");
    }
    
    public void setAlignLeft() {
        exec("javascript:RE.setJustifyLeft();");
    }
    
    public void setAlignCenter() {
        exec("javascript:RE.setJustifyCenter();");
    }
    
    public void setAlignRight() {
        exec("javascript:RE.setJustifyRight();");
    }
    
    public void setBlockquote() {
        exec("javascript:RE.setBlockquote();");
    }
    
    public void setBullets() {
        exec("javascript:RE.setBullets();");
    }
    
    public void setNumbers() {
        exec("javascript:RE.setNumbers();");
    }
    
    public void insertImage(String url, String alt) {
        exec("javascript:RE.prepareInsert();");
        exec("javascript:RE.insertImage('" + url + "', '" + alt + "');");
    }
    
    public void insertLink(String href, String title) {
        exec("javascript:RE.prepareInsert();");
        exec("javascript:RE.insertLink('" + href + "', '" + title + "');");
    }
    
    public void insertTodo() {
        exec("javascript:RE.prepareInsert();");
        exec("javascript:RE.setTodo('" + Utils.getCurrentTime() + "');");
    }
    
    public void focusEditor() {
        requestFocus();
        exec("javascript:RE.focus();");
    }
    
    public void clearFocusEditor() {
        exec("javascript:RE.blurFocus();");
    }
    
    private String convertHexColorString(int color) {
        return String.format("#%06X", (0xFFFFFF & color));
    }
    
    protected void exec(final String trigger) {
        if (isReady) {
            load(trigger);
        } else {
            postDelayed(new Runnable() {
                @Override
                public void run() {
                    exec(trigger);
                }
            }, 200);
        }
    }
    
    private void load(String trigger) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            evaluateJavascript(trigger, null);
        } else {
            loadUrl(trigger);
        }
    }
    
    protected class EditorWebChromeClient extends WebChromeClient {
    
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
    

    // if (newProgress == 100) {
    // if (mLoadListener != null) {
    // mLoadListener.onAfterInitialLoad(isReady);
    // }
    // }
    }
    }

    protected class EditorWebViewClient extends WebViewClient {
    
        @Override
        public void onPageFinished(WebView view, String url) {
            isReady = url.equalsIgnoreCase(SETUP_HTML);
            if (mLoadListener != null) {
                mLoadListener.onAfterInitialLoad(isReady);
            }
        }
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            String decode;
            try {
                decode = URLDecoder.decode(url, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                // No handling
                return false;
            }
    
            if (TextUtils.indexOf(url, CALLBACK_SCHEME) == 0) {
                callback(decode);
                return true;
            } else if (TextUtils.indexOf(url, STATE_SCHEME) == 0) {
                stateCheck(decode);
                return true;
            }
    
            return super.shouldOverrideUrlLoading(view, url);
        }
    }
    

    }

    别忘了assets四个文件:editor.html ,normalize.css,rich_editor.js,style.css
    demo github地址:https://github.com/wasabeef/richeditor-android

    相关文章

      网友评论

          本文标题:Android用过觉得最满意的富文本编辑器(自定义方便),基于w

          本文链接:https://www.haomeiwen.com/subject/ltefuqtx.html