package raw; import android.app.ProgressDialog; import android.content.Context; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.webkit.JavascriptInterface; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; import com.lfk.demo.View.CodeView.OnCodeChangedListener; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.Charset; public class CodeView extends WebView{ //常量表 private final String STYLE_DIR = "file:///android_asset/"; //样式保存地址 private final String JS_COMMAND_READ = "javascript:window.reader.read(document.body.innerText);"; private final String JS_COMMAND_WRITE = "javascript:window.writer.write(document.body.innerText);"; private final String JS_COMMAND_EDITABLE = "javascript:document.body.contentEditable = true;"; private final String JS_COMMAND_UNEDITABLE = "javascript:document.body.contentEditable = false;"; private final String JS_VAR_READ = "reader"; private final String JS_VAR_WRITE = "writer"; private boolean editEnable = false; private ProgressDialog progressDialog = null; private final JSContentReader reader = new JSContentReader(); private final JSContentWriter writer = new JSContentWriter(); private OnCodeChangedListener listener = null; private File codeFile = null; private Context context; ///////////////////////////////////////////////////////////////////////////////////// //////////////////////////// CONSTRUCTOR /////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// public CodeView(Context context) { super(context); init(context); } public CodeView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public CodeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public CodeView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) { super(context, attrs, defStyle, privateBrowsing); init(context); } ///////////////////////////////////////////////////////////////////////////////////// //////////////////////////// INITIALIZE /////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// /** * 初始化,添加回调,以后只要运行reload就会自动执行回调 */ private void init(final Context context) { this.context = context; //初始化等待Dialog progressDialog = ProgressDialog.show(context, "请等待", "正在载入...", true); //初始化CodeView的样式 this.setScrollBarStyle(SCROLLBARS_INSIDE_OVERLAY); this.getSettings().setBuiltInZoomControls(true); this.getSettings().setDisplayZoomControls(false); this.getSettings().setJavaScriptEnabled(true); //给网页添加一个JS回调变量,名字叫"reader",通过loadURL载入JS命令执行回调 this.addJavascriptInterface(reader, JS_VAR_READ); this.addJavascriptInterface(writer, JS_VAR_WRITE); this.setWebViewClient(new WebViewClient()); this.setWebChromeClient(new WebChromeClient(){ @Override public void onProgressChanged(WebView view, int newProgress) { if(newProgress >= 100 && progressDialog.isShowing()) { progressDialog.dismiss(); } } }); } ///////////////////////////////////////////////////////////////////////////////////// //////////////////////////// READER /////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// /** * JS网页信息回调监听器。注意,4.2以后必须加 @JavascriptInterface 否则无法获取信息 * 更新信息后写出到文件 * 获取到信息后发送信息到Listener(如果存在) */ class JSContentReader{ @JavascriptInterface public void read(final String data){ if(listener != null) { listener.onCodeChanged(data); } } } ///////////////////////////////////////////////////////////////////////////////////// //////////////////////////// WRITER /////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// class JSContentWriter { @JavascriptInterface public void write(final String data) { try { FileOutputStream out = new FileOutputStream(codeFile); out.write(data.getBytes()); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } //激活Handler在主线程处理刷新事件 handler.sendEmptyMessage(0); } } private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { setDirSource(codeFile); } }; ///////////////////////////////////////////////////////////////////////////////////// //////////////////////////// SOURCE /////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// /** * 设置文件源,以代码形式载入文件信息 * * @param dir 文件路径。注意,必须是路径形式。 * 例:new File("dir/cache/source.java"); * 错:new File("dir/cache/", "source.java"); */ public void setDirSource(File dir) { //先启动等待Dialog progressDialog.show(); //更新文件对象 this.codeFile = dir; String content = ""; ///////////////// //// Read File try { FileInputStream in = new FileInputStream(dir); ByteArrayOutputStream bufferOut = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; for(int i = in.read(buffer, 0, buffer.length); i > 0 ; i = in.read(buffer, 0, buffer.length)) { bufferOut.write(buffer, 0, i); } content = new String(bufferOut.toByteArray(), Charset.forName("utf-8")); } catch (IOException e) { e.printStackTrace(); } ///////////////// //// Load File // try { // Log.e("PATH----->", content); // this.loadUrl(dir.toURI().toURL().toString()); this.loadDataWithBaseURL(STYLE_DIR, HTMLcode.HTMLHEAD + content + HTMLcode.HTMLTAIL, "text/html", null, null); // } catch (MalformedURLException e) { // e.printStackTrace(); // } } public void requestContentReader(){ loadUrl(JS_COMMAND_READ); } ///////////////////////////////////////////////////////////////////////////////////// //////////////////////////// EDITABLE /////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// /** * 通过JS修改代码域“可编辑”属性 * * @param enable 使能状态 True for Editable False for UnEditable * 关闭编辑模式时存储改变后内容 */ public void setContentEditable(boolean enable){ editEnable = enable; if(editEnable) this.loadUrl(JS_COMMAND_EDITABLE); else { this.loadUrl(JS_COMMAND_UNEDITABLE); this.loadUrl(JS_COMMAND_WRITE); } } public boolean isEditable() { return editEnable; } ///////////////////////////////////////////////////////////////////////////////////// //////////////////////////// LISTENER /////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// public void setListener(OnCodeChangedListener listener) { this.listener = listener; } ///////////////////////////////////////////////////////////////////////////////////// //////////////////////////// HTML /////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// public static class HTMLcode { public static String HTMLHEAD = "<head> <script src=\"code.js\"></script> " + "<link href=\"code.css\" rel=\"stylesheet\"> " + "</head>" + "<body bgcolor=\"#272822\"> " + " <pre class=\"line-numbers\"><code class=\"language-javascript\">"; public static String HTMLTAIL = "</code></pre></body>"; } }