[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n"
  },
  {
    "path": ".idea/dictionaries/zhouqiong.xml",
    "content": "<component name=\"ProjectDictionaryState\">\n  <dictionary name=\"zhouqiong\" />\n</component>"
  },
  {
    "path": ".idea/gradle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleSettings\">\n    <option name=\"linkedExternalProjectsSettings\">\n      <GradleProjectSettings>\n        <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n        <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n        <option name=\"modules\">\n          <set>\n            <option value=\"$PROJECT_DIR$\" />\n            <option value=\"$PROJECT_DIR$/app\" />\n          </set>\n        </option>\n        <option name=\"resolveModulePerSourceSet\" value=\"false\" />\n      </GradleProjectSettings>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"NullableNotNullManager\">\n    <option name=\"myDefaultNullable\" value=\"android.support.annotation.Nullable\" />\n    <option name=\"myDefaultNotNull\" value=\"android.support.annotation.NonNull\" />\n    <option name=\"myNullables\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.Nullable\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nullable\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.Nullable\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.Nullable\" />\n        </list>\n      </value>\n    </option>\n    <option name=\"myNotNulls\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.NotNull\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nonnull\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.NonNull\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.NonNull\" />\n        </list>\n      </value>\n    </option>\n  </component>\n  <component name=\"ProjectInspectionProfilesVisibleTreeState\">\n    <entry key=\"Project Default\">\n      <profile-state>\n        <expanded-state>\n          <State>\n            <id />\n          </State>\n          <State>\n            <id>Android</id>\n          </State>\n          <State>\n            <id>CorrectnessLintAndroid</id>\n          </State>\n          <State>\n            <id>LintAndroid</id>\n          </State>\n          <State>\n            <id>PerformanceLintAndroid</id>\n          </State>\n        </expanded-state>\n        <selected-state>\n          <State>\n            <id>Android</id>\n          </State>\n        </selected-state>\n      </profile-state>\n    </entry>\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_7\" project-jdk-name=\"1.8\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n  <component name=\"masterDetails\">\n    <states>\n      <state key=\"Copyright.UI\">\n        <settings>\n          <splitter-proportions>\n            <option name=\"proportions\">\n              <list>\n                <option value=\"0.2\" />\n              </list>\n            </option>\n          </splitter-proportions>\n        </settings>\n      </state>\n      <state key=\"ScopeChooserConfigurable.UI\">\n        <settings>\n          <splitter-proportions>\n            <option name=\"proportions\">\n              <list>\n                <option value=\"0.2\" />\n              </list>\n            </option>\n          </splitter-proportions>\n        </settings>\n      </state>\n    </states>\n  </component>\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/RichEditotAndroid.iml\" filepath=\"$PROJECT_DIR$/RichEditotAndroid.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/app/app.iml\" filepath=\"$PROJECT_DIR$/app/app.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/runConfigurations.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RunConfigurationProducerService\">\n    <option name=\"ignoredProducers\">\n      <set>\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer\" />\n      </set>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": "README.md",
    "content": "# RichEditotAndroid\nWebView + JavaScript 方式的实现一个android富文本编辑器\n>最近产品提出在移动端实现富文本编辑器功能，需要能编辑文字加粗、颜色、插入图片、下划线等一系列功能等，最后要生成一个html格式然后base64转码后上传服务端，最后在前端网页和移动端显示。\n关于作者 的 《简书》 主页点击这里：[Android富文本编辑器](https://www.jianshu.com/p/9c2c1416d894)\n\n\n这里的功能需要根据需求实现，通过insertImage传入一个URL或者本地图片路径都可以，这里用户可以自己调用本地相或者拍照获取图片，传图本地图片路径，也可以将本地图片路径上传到服务器（自己的服务器或者免费的七牛服务器），返回在服务端的URL地址，将地址传如即可（我这里传了一张写死的图片URL，如果你插入的图片不现实，请检查你是否添加网络请求权限<uses-permission android:name=\"android.permission.INTERNET\" />）\n\n![](https://upload-images.jianshu.io/upload_images/3278692-937a13db04c28c9f.gif?imageMogr2/auto-orient/strip)\n![](https://upload-images.jianshu.io/upload_images/3278692-d309391fbdf9c3f6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n![](https://upload-images.jianshu.io/upload_images/3278692-960adde8b912f4af.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n![](https://upload-images.jianshu.io/upload_images/3278692-bf1fbb1028586dba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 26\n    defaultConfig {\n        applicationId \"com.example.zhouqiong.richeditotandroid\"\n        minSdkVersion 15\n        targetSdkVersion 26\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation 'com.android.support:appcompat-v7:26.1.0'\n    implementation 'com.android.support.constraint:constraint-layout:1.0.2'\n    testImplementation 'junit:junit:4.12'\n    androidTestImplementation 'com.android.support.test:runner:1.0.1'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/androidTest/java/com/example/zhouqiong/richeditotandroid/ExampleInstrumentedTest.java",
    "content": "package com.example.zhouqiong.richeditotandroid;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.example.zhouqiong.richeditotandroid\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.zhouqiong.richeditotandroid\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\"\n        android:windowSoftInputMode=\"adjustResize\">\n        <activity android:name=\".ui.MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <activity android:name=\".ui.WebDataActivity\" />\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/assets/editor.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta name=\"viewport\" content=\"user-scalable=no\">\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"normalize.css\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">\n</head>\n<body>\n<div id=\"editor\" contenteditable=\"true\"></div>\n<script type=\"text/javascript\" src=\"rich_editor.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "app/src/main/assets/normalize.css",
    "content": "/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\n\n/**\n * 1. Set default font family to sans-serif.\n * 2. Prevent iOS text size adjust after orientation change, without disabling\n *    user zoom.\n */\n\nhtml {\n  font-family: sans-serif; /* 1 */\n  -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/**\n * Remove default margin.\n */\n\nbody {\n  margin: 0;\n}\n\n/* HTML5 display definitions\n   ========================================================================== */\n\n/**\n * Correct `block` display not defined for any HTML5 element in IE 8/9.\n * Correct `block` display not defined for `details` or `summary` in IE 10/11\n * and Firefox.\n * Correct `block` display not defined for `main` in IE 11.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n/**\n * 1. Correct `inline-block` display not defined in IE 8/9.\n * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n */\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; /* 1 */\n  vertical-align: baseline; /* 2 */\n}\n\n/**\n * Prevent modern browsers from displaying `audio` without controls.\n * Remove excess height in iOS 5 devices.\n */\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n/**\n * Address `[hidden]` styling not present in IE 8/9/10.\n * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.\n */\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n/* Links\n   ========================================================================== */\n\n/**\n * Remove the gray background color from active links in IE 10.\n */\n\na {\n  background-color: transparent;\n}\n\n/**\n * Improve readability when focused and also mouse hovered in all browsers.\n */\n\na:active,\na:hover {\n  outline: 0;\n}\n\n/* Text-level semantics\n   ========================================================================== */\n\n/**\n * Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n */\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n/**\n * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n */\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n/**\n * Address styling not present in Safari and Chrome.\n */\n\ndfn {\n  font-style: italic;\n}\n\n/**\n * Address variable `h1` font-size and margin within `section` and `article`\n * contexts in Firefox 4+, Safari, and Chrome.\n */\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n/**\n * Address styling not present in IE 8/9.\n */\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n/**\n * Address inconsistent and variable font size in all browsers.\n */\n\nsmall {\n  font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\n */\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n/* Embedded content\n   ========================================================================== */\n\n/**\n * Remove border when inside `a` element in IE 8/9/10.\n */\n\nimg {\n  border: 0;\n}\n\n/**\n * Correct overflow not hidden in IE 9/10/11.\n */\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n/* Grouping content\n   ========================================================================== */\n\n/**\n * Address margin not present in IE 8/9 and Safari.\n */\n\nfigure {\n  margin: 1em 40px;\n}\n\n/**\n * Address differences between Firefox and other browsers.\n */\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\n/**\n * Contain overflow in all browsers.\n */\n\npre {\n  overflow: auto;\n}\n\n/**\n * Address odd `em`-unit font size rendering in all browsers.\n */\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n/* Forms\n   ========================================================================== */\n\n/**\n * Known limitation: by default, Chrome and Safari on OS X allow very limited\n * styling of `select`, unless a `border` property is set.\n */\n\n/**\n * 1. Correct color not being inherited.\n *    Known issue: affects color of disabled elements.\n * 2. Correct font properties not being inherited.\n * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; /* 1 */\n  font: inherit; /* 2 */\n  margin: 0; /* 3 */\n}\n\n/**\n * Address `overflow` set to `hidden` in IE 8/9/10/11.\n */\n\nbutton {\n  overflow: visible;\n}\n\n/**\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\n * All other form control elements do not inherit `text-transform` values.\n * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n * Correct `select` style inheritance in Firefox.\n */\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n/**\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n *    and `video` controls.\n * 2. Correct inability to style clickable `input` types in iOS.\n * 3. Improve usability and consistency of cursor style between image-type\n *    `input` and others.\n */\n\nbutton,\nhtml input[type=\"button\"], /* 1 */\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; /* 2 */\n  cursor: pointer; /* 3 */\n}\n\n/**\n * Re-set default cursor for disabled elements.\n */\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n/**\n * Address Firefox 4+ setting `line-height` on `input` using `!important` in\n * the UA stylesheet.\n */\n\ninput {\n  line-height: normal;\n}\n\n/**\n * It's recommended that you don't attempt to style these elements.\n * Firefox's implementation doesn't respect box-sizing, padding, or width.\n *\n * 1. Address box sizing set to `content-box` in IE 8/9/10.\n * 2. Remove excess padding in IE 8/9/10.\n */\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Fix the cursor style for Chrome's increment/decrement buttons. For certain\n * `font-size` values of the `input`, it causes the cursor style of the\n * decrement button to change from `default` to `text`.\n */\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/**\n * 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n * 2. Address `box-sizing` set to `border-box` in Safari and Chrome\n */\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; /* 1 */\n  -webkit-box-sizing: content-box; /* 2 */\n  box-sizing: content-box;\n}\n\n/**\n * Remove inner padding and search cancel button in Safari and Chrome on OS X.\n * Safari (but not Chrome) clips the cancel button when the search input has\n * padding (and `textfield` appearance).\n */\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/**\n * Define consistent border, margin, and padding.\n */\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n/**\n * 1. Correct `color` not being inherited in IE 8/9/10/11.\n * 2. Remove padding so people aren't caught out if they zero out fieldsets.\n */\n\nlegend {\n  border: 0; /* 1 */\n  padding: 0; /* 2 */\n}\n\n/**\n * Remove default vertical scrollbar in IE 8/9/10/11.\n */\n\ntextarea {\n  overflow: auto;\n}\n\n/**\n * Don't inherit the `font-weight` (applied by a rule above).\n * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n */\n\noptgroup {\n  font-weight: bold;\n}\n\n/* Tables\n   ========================================================================== */\n\n/**\n * Remove most spacing between table cells.\n */\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}"
  },
  {
    "path": "app/src/main/assets/rich_editor.js",
    "content": "/**\n * Copyright (C) 2017 Wasabeef\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nvar RE = {};\n\nRE.currentSelection = {\n    \"startContainer\": 0,\n    \"startOffset\": 0,\n    \"endContainer\": 0,\n    \"endOffset\": 0};\n\nRE.editor = document.getElementById('editor');\n\ndocument.addEventListener(\"selectionchange\", function() { RE.backuprange(); });\n\n// Initializations\nRE.callback = function() {\n    window.location.href = \"re-callback://\" + encodeURI(RE.getHtml());\n}\n\nRE.setHtml = function(contents) {\n    RE.editor.innerHTML = decodeURIComponent(contents.replace(/\\+/g, '%20'));\n}\n\nRE.getHtml = function() {\n    return RE.editor.innerHTML;\n}\n\nRE.getText = function() {\n    return RE.editor.innerText;\n}\n\nRE.setBaseTextColor = function(color) {\n    RE.editor.style.color  = color;\n}\n\nRE.setBaseFontSize = function(size) {\n    RE.editor.style.fontSize = size;\n}\n\nRE.setPadding = function(left, top, right, bottom) {\n  RE.editor.style.paddingLeft = left;\n  RE.editor.style.paddingTop = top;\n  RE.editor.style.paddingRight = right;\n  RE.editor.style.paddingBottom = bottom;\n}\n\nRE.setBackgroundColor = function(color) {\n    document.body.style.backgroundColor = color;\n}\n\nRE.setBackgroundImage = function(image) {\n    RE.editor.style.backgroundImage = image;\n}\n\nRE.setWidth = function(size) {\n    RE.editor.style.minWidth = size;\n}\n\nRE.setHeight = function(size) {\n    RE.editor.style.height = size;\n}\n\nRE.setTextAlign = function(align) {\n    RE.editor.style.textAlign = align;\n}\n\nRE.setVerticalAlign = function(align) {\n    RE.editor.style.verticalAlign = align;\n}\n\nRE.setPlaceholder = function(placeholder) {\n    RE.editor.setAttribute(\"placeholder\", placeholder);\n}\n\nRE.setInputEnabled = function(inputEnabled) {\n    RE.editor.contentEditable = String(inputEnabled);\n}\n\nRE.undo = function() {\n    document.execCommand('undo', false, null);\n}\n\nRE.redo = function() {\n    document.execCommand('redo', false, null);\n}\n\nRE.setBold = function() {\n    document.execCommand('bold', false, null);\n}\n\nRE.setItalic = function() {\n    document.execCommand('italic', false, null);\n}\n\nRE.setSubscript = function() {\n    document.execCommand('subscript', false, null);\n}\n\nRE.setSuperscript = function() {\n    document.execCommand('superscript', false, null);\n}\n\nRE.setStrikeThrough = function() {\n    document.execCommand('strikeThrough', false, null);\n}\n\nRE.setUnderline = function() {\n    document.execCommand('underline', false, null);\n}\n\nRE.setBullets = function() {\n    document.execCommand('insertUnorderedList', false, null);\n}\n\nRE.setNumbers = function() {\n    document.execCommand('insertOrderedList', false, null);\n}\n\nRE.setTextColor = function(color) {\n    RE.restorerange();\n    document.execCommand(\"styleWithCSS\", null, true);\n    document.execCommand('foreColor', false, color);\n    document.execCommand(\"styleWithCSS\", null, false);\n}\n\nRE.setTextBackgroundColor = function(color) {\n    RE.restorerange();\n    document.execCommand(\"styleWithCSS\", null, true);\n    document.execCommand('hiliteColor', false, color);\n    document.execCommand(\"styleWithCSS\", null, false);\n}\n\nRE.setFontSize = function(fontSize){\n    document.execCommand(\"fontSize\", false, fontSize);\n}\n\nRE.setHeading = function(heading) {\n    document.execCommand('formatBlock', false, '<h'+heading+'>');\n}\n\nRE.setIndent = function() {\n    document.execCommand('indent', false, null);\n}\n\nRE.setOutdent = function() {\n    document.execCommand('outdent', false, null);\n}\n\nRE.setJustifyLeft = function() {\n    document.execCommand('justifyLeft', false, null);\n}\n\nRE.setJustifyCenter = function() {\n    document.execCommand('justifyCenter', false, null);\n}\n\nRE.setJustifyRight = function() {\n    document.execCommand('justifyRight', false, null);\n}\n\nRE.setBlockquote = function() {\n    document.execCommand('formatBlock', false, '<blockquote>');\n}\n\nRE.insertImage = function(url, alt) {\n    var html = '<img src=\"' + url + '\" alt=\"' + alt + '\" />';\n    RE.insertHTML(html);\n}\n\nRE.insertHTML = function(html) {\n    RE.restorerange();\n    document.execCommand('insertHTML', false, html);\n}\n\nRE.insertLink = function(url, title) {\n    RE.restorerange();\n    var sel = document.getSelection();\n    if (sel.toString().length == 0) {\n        document.execCommand(\"insertHTML\",false,\"<a href='\"+url+\"'>\"+title+\"</a>\");\n    } else if (sel.rangeCount) {\n       var el = document.createElement(\"a\");\n       el.setAttribute(\"href\", url);\n       el.setAttribute(\"title\", title);\n\n       var range = sel.getRangeAt(0).cloneRange();\n       range.surroundContents(el);\n       sel.removeAllRanges();\n       sel.addRange(range);\n   }\n    RE.callback();\n}\n\nRE.setTodo = function(text) {\n    var html = '<input type=\"checkbox\" name=\"'+ text +'\" value=\"'+ text +'\"/> &nbsp;';\n    document.execCommand('insertHTML', false, html);\n}\n\nRE.prepareInsert = function() {\n    RE.backuprange();\n}\n\nRE.backuprange = function(){\n    var selection = window.getSelection();\n    if (selection.rangeCount > 0) {\n      var range = selection.getRangeAt(0);\n      RE.currentSelection = {\n          \"startContainer\": range.startContainer,\n          \"startOffset\": range.startOffset,\n          \"endContainer\": range.endContainer,\n          \"endOffset\": range.endOffset};\n    }\n}\n\nRE.restorerange = function(){\n    var selection = window.getSelection();\n    selection.removeAllRanges();\n    var range = document.createRange();\n    range.setStart(RE.currentSelection.startContainer, RE.currentSelection.startOffset);\n    range.setEnd(RE.currentSelection.endContainer, RE.currentSelection.endOffset);\n    selection.addRange(range);\n}\n\nRE.enabledEditingItems = function(e) {\n    var items = [];\n    if (document.queryCommandState('bold')) {\n        items.push('bold');\n    }\n    if (document.queryCommandState('italic')) {\n        items.push('italic');\n    }\n    if (document.queryCommandState('subscript')) {\n        items.push('subscript');\n    }\n    if (document.queryCommandState('superscript')) {\n        items.push('superscript');\n    }\n    if (document.queryCommandState('strikeThrough')) {\n        items.push('strikeThrough');\n    }\n    if (document.queryCommandState('underline')) {\n        items.push('underline');\n    }\n    if (document.queryCommandState('insertOrderedList')) {\n        items.push('orderedList');\n    }\n    if (document.queryCommandState('insertUnorderedList')) {\n        items.push('unorderedList');\n    }\n    if (document.queryCommandState('justifyCenter')) {\n        items.push('justifyCenter');\n    }\n    if (document.queryCommandState('justifyFull')) {\n        items.push('justifyFull');\n    }\n    if (document.queryCommandState('justifyLeft')) {\n        items.push('justifyLeft');\n    }\n    if (document.queryCommandState('justifyRight')) {\n        items.push('justifyRight');\n    }\n    if (document.queryCommandState('insertHorizontalRule')) {\n        items.push('horizontalRule');\n    }\n    var formatBlock = document.queryCommandValue('formatBlock');\n    if (formatBlock.length > 0) {\n        items.push(formatBlock);\n    }\n\n    window.location.href = \"re-state://\" + encodeURI(items.join(','));\n}\n\nRE.focus = function() {\n    var range = document.createRange();\n    range.selectNodeContents(RE.editor);\n    range.collapse(false);\n    var selection = window.getSelection();\n    selection.removeAllRanges();\n    selection.addRange(range);\n    RE.editor.focus();\n}\n\nRE.blurFocus = function() {\n    RE.editor.blur();\n}\n\nRE.removeFormat = function() {\n    document.execCommand('removeFormat', false, null);\n}\n\n// Event Listeners\nRE.editor.addEventListener(\"input\", RE.callback);\nRE.editor.addEventListener(\"keyup\", function(e) {\n    var KEY_LEFT = 37, KEY_RIGHT = 39;\n    if (e.which == KEY_LEFT || e.which == KEY_RIGHT) {\n        RE.enabledEditingItems(e);\n    }\n});\nRE.editor.addEventListener(\"click\", RE.enabledEditingItems);\n"
  },
  {
    "path": "app/src/main/assets/style.css",
    "content": "/**\n * Copyright (C) 2017 Wasabeef\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@charset \"UTF-8\";\n\n\nhtml {\n  height: 100%;\n}\n\nbody {\n  overflow: scroll;\n  display: table;\n  table-layout: fixed;\n  width: 100%;\n  min-height:100%;\n}\n\n#editor {\n  display: table-cell;\n  outline: 0px solid transparent;\n  background-repeat: no-repeat;\n  background-position: center;\n  background-size: cover;\n}\n\n#editor[placeholder]:empty:not(:focus):before {\n  content: attr(placeholder);\n  opacity: .5;\n}}\n"
  },
  {
    "path": "app/src/main/java/com/example/zhouqiong/richeditotandroid/ui/MainActivity.java",
    "content": "package com.example.zhouqiong.richeditotandroid.ui;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListenerAdapter;\nimport android.animation.ValueAnimator;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.example.zhouqiong.richeditotandroid.R;\nimport com.example.zhouqiong.richeditotandroid.view.ColorPickerView;\nimport com.example.zhouqiong.richeditotandroid.view.RichEditor;\n\npublic class MainActivity extends AppCompatActivity implements View.OnClickListener {\n    /********************View**********************/\n    //文本编辑器\n    private RichEditor mEditor;\n    //加粗按钮\n    private ImageView mBold;\n    //颜色编辑器\n    private TextView mTextColor;\n    //显示显示View\n    private LinearLayout llColorView;\n    //预览按钮\n    private TextView mPreView;\n    //图片按钮\n    private TextView mImage;\n    //按序号排列（ol）\n    private ImageView mListOL;\n    //按序号排列（ul）\n    private ImageView mListUL;\n    //字体下划线\n    private ImageView mLean;\n    //字体倾斜\n    private ImageView mItalic;\n    //字体左对齐\n    private ImageView mAlignLeft;\n    //字体右对齐\n    private ImageView mAlignRight;\n    //字体居中对齐\n    private ImageView mAlignCenter;\n    //字体缩进\n    private ImageView mIndent;\n    //字体较少缩进\n    private ImageView mOutdent;\n    //字体索引\n    private ImageView mBlockquote;\n    //字体中划线\n    private ImageView mStrikethrough;\n    //字体上标\n    private ImageView mSuperscript;\n    //字体下标\n    private ImageView mSubscript;\n    /********************boolean开关**********************/\n    //是否加粗\n    boolean isClickBold = false;\n    //是否正在执行动画\n    boolean isAnimating = false;\n    //是否按ol排序\n    boolean isListOl = false;\n    //是否按ul排序\n    boolean isListUL = false;\n    //是否下划线字体\n    boolean isTextLean = false;\n    //是否下倾斜字体\n    boolean isItalic = false;\n    //是否左对齐\n    boolean isAlignLeft = false;\n    //是否右对齐\n    boolean isAlignRight = false;\n    //是否中对齐\n    boolean isAlignCenter = false;\n    //是否缩进\n    boolean isIndent = false;\n    //是否较少缩进\n    boolean isOutdent = false;\n    //是否索引\n    boolean isBlockquote = false;\n    //字体中划线\n    boolean isStrikethrough = false;\n    //字体上标\n    boolean isSuperscript = false;\n    //字体下标\n    boolean isSubscript = false;\n    /********************变量**********************/\n    //折叠视图的宽高\n    private int mFoldedViewMeasureHeight;\n\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        initView();\n        initClickListener();\n    }\n\n    /**\n     * 初始化View\n     */\n    private void initView() {\n        initEditor();\n        initMenu();\n        initColorPicker();\n    }\n\n    /**\n     * 初始化文本编辑器\n     */\n    private void initEditor() {\n        mEditor = findViewById(R.id.re_main_editor);\n        //mEditor.setEditorHeight(400);\n        //输入框显示字体的大小\n        mEditor.setEditorFontSize(18);\n        //输入框显示字体的颜色\n        mEditor.setEditorFontColor(Color.BLACK);\n        //输入框背景设置\n        mEditor.setEditorBackgroundColor(Color.WHITE);\n        //mEditor.setBackgroundColor(Color.BLUE);\n        //mEditor.setBackgroundResource(R.drawable.bg);\n        //mEditor.setBackground(\"https://raw.githubusercontent.com/wasabeef/art/master/chip.jpg\");\n        //输入框文本padding\n        mEditor.setPadding(10, 10, 10, 10);\n        //输入提示文本\n        mEditor.setPlaceholder(\"请输入编辑内容\");\n        //是否允许输入\n        //mEditor.setInputEnabled(false);\n        //文本输入框监听事件\n        mEditor.setOnTextChangeListener(new RichEditor.OnTextChangeListener() {\n            @Override\n            public void onTextChange(String text) {\n                Log.d(\"mEditor\", \"html文本：\" + text);\n            }\n        });\n    }\n\n    /**\n     * 初始化颜色选择器\n     */\n    private void initColorPicker() {\n        ColorPickerView right = findViewById(R.id.cpv_main_color);\n        right.setOnColorPickerChangeListener(new ColorPickerView.OnColorPickerChangeListener() {\n            @Override\n            public void onColorChanged(ColorPickerView picker, int color) {\n                mTextColor.setBackgroundColor(color);\n                mEditor.setTextColor(color);\n            }\n\n            @Override\n            public void onStartTrackingTouch(ColorPickerView picker) {\n\n            }\n\n            @Override\n            public void onStopTrackingTouch(ColorPickerView picker) {\n\n            }\n        });\n    }\n\n    /**\n     * 初始化菜单按钮\n     */\n    private void initMenu() {\n        mBold = findViewById(R.id.button_bold);\n        mTextColor = findViewById(R.id.button_text_color);\n        llColorView = findViewById(R.id.ll_main_color);\n        mPreView = findViewById(R.id.tv_main_preview);\n        mImage = findViewById(R.id.button_image);\n        mListOL = findViewById(R.id.button_list_ol);\n        mListUL = findViewById(R.id.button_list_ul);\n        mLean = findViewById(R.id.button_underline);\n        mItalic = findViewById(R.id.button_italic);\n        mAlignLeft = findViewById(R.id.button_align_left);\n        mAlignRight = findViewById(R.id.button_align_right);\n        mAlignCenter = findViewById(R.id.button_align_center);\n        mIndent = findViewById(R.id.button_indent);\n        mOutdent = findViewById(R.id.button_outdent);\n        mBlockquote = findViewById(R.id.action_blockquote);\n        mStrikethrough = findViewById(R.id.action_strikethrough);\n        mSuperscript = findViewById(R.id.action_superscript);\n        mSubscript = findViewById(R.id.action_subscript);\n        getViewMeasureHeight();\n    }\n\n    /**\n     * 获取控件的高度\n     */\n    private void getViewMeasureHeight() {\n        //获取像素密度\n        float mDensity = getResources().getDisplayMetrics().density;\n        //获取布局的高度\n        int w = View.MeasureSpec.makeMeasureSpec(0,\n                View.MeasureSpec.UNSPECIFIED);\n        int h = View.MeasureSpec.makeMeasureSpec(0,\n                View.MeasureSpec.UNSPECIFIED);\n        llColorView.measure(w, h);\n        int height = llColorView.getMeasuredHeight();\n        mFoldedViewMeasureHeight = (int) (mDensity * height + 0.5);\n    }\n\n    private void initClickListener() {\n        mBold.setOnClickListener(this);\n        mTextColor.setOnClickListener(this);\n        mPreView.setOnClickListener(this);\n        mImage.setOnClickListener(this);\n        mListOL.setOnClickListener(this);\n        mListUL.setOnClickListener(this);\n        mLean.setOnClickListener(this);\n        mItalic.setOnClickListener(this);\n        mAlignLeft.setOnClickListener(this);\n        mAlignRight.setOnClickListener(this);\n        mAlignCenter.setOnClickListener(this);\n        mIndent.setOnClickListener(this);\n        mOutdent.setOnClickListener(this);\n        mBlockquote.setOnClickListener(this);\n        mStrikethrough.setOnClickListener(this);\n        mSuperscript.setOnClickListener(this);\n        mSubscript.setOnClickListener(this);\n    }\n\n    @Override\n    public void onClick(View v) {\n        int id = v.getId();\n        if (id == R.id.button_bold) {//字体加粗\n            if (isClickBold) {\n                mBold.setImageResource(R.mipmap.bold);\n            } else {  //加粗\n                mBold.setImageResource(R.mipmap.bold_);\n            }\n            isClickBold = !isClickBold;\n            mEditor.setBold();\n        } else if (id == R.id.button_text_color) {//设置字体颜色\n            //如果动画正在执行,直接return,相当于点击无效了,不会出现当快速点击时,\n            // 动画的执行和ImageButton的图标不一致的情况\n            if (isAnimating) return;\n            //如果动画没在执行,走到这一步就将isAnimating制为true , 防止这次动画还没有执行完毕的\n            //情况下,又要执行一次动画,当动画执行完毕后会将isAnimating制为false,这样下次动画又能执行\n            isAnimating = true;\n\n            if (llColorView.getVisibility() == View.GONE) {\n                //打开动画\n                animateOpen(llColorView);\n            } else {\n                //关闭动画\n                animateClose(llColorView);\n            }\n        } else if (id == R.id.button_image) {//插入图片\n            //这里的功能需要根据需求实现，通过insertImage传入一个URL或者本地图片路径都可以，这里用户可以自己调用本地相\n            //或者拍照获取图片，传图本地图片路径，也可以将本地图片路径上传到服务器（自己的服务器或者免费的七牛服务器），\n            //返回在服务端的URL地址，将地址传如即可（我这里传了一张写死的图片URL，如果你插入的图片不现实，请检查你是否添加\n            // 网络请求权限<uses-permission android:name=\"android.permission.INTERNET\" />）\n            mEditor.insertImage(\"http://www.1honeywan.com/dachshund/image/7.21/7.21_3_thumb.JPG\",\n                    \"dachshund\");\n        } else if (id == R.id.button_list_ol) {\n            if (isListOl) {\n                mListOL.setImageResource(R.mipmap.list_ol);\n            } else {\n                mListOL.setImageResource(R.mipmap.list_ol_);\n            }\n            isListOl = !isListOl;\n            mEditor.setNumbers();\n        } else if (id == R.id.button_list_ul) {\n            if (isListUL) {\n                mListUL.setImageResource(R.mipmap.list_ul);\n            } else {\n                mListUL.setImageResource(R.mipmap.list_ul_);\n            }\n            isListUL = !isListUL;\n            mEditor.setBullets();\n        } else if (id == R.id.button_underline) {\n            if (isTextLean) {\n                mLean.setImageResource(R.mipmap.underline);\n            } else {\n                mLean.setImageResource(R.mipmap.underline_);\n            }\n            isTextLean = !isTextLean;\n            mEditor.setUnderline();\n        } else if (id == R.id.button_italic) {\n            if (isItalic) {\n                mItalic.setImageResource(R.mipmap.lean);\n            } else {\n                mItalic.setImageResource(R.mipmap.lean_);\n            }\n            isItalic = !isItalic;\n            mEditor.setItalic();\n        } else if (id == R.id.button_align_left) {\n            if (isAlignLeft) {\n                mAlignLeft.setImageResource(R.mipmap.align_left);\n            } else {\n                mAlignLeft.setImageResource(R.mipmap.align_left_);\n            }\n            isAlignLeft = !isAlignLeft;\n            mEditor.setAlignLeft();\n        } else if (id == R.id.button_align_right) {\n            if (isAlignRight) {\n                mAlignRight.setImageResource(R.mipmap.align_right);\n            } else {\n                mAlignRight.setImageResource(R.mipmap.align_right_);\n            }\n            isAlignRight = !isAlignRight;\n            mEditor.setAlignRight();\n        } else if (id == R.id.button_align_center) {\n            if (isAlignCenter) {\n                mAlignCenter.setImageResource(R.mipmap.align_center);\n            } else {\n                mAlignCenter.setImageResource(R.mipmap.align_center_);\n            }\n            isAlignCenter = !isAlignCenter;\n            mEditor.setAlignCenter();\n        } else if (id == R.id.button_indent) {\n            if (isIndent) {\n                mIndent.setImageResource(R.mipmap.indent);\n            } else {\n                mIndent.setImageResource(R.mipmap.indent_);\n            }\n            isIndent = !isIndent;\n            mEditor.setIndent();\n        } else if (id == R.id.button_outdent) {\n            if (isOutdent) {\n                mOutdent.setImageResource(R.mipmap.outdent);\n            } else {\n                mOutdent.setImageResource(R.mipmap.outdent_);\n            }\n            isOutdent = !isOutdent;\n            mEditor.setOutdent();\n        } else if (id == R.id.action_blockquote) {\n            if (isBlockquote) {\n                mBlockquote.setImageResource(R.mipmap.blockquote);\n            } else {\n                mBlockquote.setImageResource(R.mipmap.blockquote_);\n            }\n            isBlockquote = !isBlockquote;\n            mEditor.setBlockquote();\n        } else if (id == R.id.action_strikethrough) {\n            if (isStrikethrough) {\n                mStrikethrough.setImageResource(R.mipmap.strikethrough);\n            } else {\n                mStrikethrough.setImageResource(R.mipmap.strikethrough_);\n            }\n            isStrikethrough = !isStrikethrough;\n            mEditor.setStrikeThrough();\n        } else if (id == R.id.action_superscript) {\n            if (isSuperscript) {\n                mSuperscript.setImageResource(R.mipmap.superscript);\n            } else {\n                mSuperscript.setImageResource(R.mipmap.superscript_);\n            }\n            isSuperscript = !isSuperscript;\n            mEditor.setSuperscript();\n        } else if (id == R.id.action_subscript) {\n            if (isSubscript) {\n                mSubscript.setImageResource(R.mipmap.subscript);\n            } else {\n                mSubscript.setImageResource(R.mipmap.subscript_);\n            }\n            isSubscript = !isSubscript;\n            mEditor.setSubscript();\n        }\n\n        //H1--H6省略，需要的自己添加\n\n        else if (id == R.id.tv_main_preview) {//预览\n            Intent intent = new Intent(MainActivity.this, WebDataActivity.class);\n            intent.putExtra(\"diarys\", mEditor.getHtml());\n            startActivity(intent);\n        }\n    }\n\n    /**\n     * 开启动画\n     *\n     * @param view 开启动画的view\n     */\n    private void animateOpen(LinearLayout view) {\n        view.setVisibility(View.VISIBLE);\n        ValueAnimator animator = createDropAnimator(view, 0, mFoldedViewMeasureHeight);\n        animator.addListener(new AnimatorListenerAdapter() {\n            @Override\n            public void onAnimationEnd(Animator animation) {\n                isAnimating = false;\n            }\n        });\n        animator.start();\n    }\n\n    /**\n     * 关闭动画\n     *\n     * @param view 关闭动画的view\n     */\n    private void animateClose(final LinearLayout view) {\n        int origHeight = view.getHeight();\n        ValueAnimator animator = createDropAnimator(view, origHeight, 0);\n        animator.addListener(new AnimatorListenerAdapter() {\n            @Override\n            public void onAnimationEnd(Animator animation) {\n                view.setVisibility(View.GONE);\n                isAnimating = false;\n            }\n        });\n        animator.start();\n    }\n\n\n    /**\n     * 创建动画\n     *\n     * @param view  开启和关闭动画的view\n     * @param start view的高度\n     * @param end   view的高度\n     * @return ValueAnimator对象\n     */\n    private ValueAnimator createDropAnimator(final View view, int start, int end) {\n        ValueAnimator animator = ValueAnimator.ofInt(start, end);\n        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {\n            @Override\n            public void onAnimationUpdate(ValueAnimator animation) {\n                int value = (int) animation.getAnimatedValue();\n                ViewGroup.LayoutParams layoutParams = view.getLayoutParams();\n                layoutParams.height = value;\n                view.setLayoutParams(layoutParams);\n            }\n        });\n        return animator;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/zhouqiong/richeditotandroid/ui/WebDataActivity.java",
    "content": "package com.example.zhouqiong.richeditotandroid.ui;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.webkit.JavascriptInterface;\nimport android.webkit.WebSettings;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\nimport android.widget.Toast;\n\nimport com.example.zhouqiong.richeditotandroid.R;\nimport com.example.zhouqiong.richeditotandroid.ui.MainActivity;\n\n/**\n * Created by ZQiong on 2018/3/20.\n */\n\npublic class WebDataActivity extends AppCompatActivity {\n\n\n    //自己制造的一些假数据。外加筛选图片样式\n    /****  3333333333 ***************************************************/\n//    private String dataStr=\"<html><body><style>img{ width:100% !important;}</style>\"+\"<img src=\\\"https://ss0.bdstatic.com/-0U0bnSm1A5BphGlnYG/tam-ogel/dd9d1d686cdc814db9653b254e00402e_259_194.jpg\\\" alt=\\\"\\\" /> \\r<p style=\\\"text-align:right;\\\">\\r\\t品类定位的思考\\r</p>\\r<h3>\\r\\t<strong><span style=\\\"color:#00D5FF;\\\">品类定</span></strong>\\n\" +\n//            \"<h3>\\r\\t<a href='JavaScript:android.returnAndroid(\\\"要返回给APP的数据\\\")'>点击我跳回APP</a>\"+\"</body></html>\";\n\n\n    /***  11111111111  **************************************************************************/\n    //这个数据的外层不加两层<html><body>标签，不过在下面一个地方加上一个div和图片样式\n//    private String dataStr = \"<img src=\\\"https://ss0.bdstatic.com/-0U0bnSm1A5BphGlnYG/tam-ogel/dd9d1d686cdc814db9653b254e00402e_259_194.jpg\\\" alt=\\\"\\\" /> \\r<p style=\\\"text-align:right;\\\">\\r\\t品类定位的思考\\r</p>\\r<h3>\\r\\t<strong><span style=\\\"color:#00D5FF;\\\">品类定\";\n\n    /****  11111111111  *************************************************************************/\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_show_diarys);\n        final String dataStr = getIntent().getStringExtra(\"diarys\");\n        initWebView(dataStr);\n    }\n\n    public void initWebView(String data) {\n        WebView mWebView = findViewById(R.id.showdiarys);\n        WebSettings settings = mWebView.getSettings();\n\n        //settings.setUseWideViewPort(true);//调整到适合webview的大小，不过尽量不要用，有些手机有问题\n        settings.setLoadWithOverviewMode(true);//设置WebView是否使用预览模式加载界面。\n        mWebView.setVerticalScrollBarEnabled(false);//不能垂直滑动\n        mWebView.setHorizontalScrollBarEnabled(false);//不能水平滑动\n        settings.setTextSize(WebSettings.TextSize.NORMAL);//通过设置WebSettings，改变HTML中文字的大小\n        settings.setJavaScriptCanOpenWindowsAutomatically(true);//支持通过JS打开新窗口\n        //设置WebView属性，能够执行Javascript脚本\n        mWebView.getSettings().setJavaScriptEnabled(true);//设置js可用\n        mWebView.setWebViewClient(new WebViewClient());\n        mWebView.addJavascriptInterface(new AndroidJavaScript(getApplication()), \"android\");//设置js接口\n        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);//支持内容重新布局\n\n\n/******  22222222  ***********************************************************************/\n        data = \"</Div><head><style>img{ width:100% !important;}</style></head>\" + data;//给图片设置一个样式，宽满屏\n/******  2222222222  ***********************************************************************/\n\n        mWebView.loadDataWithBaseURL(null, data, \"text/html\", \"utf-8\", null);\n    }\n\n    /**\n     * AndroidJavaScript\n     * 本地与h5页面交互的js类，这里写成内部类了\n     * returnAndroid方法上@JavascriptInterface一定不能漏了\n     */\n    private class AndroidJavaScript {\n        Context mContxt;\n\n        public AndroidJavaScript(Context mContxt) {\n            this.mContxt = mContxt;\n        }\n\n        @JavascriptInterface\n        public void returnAndroid(String name) {//从网页跳回到APP，这个方法已经在上面的HTML中写上了\n            if (name.isEmpty() || name.equals(\"\")) {\n                return;\n            }\n            Toast.makeText(getApplication(), name, Toast.LENGTH_SHORT).show();\n            //这里写你的操作///////////////////////\n            //MainActivity就是一个空页面，不影响\n            Intent intent = new Intent(WebDataActivity.this, MainActivity.class);\n            intent.putExtra(\"name\", name);\n            startActivity(intent);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/zhouqiong/richeditotandroid/utils/Utils.java",
    "content": "package com.example.zhouqiong.richeditotandroid.utils;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.util.Base64;\n\nimport java.io.ByteArrayOutputStream;\n\n/**\n * Created by ZQiong on 2018/3/22.\n */\n\npublic final class Utils {\n\n    private Utils() throws InstantiationException {\n        throw new InstantiationException(\"This class is not for instantiation\");\n    }\n\n    public static String toBase64(Bitmap bitmap) {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);\n        byte[] bytes = baos.toByteArray();\n\n        return Base64.encodeToString(bytes, Base64.NO_WRAP);\n    }\n\n    public static Bitmap toBitmap(Drawable drawable) {\n        if (drawable instanceof BitmapDrawable) {\n            return ((BitmapDrawable) drawable).getBitmap();\n        }\n\n        int width = drawable.getIntrinsicWidth();\n        width = width > 0 ? width : 1;\n        int height = drawable.getIntrinsicHeight();\n        height = height > 0 ? height : 1;\n\n        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n        Canvas canvas = new Canvas(bitmap);\n        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());\n        drawable.draw(canvas);\n\n        return bitmap;\n    }\n\n    public static Bitmap decodeResource(Context context, int resId) {\n        return BitmapFactory.decodeResource(context.getResources(), resId);\n    }\n\n    public static long getCurrentTime() {\n        return System.currentTimeMillis();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/zhouqiong/richeditotandroid/view/ColorPickerView.java",
    "content": "package com.example.zhouqiong.richeditotandroid.view;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.LinearGradient;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.Shader;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\n\nimport com.example.zhouqiong.richeditotandroid.R;\n\n/**\n * Created by ZQiong on 2018/3/22.\n * <p>\n * 指示点的半径是颜色条宽度的 4/3 ,两端会有指示点半径长的距离是空白的，这是为了给指示点滑动到端点时留出足够的显示空间，\n * 这也导致当控件宽高的差值太小时，指示点会完全覆盖住颜色条，使颜色条不可见，<strong>因此应尽量根据控件的不同模式使长\n * 边与段边的比例不小于 3 ： 1</strong>\n * <br>\n * <p>\n * 两种模式：\n * <p>\n * HORIZONTAL 水平\n * <p>\n * VERTICAL 竖直\n */\n\npublic class ColorPickerView extends View {\n\n    /**\n     * 指示点颜色\n     */\n    private int mIndicatorColor;\n    /**\n     * 是否启用指示点\n     */\n    private boolean mIndicatorEnable;\n\n    /**\n     * View 和 bitmapForColor 的画笔\n     */\n    private final Paint paint;\n\n    /**\n     * 指示点专用画笔，这样可以避免 mIndicatorColor 有 alpha 时，alpha 作用于 View\n     */\n    private final Paint paintForIndicator;\n\n    private LinearGradient linearGradient;\n\n    /**\n     * 除去上下 padding 的端点坐标\n     */\n    private int mTop, mLeft, mRight, mBottom;\n\n    /**\n     * 颜色条圆角矩形边界\n     */\n    private final Rect rect = new Rect();\n\n    /**\n     * bitmapForIndicator 在 View 上的绘制位置\n     */\n    private final Rect rectForIndicator = new Rect();\n\n    /**\n     * 指示点半径\n     */\n    private int mRadius;\n\n    /**\n     * 控件方向\n     */\n    private Orientation orientation;\n\n    // 默认状态下长边与短边的比例为 6 ：1\n    private static final int defaultSizeShort = 70; // * 6\n    private static final int defaultSizeLong = 420;\n\n    // 不直接绘制在 View 提供的画布上的原因是：选取颜色时需要提取 Bitmap 上的颜色，View 的 Bitmap 无法获取，\n    // 而且有指示点时指示点会覆盖主颜色条(重绘颜色条的颜色)\n    private Bitmap bitmapForColor;\n    private Bitmap bitmapForIndicator;\n\n    /**\n     * 是否需要绘制颜色条(指示点)，颜色条在选取颜色时不需要再次生成(bitmapForColor)，直接绘制就行\n     */\n    private boolean needReDrawColorTable = true;\n    private boolean needReDrawIndicator = true;\n\n    /**\n     * 手指在颜色条上的坐标\n     */\n    private int curX, curY;\n\n    private int[] colors = null;\n\n    private int currentColor;\n\n    /**\n     * 控件方向\n     */\n    public enum Orientation {\n        /**\n         * 水平\n         */\n        HORIZONTAL, // 0\n\n        /**\n         * 竖直\n         */\n        VERTICAL // 1\n\n    }\n\n    {\n        bitmapForColor = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);\n        bitmapForIndicator = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);\n\n        //Android4.0（API14）之后硬件加速功能就被默认开启了,setShadowLayer 在开启硬件加速的情况下无效，需要关闭硬件加速\n        this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);\n\n        paint = new Paint();\n        paint.setAntiAlias(true);\n\n        paintForIndicator = new Paint();\n        paintForIndicator.setAntiAlias(true);\n\n        curX = curY = Integer.MAX_VALUE;\n    }\n\n    public ColorPickerView(Context context) {\n        super(context);\n    }\n\n    public ColorPickerView(Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public ColorPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        final TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ColorPickerView, defStyleAttr, 0);\n        mIndicatorColor = array.getColor(R.styleable.ColorPickerView_indicatorColor, Color.WHITE);\n\n        int or = array.getInteger(R.styleable.ColorPickerView_orientation, 0);\n        orientation = or == 0 ? Orientation.HORIZONTAL : Orientation.VERTICAL;\n\n        mIndicatorEnable = array.getBoolean(R.styleable.ColorPickerView_indicatorEnable, true);\n\n        array.recycle();\n\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        int widthMode = MeasureSpec.getMode(widthMeasureSpec);\n        int widthSize = MeasureSpec.getSize(widthMeasureSpec);\n        int heightMode = MeasureSpec.getMode(heightMeasureSpec);\n        int heightSize = MeasureSpec.getSize(heightMeasureSpec);\n        int width;\n        int height;\n\n        if (widthMode == MeasureSpec.EXACTLY) {\n            width = widthSize;\n        } else {//xml中宽度设为warp_content\n            width = getSuggestedMinimumWidth() + getPaddingLeft() + getPaddingRight();\n        }\n\n        if (heightMode == MeasureSpec.EXACTLY) {\n            height = heightSize;\n        } else {\n            height = getSuggestedMinimumHeight() + getPaddingTop() + getPaddingBottom();\n        }\n\n        width = Math.max(width, orientation == Orientation.HORIZONTAL ? defaultSizeLong : defaultSizeShort);\n        height = Math.max(height, orientation == Orientation.HORIZONTAL ? defaultSizeShort : defaultSizeLong);\n\n        setMeasuredDimension(width, height);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        super.onLayout(changed, left, top, right, bottom);\n        mTop = getPaddingTop();\n        mLeft = getPaddingLeft();\n        mBottom = getMeasuredHeight() - getPaddingBottom();\n        mRight = getMeasuredWidth() - getPaddingRight();\n\n        if (curX == curY || curY == Integer.MAX_VALUE) {\n            curX = getWidth() / 2;\n            curY = getHeight() / 2;\n        }\n\n        calculBounds();\n        if (colors == null) {\n            setColors(createDefaultColorTable());\n        } else {\n            setColors(colors);\n        }\n        createBitmap();\n\n        if (mIndicatorEnable) {\n            needReDrawIndicator = true;\n        }\n\n    }\n\n    private void createBitmap() {\n\n        int hc = rect.height();\n        int wc = rect.width();\n        int hi = mRadius * 2;\n        int wi = hi;\n\n        if (bitmapForColor != null) {\n            if (!bitmapForColor.isRecycled()) {\n                bitmapForColor.recycle();\n                bitmapForColor = null;\n            }\n        }\n\n        if (bitmapForIndicator != null) {\n            if (!bitmapForIndicator.isRecycled()) {\n                bitmapForIndicator.recycle();\n                bitmapForIndicator = null;\n            }\n        }\n\n        bitmapForColor = Bitmap.createBitmap(wc, hc, Bitmap.Config.ARGB_8888);\n        bitmapForIndicator = Bitmap.createBitmap(wi, hi, Bitmap.Config.ARGB_8888);\n\n    }\n\n    /**\n     * 计算颜色条边界\n     */\n    private void calculBounds() {\n\n        /*\n         * 将控件可用高度(除去上下 padding )均分为 6 份，以此计算指示点半径，颜色条宽高\n         * 控件方向为 HORIZONTAL 时，从上往下依次占的份额为：\n         * 1/9 留白\n         * 2/9 颜色条上面部分圆\n         * 3/9 颜色条宽\n         * 2/9 颜色条上面部分圆\n         * 1/9 留白\n         */\n        final int average = 9;\n\n        /*\n         * 每一份的高度\n         */\n        int each;\n\n        int h = mBottom - mTop;\n        int w = mRight - mLeft;\n        int size = Math.min(w, h);\n\n        if (orientation == Orientation.HORIZONTAL) {\n            if (w <= h) { // HORIZONTAL 模式，然而宽却小于高，以 6 ：1 的方式重新计算高\n                size = w / 6;\n            }\n        } else {\n            if (w >= h) {\n                size = h / 6;\n            }\n        }\n\n        each = size / average;\n        mRadius = each * 7 / 2;\n\n        int t, l, b, r;\n        final int s = each * 3 / 2;\n\n        if (orientation == Orientation.HORIZONTAL) {\n            l = mLeft + mRadius;\n            r = mRight - mRadius;\n\n            t = (getHeight() / 2) - s;\n            b = (getHeight() / 2) + s;\n        } else {\n            t = mTop + mRadius;\n            b = mBottom - mRadius;\n\n            l = getWidth() / 2 - s;\n            r = getWidth() / 2 + s;\n        }\n\n        rect.set(l, t, r, b);\n    }\n\n    /**\n     * 设置颜色条的渐变颜色，不支持具有 alpha 的颜色，{@link Color#TRANSPARENT}会被当成 {@link Color#BLACK}处理\n     * 如果想设置 alpha ，可以在{@link OnColorPickerChangeListener#onColorChanged(ColorPickerView, int)} 回调\n     * 中调用{@link android.support.v4.graphics.ColorUtils#setAlphaComponent(int, int)}方法添加 alpha 值。\n     *\n     * @param colors 颜色值\n     */\n    public void setColors(int... colors) {\n        linearGradient = null;\n        this.colors = colors;\n\n        if (orientation == Orientation.HORIZONTAL) {\n            linearGradient = new LinearGradient(\n                    rect.left, rect.top,\n                    rect.right, rect.top,\n                    colors,\n                    null,\n                    Shader.TileMode.CLAMP\n            );\n        } else {\n            linearGradient = new LinearGradient(\n                    rect.left, rect.top,\n                    rect.left, rect.bottom,\n                    colors,\n                    null,\n                    Shader.TileMode.CLAMP\n            );\n        }\n\n        needReDrawColorTable = true;\n        invalidate();\n    }\n\n    public int[] createDefaultColorTable() {\n\n//        int[] cs = {\n//                Color.rgb(0, 0, 0),//白色\n//                Color.rgb(255, 0, 0),//红色\n//                Color.rgb(0, 255, 0),//绿色\n//                Color.rgb(0, 255, 255),//青色\n//                Color.rgb(0, 0, 255),//蓝色\n//                Color.rgb(255, 0, 255),//紫色\n//                Color.rgb(255, 255, 255)//黑色\n//        };\n        int[] cs = {\n                Color.rgb(0, 0, 0),\n                Color.rgb(255, 0, 0),//红色\n                Color.rgb(255, 255, 0),\n                Color.rgb(0, 255, 0),//绿色\n                Color.rgb(0, 255, 255),//青色\n                Color.rgb(0, 0, 255),//蓝色\n                Color.rgb(255, 0, 255),\n                Color.rgb(255, 0, 0)//红色\n        };\n        return cs;\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n\n        if (needReDrawColorTable) {\n            createColorTableBitmap();\n        }\n        // 绘制颜色条\n        canvas.drawBitmap(bitmapForColor, null, rect, paint);\n\n        if (mIndicatorEnable) {\n            if (needReDrawIndicator) {\n                createIndicatorBitmap();\n            }\n\n            // 绘制指示点\n            rectForIndicator.set(curX - mRadius, curY - mRadius, curX + mRadius, curY + mRadius);\n            canvas.drawBitmap(bitmapForIndicator, null, rectForIndicator, paint);\n        }\n    }\n\n    private void createIndicatorBitmap() {\n\n        paintForIndicator.setColor(mIndicatorColor);\n        int radius = 3;\n        paintForIndicator.setShadowLayer(radius, 0, 0, Color.GRAY);\n\n        Canvas c = new Canvas(bitmapForIndicator);\n        c.drawCircle(mRadius, mRadius, mRadius - radius, paintForIndicator);\n\n        needReDrawIndicator = false;\n    }\n\n    private void createColorTableBitmap() {\n\n        Canvas c = new Canvas(bitmapForColor);\n        RectF rf = new RectF(0, 0, bitmapForColor.getWidth(), bitmapForColor.getHeight());\n\n        // 圆角大小\n        int r;\n        if (orientation == Orientation.HORIZONTAL) {\n            r = bitmapForColor.getHeight() / 2;\n        } else {\n            r = bitmapForColor.getWidth() / 2;\n        }\n        // 先绘制黑色背景，否则有 alpha 时绘制不正常\n        paint.setColor(Color.BLACK);\n        c.drawRoundRect(rf, r, r, paint);\n\n        paint.setShader(linearGradient);\n        c.drawRoundRect(rf, r, r, paint);\n        paint.setShader(null);\n\n        needReDrawColorTable = false;\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n\n        int ex = (int) event.getX();\n        int ey = (int) event.getY();\n\n        if (!inBoundOfColorTable(ex, ey)) {\n            return true;\n        }\n\n        if (orientation == Orientation.HORIZONTAL) {\n            curX = ex;\n            curY = getHeight() / 2;\n        } else {\n            curX = getWidth() / 2;\n            curY = ey;\n        }\n\n        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {\n            if (colorPickerChangeListener != null) {\n                colorPickerChangeListener.onStartTrackingTouch(this);\n                calcuColor();\n                colorPickerChangeListener.onColorChanged(this, currentColor);\n            }\n\n        } else if (event.getActionMasked() == MotionEvent.ACTION_UP) { //手抬起\n            if (colorPickerChangeListener != null) {\n                colorPickerChangeListener.onStopTrackingTouch(this);\n                calcuColor();\n                colorPickerChangeListener.onColorChanged(this, currentColor);\n            }\n\n        } else { //按着+拖拽\n            if (colorPickerChangeListener != null) {\n                calcuColor();\n                colorPickerChangeListener.onColorChanged(this, currentColor);\n            }\n        }\n\n        invalidate();\n        return true;\n    }\n\n    /**\n     * 获得当前指示点所指颜色\n     *\n     * @return 颜色值\n     */\n    public int getColor() {\n        return calcuColor();\n    }\n\n    private boolean inBoundOfColorTable(int ex, int ey) {\n        if (orientation == Orientation.HORIZONTAL) {\n            if (ex <= mLeft + mRadius || ex >= mRight - mRadius) {\n                return false;\n            }\n        } else {\n            if (ey <= mTop + mRadius || ey >= mBottom - mRadius) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private int calcuColor() {\n        int x, y;\n        if (orientation == Orientation.HORIZONTAL) { // 水平\n            y = (rect.bottom - rect.top) / 2;\n            if (curX < rect.left) {\n                x = 1;\n            } else if (curX > rect.right) {\n                x = bitmapForColor.getWidth() - 1;\n            } else {\n                x = curX - rect.left;\n            }\n        } else { // 竖直\n            x = (rect.right - rect.left) / 2;\n            if (curY < rect.top) {\n                y = 1;\n            } else if (curY > rect.bottom) {\n                y = bitmapForColor.getHeight() - 1;\n            } else {\n                y = curY - rect.top;\n            }\n        }\n        int pixel = bitmapForColor.getPixel(x, y);\n        currentColor = pixelToColor(pixel);\n        return currentColor;\n    }\n\n    private int pixelToColor(int pixel) {\n\n        int alpha = Color.alpha(pixel);\n        int red = Color.red(pixel);\n        int green = Color.green(pixel);\n        int blue = Color.blue(pixel);\n\n        return Color.argb(alpha, red, green, blue);\n    }\n\n    private OnColorPickerChangeListener colorPickerChangeListener;\n\n    public void setOnColorPickerChangeListener(OnColorPickerChangeListener l) {\n        this.colorPickerChangeListener = l;\n    }\n\n    public interface OnColorPickerChangeListener {\n\n        /**\n         * 选取的颜色值改变时回调\n         *\n         * @param picker ColorPickerView\n         * @param color  颜色\n         */\n        void onColorChanged(ColorPickerView picker, int color);\n\n        /**\n         * 开始颜色选取\n         *\n         * @param picker ColorPickerView\n         */\n        void onStartTrackingTouch(ColorPickerView picker);\n\n        /**\n         * 停止颜色选取\n         *\n         * @param picker ColorPickerView\n         */\n        void onStopTrackingTouch(ColorPickerView picker);\n    }\n\n\n    @Override\n    protected Parcelable onSaveInstanceState() {\n        Parcelable parcelable = super.onSaveInstanceState();\n        SavedState ss = new SavedState(parcelable);\n        ss.selX = curX;\n        ss.selY = curY;\n        ss.color = bitmapForColor;\n        if (mIndicatorEnable) {\n            ss.indicator = bitmapForIndicator;\n        }\n        return ss;\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Parcelable state) {\n        if (!(state instanceof SavedState)) {\n            super.onRestoreInstanceState(state);\n            return;\n        }\n        SavedState ss = (SavedState) state;\n        super.onRestoreInstanceState(ss.getSuperState());\n\n        curX = ss.selX;\n        curY = ss.selY;\n        colors = ss.colors;\n\n        bitmapForColor = ss.color;\n        if (mIndicatorEnable) {\n            bitmapForIndicator = ss.indicator;\n            needReDrawIndicator = true;\n        }\n        needReDrawColorTable = true;\n\n    }\n\n    private class SavedState extends BaseSavedState {\n        int selX, selY;\n        int[] colors;\n        Bitmap color;\n        Bitmap indicator = null;\n\n        SavedState(Parcelable source) {\n            super(source);\n        }\n\n        @Override\n        public void writeToParcel(Parcel out, int flags) {\n            super.writeToParcel(out, flags);\n            out.writeInt(selX);\n            out.writeInt(selY);\n            out.writeParcelable(color, flags);\n            out.writeIntArray(colors);\n            if (indicator != null) {\n                out.writeParcelable(indicator, flags);\n            }\n        }\n    }\n\n    public void setPosition(int x, int y) {\n        if (inBoundOfColorTable(x, y)) {\n            curX = x;\n            curY = y;\n            if (mIndicatorEnable) {\n                needReDrawIndicator = true;\n            }\n            invalidate();\n        }\n    }\n\n\n    /**\n     * 显示默认的颜色选择器\n     */\n    public void showDefaultColorTable() {\n        setColors(createDefaultColorTable());\n    }\n\n    public int getIndicatorColor() {\n        return mIndicatorColor;\n    }\n\n    public void setIndicatorColor(int color) {\n        this.mIndicatorColor = color;\n        needReDrawIndicator = true;\n        invalidate();\n    }\n\n    public void setOrientation(Orientation orientation) {\n        this.orientation = orientation;\n        needReDrawIndicator = true;\n        needReDrawColorTable = true;\n        requestLayout();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/zhouqiong/richeditotandroid/view/RichEditor.java",
    "content": "package com.example.zhouqiong.richeditotandroid.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.webkit.WebChromeClient;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\n\n\nimport com.example.zhouqiong.richeditotandroid.utils.Utils;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\n/**\n * 富文本编辑实现类\n * Created by ZQiong on 2018/3/22.\n */\n\npublic class RichEditor extends WebView {\n\n    public enum Type {\n        BOLD,\n        ITALIC,\n        SUBSCRIPT,\n        SUPERSCRIPT,\n        STRIKETHROUGH,\n        UNDERLINE,\n        H1,\n        H2,\n        H3,\n        H4,\n        H5,\n        H6,\n        ORDEREDLIST,\n        UNORDEREDLIST,\n        JUSTIFYCENTER,\n        JUSTIFYFULL,\n        JUSTUFYLEFT,\n        JUSTIFYRIGHT\n    }\n\n    public interface OnTextChangeListener {\n\n        void onTextChange(String text);\n    }\n\n    public interface OnDecorationStateListener {\n\n        void onStateChangeListener(String text, List<Type> types);\n    }\n\n    public interface AfterInitialLoadListener {\n\n        void onAfterInitialLoad(boolean isReady);\n    }\n\n    private static final String SETUP_HTML = \"file:///android_asset/editor.html\";\n    private static final String CALLBACK_SCHEME = \"re-callback://\";\n    private static final String STATE_SCHEME = \"re-state://\";\n    private boolean isReady = false;\n    private String mContents;\n    private OnTextChangeListener mTextChangeListener;\n    private OnDecorationStateListener mDecorationStateListener;\n    private AfterInitialLoadListener mLoadListener;\n\n    public RichEditor(Context context) {\n        this(context, null);\n    }\n\n    public RichEditor(Context context, AttributeSet attrs) {\n        this(context, attrs, android.R.attr.webViewStyle);\n    }\n\n    @SuppressLint(\"SetJavaScriptEnabled\")\n    public RichEditor(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        setVerticalScrollBarEnabled(false);\n        setHorizontalScrollBarEnabled(false);\n        getSettings().setJavaScriptEnabled(true);\n        setWebChromeClient(new WebChromeClient());\n        setWebViewClient(createWebviewClient());\n        loadUrl(SETUP_HTML);\n\n        applyAttributes(context, attrs);\n    }\n\n    protected EditorWebViewClient createWebviewClient() {\n        return new EditorWebViewClient();\n    }\n\n    public void setOnTextChangeListener(OnTextChangeListener listener) {\n        mTextChangeListener = listener;\n    }\n\n    public void setOnDecorationChangeListener(OnDecorationStateListener listener) {\n        mDecorationStateListener = listener;\n    }\n\n    public void setOnInitialLoadListener(AfterInitialLoadListener listener) {\n        mLoadListener = listener;\n    }\n\n    private void callback(String text) {\n        mContents = text.replaceFirst(CALLBACK_SCHEME, \"\");\n        if (mTextChangeListener != null) {\n            mTextChangeListener.onTextChange(mContents);\n        }\n    }\n\n    private void stateCheck(String text) {\n        String state = text.replaceFirst(STATE_SCHEME, \"\").toUpperCase(Locale.ENGLISH);\n        List<Type> types = new ArrayList<>();\n        for (Type type : Type.values()) {\n            if (TextUtils.indexOf(state, type.name()) != -1) {\n                types.add(type);\n            }\n        }\n\n        if (mDecorationStateListener != null) {\n            mDecorationStateListener.onStateChangeListener(state, types);\n        }\n    }\n\n    private void applyAttributes(Context context, AttributeSet attrs) {\n        final int[] attrsArray = new int[]{\n                android.R.attr.gravity\n        };\n        TypedArray ta = context.obtainStyledAttributes(attrs, attrsArray);\n\n        int gravity = ta.getInt(0, NO_ID);\n        switch (gravity) {\n            case Gravity.LEFT:\n                exec(\"javascript:RE.setTextAlign(\\\"left\\\")\");\n                break;\n            case Gravity.RIGHT:\n                exec(\"javascript:RE.setTextAlign(\\\"right\\\")\");\n                break;\n            case Gravity.TOP:\n                exec(\"javascript:RE.setVerticalAlign(\\\"top\\\")\");\n                break;\n            case Gravity.BOTTOM:\n                exec(\"javascript:RE.setVerticalAlign(\\\"bottom\\\")\");\n                break;\n            case Gravity.CENTER_VERTICAL:\n                exec(\"javascript:RE.setVerticalAlign(\\\"middle\\\")\");\n                break;\n            case Gravity.CENTER_HORIZONTAL:\n                exec(\"javascript:RE.setTextAlign(\\\"center\\\")\");\n                break;\n            case Gravity.CENTER:\n                exec(\"javascript:RE.setVerticalAlign(\\\"middle\\\")\");\n                exec(\"javascript:RE.setTextAlign(\\\"center\\\")\");\n                break;\n        }\n\n        ta.recycle();\n    }\n\n    public void setHtml(String contents) {\n        if (contents == null) {\n            contents = \"\";\n        }\n        try {\n            exec(\"javascript:RE.setHtml('\" + URLEncoder.encode(contents, \"UTF-8\") + \"');\");\n        } catch (UnsupportedEncodingException e) {\n            // No handling\n        }\n        mContents = contents;\n    }\n\n    public String getHtml() {\n        return mContents;\n    }\n\n    public void setEditorFontColor(int color) {\n        String hex = convertHexColorString(color);\n        exec(\"javascript:RE.setBaseTextColor('\" + hex + \"');\");\n    }\n\n    public void setEditorFontSize(int px) {\n        exec(\"javascript:RE.setBaseFontSize('\" + px + \"px');\");\n    }\n\n    @Override\n    public void setPadding(int left, int top, int right, int bottom) {\n        super.setPadding(left, top, right, bottom);\n        exec(\"javascript:RE.setPadding('\" + left + \"px', '\" + top + \"px', '\" + right + \"px', '\" + bottom\n                + \"px');\");\n    }\n\n    @Override\n    public void setPaddingRelative(int start, int top, int end, int bottom) {\n        // still not support RTL.\n        setPadding(start, top, end, bottom);\n    }\n\n    public void setEditorBackgroundColor(int color) {\n        setBackgroundColor(color);\n    }\n\n    @Override\n    public void setBackgroundColor(int color) {\n        super.setBackgroundColor(color);\n    }\n\n    @Override\n    public void setBackgroundResource(int resid) {\n        Bitmap bitmap = Utils.decodeResource(getContext(), resid);\n        String base64 = Utils.toBase64(bitmap);\n        bitmap.recycle();\n\n        exec(\"javascript:RE.setBackgroundImage('url(data:image/png;base64,\" + base64 + \")');\");\n    }\n\n    @Override\n    public void setBackground(Drawable background) {\n        Bitmap bitmap = Utils.toBitmap(background);\n        String base64 = Utils.toBase64(bitmap);\n        bitmap.recycle();\n\n        exec(\"javascript:RE.setBackgroundImage('url(data:image/png;base64,\" + base64 + \")');\");\n    }\n\n    public void setBackground(String url) {\n        exec(\"javascript:RE.setBackgroundImage('url(\" + url + \")');\");\n    }\n\n    public void setEditorWidth(int px) {\n        exec(\"javascript:RE.setWidth('\" + px + \"px');\");\n    }\n\n    public void setEditorHeight(int px) {\n        exec(\"javascript:RE.setHeight('\" + px + \"px');\");\n    }\n\n    public void setPlaceholder(String placeholder) {\n        exec(\"javascript:RE.setPlaceholder('\" + placeholder + \"');\");\n    }\n\n    public void setInputEnabled(Boolean inputEnabled) {\n        exec(\"javascript:RE.setInputEnabled(\" + inputEnabled + \")\");\n    }\n\n    public void loadCSS(String cssFile) {\n        String jsCSSImport = \"(function() {\" +\n                \"    var head  = document.getElementsByTagName(\\\"head\\\")[0];\" +\n                \"    var link  = document.createElement(\\\"link\\\");\" +\n                \"    link.rel  = \\\"stylesheet\\\";\" +\n                \"    link.type = \\\"text/css\\\";\" +\n                \"    link.href = \\\"\" + cssFile + \"\\\";\" +\n                \"    link.media = \\\"all\\\";\" +\n                \"    head.appendChild(link);\" +\n                \"}) ();\";\n        exec(\"javascript:\" + jsCSSImport + \"\");\n    }\n\n    public void undo() {\n        exec(\"javascript:RE.undo();\");\n    }\n\n    public void redo() {\n        exec(\"javascript:RE.redo();\");\n    }\n\n    public void setBold() {\n        exec(\"javascript:RE.setBold();\");\n    }\n\n    public void setItalic() {\n        exec(\"javascript:RE.setItalic();\");\n    }\n\n    public void setSubscript() {\n        exec(\"javascript:RE.setSubscript();\");\n    }\n\n    public void setSuperscript() {\n        exec(\"javascript:RE.setSuperscript();\");\n    }\n\n    public void setStrikeThrough() {\n        exec(\"javascript:RE.setStrikeThrough();\");\n    }\n\n    public void setUnderline() {\n        exec(\"javascript:RE.setUnderline();\");\n    }\n\n    public void setTextColor(int color) {\n        exec(\"javascript:RE.prepareInsert();\");\n\n        String hex = convertHexColorString(color);\n        exec(\"javascript:RE.setTextColor('\" + hex + \"');\");\n    }\n\n    public void setTextBackgroundColor(int color) {\n        exec(\"javascript:RE.prepareInsert();\");\n\n        String hex = convertHexColorString(color);\n        exec(\"javascript:RE.setTextBackgroundColor('\" + hex + \"');\");\n    }\n\n    public void setFontSize(int fontSize) {\n        if (fontSize > 7 || fontSize < 1) {\n            Log.e(\"RichEditor\", \"Font size should have a value between 1-7\");\n        }\n        exec(\"javascript:RE.setFontSize('\" + fontSize + \"');\");\n    }\n\n    public void removeFormat() {\n        exec(\"javascript:RE.removeFormat();\");\n    }\n\n    public void setHeading(int heading) {\n        exec(\"javascript:RE.setHeading('\" + heading + \"');\");\n    }\n\n    public void setIndent() {\n        exec(\"javascript:RE.setIndent();\");\n    }\n\n    public void setOutdent() {\n        exec(\"javascript:RE.setOutdent();\");\n    }\n\n    public void setAlignLeft() {\n        exec(\"javascript:RE.setJustifyLeft();\");\n    }\n\n    public void setAlignCenter() {\n        exec(\"javascript:RE.setJustifyCenter();\");\n    }\n\n    public void setAlignRight() {\n        exec(\"javascript:RE.setJustifyRight();\");\n    }\n\n    public void setBlockquote() {\n        exec(\"javascript:RE.setBlockquote();\");\n    }\n\n    public void setBullets() {\n        exec(\"javascript:RE.setBullets();\");\n    }\n\n    public void setNumbers() {\n        exec(\"javascript:RE.setNumbers();\");\n    }\n\n    public void insertImage(String url, String alt) {\n        exec(\"javascript:RE.prepareInsert();\");\n        exec(\"javascript:RE.insertImage('\" + url + \"', '\" + alt + \"');\");\n    }\n\n    public void insertLink(String href, String title) {\n        exec(\"javascript:RE.prepareInsert();\");\n        exec(\"javascript:RE.insertLink('\" + href + \"', '\" + title + \"');\");\n    }\n\n    public void insertTodo() {\n        exec(\"javascript:RE.prepareInsert();\");\n        exec(\"javascript:RE.setTodo('\" + Utils.getCurrentTime() + \"');\");\n    }\n\n    public void focusEditor() {\n        requestFocus();\n        exec(\"javascript:RE.focus();\");\n    }\n\n    public void clearFocusEditor() {\n        exec(\"javascript:RE.blurFocus();\");\n    }\n\n    private String convertHexColorString(int color) {\n        return String.format(\"#%06X\", (0xFFFFFF & color));\n    }\n\n    protected void exec(final String trigger) {\n        if (isReady) {\n            load(trigger);\n        } else {\n            postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    exec(trigger);\n                }\n            }, 100);\n        }\n    }\n\n    private void load(String trigger) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            evaluateJavascript(trigger, null);\n        } else {\n            loadUrl(trigger);\n        }\n    }\n\n    protected class EditorWebViewClient extends WebViewClient {\n        @Override\n        public void onPageFinished(WebView view, String url) {\n            isReady = url.equalsIgnoreCase(SETUP_HTML);\n            if (mLoadListener != null) {\n                mLoadListener.onAfterInitialLoad(isReady);\n            }\n        }\n\n        @Override\n        public boolean shouldOverrideUrlLoading(WebView view, String url) {\n            String decode;\n            try {\n                decode = URLDecoder.decode(url, \"UTF-8\");\n            } catch (UnsupportedEncodingException e) {\n                // No handling\n                return false;\n            }\n\n            if (TextUtils.indexOf(url, CALLBACK_SCHEME) == 0) {\n                callback(decode);\n                return true;\n            } else if (TextUtils.indexOf(url, STATE_SCHEME) == 0) {\n                stateCheck(decode);\n                return true;\n            }\n\n            return super.shouldOverrideUrlLoading(view, url);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/anim/dialog_enter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n      <scale   \n        android:interpolator=\"@android:anim/accelerate_interpolator\"  \n        android:fromXScale=\"1.0\"  \n        android:toXScale=\"1.0\"  \n        android:fromYScale=\"0.0\"  \n        android:toYScale=\"1.0\"  \n        android:pivotX=\"0%\"  \n        android:pivotY=\"100%\"  \n        android:fillAfter=\"false\"  \n        android:duration=\"200\"/>\n</set>\n"
  },
  {
    "path": "app/src/main/res/anim/dialog_exit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n      <scale   \n        android:interpolator=\"@android:anim/accelerate_interpolator\"  \n        android:fromXScale=\"1.0\"  \n        android:toXScale=\"1.0\"  \n        android:fromYScale=\"1.0\"  \n        android:toYScale=\"0.0\"  \n        android:pivotX=\"0%\"  \n        android:pivotY=\"100%\"  \n        android:fillAfter=\"false\"  \n        android:duration=\"200\"/>\n</set>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillColor=\"#26A69A\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\">\n\n    <com.example.zhouqiong.richeditotandroid.view.RichEditor\n        android:id=\"@+id/re_main_editor\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_main_color\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:background=\"#f2f1f6\"\n        android:visibility=\"gone\">\n\n        <com.example.zhouqiong.richeditotandroid.view.ColorPickerView\n            android:id=\"@+id/cpv_main_color\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"8dp\"\n            android:layout_gravity=\"center\"\n            android:background=\"#f2f1f6\"\n            app:indicatorColor=\"#fff\"\n            app:indicatorEnable=\"true\"\n            app:orientation=\"horizontal\" />\n    </LinearLayout>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:background=\"#f2f1f6\">\n\n        <HorizontalScrollView\n            style=\"@style/EditorIcon\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_toLeftOf=\"@+id/tv_main_preview\"\n            android:layout_toStartOf=\"@+id/tv_main_preview\"\n            android:scrollbars=\"none\">\n\n            <LinearLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:id=\"@+id/button_image\"\n                    style=\"@style/EditorIcon\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:background=\"@mipmap/photo\" />\n\n                <ImageView\n                    android:id=\"@+id/button_bold\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/bold\" />\n\n                <TextView\n                    android:id=\"@+id/button_text_color\"\n                    style=\"@style/EditorIcon\"\n                    android:layout_width=\"32dp\"\n                    android:layout_height=\"20dp\"\n                    android:background=\"@color/colorPrimary\" />\n\n\n                <ImageView\n                    android:id=\"@+id/button_list_ol\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/list_ol\" />\n\n                <ImageView\n                    android:id=\"@+id/button_list_ul\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/list_ul\" />\n\n                <ImageView\n                    android:id=\"@+id/button_underline\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/underline\" />\n\n                <ImageView\n                    android:id=\"@+id/button_italic\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/lean\" />\n\n                <ImageView\n                    android:id=\"@+id/button_align_left\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/align_left\" />\n\n                <ImageView\n                    android:id=\"@+id/button_align_center\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/align_center\" />\n\n                <ImageView\n                    android:id=\"@+id/button_align_right\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/align_right\" />\n\n                <ImageView\n                    android:id=\"@+id/button_indent\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/indent\" />\n\n                <ImageView\n                    android:id=\"@+id/button_outdent\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/outdent\" />\n\n                <ImageView\n                    android:id=\"@+id/action_blockquote\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/blockquote\" />\n\n                <ImageView\n                    android:id=\"@+id/action_strikethrough\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/strikethrough\" />\n\n                <ImageView\n                    android:id=\"@+id/action_superscript\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/superscript\" />\n\n                <ImageView\n                    android:id=\"@+id/action_subscript\"\n                    style=\"@style/EditorIcon\"\n                    android:src=\"@mipmap/subscript\" />\n            </LinearLayout>\n        </HorizontalScrollView>\n\n        <TextView\n            android:id=\"@+id/tv_main_preview\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:paddingLeft=\"14dp\"\n            android:paddingRight=\"14dp\"\n            android:text=\"预览\"\n            android:textColor=\"#dd3333\"\n            android:textSize=\"18sp\" />\n    </RelativeLayout>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_show_diarys.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.constraint.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <WebView\n        android:id=\"@+id/showdiarys\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n\n</android.support.constraint.ConstraintLayout>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <declare-styleable name=\"ColorPickerView\">\n        <attr name=\"indicatorColor\" format=\"color\" /><!--指示点颜色-->\n        <attr name=\"indicatorEnable\" format=\"boolean\" /><!--是否启用指示点-->\n        <attr name=\"orientation\" format=\"integer\">\n            <enum name=\"horizontal\" value=\"0\" />\n            <enum name=\"vertical\" value=\"1\" />\n        </attr>\n    </declare-styleable>\n\n</resources>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n\n\n    <color name=\"button_enabled\">#333333</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">RichEditotAndroid</string>\n\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n\n    <style name=\"EditorIcon\">\n        <item name=\"android:layout_width\">40dp</item>\n        <item name=\"android:layout_height\">20dp</item>\n        <item name=\"android:layout_marginLeft\">20dp</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:textColor\">@color/button_enabled</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/test/java/com/example/zhouqiong/richeditotandroid/ExampleUnitTest.java",
    "content": "package com.example.zhouqiong.richeditotandroid;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    \n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.0.1'\n        \n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Mar 21 11:05:34 CST 2018\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app'\n"
  }
]