android webview图文编辑,Android用过觉得最满意的富文本编辑器(自定义方便),基于webview实现...

最要类代码:

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

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

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 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 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值