[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.idea/\n.DS_Store\n/build\n/captures\n\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright YoKey\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"
  },
  {
    "path": "README.md",
    "content": "# IndexableRecyclerView\nA RecyclerView with indexable, sticky and many other features.\n\n**轻松实现：选择城市，选择联系人等需要索引的功能**\n\n> 替代之前的IndexableStickyListView(移至该[分支](https://github.com/YoKeyword/IndexableRecyclerView/tree/listview)),进行大幅度重构，性能优化，更易使用的API，更易拓展的HeaderView/FooterView等等！\n重构历程可以看这篇文章：[［设计模式］记一次开源库的重构历程](http://www.jianshu.com/p/2ee8706c346b)\n\n# Demo演示\n<img src=\"/gif/demo_city.gif\" width=\"320px\"/>\n<img src=\"/gif/demo_contact.gif\" width=\"320px\"/>\n\n# 特性\n1、根据数据源，自动**排序生成**字母索引Bar(非字母开头,索引为\"#\",另可自由定制)，以及HeaderTitle\n\n2、非常自由的 添加各种HeaderView／FooterView，包括自定义索引，HeaderTitle，各种View等等\n\n3、HeaderTitle是粘性的（Sticky）\n\n4、UI自由定制、拓展；提供2种悬浮提示View，常规居中 以及 MD风格的右侧气泡\n\n5、绑定数据源，通过单线程的线程池优化，不怕重复绑定数据\n\n6、使用[TinyPinyin](https://github.com/promeG/TinyPinyin)代替Pinyin4j.jar库，体积更小，拼音转化速度提升4倍！\n\n# 更新日志\n1.3.0\n* 多音字借助TinyPinyin处理\n* 可以自定义排序方式\n\n1.2.4\n* Fix 数据变动时，StickTitle不及时更新问题；增加2处安全校验\n\n1.2.0\n* 支持GridLayoutManager! (感谢[guodongAndroid](https://github.com/guodongAndroid))\n\n1.0.7\n* 默认不再显示左侧的悬浮气泡\n* 默认排序方式改为快速排序，提供一个MODE_NONE的排序方式\n\n1.0.5\n为HeaderView/FooterView添加:\n* `indexableLayout.removeHeaderAdapter();`\n* `headerAdapter.addData()`\n* `headerAdapter.removeData()`\n\n# 如何使用\n### gradle\n项目下app的build.gradle中依赖：\n````xml\n compile 'me.yokeyword:indexablerecyclerview:1.3.0'\n compile 'com.android.support:appcompat-v7:你使用的版本号'\n compile 'com.android.support:recyclerview-v7:你使用的版本号'\n````\n\n### Xml\n````xml\n <me.yokeyword.indexablerv.IndexableLayout\n     ...\n     app:indexBar_layout_width=\"24dp\"           // IndexBar：width\n     app:indexBar_background=\"#08000000\"        // IndexBar：background\n     app:indexBar_textColor=\"#000000\"           // IndexBar：textColor\n     app:indexBar_selectedTextColor=\"#f33737\"   // IndexBar：isSelected textColor\n     app:indexBar_textSize=\"14sp\"               // IndexBar：textSize\n     app:indexBar_textSpace=\"6dp\" />            // IndexBar：text lineSpace\n````\n\n### 3步集成\n**1、实体类实现IndexableEntity**\n````java\npublic class CityEntity implements IndexableEntity {\n    ...\n    private String name;\n    private String pinyin;\n    \n    @Override\n    public String getFieldIndexBy() {\n        return name;  // return 你需要根据该属性排序的field\n    }\n\n    @Override\n    public void setFieldIndexBy(String indexByField) {\n        this.name = indexByField; // 同上\n    }\n\n    @Override\n    public void setFieldPinyinIndexBy(String pinyin) {\n        this.pinyin = pinyin; // 保存排序field的拼音,在执行比如搜索等功能时有用 （若不需要，空实现该方法即可）\n    }\n}\n````\n\n**2、继承IndexAdapter**\n````java\npublic class CityAdapter extends IndexableAdapter<CityEntity> {\n    @Override\n    public RecyclerView.ViewHolder onCreateTitleViewHolder(ViewGroup parent) {\n        // 创建 TitleItem 布局\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent) {\n        // 创建 内容Item 布局\n    }\n\n    @Override\n    public void onBindTitleViewHolder(RecyclerView.ViewHolder holder, String indexTitle) {\n         // 填充 TitleItem 布局\n    }\n\n    @Override\n    public void onBindContentViewHolder(RecyclerView.ViewHolder holder, CityEntity entity) {\n        // 填充 内容Item 布局\n    }\n}\n````\n\n**3、绑定视图和数据**\n````java\n// 支持LinearLayoutManager, GridLayoutManager\nindexableLayout.setLayoutManager(LayoutManager);\n\nCityAdapter adapter = new CityAdapter(this);\nindexableLayout.setAdapter(adapter);\n// 排序过程是异步的 另有setDatas(mDatas,IndexCallback callback)  // callback在datas异步排序结束后回调\nadapter.setDatas(mDatas);\n// 另有setOnItemTitleClickListener(listener)，点击TitleItem点击事件以及LongClick\nadapter.setOnItemContentClickListener(listener);\n````\n\n# 拓展\n### 1、设置 索引悬浮提示框 风格\n````java\n// 前者Material Design风格右侧气泡 ， 后者 居中 IOS风格气泡\nindexableLayout.setOverlayStyle_MaterialDesign(int Color) & setOverlayStyle_Center()\n````\n\n### 2、多音字处理\n\n多音字处理得益于使用了[TinyPinyin](https://github.com/promeG/TinyPinyin)，可以如下设置：\n````java\n// 添加中文城市词典\nPinyin.init(Pinyin.newConfig().with(CnCityDict.getInstance());\n\n// 添加自定义词典\nPinyin.init(Pinyin.newConfig()\n            .with(new PinyinMapDict() {\n                @Override\n                public Map<String, String[]> mapping() {\n                    HashMap<String, String[]> map = new HashMap<String, String[]>();\n                    map.put(\"重庆\",  new String[]{\"CHONG\", \"QING\"});\n                    return map;\n                }\n            }));\n````\n\n### 3、添加自定义HeaderView，FooterView\n````java\nindexableLayout.addHeaderAdapter(IndexableHeaderAdapter adapter)    // 添加HeaderView\nindexableLayout.addFooterAdapter(IndexableFooterAdapter adapter)    // 添加FooterView\n\n// 3个参数分别对应:IndexBar的索引,HeaderTitle,传入的Header数据源,此处泛型T可以是任何实体类,不需要和主Adapter类型一致\n// 如果不想显示某块视图，则传入null即可： 比如不想显示 HeaderTitle， 则indexTitle传入null；\nIndexableHeaderAdapter<T>(String index, String indexTitle, List<T> datas){\n    // 需要实现3个方法：\n    public abstract int getItemViewType(); // 每个HeaderView的type应当不同\n    public abstract RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent);\n    public abstract void onBindContentViewHolder(RecyclerView.ViewHolder holder, T entity);\n}\n\n// 如果想添加的HeaderView，和主Adapter的布局完全一致，则可以使用:\nnew SimpleHeaderAdapter(IndexableAdapter<T> adapter, String index, String indexTitle, List<T> datas);\n````\n\n### 4、更改排序规则\n默认根据**全拼音排序**，可根据需求更改为**按首字母排序**:\n````java\n// 设置排序规则： \n// MODE_FAST:按首字母排序（默认）；MODE_ALL_LETTERS:全字母比较，效率较低； MODE_NONE:字母模块内不排序，效率最高\nindexableLayout.setCompareMode(@CompareMode int mode);\n\n// 自定义排序规则\nindexableLayout.setComparator(yourComparator);\n````\n\n> 更多细节使用，参见Demo\n\n## 致谢\n\n[TinyPinyin](https://github.com/promeG/TinyPinyin)\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    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.3.1'\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        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Jul 05 23:28:02 CST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.3-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": ""
  },
  {
    "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\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\n"
  },
  {
    "path": "indexablerecyclerview/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "indexablerecyclerview/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 25\n    buildToolsVersion \"25.0.2\"\n\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 24\n        versionCode 1\n        versionName \"1.0\"\n    }\n}\n\ndependencies {\n    compile 'com.github.promeg:tinypinyin:2.0.3'\n    compile 'com.github.promeg:tinypinyin-lexicons-android-cncity:2.0.3'\n    provided 'com.android.support:appcompat-v7:25.3.1'\n    provided 'com.android.support:recyclerview-v7:25.3.1'\n}\n"
  },
  {
    "path": "indexablerecyclerview/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/YoKeyword/Documents/android-sdk-macosx/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\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"
  },
  {
    "path": "indexablerecyclerview/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          xmlns:tools=\"http://schemas.android.com/tools\"\n          package=\"me.yokeyword.indexablerecyclerview\">\n\n    <uses-sdk\n        tools:overrideLibrary=\"com.github.promeg.tinypinyin.lexicons.android.cncity,com.github.promeg.tinypinyin.android.asset.lexicons\"/>\n    <application/>\n</manifest>\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/AbstractHeaderFooterAdapter.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport me.yokeyword.indexablerv.database.HeaderFooterDataObservable;\nimport me.yokeyword.indexablerv.database.HeaderFooterDataObserver;\nimport me.yokeyword.indexablerv.database.IndexBarDataObservable;\nimport me.yokeyword.indexablerv.database.IndexBarDataObserver;\n\n/**\n * Created by YoKey on 16/10/16.\n */\n\nabstract class AbstractHeaderFooterAdapter<T> {\n    private final HeaderFooterDataObservable mDataSetObservable = new HeaderFooterDataObservable();\n    private final IndexBarDataObservable mIndexBarDataSetObservable = new IndexBarDataObservable();\n\n    ArrayList<EntityWrapper<T>> mEntityWrapperList = new ArrayList<>();\n    protected OnItemClickListener<T> mListener;\n    protected OnItemLongClickListener<T> mLongListener;\n\n    private String mIndex, mIndexTitle;\n\n    /**\n     * 不想显示哪个就传null\n     *\n     * @param index      IndexBar的字母索引\n     * @param indexTitle IndexTitle\n     * @param datas      数据源\n     */\n    public AbstractHeaderFooterAdapter(String index, String indexTitle, List<T> datas) {\n        this.mIndex = index;\n        this.mIndexTitle = indexTitle;\n\n        if (indexTitle != null) {\n            EntityWrapper<T> wrapper = wrapEntity();\n            wrapper.setItemType(EntityWrapper.TYPE_TITLE);\n        }\n        for (int i = 0; i < datas.size(); i++) {\n            EntityWrapper<T> wrapper = wrapEntity();\n            wrapper.setData(datas.get(i));\n        }\n    }\n\n    private EntityWrapper<T> wrapEntity() {\n        EntityWrapper<T> wrapper = new EntityWrapper<>();\n        wrapper.setIndex(mIndex);\n        wrapper.setIndexTitle(mIndexTitle);\n        wrapper.setHeaderFooterType(getHeaderFooterType());\n        mEntityWrapperList.add(wrapper);\n        return wrapper;\n    }\n\n    private EntityWrapper<T> wrapEntity(int pos) {\n        EntityWrapper<T> wrapper = new EntityWrapper<>();\n        wrapper.setIndex(mIndex);\n        wrapper.setIndexTitle(mIndexTitle);\n        wrapper.setHeaderFooterType(getHeaderFooterType());\n        mEntityWrapperList.add(pos, wrapper);\n        return wrapper;\n    }\n\n    public abstract int getItemViewType();\n\n    public abstract RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent);\n\n    public abstract void onBindContentViewHolder(RecyclerView.ViewHolder holder, T entity);\n\n    /**\n     * Notifies the attached observers that the underlying data has been changed\n     * and any View reflecting the data set should refresh itself.\n     */\n    public void notifyDataSetChanged() {\n        mDataSetObservable.notifyChanged();\n    }\n\n    public void addData(T data) {\n        int size = mEntityWrapperList.size();\n\n        EntityWrapper<T> wrapper = wrapEntity();\n        wrapper.setItemType(getItemViewType());\n        wrapper.setData(data);\n\n        if (size > 0) {\n            mDataSetObservable.notifyAdd(getHeaderFooterType() == EntityWrapper.TYPE_HEADER, mEntityWrapperList.get(size - 1), wrapper);\n            mIndexBarDataSetObservable.notifyChanged();\n        }\n    }\n\n    public void removeData(T data) {\n        for (EntityWrapper wrapper : mEntityWrapperList) {\n            if (wrapper.getData() == data) {\n                mEntityWrapperList.remove(wrapper);\n                mDataSetObservable.notifyRemove(getHeaderFooterType() == EntityWrapper.TYPE_HEADER, wrapper);\n                mIndexBarDataSetObservable.notifyChanged();\n                return;\n            }\n        }\n    }\n\n    int getHeaderFooterType() {\n        return EntityWrapper.TYPE_HEADER;\n    }\n\n    public void addData(int position, T data) {\n        int size = mEntityWrapperList.size();\n        if (position >= size) {\n            return;\n        }\n\n        EntityWrapper<T> wrapper = wrapEntity(position + 1);\n        wrapper.setItemType(getItemViewType());\n        wrapper.setData(data);\n\n        if (size > 0) {\n            mDataSetObservable.notifyAdd(getHeaderFooterType() == EntityWrapper.TYPE_HEADER, mEntityWrapperList.get(position), wrapper);\n            mIndexBarDataSetObservable.notifyChanged();\n        }\n    }\n\n    public void addDatas(List<T> datas) {\n        for (int i = 0; i < datas.size(); i++) {\n            addData(datas.get(i));\n        }\n    }\n\n    public void addDatas(int position, List<T> datas) {\n        int size = mEntityWrapperList.size();\n        if (position >= size) {\n            return;\n        }\n\n        for (int i = datas.size() - 1; i >= 0; i--) {\n            addData(position, datas.get(i));\n        }\n    }\n\n//    public void removeAll(List<T> datas) {\n//        // TODO: 16/10/27\n//    }\n\n    OnItemClickListener<T> getOnItemClickListener() {\n        return mListener;\n    }\n\n\n    OnItemLongClickListener getOnItemLongClickListener() {\n        return mLongListener;\n    }\n\n    ArrayList<EntityWrapper<T>> getDatas() {\n        for (EntityWrapper<T> wrapper : mEntityWrapperList) {\n            if (wrapper.getItemType() == EntityWrapper.TYPE_CONTENT) {\n                wrapper.setItemType(getItemViewType());\n            }\n        }\n        return mEntityWrapperList;\n    }\n\n    void registerDataSetObserver(HeaderFooterDataObserver observer) {\n        mDataSetObservable.registerObserver(observer);\n    }\n\n    void unregisterDataSetObserver(HeaderFooterDataObserver observer) {\n        mDataSetObservable.unregisterObserver(observer);\n    }\n\n    void registerIndexBarDataSetObserver(IndexBarDataObserver observer) {\n        mIndexBarDataSetObservable.registerObserver(observer);\n    }\n\n    void unregisterIndexBarDataSetObserver(IndexBarDataObserver observer) {\n        mIndexBarDataSetObservable.unregisterObserver(observer);\n    }\n\n    interface OnItemClickListener<T> {\n        void onItemClick(View v, int currentPosition, T entity);\n    }\n\n    interface OnItemLongClickListener<T> {\n        boolean onItemLongClick(View v, int currentPosition, T entity);\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/EntityWrapper.java",
    "content": "package me.yokeyword.indexablerv;\n\n/**\n * Created by YoKey on 16/10/6.\n */\npublic class EntityWrapper<T> {\n    static final int TYPE_TITLE = Integer.MAX_VALUE - 1;\n    static final int TYPE_CONTENT = Integer.MAX_VALUE;\n\n    static final int TYPE_HEADER = 1;\n    static final int TYPE_FOOTER = 2;\n\n    private String index;\n    private String indexTitle;\n    private String pinyin;\n    private String indexByField;\n    private T data;\n    private int originalPosition = -1;\n    private int itemType = TYPE_CONTENT;\n    private int headerFooterType;\n\n    EntityWrapper() {\n    }\n\n    EntityWrapper(String index, int itemType) {\n        this.index = index;\n        this.indexTitle = index;\n        this.pinyin = index;\n        this.itemType = itemType;\n    }\n\n    public String getIndex() {\n        return index;\n    }\n\n    void setIndex(String index) {\n        this.index = index;\n    }\n\n    public String getIndexTitle() {\n        return indexTitle;\n    }\n\n    void setIndexTitle(String indexTitle) {\n        this.indexTitle = indexTitle;\n    }\n\n    public String getPinyin() {\n        return pinyin;\n    }\n\n    void setPinyin(String pinyin) {\n        this.pinyin = pinyin;\n    }\n\n    public String getIndexByField() {\n        return indexByField;\n    }\n\n    void setIndexByField(String indexByField) {\n        this.indexByField = indexByField;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    void setData(T data) {\n        this.data = data;\n    }\n\n    public int getOriginalPosition() {\n        return originalPosition;\n    }\n\n    void setOriginalPosition(int originalPosition) {\n        this.originalPosition = originalPosition;\n    }\n\n    int getItemType() {\n        return itemType;\n    }\n\n    void setItemType(int itemType) {\n        this.itemType = itemType;\n    }\n\n    int getHeaderFooterType() {\n        return headerFooterType;\n    }\n\n    void setHeaderFooterType(int headerFooterType) {\n        this.headerFooterType = headerFooterType;\n    }\n\n    public boolean isTitle(){\n        return itemType == TYPE_TITLE;\n    }\n\n    public boolean isContent(){\n        return itemType == TYPE_CONTENT;\n    }\n\n    public boolean isHeader(){\n        return headerFooterType == TYPE_HEADER;\n    }\n\n    public boolean isFooter(){\n        return headerFooterType == TYPE_FOOTER;\n    }\n}"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/IndexBar.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.util.TypedValue;\nimport android.view.View;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport me.yokeyword.indexablerecyclerview.R;\n\n/**\n * Created by YoKey on 16/10/6.\n */\nclass IndexBar extends View {\n    private int mTotalHeight;\n    private float mTextSpace;\n\n    private List<String> mIndexList = new ArrayList<>();\n    // 首字母 到 mIndexList 的映射\n    private HashMap<String, Integer> mMapping = new HashMap<>();\n    private ArrayList<EntityWrapper> mDatas;\n\n    private int mSelectionPosition;\n    private float mIndexHeight;\n\n    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n    private Paint mFocusPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n\n    public IndexBar(Context context) {\n        super(context);\n    }\n\n    void init(Drawable barBg, int barTextColor, int barFocusTextColor, float barTextSize, float textSpace) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            setBackground(barBg);\n        } else {\n            setBackgroundDrawable(barBg);\n        }\n\n        this.mTextSpace = textSpace;\n\n        mPaint.setColor(barTextColor);\n        mPaint.setTextAlign(Paint.Align.CENTER);\n        mPaint.setTextSize(barTextSize);\n\n        mFocusPaint.setTextAlign(Paint.Align.CENTER);\n        mFocusPaint.setTextSize(barTextSize + (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()));\n        mFocusPaint.setColor(barFocusTextColor);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        int mode = MeasureSpec.getMode(widthMeasureSpec);\n        int height = MeasureSpec.getSize(heightMeasureSpec);\n\n        if (mIndexList.size() > 0) {\n            mTotalHeight = (int) (((mIndexList.size() - 1) * mPaint.getTextSize()\n                    + mFocusPaint.getTextSize())\n                    + (mIndexList.size() + 1) * mTextSpace);\n        }\n\n        if (mTotalHeight > height) {\n            mTotalHeight = height;\n        }\n\n//        // TODO: 16/10/8  Measure AT_MOST\n//        if (mode == MeasureSpec.AT_MOST) {\n//            int maxWidth = (int) getResources().getDimension(R.dimen.default_indexBar_layout_width);\n//            super.onMeasure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mTotalHeight, MeasureSpec.EXACTLY));\n//            return;\n//        }\n        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(mTotalHeight, MeasureSpec.EXACTLY));\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n\n        if (mIndexList.size() == 0) return;\n\n        mIndexHeight = ((float) getHeight()) / mIndexList.size();\n\n        for (int i = 0; i < mIndexList.size(); i++) {\n            if (mSelectionPosition == i) {\n                canvas.drawText(mIndexList.get(i), getWidth() / 2, mIndexHeight * 0.85f + mIndexHeight * i, mFocusPaint);\n            } else {\n                canvas.drawText(mIndexList.get(i), getWidth() / 2, mIndexHeight * 0.85f + mIndexHeight * i, mPaint);\n            }\n        }\n    }\n\n    int getPositionForPointY(float y) {\n        if (mIndexList.size() <= 0) return -1;\n\n        int position = (int) (y / mIndexHeight);\n\n        if (position < 0) {\n            position = 0;\n        } else if (position > mIndexList.size() - 1) {\n            position = mIndexList.size() - 1;\n        }\n\n        return position;\n    }\n\n\n    int getSelectionPosition() {\n        return mSelectionPosition;\n    }\n\n    void setSelectionPosition(int position) {\n        this.mSelectionPosition = position;\n        invalidate();\n    }\n\n    int getFirstRecyclerViewPositionBySelection() {\n        String index = mIndexList.get(mSelectionPosition);\n        if (mMapping.containsKey(index)) {\n            return mMapping.get(index);\n        }\n        return -1;\n    }\n\n    List<String> getIndexList() {\n        return mIndexList;\n    }\n\n    void setDatas(boolean showAllLetter, ArrayList<EntityWrapper> datas) {\n        this.mDatas = datas;\n        this.mIndexList.clear();\n        this.mMapping.clear();\n\n        ArrayList<String> tempHeaderList = null;\n        if (showAllLetter) {\n            mIndexList = Arrays.asList(getResources().getStringArray(R.array.indexable_letter));\n            mIndexList = new ArrayList<>(mIndexList);\n            tempHeaderList = new ArrayList<>();\n        }\n        for (int i = 0; i < datas.size(); i++) {\n            EntityWrapper wrapper = datas.get(i);\n            if (wrapper.getItemType() == EntityWrapper.TYPE_TITLE || wrapper.getIndexTitle() == null) {\n                String index = wrapper.getIndex();\n                if (!TextUtils.isEmpty(index)) {\n                    if (!showAllLetter) {\n                        mIndexList.add(index);\n                    } else {\n                        if (IndexableLayout.INDEX_SIGN.equals(index)) {\n                            mIndexList.add(IndexableLayout.INDEX_SIGN);\n                        } else if (mIndexList.indexOf(index) < 0) {\n                            if (wrapper.getHeaderFooterType() == EntityWrapper.TYPE_HEADER && tempHeaderList.indexOf(index) < 0) {\n                                tempHeaderList.add(index);\n                            } else if (wrapper.getHeaderFooterType() == EntityWrapper.TYPE_FOOTER) {\n                                mIndexList.add(index);\n                            }\n                        }\n                    }\n                    if (!mMapping.containsKey(index)) {\n                        mMapping.put(index, i);\n                    }\n                }\n            }\n        }\n        if (showAllLetter) {\n            mIndexList.addAll(0, tempHeaderList);\n        }\n        requestLayout();\n    }\n\n    void setSelection(int firstVisibleItemPosition) {\n        if (mDatas == null || mDatas.size() <= firstVisibleItemPosition || firstVisibleItemPosition < 0)\n            return;\n        EntityWrapper wrapper = mDatas.get(firstVisibleItemPosition);\n        int position = mIndexList.indexOf(wrapper.getIndex());\n\n        if (mSelectionPosition != position && position >= 0) {\n            mSelectionPosition = position;\n            invalidate();\n        }\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/IndexableAdapter.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport java.util.List;\n\nimport me.yokeyword.indexablerv.database.DataObservable;\nimport me.yokeyword.indexablerv.database.DataObserver;\n\n/**\n * Created by YoKey on 16/10/6.\n */\npublic abstract class IndexableAdapter<T extends IndexableEntity> {\n    static final int TYPE_ALL = 0;\n    static final int TYPE_CLICK_TITLE = 1;\n    static final int TYPE_CLICK_CONTENT = 2;\n    static final int TYPE_LONG_CLICK_TITLE = 3;\n    static final int TYPE_LONG_CLICK_CONTENT = 4;\n    private final DataObservable mDataSetObservable = new DataObservable();\n\n    private List<T> mDatas;\n\n    private IndexCallback<T> mCallback;\n    private OnItemTitleClickListener mTitleClickListener;\n    private OnItemContentClickListener mContentClickListener;\n    private OnItemTitleLongClickListener mTitleLongClickListener;\n    private OnItemContentLongClickListener mContentLongClickListener;\n\n    public abstract RecyclerView.ViewHolder onCreateTitleViewHolder(ViewGroup parent);\n\n    public abstract RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent);\n\n    public abstract void onBindTitleViewHolder(RecyclerView.ViewHolder holder, String indexTitle);\n\n    public abstract void onBindContentViewHolder(RecyclerView.ViewHolder holder, T entity);\n\n    public void setDatas(List<T> datas) {\n        setDatas(datas, null);\n    }\n\n    /**\n     * @param callback Register a callback to be invoked when this datas is processed.\n     */\n    public void setDatas(List<T> datas, IndexCallback<T> callback) {\n        this.mCallback = callback;\n        mDatas = datas;\n        notifyInited();\n    }\n\n    /**\n     * set Index-ItemView click listener\n     */\n    public void setOnItemTitleClickListener(OnItemTitleClickListener listener) {\n        this.mTitleClickListener = listener;\n        notifySetListener(TYPE_CLICK_TITLE);\n    }\n\n    /**\n     * set Content-ItemView click listener\n     */\n    public void setOnItemContentClickListener(OnItemContentClickListener<T> listener) {\n        this.mContentClickListener = listener;\n        notifySetListener(TYPE_CLICK_CONTENT);\n    }\n\n    /**\n     * set Index-ItemView longClick listener\n     */\n    public void setOnItemTitleLongClickListener(OnItemTitleLongClickListener listener) {\n        this.mTitleLongClickListener = listener;\n        notifySetListener(TYPE_LONG_CLICK_TITLE);\n    }\n\n    /**\n     * set Content-ItemView longClick listener\n     */\n    public void setOnItemContentLongClickListener(OnItemContentLongClickListener<T> listener) {\n        this.mContentLongClickListener = listener;\n        notifySetListener(TYPE_LONG_CLICK_CONTENT);\n    }\n\n    /**\n     * Notifies the attached observers that the underlying data has been changed\n     * and any View reflecting the data set should refresh itself.\n     */\n    public void notifyDataSetChanged() {\n        mDataSetObservable.notifyInited();\n//        mDataSetObservable.notifyChanged();\n    }\n\n    private void notifyInited() {\n        mDataSetObservable.notifyInited();\n    }\n\n    private void notifySetListener(int type) {\n        mDataSetObservable.notifySetListener(type);\n    }\n\n    public List<T> getItems() {\n        return mDatas;\n    }\n\n    IndexCallback<T> getIndexCallback() {\n        return mCallback;\n    }\n\n    OnItemTitleClickListener getOnItemTitleClickListener() {\n        return mTitleClickListener;\n    }\n\n    OnItemTitleLongClickListener getOnItemTitleLongClickListener() {\n        return mTitleLongClickListener;\n    }\n\n    OnItemContentClickListener getOnItemContentClickListener() {\n        return mContentClickListener;\n    }\n\n    OnItemContentLongClickListener getOnItemContentLongClickListener() {\n        return mContentLongClickListener;\n    }\n\n    void registerDataSetObserver(DataObserver observer) {\n        mDataSetObservable.registerObserver(observer);\n    }\n\n    void unregisterDataSetObserver(DataObserver observer) {\n        mDataSetObservable.unregisterObserver(observer);\n    }\n\n    public interface IndexCallback<T> {\n        void onFinished(List<EntityWrapper<T>> datas);\n    }\n\n    public interface OnItemTitleClickListener {\n        void onItemClick(View v, int currentPosition, String indexTitle);\n    }\n\n    public interface OnItemContentClickListener<T> {\n        void onItemClick(View v, int originalPosition, int currentPosition, T entity);\n    }\n\n    public interface OnItemTitleLongClickListener {\n        boolean onItemLongClick(View v, int currentPosition, String indexTitle);\n    }\n\n    public interface OnItemContentLongClickListener<T> {\n        boolean onItemLongClick(View v, int originalPosition, int currentPosition, T entity);\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/IndexableEntity.java",
    "content": "package me.yokeyword.indexablerv;\n\n/**\n * Created by YoKey on 16/10/9.\n */\npublic interface IndexableEntity {\n\n    String getFieldIndexBy();\n\n    void setFieldIndexBy(String indexField);\n\n    void setFieldPinyinIndexBy(String pinyin);\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/IndexableFooterAdapter.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport java.util.List;\n\n/**\n * FooterView Adapter\n * Created by YoKey on 16/10/14.\n */\npublic abstract class IndexableFooterAdapter<T> extends AbstractHeaderFooterAdapter<T> {\n\n    public IndexableFooterAdapter(String index, String indexTitle, List<T> datas) {\n        super(index, indexTitle, datas);\n    }\n\n    @Override\n    int getHeaderFooterType() {\n        return EntityWrapper.TYPE_FOOTER;\n    }\n\n    /**\n     * set Content-ItemView click listener\n     */\n    public void setOnItemFooterClickListener(OnItemFooterClickListener<T> listener) {\n        this.mListener = listener;\n    }\n\n    /**\n     * set Content-ItemView longClick listener\n     */\n    public void setOnItemFooterLongClickListener(OnItemFooterLongClickListener<T> listener) {\n        this.mLongListener = listener;\n    }\n\n    public interface OnItemFooterClickListener<T> extends OnItemClickListener<T>{\n    }\n\n    public interface OnItemFooterLongClickListener<T> extends OnItemLongClickListener<T>{\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/IndexableHeaderAdapter.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport java.util.List;\n\n/**\n * HeaderView Adapter\n * Created by YoKey on 16/10/8.\n */\npublic abstract class IndexableHeaderAdapter<T> extends AbstractHeaderFooterAdapter<T>{\n\n    public IndexableHeaderAdapter(String index, String indexTitle, List<T> datas) {\n        super(index, indexTitle, datas);\n    }\n\n    @Override\n    int getHeaderFooterType() {\n        return EntityWrapper.TYPE_HEADER;\n    }\n\n    /**\n     * set Content-ItemView click listener\n     */\n    public void setOnItemHeaderClickListener(OnItemHeaderClickListener<T> listener) {\n        this.mListener = listener;\n    }\n\n    /**\n     * set Content-ItemView longClick listener\n     */\n    public void setOnItemHeaderLongClickListener(OnItemHeaderLongClickListener<T> listener) {\n        this.mLongListener = listener;\n    }\n\n    public interface OnItemHeaderClickListener<T> extends OnItemClickListener<T>{\n    }\n\n    public interface OnItemHeaderLongClickListener<T> extends OnItemLongClickListener<T>{\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/IndexableLayout.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.content.res.TypedArray;\nimport android.graphics.Color;\nimport android.graphics.drawable.Drawable;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.support.annotation.IntDef;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v7.widget.AppCompatTextView;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.Gravity;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.WindowManager;\nimport android.widget.FrameLayout;\nimport android.widget.TextView;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport me.yokeyword.indexablerecyclerview.R;\nimport me.yokeyword.indexablerv.database.DataObserver;\nimport me.yokeyword.indexablerv.database.HeaderFooterDataObserver;\nimport me.yokeyword.indexablerv.database.IndexBarDataObserver;\n\n/**\n * RecyclerView + IndexBar\n * Created by YoKey on 16/10/6.\n */\n@SuppressWarnings(\"unchecked\")\npublic class IndexableLayout extends FrameLayout {\n    // 快速排序，只比对首字母(默认)\n    public static final int MODE_FAST = 0;\n    // 全字母比较排序, 效率最低\n    public static final int MODE_ALL_LETTERS = 1;\n    // 每个字母模块内：无需排序，效率最高\n    public static final int MODE_NONE = 2;\n\n    private static int PADDING_RIGHT_OVERLAY;\n    static final String INDEX_SIGN = \"#\";\n\n    private Context mContext;\n    private boolean mShowAllLetter = true;\n\n    private ExecutorService mExecutorService;\n    private Future mFuture;\n\n    private RecyclerView mRecy;\n    private IndexBar mIndexBar;\n    /**\n     * 保存正在Invisible的ItemView\n     * <p>\n     * 使用mLastInvisibleRecyclerViewItemView来保存当前Invisible的ItemView，\n     * 每次有新的ItemView需要Invisible的时候，把旧的Invisible的ItemView设为Visible。\n     * 这样就修复了View复用导致的Invisible状态传递的问题。\n     */\n    private View mLastInvisibleRecyclerViewItemView;\n\n    private boolean mSticyEnable = true;\n    private RecyclerView.ViewHolder mStickyViewHolder;\n    private String mStickyTitle;\n\n    private RealAdapter mRealAdapter;\n    private RecyclerView.LayoutManager mLayoutManager;\n\n    private IndexableAdapter mIndexableAdapter;\n\n    private TextView mCenterOverlay, mMDOverlay;\n\n    private int mBarTextColor, mBarFocusTextColor;\n    private float mBarTextSize, mBarTextSpace, mBarWidth;\n    private Drawable mBarBg;\n\n    private DataObserver mDataSetObserver;\n\n    private int mCompareMode = MODE_FAST;\n    private Comparator mComparator;\n    private Handler mHandler;\n\n    private HeaderFooterDataObserver<EntityWrapper> mHeaderFooterDataSetObserver = new HeaderFooterDataObserver<EntityWrapper>() {\n        @Override\n        public void onChanged() {\n            if (mRealAdapter == null) return;\n            mRealAdapter.notifyDataSetChanged();\n        }\n\n        @Override\n        public void onAdd(boolean header, EntityWrapper preData, EntityWrapper data) {\n            if (mRealAdapter == null) return;\n            mRealAdapter.addHeaderFooterData(header, preData, data);\n        }\n\n        @Override\n        public void onRemove(boolean header, EntityWrapper data) {\n            if (mRealAdapter == null) return;\n            mRealAdapter.removeHeaderFooterData(header, data);\n        }\n    };\n\n    private IndexBarDataObserver mIndexBarDataSetObserver = new IndexBarDataObserver() {\n        @Override\n        public void onChanged() {\n            mIndexBar.setDatas(mShowAllLetter, mRealAdapter.getItems());\n        }\n    };\n\n    public IndexableLayout(Context context) {\n        this(context, null);\n    }\n\n    public IndexableLayout(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public IndexableLayout(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs);\n    }\n\n    /**\n     * set RealAdapter\n     * {@link #setLayoutManager(RecyclerView.LayoutManager)}\n     */\n    public <T extends IndexableEntity> void setAdapter(final IndexableAdapter<T> adapter) {\n\n        if (mLayoutManager == null) {\n            throw new NullPointerException(\"You must set the LayoutManager first\");\n        }\n\n        this.mIndexableAdapter = adapter;\n\n        if (mDataSetObserver != null) {\n            adapter.unregisterDataSetObserver(mDataSetObserver);\n        }\n        mDataSetObserver = new DataObserver() {\n\n            @Override\n            public void onInited() {\n                onSetListener(IndexableAdapter.TYPE_ALL);\n                onDataChanged();\n            }\n\n            @Override\n            public void onChanged() {\n                if (mRealAdapter != null) {\n                    mRealAdapter.notifyDataSetChanged();\n                }\n            }\n\n            @Override\n            public void onSetListener(int type) {\n                // set listeners\n                if ((type == IndexableAdapter.TYPE_CLICK_TITLE || type == IndexableAdapter.TYPE_ALL) && adapter.getOnItemTitleClickListener() != null) {\n                    mRealAdapter.setOnItemTitleClickListener(adapter.getOnItemTitleClickListener());\n                }\n                if ((type == IndexableAdapter.TYPE_LONG_CLICK_TITLE || type == IndexableAdapter.TYPE_ALL) && adapter.getOnItemTitleLongClickListener() != null) {\n                    mRealAdapter.setOnItemTitleLongClickListener(adapter.getOnItemTitleLongClickListener());\n                }\n                if ((type == IndexableAdapter.TYPE_CLICK_CONTENT || type == IndexableAdapter.TYPE_ALL) && adapter.getOnItemContentClickListener() != null) {\n                    mRealAdapter.setOnItemContentClickListener(adapter.getOnItemContentClickListener());\n                }\n                if ((type == IndexableAdapter.TYPE_LONG_CLICK_CONTENT || type == IndexableAdapter.TYPE_ALL) && adapter.getOnItemContentLongClickListener() != null) {\n                    mRealAdapter.setOnItemContentLongClickListener(adapter.getOnItemContentLongClickListener());\n                }\n            }\n        };\n\n        adapter.registerDataSetObserver(mDataSetObserver);\n        mRealAdapter.setIndexableAdapter(adapter);\n        if (mSticyEnable) {\n            initStickyView(adapter);\n        }\n    }\n\n    /**\n     * add HeaderView Adapter\n     */\n    public <T> void addHeaderAdapter(IndexableHeaderAdapter<T> adapter) {\n        adapter.registerDataSetObserver(mHeaderFooterDataSetObserver);\n        adapter.registerIndexBarDataSetObserver(mIndexBarDataSetObserver);\n        mRealAdapter.addIndexableHeaderAdapter(adapter);\n    }\n\n    /**\n     * removeData HeaderView Adapter\n     */\n    public <T> void removeHeaderAdapter(IndexableHeaderAdapter<T> adapter) {\n        try {\n            adapter.unregisterDataSetObserver(mHeaderFooterDataSetObserver);\n            adapter.unregisterIndexBarDataSetObserver(mIndexBarDataSetObserver);\n            mRealAdapter.removeIndexableHeaderAdapter(adapter);\n        } catch (Exception ignored) {\n        }\n    }\n\n    /**\n     * add FooterView Adapter\n     */\n    public <T> void addFooterAdapter(IndexableFooterAdapter<T> adapter) {\n        adapter.registerDataSetObserver(mHeaderFooterDataSetObserver);\n        adapter.registerIndexBarDataSetObserver(mIndexBarDataSetObserver);\n        mRealAdapter.addIndexableFooterAdapter(adapter);\n    }\n\n    /**\n     * removeData FooterView Adapter\n     */\n    public <T> void removeFooterAdapter(IndexableFooterAdapter<T> adapter) {\n        try {\n            adapter.unregisterDataSetObserver(mHeaderFooterDataSetObserver);\n            adapter.unregisterIndexBarDataSetObserver(mIndexBarDataSetObserver);\n            mRealAdapter.removeIndexableFooterAdapter(adapter);\n        } catch (Exception ignored) {\n        }\n    }\n\n    /**\n     * set sort-mode\n     * Deprecated {@link #setCompareMode(int)}\n     */\n    @Deprecated\n    public void setFastCompare(boolean fastCompare) {\n        setCompareMode(fastCompare ? MODE_FAST : MODE_ALL_LETTERS);\n    }\n\n    @IntDef({MODE_FAST, MODE_ALL_LETTERS, MODE_NONE})\n    @Retention(RetentionPolicy.SOURCE)\n    @interface CompareMode {\n    }\n\n    /**\n     * set sort-mode\n     */\n    public void setCompareMode(@CompareMode int mode) {\n        this.mCompareMode = mode;\n    }\n\n    /**\n     * set sort-mode\n     */\n    public <T extends IndexableEntity> void setComparator(Comparator<EntityWrapper<T>> comparator) {\n        this.mComparator = comparator;\n    }\n\n    /**\n     * set Sticky Enable\n     */\n    public void setStickyEnable(boolean enable) {\n        this.mSticyEnable = enable;\n    }\n\n    /**\n     * display all letter-index\n     */\n    public void showAllLetter(boolean show) {\n        mShowAllLetter = show;\n    }\n\n    /**\n     * display Material Design OverlayView\n     */\n    public void setOverlayStyle_MaterialDesign(int color) {\n        if (mMDOverlay == null) {\n            initMDOverlay(color);\n        } else {\n            ViewCompat.setBackgroundTintList(mMDOverlay, ColorStateList.valueOf(color));\n        }\n        mCenterOverlay = null;\n    }\n\n    /**\n     * display Center OverlayView\n     */\n    public void setOverlayStyle_Center() {\n        if (mCenterOverlay == null) {\n            initCenterOverlay();\n        }\n        mMDOverlay = null;\n    }\n\n    /**\n     * get OverlayView\n     */\n    public TextView getOverlayView() {\n        return mMDOverlay != null ? mMDOverlay : mCenterOverlay;\n    }\n\n    /**\n     * get RecyclerView\n     */\n    public RecyclerView getRecyclerView() {\n        return mRecy;\n    }\n\n    /**\n     * Set the enabled state of this IndexBar.\n     */\n    public void setIndexBarVisibility(boolean visible) {\n        mIndexBar.setVisibility(visible ? VISIBLE : GONE);\n    }\n\n    private void init(Context context, AttributeSet attrs) {\n        this.mContext = context;\n        this.mExecutorService = Executors.newSingleThreadExecutor();\n        PADDING_RIGHT_OVERLAY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80, getResources().getDisplayMetrics());\n\n        if (attrs != null) {\n            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IndexableRecyclerView);\n            mBarTextColor = a.getColor(R.styleable.IndexableRecyclerView_indexBar_textColor, ContextCompat.getColor(context, R.color.default_indexBar_textColor));\n            mBarTextSize = a.getDimension(R.styleable.IndexableRecyclerView_indexBar_textSize, getResources().getDimension(R.dimen.default_indexBar_textSize));\n            mBarFocusTextColor = a.getColor(R.styleable.IndexableRecyclerView_indexBar_selectedTextColor, ContextCompat.getColor(context, R.color.default_indexBar_selectedTextColor));\n            mBarTextSpace = a.getDimension(R.styleable.IndexableRecyclerView_indexBar_textSpace, getResources().getDimension(R.dimen.default_indexBar_textSpace));\n            mBarBg = a.getDrawable(R.styleable.IndexableRecyclerView_indexBar_background);\n            mBarWidth = a.getDimension(R.styleable.IndexableRecyclerView_indexBar_layout_width, getResources().getDimension(R.dimen.default_indexBar_layout_width));\n            a.recycle();\n        }\n\n        if (mContext instanceof Activity) {\n            ((Activity) mContext).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);\n        }\n\n        mRecy = new RecyclerView(context);\n        mRecy.setVerticalScrollBarEnabled(false);\n        mRecy.setOverScrollMode(View.OVER_SCROLL_NEVER);\n        addView(mRecy, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));\n\n        mIndexBar = new IndexBar(context);\n        mIndexBar.init(mBarBg, mBarTextColor, mBarFocusTextColor, mBarTextSize, mBarTextSpace);\n        LayoutParams params = new LayoutParams((int) mBarWidth, LayoutParams.WRAP_CONTENT);\n        params.gravity = Gravity.END | Gravity.CENTER_VERTICAL;\n        addView(mIndexBar, params);\n\n        mRealAdapter = new RealAdapter();\n        mRecy.setHasFixedSize(true);\n        mRecy.setAdapter(mRealAdapter);\n\n        initListener();\n    }\n\n    /**\n     * {@link #setAdapter(IndexableAdapter)}\n     *\n     * @param layoutManager One of LinearLayoutManager and GridLayoutManager\n     */\n    public void setLayoutManager(RecyclerView.LayoutManager layoutManager) {\n        if (layoutManager == null)\n            throw new NullPointerException(\"LayoutManager == null\");\n\n        mLayoutManager = layoutManager;\n        if (layoutManager instanceof GridLayoutManager) {\n            final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;\n            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {\n                @Override\n                public int getSpanSize(int position) {\n                    int spanSize = 0;\n                    if (mRealAdapter.getItemViewType(position) == EntityWrapper.TYPE_TITLE) {\n                        spanSize = gridLayoutManager.getSpanCount();\n                    } else if (mRealAdapter.getItemViewType(position) == EntityWrapper.TYPE_CONTENT) {\n                        spanSize = 1;\n                    }\n                    return spanSize;\n                }\n            });\n        }\n\n        mRecy.setLayoutManager(mLayoutManager);\n    }\n\n    private void initListener() {\n        mRecy.addOnScrollListener(new RecyclerView.OnScrollListener() {\n            @Override\n            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {\n                super.onScrolled(recyclerView, dx, dy);\n                processScrollListener();\n            }\n        });\n\n        mIndexBar.setOnTouchListener(new OnTouchListener() {\n\n            @Override\n            public boolean onTouch(View v, MotionEvent event) {\n                int touchPos = mIndexBar.getPositionForPointY(event.getY());\n                if (touchPos < 0) return true;\n\n                if (!(mLayoutManager instanceof LinearLayoutManager)) return true;\n                LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mLayoutManager;\n\n                switch (event.getAction()) {\n                    case MotionEvent.ACTION_DOWN:\n                    case MotionEvent.ACTION_MOVE:\n                        showOverlayView(event.getY(), touchPos);\n\n                        if (touchPos != mIndexBar.getSelectionPosition()) {\n                            mIndexBar.setSelectionPosition(touchPos);\n\n                            if (touchPos == 0) {\n                                linearLayoutManager.scrollToPositionWithOffset(0, 0);\n                            } else {\n                                linearLayoutManager.scrollToPositionWithOffset(mIndexBar.getFirstRecyclerViewPositionBySelection(), 0);\n                            }\n                        }\n                        break;\n                    case MotionEvent.ACTION_UP:\n                    case MotionEvent.ACTION_CANCEL:\n                        if (mCenterOverlay != null) mCenterOverlay.setVisibility(GONE);\n                        if (mMDOverlay != null) mMDOverlay.setVisibility(GONE);\n                        break;\n                }\n                return true;\n            }\n        });\n    }\n\n    private void processScrollListener() {\n        if (!(mLayoutManager instanceof LinearLayoutManager)) return;\n\n        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mLayoutManager;\n\n        int firstItemPosition;\n        firstItemPosition = linearLayoutManager.findFirstVisibleItemPosition();\n        if (firstItemPosition == RecyclerView.NO_POSITION) return;\n\n        mIndexBar.setSelection(firstItemPosition);\n\n        if (!mSticyEnable) return;\n        ArrayList<EntityWrapper> list = mRealAdapter.getItems();\n        if (mStickyViewHolder != null && list.size() > firstItemPosition) {\n            EntityWrapper wrapper = list.get(firstItemPosition);\n            String wrapperTitle = wrapper.getIndexTitle();\n\n            if (EntityWrapper.TYPE_TITLE == wrapper.getItemType()) {\n                if (mLastInvisibleRecyclerViewItemView != null && mLastInvisibleRecyclerViewItemView.getVisibility() == INVISIBLE) {\n                    mLastInvisibleRecyclerViewItemView.setVisibility(VISIBLE);\n                    mLastInvisibleRecyclerViewItemView = null;\n                }\n\n                mLastInvisibleRecyclerViewItemView = linearLayoutManager.findViewByPosition(firstItemPosition);\n\n                if (mLastInvisibleRecyclerViewItemView != null) {\n                    mLastInvisibleRecyclerViewItemView.setVisibility(INVISIBLE);\n                }\n            }\n\n            // hide -> show\n            if (wrapperTitle == null && mStickyViewHolder.itemView.getVisibility() == VISIBLE) {\n                mStickyTitle = null;\n                mStickyViewHolder.itemView.setVisibility(INVISIBLE);\n            } else {\n                stickyNewViewHolder(wrapperTitle);\n            }\n\n            // GirdLayoutManager\n            if (mLayoutManager instanceof GridLayoutManager) {\n                GridLayoutManager gridLayoutManager = (GridLayoutManager) mLayoutManager;\n                if (firstItemPosition + gridLayoutManager.getSpanCount() < list.size()) {\n                    for (int i = firstItemPosition + 1; i <= firstItemPosition + gridLayoutManager.getSpanCount(); i++) {\n                        processScroll(linearLayoutManager, list, i, wrapperTitle);\n                    }\n                }\n            } else {   // LinearLayoutManager\n                if (firstItemPosition + 1 < list.size()) {\n                    processScroll(linearLayoutManager, list, firstItemPosition + 1, wrapperTitle);\n                }\n            }\n        }\n    }\n\n    private void processScroll(LinearLayoutManager layoutManager, ArrayList<EntityWrapper> list, int position, String title) {\n        EntityWrapper nextWrapper = list.get(position);\n        View nextTitleView = layoutManager.findViewByPosition(position);\n        if (nextTitleView == null) return;\n        if (nextWrapper.getItemType() == EntityWrapper.TYPE_TITLE) {\n            if (nextTitleView.getTop() <= mStickyViewHolder.itemView.getHeight() && title != null) {\n                mStickyViewHolder.itemView.setTranslationY(nextTitleView.getTop() - mStickyViewHolder.itemView.getHeight());\n            }\n            if (INVISIBLE == nextTitleView.getVisibility()) {\n                //特殊情况：手指向下滑动的时候，需要及时把成为第二个可见View的TitleView设置Visible，\n                // 这样才能配合StickyView制造两个TitleView切换的动画。\n                nextTitleView.setVisibility(VISIBLE);\n            }\n            return;\n        } else if (mStickyViewHolder.itemView.getTranslationY() != 0) {\n            mStickyViewHolder.itemView.setTranslationY(0);\n        }\n        return;\n    }\n\n    private void stickyNewViewHolder(String wrapperTitle) {\n        if ((wrapperTitle != null && !wrapperTitle.equals(mStickyTitle))) {\n\n            if (mStickyViewHolder.itemView.getVisibility() != VISIBLE) {\n                mStickyViewHolder.itemView.setVisibility(VISIBLE);\n            }\n\n            mStickyTitle = wrapperTitle;\n            mIndexableAdapter.onBindTitleViewHolder(mStickyViewHolder, wrapperTitle);\n        }\n    }\n\n    private <T extends IndexableEntity> void initStickyView(final IndexableAdapter<T> adapter) {\n        mStickyViewHolder = adapter.onCreateTitleViewHolder(mRecy);\n        mStickyViewHolder.itemView.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (adapter.getOnItemTitleClickListener() != null) {\n                    int position = mIndexBar.getFirstRecyclerViewPositionBySelection();\n                    ArrayList<EntityWrapper> datas = mRealAdapter.getItems();\n                    if (datas.size() > position && position >= 0) {\n                        adapter.getOnItemTitleClickListener().onItemClick(\n                                v, position, datas.get(position).getIndexTitle());\n                    }\n                }\n            }\n        });\n        mStickyViewHolder.itemView.setOnLongClickListener(new OnLongClickListener() {\n            @Override\n            public boolean onLongClick(View v) {\n                if (adapter.getOnItemTitleLongClickListener() != null) {\n                    int position = mIndexBar.getFirstRecyclerViewPositionBySelection();\n                    ArrayList<EntityWrapper> datas = mRealAdapter.getItems();\n                    if (datas.size() > position && position >= 0) {\n                        return adapter.getOnItemTitleLongClickListener().onItemLongClick(\n                                v, position, datas.get(position).getIndexTitle());\n                    }\n                }\n                return false;\n            }\n        });\n        for (int i = 0; i < getChildCount(); i++) {\n            if (getChildAt(i) == mRecy) {\n                mStickyViewHolder.itemView.setVisibility(INVISIBLE);\n                addView(mStickyViewHolder.itemView, i + 1);\n                return;\n            }\n        }\n    }\n\n\n    private void showOverlayView(float y, final int touchPos) {\n        if (mIndexBar.getIndexList().size() <= touchPos) return;\n\n        if (mMDOverlay != null) {\n            if (mMDOverlay.getVisibility() != VISIBLE) {\n                mMDOverlay.setVisibility(VISIBLE);\n            }\n\n            if (y < PADDING_RIGHT_OVERLAY - mIndexBar.getTop() && y >= 0) {\n                y = PADDING_RIGHT_OVERLAY - mIndexBar.getTop();\n            } else if (y < 0) {\n                if (mIndexBar.getTop() > PADDING_RIGHT_OVERLAY) {\n                    y = 0;\n                } else {\n                    y = PADDING_RIGHT_OVERLAY - mIndexBar.getTop();\n                }\n            } else if (y > mIndexBar.getHeight()) {\n                y = mIndexBar.getHeight();\n            }\n            mMDOverlay.setY(mIndexBar.getTop() + y - PADDING_RIGHT_OVERLAY);\n\n            String index = mIndexBar.getIndexList().get(touchPos);\n            if (!mMDOverlay.getText().equals(index)) {\n                if (index.length() > 1) {\n                    mMDOverlay.setTextSize(30);\n                }\n                mMDOverlay.setText(index);\n            }\n        }\n        if (mCenterOverlay != null) {\n            if (mCenterOverlay.getVisibility() != VISIBLE) {\n                mCenterOverlay.setVisibility(VISIBLE);\n            }\n            String index = mIndexBar.getIndexList().get(touchPos);\n            if (!mCenterOverlay.getText().equals(index)) {\n                if (index.length() > 1) {\n                    mCenterOverlay.setTextSize(32);\n                }\n                mCenterOverlay.setText(index);\n            }\n        }\n    }\n\n    private void initCenterOverlay() {\n        mCenterOverlay = new TextView(mContext);\n        mCenterOverlay.setBackgroundResource(R.drawable.indexable_bg_center_overlay);\n        mCenterOverlay.setTextColor(Color.WHITE);\n        mCenterOverlay.setTextSize(40);\n        mCenterOverlay.setGravity(Gravity.CENTER);\n        int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 70, getResources().getDisplayMetrics());\n        LayoutParams params = new LayoutParams(size, size);\n        params.gravity = Gravity.CENTER;\n        mCenterOverlay.setLayoutParams(params);\n        mCenterOverlay.setVisibility(INVISIBLE);\n\n        addView(mCenterOverlay);\n    }\n\n    private void initMDOverlay(int color) {\n        mMDOverlay = new AppCompatTextView(mContext);\n        mMDOverlay.setBackgroundResource(R.drawable.indexable_bg_md_overlay);\n        ((AppCompatTextView) mMDOverlay).setSupportBackgroundTintList(ColorStateList.valueOf(color));\n        mMDOverlay.setSingleLine();\n        mMDOverlay.setTextColor(Color.WHITE);\n        mMDOverlay.setTextSize(38);\n        mMDOverlay.setGravity(Gravity.CENTER);\n        int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 72, getResources().getDisplayMetrics());\n        LayoutParams params = new LayoutParams(size, size);\n        params.rightMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 33, getResources().getDisplayMetrics());\n        params.gravity = Gravity.END;\n        mMDOverlay.setLayoutParams(params);\n        mMDOverlay.setVisibility(INVISIBLE);\n\n        addView(mMDOverlay);\n    }\n\n    void onDataChanged() {\n        if (mFuture != null) {\n            mFuture.cancel(true);\n        }\n        mFuture = mExecutorService.submit(new Runnable() {\n            @Override\n            public void run() {\n                final ArrayList<EntityWrapper> datas = transform(mIndexableAdapter.getItems());\n                if (datas == null) return;\n\n                getSafeHandler().post(new Runnable() {\n                    @Override\n                    public void run() {\n                        mRealAdapter.setDatas(datas);\n                        mIndexBar.setDatas(mShowAllLetter, mRealAdapter.getItems());\n\n                        if (mIndexableAdapter.getIndexCallback() != null) {\n                            mIndexableAdapter.getIndexCallback().onFinished(datas);\n                        }\n\n                        processScrollListener();\n                    }\n                });\n            }\n        });\n    }\n\n    /**\n     * List<T> -> List<Indexable<T>\n     */\n    private <T extends IndexableEntity> ArrayList<EntityWrapper<T>> transform(final List<T> datas) {\n        try {\n            TreeMap<String, List<EntityWrapper<T>>> map = new TreeMap<>(new Comparator<String>() {\n                @Override\n                public int compare(String lhs, String rhs) {\n                    if (lhs.equals(INDEX_SIGN)) {\n                        return rhs.equals(INDEX_SIGN) ? 0 : 1;\n                    } else if (rhs.equals(INDEX_SIGN)) {\n                        return -1;\n                    }\n                    return lhs.compareTo(rhs);\n                }\n            });\n\n            for (int i = 0; i < datas.size(); i++) {\n                EntityWrapper<T> entity = new EntityWrapper<>();\n                T item = datas.get(i);\n                String indexName = item.getFieldIndexBy();\n                String pinyin = PinyinUtil.getPingYin(indexName);\n                entity.setPinyin(pinyin);\n\n                // init EntityWrapper\n                if (PinyinUtil.matchingLetter(pinyin)) {\n                    entity.setIndex(pinyin.substring(0, 1).toUpperCase());\n                    entity.setIndexByField(item.getFieldIndexBy());\n                } else if (PinyinUtil.matchingPolyphone(pinyin)) {\n                    entity.setIndex(PinyinUtil.gePolyphoneInitial(pinyin).toUpperCase());\n                    entity.setPinyin(PinyinUtil.getPolyphoneRealPinyin(pinyin));\n                    String hanzi = PinyinUtil.getPolyphoneRealHanzi(indexName);\n                    entity.setIndexByField(hanzi);\n                    // 把多音字的真实indexField重新赋值\n                    item.setFieldIndexBy(hanzi);\n                } else {\n                    entity.setIndex(INDEX_SIGN);\n                    entity.setIndexByField(item.getFieldIndexBy());\n                }\n                entity.setIndexTitle(entity.getIndex());\n                entity.setData(item);\n                entity.setOriginalPosition(i);\n                item.setFieldPinyinIndexBy(entity.getPinyin());\n\n                String inital = entity.getIndex();\n\n                List<EntityWrapper<T>> list;\n                if (!map.containsKey(inital)) {\n                    list = new ArrayList<>();\n                    list.add(new EntityWrapper<T>(entity.getIndex(), EntityWrapper.TYPE_TITLE));\n                    map.put(inital, list);\n                } else {\n                    list = map.get(inital);\n                }\n\n                list.add(entity);\n            }\n\n            ArrayList<EntityWrapper<T>> list = new ArrayList<>();\n            for (List<EntityWrapper<T>> indexableEntities : map.values()) {\n                if (mComparator != null) {\n                    Collections.sort(indexableEntities, mComparator);\n                } else {\n                    Comparator comparator;\n                    if (mCompareMode == MODE_FAST) {\n                        comparator = new InitialComparator<T>();\n                        Collections.sort(indexableEntities, comparator);\n                    } else if (mCompareMode == MODE_ALL_LETTERS) {\n                        comparator = new PinyinComparator<T>();\n                        Collections.sort(indexableEntities, comparator);\n                    }\n                }\n\n                list.addAll(indexableEntities);\n            }\n            return list;\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    private Handler getSafeHandler() {\n        if (mHandler == null) {\n            mHandler = new Handler(Looper.getMainLooper());\n        }\n        return mHandler;\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/InitialComparator.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport java.util.Comparator;\n\n/**\n * Created by YoKey on 16/10/14.\n */\nclass InitialComparator<T extends IndexableEntity> implements Comparator<EntityWrapper<T>> {\n    @Override\n    public int compare(EntityWrapper<T> lhs, EntityWrapper<T> rhs) {\n        return lhs.getIndex().compareTo(rhs.getIndex());\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/PinyinComparator.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport android.support.annotation.NonNull;\n\nimport java.util.Comparator;\n\n/**\n * Created by YoKey on 16/10/7.\n */\nclass PinyinComparator<T extends IndexableEntity> implements Comparator<EntityWrapper<T>> {\n\n    @Override\n    public int compare(EntityWrapper<T> lhs, EntityWrapper<T> rhs) {\n        String lhsIndexName = lhs.getIndexByField();\n        String rhsIndexName = rhs.getIndexByField();\n\n        if (lhsIndexName == null) {\n            lhsIndexName = \"\";\n        }\n        if (rhsIndexName == null) {\n            rhsIndexName = \"\";\n        }\n        return compareIndexName(lhsIndexName.trim(), rhsIndexName.trim());\n    }\n\n    private int compareIndexName(String lhs, String rhs) {\n        int index = 0;\n\n        String lhsWord = getWord(lhs, index);\n        String rhsWord = getWord(rhs, index);\n        while (lhsWord.equals(rhsWord) && !lhsWord.equals(\"\")) {\n            index++;\n            lhsWord = getWord(lhs, index);\n            rhsWord = getWord(rhs, index);\n        }\n        return lhsWord.compareTo(rhsWord);\n    }\n\n    @NonNull\n    private String getWord(String indexName, int index) {\n        if (indexName.length() < (index + 1)) return \"\";\n        String firstWord;\n        if (PinyinUtil.matchingPolyphone(indexName)) {\n            firstWord = PinyinUtil.getPingYin(PinyinUtil.getPolyphoneRealHanzi(indexName).substring(index, index + 1));\n        } else {\n            firstWord = PinyinUtil.getPingYin(indexName.substring(index, index + 1));\n        }\n        return firstWord;\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/PinyinUtil.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport com.github.promeg.pinyinhelper.Pinyin;\n\nimport java.util.regex.Pattern;\n\n/**\n * Created by YoKey on 16/3/20.\n */\npublic class PinyinUtil {\n    private static final String PATTERN_POLYPHONE = \"^#[a-zA-Z]+#.+\";\n    private static final String PATTERN_LETTER = \"^[a-zA-Z].*+\";\n\n    /**\n     * Chinese character -> Pinyin\n     */\n    public static String getPingYin(String inputString) {\n        if (inputString == null) return \"\";\n        return Pinyin.toPinyin(inputString, \"\").toLowerCase();\n    }\n\n    /**\n     * Are start with a letter\n     *\n     * @return if return false, index should be #\n     */\n    static boolean matchingLetter(String inputString) {\n        return Pattern.matches(PATTERN_LETTER, inputString);\n    }\n\n    static boolean matchingPolyphone(String inputString) {\n        return Pattern.matches(PATTERN_POLYPHONE, inputString);\n    }\n\n    static String gePolyphoneInitial(String inputString) {\n        return inputString.substring(1, 2);\n    }\n\n    static String getPolyphoneRealPinyin(String inputString) {\n        String[] splits = inputString.split(\"#\");\n        return splits[1];\n    }\n\n    static String getPolyphoneRealHanzi(String inputString) {\n        String[] splits = inputString.split(\"#\");\n        return splits[2];\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/RealAdapter.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.util.SparseArray;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport java.util.ArrayList;\n\n/**\n * Created by YoKey on 16/10/6.\n */\n@SuppressWarnings(\"unchecked\")\nclass RealAdapter<T extends IndexableEntity> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {\n    private ArrayList<EntityWrapper<T>> mDatasList = new ArrayList<>();\n    private ArrayList<EntityWrapper<T>> mDatas;\n    private ArrayList<EntityWrapper<T>> mHeaderDatasList = new ArrayList<>();\n    private ArrayList<EntityWrapper<T>> mFooterDatasList = new ArrayList<>();\n    private IndexableAdapter<T> mAdapter;\n\n    private SparseArray<IndexableHeaderAdapter> mHeaderAdapterMap = new SparseArray<>();\n    private SparseArray<IndexableFooterAdapter> mFooterAdapterMap = new SparseArray<>();\n\n    private IndexableAdapter.OnItemTitleClickListener mTitleClickListener;\n    private IndexableAdapter.OnItemContentClickListener<T> mContentClickListener;\n    private IndexableAdapter.OnItemTitleLongClickListener mTitleLongClickListener;\n    private IndexableAdapter.OnItemContentLongClickListener<T> mContentLongClickListener;\n\n    void setIndexableAdapter(IndexableAdapter<T> adapter) {\n        this.mAdapter = adapter;\n    }\n\n    void addIndexableHeaderAdapter(IndexableHeaderAdapter adapter) {\n        mHeaderDatasList.addAll(0, adapter.getDatas());\n        mDatasList.addAll(0, adapter.getDatas());\n        mHeaderAdapterMap.put(adapter.getItemViewType(), adapter);\n        notifyDataSetChanged();\n    }\n\n    void removeIndexableHeaderAdapter(IndexableHeaderAdapter adapter) {\n        mHeaderDatasList.removeAll(adapter.getDatas());\n        if (mDatasList.size() > 0) {\n            mDatasList.removeAll(adapter.getDatas());\n        }\n        mHeaderAdapterMap.remove(adapter.getItemViewType());\n        notifyDataSetChanged();\n    }\n\n    void addIndexableFooterAdapter(IndexableFooterAdapter adapter) {\n        mFooterDatasList.addAll(adapter.getDatas());\n        mDatasList.addAll(adapter.getDatas());\n        mFooterAdapterMap.put(adapter.getItemViewType(), adapter);\n        notifyDataSetChanged();\n    }\n\n    void removeIndexableFooterAdapter(IndexableFooterAdapter adapter) {\n        mFooterDatasList.removeAll(adapter.getDatas());\n        if (mDatasList.size() > 0) {\n            mDatasList.removeAll(adapter.getDatas());\n        }\n        mFooterAdapterMap.remove(adapter.getItemViewType());\n        notifyDataSetChanged();\n    }\n\n    void setDatas(ArrayList<EntityWrapper<T>> datas) {\n        if (mDatas != null && mDatasList.size() > mHeaderDatasList.size() + mFooterDatasList.size()) {\n            mDatasList.removeAll(mDatas);\n        }\n\n        this.mDatas = datas;\n\n        mDatasList.addAll(mHeaderDatasList.size(), datas);\n        notifyDataSetChanged();\n    }\n\n    ArrayList<EntityWrapper<T>> getItems() {\n        return mDatasList;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return mDatasList.get(position).getItemType();\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {\n        final RecyclerView.ViewHolder holder;\n\n        if (viewType == EntityWrapper.TYPE_TITLE) {\n            holder = mAdapter.onCreateTitleViewHolder(parent);\n        } else if (viewType == EntityWrapper.TYPE_CONTENT) {\n            holder = mAdapter.onCreateContentViewHolder(parent);\n        } else {\n            AbstractHeaderFooterAdapter adapter;\n            if (mHeaderAdapterMap.indexOfKey(viewType) >= 0) {\n                adapter = mHeaderAdapterMap.get(viewType);\n            } else {\n                adapter = mFooterAdapterMap.get(viewType);\n            }\n            holder = adapter.onCreateContentViewHolder(parent);\n        }\n\n        holder.itemView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                int position = holder.getAdapterPosition();\n                if (position == RecyclerView.NO_POSITION) return;\n                EntityWrapper<T> wrapper = mDatasList.get(position);\n                if (viewType == EntityWrapper.TYPE_TITLE) {\n                    if (mTitleClickListener != null) {\n                        mTitleClickListener.onItemClick(v, position, wrapper.getIndexTitle());\n                    }\n                } else if (viewType == EntityWrapper.TYPE_CONTENT) {\n                    if (mContentClickListener != null) {\n                        mContentClickListener.onItemClick(v, wrapper.getOriginalPosition(), position, wrapper.getData());\n                    }\n                } else {\n                    AbstractHeaderFooterAdapter adapter;\n                    if (mHeaderAdapterMap.indexOfKey(viewType) >= 0) {\n                        adapter = mHeaderAdapterMap.get(viewType);\n                    } else {\n                        adapter = mFooterAdapterMap.get(viewType);\n                    }\n\n                    if (adapter != null) {\n                        AbstractHeaderFooterAdapter.OnItemClickListener listener = adapter.getOnItemClickListener();\n                        if (listener != null) {\n                            listener.onItemClick(v, position, wrapper.getData());\n                        }\n                    }\n                }\n            }\n        });\n\n        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {\n            @Override\n            public boolean onLongClick(View v) {\n                int position = holder.getAdapterPosition();\n                EntityWrapper<T> wrapper = mDatasList.get(position);\n                if (viewType == EntityWrapper.TYPE_TITLE) {\n                    if (mTitleLongClickListener != null) {\n                        return mTitleLongClickListener.onItemLongClick(v, position, wrapper.getIndexTitle());\n                    } else {\n                        return true;\n                    }\n                } else if (viewType == EntityWrapper.TYPE_CONTENT) {\n                    if (mContentLongClickListener != null) {\n                        return mContentLongClickListener.onItemLongClick(v, wrapper.getOriginalPosition(), position, wrapper.getData());\n                    } else {\n                        return true;\n                    }\n                } else {\n                    AbstractHeaderFooterAdapter adapter;\n                    if (mHeaderAdapterMap.indexOfKey(viewType) >= 0) {\n                        adapter = mHeaderAdapterMap.get(viewType);\n                    } else {\n                        adapter = mFooterAdapterMap.get(viewType);\n                    }\n\n                    if (adapter != null) {\n                        AbstractHeaderFooterAdapter.OnItemLongClickListener listener = adapter.getOnItemLongClickListener();\n                        if (listener != null) {\n                            return listener.onItemLongClick(v, position, wrapper.getData());\n                        }\n                    }\n                }\n                return false;\n            }\n        });\n        return holder;\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {\n        EntityWrapper<T> item = mDatasList.get(position);\n\n        int viewType = getItemViewType(position);\n        if (viewType == EntityWrapper.TYPE_TITLE) {\n            if (View.INVISIBLE == holder.itemView.getVisibility()) {\n                holder.itemView.setVisibility(View.VISIBLE);\n            }\n            mAdapter.onBindTitleViewHolder(holder, item.getIndexTitle());\n        } else if (viewType == EntityWrapper.TYPE_CONTENT) {\n            mAdapter.onBindContentViewHolder(holder, item.getData());\n        } else {\n            AbstractHeaderFooterAdapter adapter;\n            if (mHeaderAdapterMap.indexOfKey(viewType) >= 0) {\n                adapter = mHeaderAdapterMap.get(viewType);\n            } else {\n                adapter = mFooterAdapterMap.get(viewType);\n            }\n            adapter.onBindContentViewHolder(holder, item.getData());\n        }\n    }\n\n    @Override\n    public int getItemCount() {\n        return mDatasList.size();\n    }\n\n    void setOnItemTitleClickListener(IndexableAdapter.OnItemTitleClickListener listener) {\n        this.mTitleClickListener = listener;\n    }\n\n    void setOnItemContentClickListener(IndexableAdapter.OnItemContentClickListener<T> listener) {\n        this.mContentClickListener = listener;\n    }\n\n    void setOnItemTitleLongClickListener(IndexableAdapter.OnItemTitleLongClickListener listener) {\n        this.mTitleLongClickListener = listener;\n    }\n\n    void setOnItemContentLongClickListener(IndexableAdapter.OnItemContentLongClickListener<T> listener) {\n        this.mContentLongClickListener = listener;\n    }\n\n    void addHeaderFooterData(boolean header, EntityWrapper preData, EntityWrapper data) {\n        processAddHeaderFooterData(header ? mHeaderDatasList : mFooterDatasList, preData, data);\n    }\n\n    private void processAddHeaderFooterData(ArrayList<EntityWrapper<T>> list, EntityWrapper preData, EntityWrapper data) {\n        for (int i = 0; i < list.size(); i++) {\n            EntityWrapper wrapper = list.get(i);\n            if (wrapper == preData) {\n                int index = i + 1;\n                list.add(index, data);\n                if (list == mFooterDatasList) {\n                    index += mDatasList.size() - mFooterDatasList.size() + 1;\n                }\n                mDatasList.add(index, data);\n                notifyItemInserted(i + 1);\n                return;\n            }\n        }\n    }\n\n    void removeHeaderFooterData(boolean header, EntityWrapper data) {\n        processremoveHeaderFooterData(header ? mHeaderDatasList : mFooterDatasList, data);\n    }\n\n    private void processremoveHeaderFooterData(ArrayList<EntityWrapper<T>> list, EntityWrapper data) {\n        for (int i = 0; i < list.size(); i++) {\n            EntityWrapper wrapper = list.get(i);\n            if (wrapper == data) {\n                list.remove(data);\n                mDatasList.remove(data);\n                notifyItemRemoved(i);\n                return;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/SimpleFooterAdapter.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.view.ViewGroup;\n\nimport java.util.List;\n\n/**\n * 该HeaderAdapter 接收一个IndexableAdapter, 使其布局以及点击事件和IndexableAdapter一致\n * Created by YoKey on 16/10/14.\n */\npublic class SimpleFooterAdapter<T extends IndexableEntity> extends IndexableFooterAdapter<T> {\n    private IndexableAdapter<T> mAdapter;\n\n    public SimpleFooterAdapter(IndexableAdapter<T> adapter, String index, String indexTitle, List<T> datas) {\n        super(index, indexTitle, datas);\n        this.mAdapter = adapter;\n    }\n\n    @Override\n    public int getItemViewType() {\n        return EntityWrapper.TYPE_CONTENT;\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent) {\n        return mAdapter.onCreateContentViewHolder(parent);\n    }\n\n    @Override\n    public void onBindContentViewHolder(RecyclerView.ViewHolder holder, T entity) {\n        mAdapter.onBindContentViewHolder(holder, entity);\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/SimpleHeaderAdapter.java",
    "content": "package me.yokeyword.indexablerv;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.view.ViewGroup;\n\nimport java.util.List;\n\n/**\n * 该HeaderAdapter 接收一个IndexableAdapter, 使其布局以及点击事件和IndexableAdapter一致\n * Created by YoKey on 16/10/8.\n */\npublic class SimpleHeaderAdapter<T extends IndexableEntity> extends IndexableHeaderAdapter<T> {\n    private IndexableAdapter<T> mAdapter;\n\n    public SimpleHeaderAdapter(IndexableAdapter<T> adapter, String index, String indexTitle, List<T> datas) {\n        super(index, indexTitle, datas);\n        this.mAdapter = adapter;\n    }\n\n    @Override\n    public int getItemViewType() {\n        return EntityWrapper.TYPE_CONTENT;\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent) {\n        return mAdapter.onCreateContentViewHolder(parent);\n    }\n\n    @Override\n    public void onBindContentViewHolder(RecyclerView.ViewHolder holder, T entity) {\n        mAdapter.onBindContentViewHolder(holder, entity);\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/database/DataObservable.java",
    "content": "/*\n * Copyright (C) 2007 The Android Open Source Project\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\npackage me.yokeyword.indexablerv.database;\n\nimport android.database.Observable;\n\n/**\n * A specialization of {@link Observable} for {@link DataObserver}\n * that provides methods for sending notifications to a list of\n * {@link DataObserver} objects.\n */\npublic class DataObservable extends Observable<DataObserver> {\n\n    /**\n     * Invokes {@link DataObserver#onInited()}  on each observer.\n     * Called when the data set is no longer valid and cannot be queried again,\n     * such as when the data set has been closed.\n     */\n    public void notifyInited() {\n        synchronized (mObservers) {\n            for (int i = mObservers.size() - 1; i >= 0; i--) {\n                mObservers.get(i).onInited();\n            }\n        }\n    }\n\n    /**\n     * Invokes {@link DataObserver#onChanged} on each observer.\n     * Called when the contents of the data set have changed.  The recipient\n     * will obtain the new contents the next time it queries the data set.\n     */\n    public void notifyChanged() {\n        synchronized (mObservers) {\n            // since onChanged() is implemented by the app, it could do anything, including\n            // removing itself from {@link mObservers} - and that could cause problems if\n            // an iterator is used on the ArrayList {@link mObservers}.\n            // to avoid such problems, just march thru the list in the reverse order.\n            for (int i = mObservers.size() - 1; i >= 0; i--) {\n                mObservers.get(i).onChanged();\n            }\n        }\n    }\n\n    /**\n     * Invokes {@link DataObserver#onSetListener(int)} on each observer.\n     * Called when the data set is no longer valid and cannot be queried again,\n     * such as when the data set has been closed.\n     */\n    public void notifySetListener(int type) {\n        synchronized (mObservers) {\n            for (int i = mObservers.size() - 1; i >= 0; i--) {\n                mObservers.get(i).onSetListener(type);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/database/DataObserver.java",
    "content": "package me.yokeyword.indexablerv.database;\n\n/**\n * Created by YoKey on 16/10/13.\n */\npublic class DataObserver {\n    /**\n     * This method is called when the entire data set has changed,\n     * init datas\n     */\n    public void onInited() {\n        // Do nothing\n    }\n\n    /**\n     * This method is called when the entire data set has changed,\n     * refresh UI\n     */\n    public void onChanged() {\n        // Do nothing\n    }\n\n    /**\n     * This method is called when the entire data becomes invalid,\n     * setListener\n     */\n    public void onSetListener(int type) {\n        // Do nothing\n    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/database/HeaderFooterDataObservable.java",
    "content": "/*\n * Copyright (C) 2007 The Android Open Source Project\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\npackage me.yokeyword.indexablerv.database;\n\nimport android.database.Observable;\n\n/**\n * A specialization of {@link Observable} for {@link DataObserver}\n * that provides methods for sending notifications to a list of\n * {@link DataObserver} objects.\n */\npublic class HeaderFooterDataObservable extends Observable<HeaderFooterDataObserver> {\n\n    /**\n     * Invokes {@link DataObserver#onChanged} on each observer.\n     * Called when the contents of the data set have changed.  The recipient\n     * will obtain the new contents the next time it queries the data set.\n     */\n    public void notifyChanged() {\n        synchronized (mObservers) {\n            // since onChanged() is implemented by the app, it could do anything, including\n            // removing itself from {@link mObservers} - and that could cause problems if\n            // an iterator is used on the ArrayList {@link mObservers}.\n            // to avoid such problems, just march thru the list in the reverse order.\n            for (int i = mObservers.size() - 1; i >= 0; i--) {\n                mObservers.get(i).onChanged();\n            }\n        }\n    }\n\n    public void notifyAdd(boolean header, Object preData, Object data) {\n        synchronized (mObservers) {\n            // since onChanged() is implemented by the app, it could do anything, including\n            // removing itself from {@link mObservers} - and that could cause problems if\n            // an iterator is used on the ArrayList {@link mObservers}.\n            // to avoid such problems, just march thru the list in the reverse order.\n            for (int i = mObservers.size() - 1; i >= 0; i--) {\n                mObservers.get(i).onAdd(header, preData, data);\n            }\n        }\n    }\n\n    public void notifyRemove(boolean header, Object object) {\n        synchronized (mObservers) {\n            // since onChanged() is implemented by the app, it could do anything, including\n            // removing itself from {@link mObservers} - and that could cause problems if\n            // an iterator is used on the ArrayList {@link mObservers}.\n            // to avoid such problems, just march thru the list in the reverse order.\n            for (int i = mObservers.size() - 1; i >= 0; i--) {\n                mObservers.get(i).onRemove(header, object);\n            }\n        }\n    }\n//\n//    public void notifyAddAll(Object preData, Object data) {\n//        synchronized (mObservers) {\n//            // since onChanged() is implemented by the app, it could do anything, including\n//            // removing itself from {@link mObservers} - and that could cause problems if\n//            // an iterator is used on the ArrayList {@link mObservers}.\n//            // to avoid such problems, just march thru the list in the reverse order.\n//            for (int i = mObservers.size() - 1; i >= 0; i--) {\n//                mObservers.get(i).onAddAll(itemType, position, datas);\n//            }\n//        }\n//    }\n//\n//    public void notifyRemoveAll(Collection datas) {\n//        synchronized (mObservers) {\n//            // since onChanged() is implemented by the app, it could do anything, including\n//            // removing itself from {@link mObservers} - and that could cause problems if\n//            // an iterator is used on the ArrayList {@link mObservers}.\n//            // to avoid such problems, just march thru the list in the reverse order.\n//            for (int i = mObservers.size() - 1; i >= 0; i--) {\n//                mObservers.get(i).onRemoveAll(itemType, datas);\n//            }\n//        }\n//    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/database/HeaderFooterDataObserver.java",
    "content": "package me.yokeyword.indexablerv.database;\n\n/**\n * Created by YoKey on 16/10/13.\n */\npublic class HeaderFooterDataObserver<T> {\n    /**\n     * This method is called when the entire data set has changed,\n     * refresh UI\n     */\n    public void onChanged() {\n        // Do nothing\n    }\n\n    public void onAdd(boolean header, T preData, T data) {\n        // Do nothing\n    }\n\n    public void onRemove(boolean header, T object) {\n        // Do nothing\n    }\n//\n//    public void onAddAll(int itemType, int position, Collection<T> datas) {\n//        // Do nothing\n//    }\n//\n//    public void onRemoveAll(int itemType, Collection<T> datas) {\n//        // Do nothing\n//    }\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/database/IndexBarDataObservable.java",
    "content": "package me.yokeyword.indexablerv.database;\n\nimport android.database.Observable;\n\n/**\n * Created by Sun on 16/10/13.\n */\npublic class IndexBarDataObservable extends Observable<IndexBarDataObserver> {\n\n    public void notifyChanged() {\n        synchronized (mObservers) {\n            for (int i = mObservers.size() - 1; i >= 0; i--) {\n                mObservers.get(i).onChanged();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/java/me/yokeyword/indexablerv/database/IndexBarDataObserver.java",
    "content": "package me.yokeyword.indexablerv.database;\n\n/**\n * Created by Sun on 16/10/13.\n */\npublic class IndexBarDataObserver {\n\n    /**\n     * This method is called when the entire data set has changed,\n     * refresh UI\n     */\n    public void onChanged() {\n        // Do nothing\n    }\n\n}\n"
  },
  {
    "path": "indexablerecyclerview/src/main/res/drawable/indexable_bg_center_overlay.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"#70000000\"/>\n    <corners android:radius=\"4dp\"/>\n</shape>"
  },
  {
    "path": "indexablerecyclerview/src/main/res/values/indexable_attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"IndexableRecyclerView\">\n        <attr name=\"indexBar_selectedTextColor\" format=\"color\" />\n        <attr name=\"indexBar_textColor\" format=\"color\" />\n        <attr name=\"indexBar_textSize\" format=\"dimension\" />\n        <attr name=\"indexBar_textSpace\" format=\"dimension\" />\n        <attr name=\"indexBar_background\" format=\"reference|color\" />\n        <attr name=\"indexBar_layout_width\" format=\"dimension\">\n            <!--<enum name=\"wrap_content\" value=\"-2\" /> 暂不支持 -->\n        </attr>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "indexablerecyclerview/src/main/res/values/indexable_default.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"default_indexBar_textColor\">#8c8c8c</color>\n    <dimen name=\"default_indexBar_textSize\">14sp</dimen>\n    <color name=\"default_indexBar_selectedTextColor\">#f33737</color>\n    <dimen name=\"default_indexBar_textSpace\">4dp</dimen>\n    <drawable name=\"dafault_indexBar_background\">@android:color/transparent</drawable>\n    <dimen name=\"default_indexBar_layout_width\">24dp</dimen>\n</resources>"
  },
  {
    "path": "indexablerecyclerview/src/main/res/values/indexable_strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string-array name=\"indexable_letter\">\n        <item>A</item>\n        <item>B</item>\n        <item>C</item>\n        <item>D</item>\n        <item>E</item>\n        <item>F</item>\n        <item>G</item>\n        <item>H</item>\n        <item>I</item>\n        <item>J</item>\n        <item>K</item>\n        <item>L</item>\n        <item>M</item>\n        <item>N</item>\n        <item>O</item>\n        <item>P</item>\n        <item>Q</item>\n        <item>R</item>\n        <item>S</item>\n        <item>T</item>\n        <item>U</item>\n        <item>V</item>\n        <item>W</item>\n        <item>X</item>\n        <item>Y</item>\n        <item>Z</item>\n    </string-array>\n</resources>"
  },
  {
    "path": "sample/.gitignore",
    "content": "/build\n\n"
  },
  {
    "path": "sample/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 25\n    buildToolsVersion \"25.0.2\"\n\n    defaultConfig {\n        applicationId \"me.yokeyword.indexablecv.sample\"\n        minSdkVersion 14\n        targetSdkVersion 24\n        versionCode 1\n        versionName \"1.0\"\n    }\n    \n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile 'com.android.support:appcompat-v7:25.3.1'\n    compile 'com.android.support:recyclerview-v7:25.3.1'\n    compile project(':indexablerecyclerview')\n}\n"
  },
  {
    "path": "sample/proguard-rules.pro",
    "content": ""
  },
  {
    "path": "sample/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=\"me.yokeyword.sample\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".MainActivity\"\n            android:screenOrientation=\"portrait\">\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\n            android:name=\".city.PickCityActivity\"\n            android:screenOrientation=\"portrait\" />\n        <activity\n            android:name=\".contact.PickContactActivity\"\n            android:screenOrientation=\"portrait\" />\n    </application>\n\n</manifest>"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/MainActivity.java",
    "content": "package me.yokeyword.sample;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.View;\n\nimport me.yokeyword.sample.city.PickCityActivity;\nimport me.yokeyword.sample.contact.PickContactActivity;\n\n\n/**\n * Created by YoKey on 16/10/7.\n */\npublic class MainActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        findViewById(R.id.btn_pick_city).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                startActivity(new Intent(MainActivity.this, PickCityActivity.class));\n            }\n        });\n        findViewById(R.id.btn_pick_contact).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                startActivity(new Intent(MainActivity.this, PickContactActivity.class));\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/ToastUtil.java",
    "content": "package me.yokeyword.sample;\n\nimport android.content.Context;\nimport android.widget.Toast;\n\n/**\n * Created by YoKey on 16/10/9.\n */\npublic class ToastUtil {\n    private static Toast toast;\n\n    /**\n     * 短时间显示Toast\n     *\n     * @param context\n     * @param message\n     */\n    public static Toast showShort(Context context, CharSequence message) {\n        if (null == toast) {\n            toast = Toast.makeText(context, message, Toast.LENGTH_SHORT);\n        } else {\n            toast.setText(message);\n        }\n        toast.show();\n\n        return toast;\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/city/CityAdapter.java",
    "content": "package me.yokeyword.sample.city;\n\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport me.yokeyword.indexablerv.IndexableAdapter;\nimport me.yokeyword.sample.R;\n\n/**\n * Created by YoKey on 16/10/7.\n */\npublic class CityAdapter extends IndexableAdapter<CityEntity> {\n    private LayoutInflater mInflater;\n\n    public CityAdapter(Context context) {\n        mInflater = LayoutInflater.from(context);\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateTitleViewHolder(ViewGroup parent) {\n        View view = mInflater.inflate(R.layout.item_index_city, parent, false);\n        return new IndexVH(view);\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent) {\n        View view = mInflater.inflate(R.layout.item_city, parent, false);\n        return new ContentVH(view);\n    }\n\n    @Override\n    public void onBindTitleViewHolder(RecyclerView.ViewHolder holder, String indexTitle) {\n        IndexVH vh = (IndexVH) holder;\n        vh.tv.setText(indexTitle);\n    }\n\n    @Override\n    public void onBindContentViewHolder(RecyclerView.ViewHolder holder, CityEntity entity) {\n        ContentVH vh = (ContentVH) holder;\n        vh.tv.setText(entity.getName());\n    }\n\n    private class IndexVH extends RecyclerView.ViewHolder {\n        TextView tv;\n\n        public IndexVH(View itemView) {\n            super(itemView);\n            tv = (TextView) itemView.findViewById(R.id.tv_index);\n        }\n    }\n\n    private class ContentVH extends RecyclerView.ViewHolder {\n        TextView tv;\n\n        public ContentVH(View itemView) {\n            super(itemView);\n            tv = (TextView) itemView.findViewById(R.id.tv_name);\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/city/CityEntity.java",
    "content": "package me.yokeyword.sample.city;\n\nimport me.yokeyword.indexablerv.IndexableEntity;\n\n/**\n * Created by YoKey on 16/10/7.\n */\npublic class CityEntity implements IndexableEntity {\n    private long id;\n    private String name;\n    private String pinyin;\n\n    public CityEntity() {\n    }\n\n    public CityEntity(String name) {\n        this.name = name;\n    }\n\n    public long getId() {\n        return id;\n    }\n\n    public void setId(long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getPinyin() {\n        return pinyin;\n    }\n\n    public void setPinyin(String pinyin) {\n        this.pinyin = pinyin;\n    }\n\n    @Override\n    public String getFieldIndexBy() {\n        return name;\n    }\n\n    @Override\n    public void setFieldIndexBy(String indexByField) {\n        this.name = indexByField;\n    }\n\n    @Override\n    public void setFieldPinyinIndexBy(String pinyin) {\n        this.pinyin = pinyin;\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/city/PickCityActivity.java",
    "content": "package me.yokeyword.sample.city;\n\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.SearchView;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.Toast;\n\nimport com.github.promeg.pinyinhelper.Pinyin;\nimport com.github.promeg.tinypinyin.lexicons.android.cncity.CnCityDict;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport me.yokeyword.indexablerv.EntityWrapper;\nimport me.yokeyword.indexablerv.IndexableAdapter;\nimport me.yokeyword.indexablerv.IndexableLayout;\nimport me.yokeyword.indexablerv.SimpleHeaderAdapter;\nimport me.yokeyword.sample.R;\nimport me.yokeyword.sample.ToastUtil;\n\n/**\n * 选择城市\n * Created by YoKey on 16/10/7.\n */\npublic class PickCityActivity extends AppCompatActivity {\n    private List<CityEntity> mDatas;\n    private SearchFragment mSearchFragment;\n    private SearchView mSearchView;\n    private FrameLayout mProgressBar;\n    private SimpleHeaderAdapter mHotCityAdapter;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_pick_city);\n        getSupportActionBar().setTitle(\"选择城市\");\n\n        mSearchFragment = (SearchFragment) getSupportFragmentManager().findFragmentById(R.id.search_fragment);\n        IndexableLayout indexableLayout = (IndexableLayout) findViewById(R.id.indexableLayout);\n        mSearchView = (SearchView) findViewById(R.id.searchview);\n        mProgressBar = (FrameLayout) findViewById(R.id.progress);\n\n\n//        indexableLayout.setLayoutManager(new LinearLayoutManager(this));\n        indexableLayout.setLayoutManager(new GridLayoutManager(this, 2));\n\n        // 多音字处理\n        Pinyin.init(Pinyin.newConfig().with(CnCityDict.getInstance(this)));\n\n        // 添加自定义多音字词典\n//        Pinyin.init(Pinyin.newConfig()\n//                .with(new PinyinMapDict() {\n//                    @Override\n//                    public Map<String, String[]> mapping() {\n//                        HashMap<String, String[]> map = new HashMap<String, String[]>();\n//                        map.put(\"重庆\",  new String[]{\"CHONG\", \"QING\"});\n//                        return map;\n//                    }\n//                }));\n\n\n        // 快速排序。  排序规则设置为：只按首字母  （默认全拼音排序）  效率很高，是默认的10倍左右。  按需开启～\n        indexableLayout.setCompareMode(IndexableLayout.MODE_FAST);\n        // 自定义排序规则\n//        indexableLayout.setComparator(new Comparator<EntityWrapper<CityEntity>>() {\n//            @Override\n//            public int compare(EntityWrapper<CityEntity> lhs, EntityWrapper<CityEntity> rhs) {\n//                return lhs.getPinyin().compareTo(rhs.getPinyin());\n//            }\n//        });\n\n        // setAdapter\n        CityAdapter adapter = new CityAdapter(this);\n        indexableLayout.setAdapter(adapter);\n        // set Datas\n        mDatas = initDatas();\n\n        adapter.setDatas(mDatas, new IndexableAdapter.IndexCallback<CityEntity>() {\n            @Override\n            public void onFinished(List<EntityWrapper<CityEntity>> datas) {\n                // 数据处理完成后回调\n                mSearchFragment.bindDatas(mDatas);\n                mProgressBar.setVisibility(View.GONE);\n            }\n        });\n\n        // set Center OverlayView\n        indexableLayout.setOverlayStyle_Center();\n\n        // set Listener\n        adapter.setOnItemContentClickListener(new IndexableAdapter.OnItemContentClickListener<CityEntity>() {\n            @Override\n            public void onItemClick(View v, int originalPosition, int currentPosition, CityEntity entity) {\n                if (originalPosition >= 0) {\n                    ToastUtil.showShort(PickCityActivity.this, \"选中:\" + entity.getName() + \"  当前位置:\" + currentPosition + \"  原始所在数组位置:\" + originalPosition);\n                } else {\n                    ToastUtil.showShort(PickCityActivity.this, \"选中Header:\" + entity.getName() + \"  当前位置:\" + currentPosition);\n                }\n            }\n        });\n\n        adapter.setOnItemTitleClickListener(new IndexableAdapter.OnItemTitleClickListener() {\n            @Override\n            public void onItemClick(View v, int currentPosition, String indexTitle) {\n                ToastUtil.showShort(PickCityActivity.this, \"选中:\" + indexTitle + \"  当前位置:\" + currentPosition);\n            }\n        });\n\n        // 添加 HeaderView DefaultHeaderAdapter接收一个IndexableAdapter, 使其布局以及点击事件和IndexableAdapter一致\n        // 如果想自定义布局,点击事件, 可传入 new IndexableHeaderAdapter\n\n        mHotCityAdapter = new SimpleHeaderAdapter<>(adapter, \"热\", \"热门城市\", iniyHotCityDatas());\n        // 热门城市\n        indexableLayout.addHeaderAdapter(mHotCityAdapter);\n        // 定位\n        final List<CityEntity> gpsCity = iniyGPSCityDatas();\n        final SimpleHeaderAdapter gpsHeaderAdapter = new SimpleHeaderAdapter<>(adapter, \"定\", \"当前城市\", gpsCity);\n        indexableLayout.addHeaderAdapter(gpsHeaderAdapter);\n\n        // 显示真实索引\n//        indexableLayout.showAllLetter(false);\n\n        // 模拟定位\n        indexableLayout.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                gpsCity.get(0).setName(\"杭州市\");\n                gpsHeaderAdapter.notifyDataSetChanged();\n            }\n        }, 3000);\n\n        // 搜索Demo\n        initSearch();\n    }\n\n    // 更新数据点击事件\n    public void update(View view) {\n        List<CityEntity> list = new ArrayList<>();\n        list.add(new CityEntity(\"杭州市\"));\n        list.add(new CityEntity(\"北京市\"));\n        list.add(new CityEntity(\"上海市\"));\n        list.add(new CityEntity(\"广州市\"));\n        mHotCityAdapter.addDatas(list);\n        Toast.makeText(this, \"更新数据\", Toast.LENGTH_SHORT).show();\n    }\n\n    private List<CityEntity> initDatas() {\n        List<CityEntity> list = new ArrayList<>();\n        List<String> cityStrings = Arrays.asList(getResources().getStringArray(R.array.city_array));\n        for (String item : cityStrings) {\n            CityEntity cityEntity = new CityEntity();\n            cityEntity.setName(item);\n            list.add(cityEntity);\n        }\n        return list;\n    }\n\n    private List<CityEntity> iniyHotCityDatas() {\n        List<CityEntity> list = new ArrayList<>();\n        list.add(new CityEntity(\"杭州市\"));\n        list.add(new CityEntity(\"北京市\"));\n        list.add(new CityEntity(\"上海市\"));\n        list.add(new CityEntity(\"广州市\"));\n        return list;\n    }\n\n    private List<CityEntity> iniyGPSCityDatas() {\n        List<CityEntity> list = new ArrayList<>();\n        list.add(new CityEntity(\"定位中...\"));\n        return list;\n    }\n\n    private void initSearch() {\n        getSupportFragmentManager().beginTransaction().hide(mSearchFragment).commit();\n\n        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {\n            @Override\n            public boolean onQueryTextSubmit(String query) {\n                return false;\n            }\n\n            @Override\n            public boolean onQueryTextChange(String newText) {\n                if (newText.trim().length() > 0) {\n                    if (mSearchFragment.isHidden()) {\n                        getSupportFragmentManager().beginTransaction().show(mSearchFragment).commit();\n                    }\n                } else {\n                    if (!mSearchFragment.isHidden()) {\n                        getSupportFragmentManager().beginTransaction().hide(mSearchFragment).commit();\n                    }\n                }\n\n                mSearchFragment.bindQueryText(newText);\n                return false;\n            }\n        });\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (!mSearchFragment.isHidden()) {\n            // 隐藏 搜索\n            mSearchView.setQuery(null, false);\n            getSupportFragmentManager().beginTransaction().hide(mSearchFragment).commit();\n            return;\n        }\n        super.onBackPressed();\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/city/SearchFragment.java",
    "content": "package me.yokeyword.sample.city;\n\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Filter;\nimport android.widget.Filterable;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport me.yokeyword.sample.R;\nimport me.yokeyword.sample.ToastUtil;\n\n/**\n * Demo: 搜索结果显示Fragment\n * Created by YoKey on 16/10/9.\n */\npublic class SearchFragment extends Fragment {\n    private RecyclerView mRecyclerView;\n    private TextView mTvNoResult;\n    private SearchAdapter mAdapter;\n    private List<CityEntity> mDatas;\n\n    private String mQueryText;\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.fragment_search_city, container, false);\n        mTvNoResult = (TextView) view.findViewById(R.id.tv_no_result);\n        mRecyclerView = (RecyclerView) view.findViewById(R.id.recy);\n        return view;\n    }\n\n    public void bindDatas(List<CityEntity> datas) {\n        this.mDatas = datas;\n        mAdapter = new SearchAdapter();\n        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));\n        mRecyclerView.setHasFixedSize(true);\n        mRecyclerView.setAdapter(mAdapter);\n        if (mQueryText != null) {\n            mAdapter.getFilter().filter(mQueryText);\n        }\n    }\n\n    /**\n     * 根据newText 进行查找, 显示\n     */\n    public void bindQueryText(String newText) {\n        if (mDatas == null) {\n            mQueryText = newText.toLowerCase();\n        } else if (!TextUtils.isEmpty(newText)) {\n            mAdapter.getFilter().filter(newText.toLowerCase());\n        }\n    }\n\n    private class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.VH> implements Filterable {\n        private List<CityEntity> items = new ArrayList<>();\n\n        public SearchAdapter() {\n            items.clear();\n            items.addAll(mDatas);\n        }\n\n        @Override\n        public VH onCreateViewHolder(ViewGroup parent, int viewType) {\n            final VH holder = new VH(LayoutInflater.from(getActivity()).inflate(R.layout.item_city, parent, false));\n            holder.itemView.setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    int position = holder.getAdapterPosition();\n                    ToastUtil.showShort(getActivity(), \"选择了\" + items.get(position).getName());\n                }\n            });\n            return holder;\n        }\n\n        @Override\n        public int getItemCount() {\n            return items.size();\n        }\n\n        @Override\n        public void onBindViewHolder(VH holder, int position) {\n            holder.tvName.setText(items.get(position).getName());\n        }\n\n        @Override\n        public Filter getFilter() {\n            return new Filter() {\n                @Override\n                protected FilterResults performFiltering(CharSequence constraint) {\n                    ArrayList<CityEntity> list = new ArrayList<>();\n                    for (CityEntity item : mDatas) {\n                        if (item.getPinyin().startsWith(constraint.toString()) || item.getName().contains(constraint)) {\n                            list.add(item);\n                        }\n                    }\n                    FilterResults results = new FilterResults();\n                    results.count = list.size();\n                    results.values = list;\n                    return results;\n                }\n\n                @Override\n                @SuppressWarnings(\"unchecked\")\n                protected void publishResults(CharSequence constraint, FilterResults results) {\n                    ArrayList<CityEntity> list = (ArrayList<CityEntity>) results.values;\n                    items.clear();\n                    items.addAll(list);\n                    if (results.count == 0) {\n                        mTvNoResult.setVisibility(View.VISIBLE);\n                    } else {\n                        mTvNoResult.setVisibility(View.INVISIBLE);\n                    }\n                    notifyDataSetChanged();\n                }\n            };\n        }\n\n        class VH extends RecyclerView.ViewHolder {\n            private TextView tvName;\n\n            public VH(View itemView) {\n                super(itemView);\n                tvName = (TextView) itemView.findViewById(R.id.tv_name);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/contact/ContactAdapter.java",
    "content": "package me.yokeyword.sample.contact;\n\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport me.yokeyword.indexablerv.IndexableAdapter;\nimport me.yokeyword.sample.R;\n\n/**\n * Created by YoKey on 16/10/8.\n */\npublic class ContactAdapter extends IndexableAdapter<UserEntity> {\n    private LayoutInflater mInflater;\n\n    public ContactAdapter(Context context) {\n        mInflater = LayoutInflater.from(context);\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateTitleViewHolder(ViewGroup parent) {\n        View view = mInflater.inflate(R.layout.item_index_contact, parent, false);\n        return new IndexVH(view);\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent) {\n        View view = mInflater.inflate(R.layout.item_contact, parent, false);\n        return new ContentVH(view);\n    }\n\n    @Override\n    public void onBindTitleViewHolder(RecyclerView.ViewHolder holder, String indexTitle) {\n        IndexVH vh = (IndexVH) holder;\n        vh.tv.setText(indexTitle);\n    }\n\n    @Override\n    public void onBindContentViewHolder(RecyclerView.ViewHolder holder, UserEntity entity) {\n        ContentVH vh = (ContentVH) holder;\n        vh.tvName.setText(entity.getNick());\n        vh.tvMobile.setText(entity.getMobile());\n    }\n\n    private class IndexVH extends RecyclerView.ViewHolder {\n        TextView tv;\n\n        public IndexVH(View itemView) {\n            super(itemView);\n            tv = (TextView) itemView.findViewById(R.id.tv_index);\n        }\n    }\n\n    private class ContentVH extends RecyclerView.ViewHolder {\n        TextView tvName, tvMobile;\n\n        public ContentVH(View itemView) {\n            super(itemView);\n            tvName = (TextView) itemView.findViewById(R.id.tv_name);\n            tvMobile = (TextView) itemView.findViewById(R.id.tv_mobile);\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/contact/MenuEntity.java",
    "content": "package me.yokeyword.sample.contact;\n\n/**\n * Created by YoKey on 16/10/8.\n */\n\npublic class MenuEntity {\n    private long menuId;\n    private String menuTitle;\n    private int menuIconRes;\n\n    public MenuEntity(String title, int iconRes) {\n        this.menuTitle = title;\n        this.menuIconRes = iconRes;\n    }\n\n    public long getMenuId() {\n        return menuId;\n    }\n\n    public void setMenuId(long menuId) {\n        this.menuId = menuId;\n    }\n\n    public String getMenuTitle() {\n        return menuTitle;\n    }\n\n    public void setMenuTitle(String menuTitle) {\n        this.menuTitle = menuTitle;\n    }\n\n    public int getMenuIconRes() {\n        return menuIconRes;\n    }\n\n    public void setMenuIconRes(int menuIconRes) {\n        this.menuIconRes = menuIconRes;\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/contact/PickContactActivity.java",
    "content": "package me.yokeyword.sample.contact;\n\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport me.yokeyword.indexablerv.IndexableAdapter;\nimport me.yokeyword.indexablerv.IndexableHeaderAdapter;\nimport me.yokeyword.indexablerv.IndexableLayout;\nimport me.yokeyword.indexablerv.SimpleFooterAdapter;\nimport me.yokeyword.indexablerv.SimpleHeaderAdapter;\nimport me.yokeyword.sample.R;\nimport me.yokeyword.sample.ToastUtil;\n\n/**\n * Created by YoKey on 16/10/8.\n */\npublic class PickContactActivity extends AppCompatActivity {\n    private ContactAdapter mAdapter;\n    private MenuHeaderAdapter mMenuHeaderAdapter;\n    private BannerHeaderAdapter mBannerHeaderAdapter;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_pick_contact);\n        getSupportActionBar().setTitle(\"联系人\");\n        IndexableLayout indexableLayout = (IndexableLayout) findViewById(R.id.indexableLayout);\n\n        indexableLayout.setLayoutManager(new LinearLayoutManager(this));\n//        indexableLayout.setLayoutManager(new GridLayoutManager(this, 3));\n\n        // setAdapter\n        mAdapter = new ContactAdapter(this);\n        indexableLayout.setAdapter(mAdapter);\n        // set Datas\n        mAdapter.setDatas(initDatas());\n        // set Material Design OverlayView\n        indexableLayout.setOverlayStyle_MaterialDesign(Color.RED);\n\n        // 全字母排序。  排序规则设置为：每个字母都会进行比较排序；速度较慢\n        indexableLayout.setCompareMode(IndexableLayout.MODE_ALL_LETTERS);\n\n        // set Listener\n        mAdapter.setOnItemContentClickListener(new IndexableAdapter.OnItemContentClickListener<UserEntity>() {\n            @Override\n            public void onItemClick(View v, int originalPosition, int currentPosition, UserEntity entity) {\n                if (originalPosition >= 0) {\n                    ToastUtil.showShort(PickContactActivity.this, \"选中:\" + entity.getNick() + \"  当前位置:\" + currentPosition + \"  原始所在数组位置:\" + originalPosition);\n                } else {\n                    ToastUtil.showShort(PickContactActivity.this, \"选中Header/Footer:\" + entity.getNick() + \"  当前位置:\" + currentPosition);\n                }\n            }\n        });\n\n        mAdapter.setOnItemTitleClickListener(new IndexableAdapter.OnItemTitleClickListener() {\n            @Override\n            public void onItemClick(View v, int currentPosition, String indexTitle) {\n                ToastUtil.showShort(PickContactActivity.this, \"选中:\" + indexTitle + \"  当前位置:\" + currentPosition);\n            }\n        });\n\n        // 添加我关心的人\n        indexableLayout.addHeaderAdapter(new SimpleHeaderAdapter<>(mAdapter, \"☆\", \"我关心的\", initFavDatas()));\n\n        // 构造函数里3个参数,分别对应 (IndexBar的字母索引, IndexTitle, 数据源), 不想显示哪个就传null, 数据源传null时,代表add一个普通的View\n        mMenuHeaderAdapter = new MenuHeaderAdapter(\"↑\", null, initMenuDatas());\n        // 添加菜单\n        indexableLayout.addHeaderAdapter(mMenuHeaderAdapter);\n        mMenuHeaderAdapter.setOnItemHeaderClickListener(new IndexableHeaderAdapter.OnItemHeaderClickListener<MenuEntity>() {\n            @Override\n            public void onItemClick(View v, int currentPosition, MenuEntity entity) {\n                ToastUtil.showShort(PickContactActivity.this, entity.getMenuTitle());\n            }\n        });\n\n        // 这里BannerView只有一个Item, 添加一个长度为1的任意List作为第三个参数\n        List<String> bannerList = new ArrayList<>();\n        bannerList.add(\"\");\n        mBannerHeaderAdapter = new BannerHeaderAdapter(null, null, bannerList);\n        // 添加 Banner\n        indexableLayout.addHeaderAdapter(mBannerHeaderAdapter);\n\n        // FooterView\n        indexableLayout.addFooterAdapter(new SimpleFooterAdapter<>(mAdapter, \"尾\", \"我是FooterView\", initFavDatas()));\n    }\n\n    /**\n     * 自定义的MenuHeader\n     */\n    class MenuHeaderAdapter extends IndexableHeaderAdapter<MenuEntity> {\n        private static final int TYPE = 1;\n\n        public MenuHeaderAdapter(String index, String indexTitle, List<MenuEntity> datas) {\n            super(index, indexTitle, datas);\n        }\n\n        @Override\n        public int getItemViewType() {\n            return TYPE;\n        }\n\n        @Override\n        public RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent) {\n            return new VH(LayoutInflater.from(PickContactActivity.this).inflate(R.layout.header_contact_menu, parent, false));\n        }\n\n        @Override\n        public void onBindContentViewHolder(RecyclerView.ViewHolder holder, MenuEntity entity) {\n            VH vh = (VH) holder;\n            vh.tv.setText(entity.getMenuTitle());\n            vh.img.setImageResource(entity.getMenuIconRes());\n        }\n\n        private class VH extends RecyclerView.ViewHolder {\n            private TextView tv;\n            private ImageView img;\n\n            public VH(View itemView) {\n                super(itemView);\n                tv = (TextView) itemView.findViewById(R.id.tv_title);\n                img = (ImageView) itemView.findViewById(R.id.img);\n            }\n        }\n    }\n\n    /**\n     * 自定义的Banner Header\n     */\n    class BannerHeaderAdapter extends IndexableHeaderAdapter {\n        private static final int TYPE = 2;\n\n        public BannerHeaderAdapter(String index, String indexTitle, List datas) {\n            super(index, indexTitle, datas);\n        }\n\n        @Override\n        public int getItemViewType() {\n            return TYPE;\n        }\n\n        @Override\n        public RecyclerView.ViewHolder onCreateContentViewHolder(ViewGroup parent) {\n            View view = LayoutInflater.from(PickContactActivity.this).inflate(R.layout.header_contact_banner, parent, false);\n            VH holder = new VH(view);\n            holder.img.setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    ToastUtil.showShort(PickContactActivity.this, \"---点击了Banner---\");\n                }\n            });\n            return holder;\n        }\n\n        @Override\n        public void onBindContentViewHolder(RecyclerView.ViewHolder holder, Object entity) {\n            // 数据源为null时, 该方法不用实现\n        }\n\n        private class VH extends RecyclerView.ViewHolder {\n            ImageView img;\n\n            public VH(View itemView) {\n                super(itemView);\n                img = (ImageView) itemView.findViewById(R.id.img);\n            }\n        }\n    }\n\n    private List<UserEntity> initDatas() {\n        List<UserEntity> list = new ArrayList<>();\n        // 初始化数据\n        List<String> contactStrings = Arrays.asList(getResources().getStringArray(R.array.contact_array));\n        List<String> mobileStrings = Arrays.asList(getResources().getStringArray(R.array.mobile_array));\n        for (int i = 0; i < contactStrings.size(); i++) {\n            UserEntity contactEntity = new UserEntity(contactStrings.get(i), mobileStrings.get(i));\n            list.add(contactEntity);\n        }\n        return list;\n    }\n\n    private List<UserEntity> initFavDatas() {\n        List<UserEntity> list = new ArrayList<>();\n        list.add(new UserEntity(\"张三\", \"10000\"));\n        list.add(new UserEntity(\"李四\", \"10001\"));\n        return list;\n    }\n\n    private List<MenuEntity> initMenuDatas() {\n        List<MenuEntity> list = new ArrayList<>();\n        list.add(new MenuEntity(\"新的朋友\", R.mipmap.icon_1));\n        list.add(new MenuEntity(\"群聊\", R.mipmap.icon_2));\n        list.add(new MenuEntity(\"标签\", R.mipmap.icon_3));\n        list.add(new MenuEntity(\"公众号\", R.mipmap.icon_4));\n        return list;\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/me/yokeyword/sample/contact/UserEntity.java",
    "content": "package me.yokeyword.sample.contact;\n\nimport me.yokeyword.indexablerv.IndexableEntity;\n\n/**\n * Created by YoKey on 16/10/8.\n */\npublic class UserEntity implements IndexableEntity {\n    private String nick;\n    private String avatar;\n    private String mobile;\n\n    public UserEntity(String nick, String mobile) {\n        this.nick = nick;\n        this.mobile = mobile;\n    }\n\n    public String getAvatar() {\n        return avatar;\n    }\n\n    public void setAvatar(String avatar) {\n        this.avatar = avatar;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public void setMobile(String mobile) {\n        this.mobile = mobile;\n    }\n\n    public String getNick() {\n        return nick;\n    }\n\n    public void setNick(String name) {\n        this.nick = name;\n    }\n\n    @Override\n    public String getFieldIndexBy() {\n        return nick;\n    }\n\n    @Override\n    public void setFieldIndexBy(String indexField) {\n        this.nick = indexField;\n    }\n\n    @Override\n    public void setFieldPinyinIndexBy(String pinyin) {\n        // 需要用到拼音时(比如:搜索), 可增添pinyin字段 this.pinyin  = pinyin\n        // 见 CityEntity\n    }\n}\n"
  },
  {
    "path": "sample/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:gravity=\"center\">\n\n    <Button\n        android:id=\"@+id/btn_pick_city\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"选择城市Demo\"/>\n\n    <Button\n        android:id=\"@+id/btn_pick_contact\"\n        android:layout_width=\"match_parent\"\n        android:layout_marginTop=\"32dp\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"选择联系人Demo\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "sample/src/main/res/layout/activity_pick_city.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<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:background=\"@android:color/white\"\n              android:orientation=\"vertical\">\n\n    <android.support.v7.widget.SearchView\n        android:id=\"@+id/searchview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"42dp\"\n        android:layout_marginBottom=\"4dp\"\n        android:layout_marginLeft=\"16dp\"\n        android:layout_marginRight=\"16dp\"\n        android:layout_marginTop=\"8dp\"\n        android:background=\"#f3f3f3\"\n        android:focusable=\"false\"\n        android:focusableInTouchMode=\"false\"\n        android:textColor=\"#757575\"\n        app:iconifiedByDefault=\"false\"\n        app:queryBackground=\"@null\"\n        app:queryHint=\"请输入关键字\"/>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <me.yokeyword.indexablerv.IndexableLayout\n            android:id=\"@+id/indexableLayout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            app:indexBar_background=\"#08000000\"\n            app:indexBar_layout_width=\"24dp\"\n            app:indexBar_textColor=\"@android:color/black\"\n            app:indexBar_textSpace=\"8dp\"/>\n\n        <fragment\n            android:id=\"@+id/search_fragment\"\n            class=\"me.yokeyword.sample.city.SearchFragment\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n\n        <FrameLayout\n            android:id=\"@+id/progress\"\n            android:layout_width=\"match_parent\"\n            android:background=\"@android:color/white\"\n            android:layout_height=\"match_parent\">\n\n            <ProgressBar\n                android:layout_width=\"56dp\"\n                android:layout_height=\"56dp\"\n                android:layout_gravity=\"center\"/>\n        </FrameLayout>\n\n        <Button\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"bottom\"\n            android:text=\"更新数据\"\n            android:onClick=\"update\"/>\n\n    </FrameLayout>\n</LinearLayout>"
  },
  {
    "path": "sample/src/main/res/layout/activity_pick_contact.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<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:orientation=\"vertical\">\n\n    <me.yokeyword.indexablerv.IndexableLayout\n        android:id=\"@+id/indexableLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@android:color/white\"\n        app:indexBar_selectedTextColor=\"#f33737\"\n        app:indexBar_textColor=\"@android:color/black\"\n        app:indexBar_textSize=\"14sp\"\n        app:indexBar_textSpace=\"4dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "sample/src/main/res/layout/fragment_search_city.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/white\">\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/recy\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n    <TextView\n        android:id=\"@+id/tv_no_result\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginTop=\"16dp\"\n        android:text=\"没有搜索到匹配的内容\"\n        android:textSize=\"12sp\"\n        android:visibility=\"gone\" />\n</FrameLayout>"
  },
  {
    "path": "sample/src/main/res/layout/header_contact_banner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <ImageView\n        android:id=\"@+id/img\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"96dp\"\n        android:scaleType=\"center\"\n        android:alpha=\"0.6\"\n        android:src=\"@mipmap/banner\" />\n</FrameLayout>"
  },
  {
    "path": "sample/src/main/res/layout/header_contact_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"60dp\"\n    android:background=\"?attr/selectableItemBackground\">\n\n    <ImageView\n        android:id=\"@+id/img\"\n        android:layout_width=\"30dp\"\n        android:layout_centerVertical=\"true\"\n        tools:src=\"@mipmap/icon_1\"\n        android:layout_marginLeft=\"24dp\"\n        android:layout_marginRight=\"16dp\"\n        android:layout_height=\"30dp\" />\n\n    <TextView\n        android:id=\"@+id/tv_title\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginRight=\"16dp\"\n        android:layout_toRightOf=\"@id/img\"\n        android:gravity=\"center_vertical\"\n        android:textColor=\"@android:color/black\"\n        android:textSize=\"17sp\"\n        tools:text=\"张三\" />\n\n    <ImageView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0.8dp\"\n        android:background=\"#f0f0f0\" />\n</RelativeLayout>"
  },
  {
    "path": "sample/src/main/res/layout/item_city.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"?attr/selectableItemBackground\"\n    android:orientation=\"vertical\"\n    android:paddingLeft=\"16dp\">\n\n    <TextView\n        android:id=\"@+id/tv_name\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingBottom=\"12dp\"\n        android:paddingTop=\"12dp\"\n        tools:text=\"合肥市\"\n        android:textSize=\"16sp\" />\n\n    <ImageView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0.8dp\"\n        android:background=\"#f1f1f1\" />\n\n</LinearLayout>"
  },
  {
    "path": "sample/src/main/res/layout/item_contact.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingBottom=\"16dp\"\n    android:background=\"?attr/selectableItemBackground\"\n    android:paddingLeft=\"16dp\"\n    android:paddingRight=\"16dp\"\n    android:paddingTop=\"8dp\">\n\n    <ImageView\n        android:id=\"@+id/img_avatar\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginRight=\"16dp\"\n        android:src=\"@mipmap/ic_account_circle_grey_400_48dp\" />\n\n    <TextView\n        android:id=\"@+id/tv_name\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_toRightOf=\"@id/img_avatar\"\n        tools:text=\"张三\"\n        android:textColor=\"#373737\"\n        android:textSize=\"16sp\" />\n\n    <TextView\n        android:id=\"@+id/tv_mobile\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@id/tv_name\"\n        android:layout_marginTop=\"12dp\"\n        android:layout_toRightOf=\"@id/img_avatar\"\n        tools:text=\"18712345678\"\n        android:textColor=\"#969696\" />\n\n</RelativeLayout>"
  },
  {
    "path": "sample/src/main/res/layout/item_index_city.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<TextView\n    android:id=\"@+id/tv_index\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"#F1F1F1\"\n    android:paddingBottom=\"8dp\"\n    android:paddingLeft=\"16dp\"\n    android:paddingTop=\"8dp\"\n    android:textColor=\"@color/colorAccent\"\n    android:textSize=\"13sp\"/>"
  },
  {
    "path": "sample/src/main/res/layout/item_index_contact.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <TextView\n        android:id=\"@+id/tv_index\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#f9f9f9\"\n        android:paddingBottom=\"8dp\"\n        android:paddingLeft=\"24dp\"\n        android:paddingTop=\"8dp\"\n        android:textColor=\"@color/colorPrimary\"\n        android:textStyle=\"bold\"\n        android:textSize=\"14sp\" />\n\n    <ImageView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0.8dp\"\n        android:background=\"#f0f0f0\" />\n</FrameLayout>"
  },
  {
    "path": "sample/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\">#f33737</color>\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values/string_city.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string-array name=\"city_array\">\n        <item>北京市</item>\n        <item>天津市</item>\n        <item>上海市</item>\n        <item>重庆市</item>\n        <item>香港特别行政区</item>\n        <item>澳门特别行政区</item>\n        <item>沈阳市</item>\n        <item>大连市</item>\n        <item>鞍山市</item>\n        <item>抚顺市</item>\n        <item>本溪市</item>\n        <item>丹东市</item>\n        <item>锦州市</item>\n        <item>营口市</item>\n        <item>阜新市</item>\n        <item>辽阳市</item>\n        <item>铁岭市</item>\n        <item>朝阳市</item>\n        <item>盘锦市</item>\n        <item>葫芦岛市</item>\n        <item>哈尔滨市</item>\n        <item>齐齐哈尔市</item>\n        <item>鸡西市</item>\n        <item>鹤岗市</item>\n        <item>双鸭山市</item>\n        <item>大庆市</item>\n        <item>伊春市</item>\n        <item>佳木斯市</item>\n        <item>牡丹江市</item>\n        <item>七台河市</item>\n        <item>黑河市</item>\n        <item>长春市</item>\n        <item>吉林市</item>\n        <item>四平市</item>\n        <item>辽源市</item>\n        <item>通化市</item>\n        <item>白山市</item>\n        <item>松原市</item>\n        <item>白城市</item>\n        <item>延吉市</item>\n        <item>呼和浩特市</item>\n        <item>包头市</item>\n        <item>乌海市</item>\n        <item>赤峰市</item>\n        <item>通辽市</item>\n        <item>鄂尔多斯市</item>\n        <item>呼伦贝尔市</item>\n        <item>巴彦淖尔市</item>\n        <item>乌兰察布市</item>\n        <item>乌兰浩特市</item>\n        <item>二连浩特市</item>\n        <item>乌鲁木齐市</item>\n        <item>克拉玛依市</item>\n        <item>吐鲁番市</item>\n        <item>昌吉市</item>\n        <item>博乐市</item>\n        <item>库尔勒市</item>\n        <item>阿克苏市</item>\n        <item>阿图什市</item>\n        <item>喀什市</item>\n        <item>和田市</item>\n        <item>伊宁市</item>\n        <item>塔城市</item>\n        <item>阿勒泰市</item>\n        <item>西宁市</item>\n        <item>拉萨市</item>\n        <item>兰州市</item>\n        <item>嘉峪关市</item>\n        <item>金昌市</item>\n        <item>白银市</item>\n        <item>天水市</item>\n        <item>武威市</item>\n        <item>张掖市</item>\n        <item>平凉市</item>\n        <item>酒泉市</item>\n        <item>庆阳市</item>\n        <item>定西市</item>\n        <item>陇南市</item>\n        <item>临夏市</item>\n        <item>合作市</item>\n        <item>银川市</item>\n        <item>石嘴山市</item>\n        <item>吴忠市</item>\n        <item>固原市</item>\n        <item>中卫市</item>\n        <item>西安市</item>\n        <item>铜川市</item>\n        <item>宝鸡市</item>\n        <item>咸阳市</item>\n        <item>渭南市</item>\n        <item>延安市</item>\n        <item>汉中市</item>\n        <item>榆林市</item>\n        <item>安康市</item>\n        <item>商洛市</item>\n        <item>太原市</item>\n        <item>大同市</item>\n        <item>阳泉市</item>\n        <item>长治市</item>\n        <item>晋城市</item>\n        <item>朔州市</item>\n        <item>晋中市</item>\n        <item>运城市</item>\n        <item>忻州市</item>\n        <item>临汾市</item>\n        <item>吕梁市</item>\n        <item>石家庄市</item>\n        <item>唐山市</item>\n        <item>秦皇岛市</item>\n        <item>邯郸市</item>\n        <item>邢台市</item>\n        <item>保定市</item>\n        <item>承德市</item>\n        <item>沧州市</item>\n        <item>廊坊市</item>\n        <item>衡水市</item>\n        <item>济南市</item>\n        <item>青岛市</item>\n        <item>淄博市</item>\n        <item>枣庄市</item>\n        <item>东营市</item>\n        <item>烟台市</item>\n        <item>潍坊市</item>\n        <item>济宁市</item>\n        <item>泰安市</item>\n        <item>威海市</item>\n        <item>日照市</item>\n        <item>莱芜市</item>\n        <item>临沂市</item>\n        <item>德州市</item>\n        <item>聊城市</item>\n        <item>滨州市</item>\n        <item>菏泽市</item>\n        <item>南京市</item>\n        <item>无锡市</item>\n        <item>徐州市</item>\n        <item>常州市</item>\n        <item>苏州市</item>\n        <item>南通市</item>\n        <item>连云港市</item>\n        <item>淮安市</item>\n        <item>盐城市</item>\n        <item>扬州市</item>\n        <item>镇江市</item>\n        <item>泰州市</item>\n        <item>宿迁市</item>\n        <item>合肥市</item>\n        <item>芜湖市</item>\n        <item>蚌埠市</item>\n        <item>淮南市</item>\n        <item>马鞍山市</item>\n        <item>淮北市</item>\n        <item>铜陵市</item>\n        <item>安庆市</item>\n        <item>黄山市</item>\n        <item>滁州市</item>\n        <item>阜阳市</item>\n        <item>宿州市</item>\n        <item>巢湖市</item>\n        <item>六安市</item>\n        <item>毫州市</item>\n        <item>池州市</item>\n        <item>宣城市</item>\n        <item>郑州市</item>\n        <item>开封市</item>\n        <item>洛阳市</item>\n        <item>平顶山市</item>\n        <item>安阳市</item>\n        <item>鹤壁市</item>\n        <item>新乡市</item>\n        <item>焦作市</item>\n        <item>濮阳市</item>\n        <item>许昌市</item>\n        <item>漯河市</item>\n        <item>三门峡市</item>\n        <item>南阳市</item>\n        <item>商丘市</item>\n        <item>信阳市</item>\n        <item>周口市</item>\n        <item>驻马店市</item>\n        <item>武汉市</item>\n        <item>黄石市</item>\n        <item>十堰市</item>\n        <item>宜昌市</item>\n        <item>襄樊市</item>\n        <item>鄂州市</item>\n        <item>荆门市</item>\n        <item>孝感市</item>\n        <item>荆州市</item>\n        <item>黄冈市</item>\n        <item>咸宁市</item>\n        <item>随州市</item>\n        <item>恩施市</item>\n        <item>成都市</item>\n        <item>自贡市</item>\n        <item>攀枝花市</item>\n        <item>泸州市</item>\n        <item>德阳市</item>\n        <item>绵阳市</item>\n        <item>广元市</item>\n        <item>遂宁市</item>\n        <item>内江市</item>\n        <item>乐山市</item>\n        <item>南充市</item>\n        <item>眉山市</item>\n        <item>宜宾市</item>\n        <item>内广安市</item>\n        <item>达州市</item>\n        <item>雅安市</item>\n        <item>巴中市</item>\n        <item>资阳市</item>\n        <item>昆明市</item>\n        <item>曲靖市</item>\n        <item>玉溪市</item>\n        <item>保山市</item>\n        <item>昭通市</item>\n        <item>丽江市</item>\n        <item>思茅市</item>\n        <item>临沧市</item>\n        <item>贵阳市</item>\n        <item>六盘水市</item>\n        <item>遵义市</item>\n        <item>安顺市</item>\n        <item>铜仁市</item>\n        <item>兴义市</item>\n        <item>毕节市</item>\n        <item>凯里市</item>\n        <item>都匀市</item>\n        <item>长沙市</item>\n        <item>株洲市</item>\n        <item>湘潭市</item>\n        <item>衡阳市</item>\n        <item>邵阳市</item>\n        <item>岳阳市</item>\n        <item>常德市</item>\n        <item>张家界市</item>\n        <item>益阳市</item>\n        <item>郴州市</item>\n        <item>永州市</item>\n        <item>怀化市</item>\n        <item>娄底市</item>\n        <item>吉首市</item>\n        <item>南昌市</item>\n        <item>萍乡市</item>\n        <item>九江市</item>\n        <item>新余市</item>\n        <item>鹰潭市</item>\n        <item>赣州市</item>\n        <item>吉安市</item>\n        <item>宜春市</item>\n        <item>抚州市</item>\n        <item>上饶市</item>\n        <item>杭州市</item>\n        <item>宁波市</item>\n        <item>温州市</item>\n        <item>嘉兴市</item>\n        <item>湖州市</item>\n        <item>绍兴市</item>\n        <item>金华市</item>\n        <item>衢州市</item>\n        <item>舟山市</item>\n        <item>台州市</item>\n        <item>丽水市</item>\n        <item>福州市</item>\n        <item>厦门市</item>\n        <item>莆田市</item>\n        <item>三明市</item>\n        <item>泉州市</item>\n        <item>漳州市</item>\n        <item>南平市</item>\n        <item>龙岩市</item>\n        <item>宁德市</item>\n        <item>广州市</item>\n        <item>韶关市</item>\n        <item>深圳市</item>\n        <item>珠海市</item>\n        <item>汕头市</item>\n        <item>佛山市</item>\n        <item>江门市</item>\n        <item>湛江市</item>\n        <item>茂名市</item>\n        <item>肇庆市</item>\n        <item>惠州市</item>\n        <item>梅州市</item>\n        <item>汕尾市</item>\n        <item>河源市</item>\n        <item>阳江市</item>\n        <item>清远市</item>\n        <item>东莞市</item>\n        <item>中山市</item>\n        <item>潮州市</item>\n        <item>揭阳市</item>\n        <item>云浮市</item>\n        <item>南宁市</item>\n        <item>柳州市</item>\n        <item>桂林市</item>\n        <item>梧州市</item>\n        <item>北海市</item>\n        <item>防城港市</item>\n        <item>钦州市</item>\n        <item>贵港市</item>\n        <item>玉林市</item>\n        <item>百色市</item>\n        <item>贺州市</item>\n        <item>河池市</item>\n        <item>来宾市</item>\n        <item>崇左市</item>\n        <item>海口市</item>\n        <item>三亚市</item>\n        <item>台北市</item>\n        <item>高雄市</item>\n        <item>台中市</item>\n    </string-array>\n</resources>"
  },
  {
    "path": "sample/src/main/res/values/string_contact.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string-array name=\"contact_array\">\n        <item>$^*张狗蛋</item>\n        <item>000王二</item>\n        <item>张三</item>\n        <item>❤迷</item>\n        <item>boy</item>\n        <item>马蜂窝</item>\n        <item>王了了</item>\n        <item>李玖折</item>\n        <item>胡三</item>\n        <item>张政民</item>\n        <item>陈九</item>\n        <item>白玉芬</item>\n        <item>仓春莲</item>\n        <item>仓红</item>\n        <item>陈超云</item>\n        <item>陈高</item>\n        <item>陈国祥</item>\n        <item>陈小荣</item>\n        <item>陈秀芬</item>\n        <item>陈艳华</item>\n        <item>陈兆国</item>\n        <item>成秀山</item>\n        <item>仇腊梅</item>\n        <item>戴金辉</item>\n        <item>邓海燕</item>\n        <item>翟蕾</item>\n        <item>丁德明</item>\n        <item>丁素琴</item>\n        <item>董荣柱</item>\n        <item>范惠</item>\n        <item>冯霞</item>\n        <item>伏严成</item>\n        <item>皋德华</item>\n        <item>皋歌</item>\n        <item>高艳</item>\n        <item>顾其兰</item>\n        <item>管小云</item>\n        <item>何佳丽</item>\n        <item>侯志玲</item>\n        <item>黄慧</item>\n        <item>黄伟</item>\n        <item>惠志刚</item>\n        <item>季赛花</item>\n        <item>季铜然</item>\n        <item>纪海燕</item>\n        <item>蒋雯</item>\n        <item>康海霞</item>\n        <item>乐峰</item>\n        <item>李金凤</item>\n        <item>李军</item>\n        <item>李晓慧</item>\n        <item>刘琳</item>\n        <item>马丽</item>\n        <item>孟亚军</item>\n        <item>明汉琴</item>\n        <item>倪燕</item>\n        <item>潘杰</item>\n        <item>钱萍</item>\n        <item>邱文干</item>\n        <item>沈亚杰</item>\n        <item>盛静</item>\n        <item>施伟</item>\n        <item>施志胜</item>\n        <item>石磊</item>\n        <item>时扬</item>\n        <item>束长元</item>\n        <item>宋欣</item>\n        <item>孙新东</item>\n        <item>孙正兰</item>\n        <item>汤丽丽</item>\n        <item>唐新胜</item>\n        <item>陶椿燕</item>\n        <item>陶晓雷</item>\n        <item>王丹</item>\n        <item>王霞</item>\n        <item>王晓雷</item>\n        <item>王雪梅</item>\n        <item>吴长凤</item>\n        <item>吴凤祥</item>\n        <item>吴红兵</item>\n        <item>吴华强</item>\n        <item>吴萍</item>\n        <item>夏祥</item>\n        <item>肖丽丽</item>\n        <item>谢莉萍</item>\n        <item>谢艳</item>\n        <item>徐海莲</item>\n        <item>徐进</item>\n        <item>徐丽云</item>\n        <item>徐萍</item>\n        <item>刘世佳</item>\n    </string-array>\n\n    <string-array name=\"mobile_array\">\n        <item>18019913883</item>\n        <item>10086</item>\n        <item>12306</item>\n        <item>18019913333</item>\n        <item>18715689899</item>\n        <item>13877898980</item>\n        <item>15678989098</item>\n        <item>10000</item>\n        <item>0557-3130999</item>\n        <item>13907767890</item>\n        <item>13978786823</item>\n        <item>10086</item>\n        <item>12306</item>\n        <item>18019913333</item>\n        <item>18715689899</item>\n        <item>13877898980</item>\n        <item>15678989098</item>\n        <item>10000</item>\n        <item>0557-3130999</item>\n        <item>13907767890</item>\n        <item>13978786823</item>\n        <item>10086</item>\n        <item>12306</item>\n        <item>18019913333</item>\n        <item>18715689899</item>\n        <item>13877898980</item>\n        <item>15678989098</item>\n        <item>10000</item>\n        <item>0557-3130999</item>\n        <item>13907767890</item>\n        <item>13978786823</item>\n        <item>10086</item>\n        <item>12306</item>\n        <item>18019913333</item>\n        <item>18715689899</item>\n        <item>13877898980</item>\n        <item>15678989098</item>\n        <item>10000</item>\n        <item>0557-3130999</item>\n        <item>13907767890</item>\n        <item>13978786823</item>\n        <item>10086</item>\n        <item>12306</item>\n        <item>18019913333</item>\n        <item>18715689899</item>\n        <item>13877898980</item>\n        <item>15678989098</item>\n        <item>10000</item>\n        <item>0557-3130999</item>\n        <item>13907767890</item>\n        <item>13978786823</item>\n        <item>10086</item>\n        <item>12306</item>\n        <item>18019913333</item>\n        <item>18715689899</item>\n        <item>13877898980</item>\n        <item>15678989098</item>\n        <item>10000</item>\n        <item>0557-3130999</item>\n        <item>13907767890</item>\n        <item>13978786823</item>\n        <item>10086</item>\n        <item>12306</item>\n        <item>18019913333</item>\n        <item>18715689899</item>\n        <item>13877898980</item>\n        <item>15678989098</item>\n        <item>10000</item>\n        <item>0557-3130999</item>\n        <item>13907767890</item>\n        <item>13978786823</item>\n        <item>10086</item>\n        <item>12306</item>\n        <item>18019913333</item>\n        <item>18715689899</item>\n        <item>13877898980</item>\n        <item>15678989098</item>\n        <item>10000</item>\n        <item>0557-3130999</item>\n        <item>13907767890</item>\n        <item>13978786823</item>\n        <item>10086</item>\n        <item>12306</item>\n        <item>18019913333</item>\n        <item>18715689899</item>\n        <item>13877898980</item>\n        <item>15678989098</item>\n        <item>10000</item>\n        <item>0557-3130999</item>\n        <item>13907767890</item>\n        <item>13978786823</item>\n    </string-array>\n</resources>"
  },
  {
    "path": "sample/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">IndexableRecyclerView</string>\n</resources>\n"
  },
  {
    "path": "sample/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</resources>\n"
  },
  {
    "path": "sample/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':sample', ':indexablerecyclerview'\n\n"
  }
]