瀏覽代碼

家属探视机项目初始化

weizhengliang 2 年之前
當前提交
4872e959d0
共有 100 個文件被更改,包括 13002 次插入0 次删除
  1. 10 0
      .gitignore
  2. 1 0
      app/.gitignore
  3. 124 0
      app/build.gradle
  4. 592 0
      app/proguard-rules.pro
  5. 二進制
      app/release/app-release.apk
  6. 1 0
      app/release/output.json
  7. 26 0
      app/src/androidTest/java/com/enation/javashop/android/ExampleInstrumentedTest.java
  8. 80 0
      app/src/main/AndroidManifest.xml
  9. 4 0
      app/src/main/assets/config.javashop
  10. 24 0
      app/src/main/code/com/wdkl/app/ncs/activity/SchemeActivity.kt
  11. 81 0
      app/src/main/code/com/wdkl/app/ncs/application/Application.kt
  12. 63 0
      app/src/main/res/layout/notification_lay.xml
  13. 17 0
      app/src/test/java/com/enation/javashop/android/ExampleUnitTest.java
  14. 113 0
      build.gradle
  15. 1 0
      common/.gitignore
  16. 262 0
      common/build.gradle
  17. 二進制
      common/libs/chinese2py.jar
  18. 17 0
      common/proguard-rules.pro
  19. 26 0
      common/src/androidTest/java/com/enation/javashop/android/lib/ExampleInstrumentedTest.java
  20. 18 0
      common/src/main/AndroidManifest.xml
  21. 156 0
      common/src/main/code/com/wdkl/ncs/android/lib/adapter/BaseDelegateAdapter.kt
  22. 114 0
      common/src/main/code/com/wdkl/ncs/android/lib/adapter/ListViewBaseAdapter.kt
  23. 171 0
      common/src/main/code/com/wdkl/ncs/android/lib/adapter/TextViewDelegateAdapter.kt
  24. 74 0
      common/src/main/code/com/wdkl/ncs/android/lib/adapter/VlayoutHolderAdapter.kt
  25. 302 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/BaseActivity.kt
  26. 99 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/BaseApplication.kt
  27. 84 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/BaseContract.kt
  28. 32 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/BaseControl.kt
  29. 274 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/BaseFragment.kt
  30. 41 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/BaseLaunch.kt
  31. 49 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/DisposableManager.kt
  32. 384 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/GalleryActivity.kt
  33. 136 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/GalleryFragment.kt
  34. 81 0
      common/src/main/code/com/wdkl/ncs/android/lib/base/RxPresenter.kt
  35. 103 0
      common/src/main/code/com/wdkl/ncs/android/lib/bind/BaseBindingHelper.kt
  36. 97 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/framework/ActivityLifeController.kt
  37. 67 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/framework/Framework.kt
  38. 161 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/framework/InstallResourceHelper.kt
  39. 75 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/framework/JavaShopInstrumentationHook.java
  40. 269 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/framework/ResourceManager.java
  41. 141 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/framework/UnInstallResourceHelper.kt
  42. 68 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/hack/AndroidHack.kt
  43. 23 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/runtime/ClassNotFoundInterceptor.kt
  44. 136 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/runtime/JavaShopActivityTask.kt
  45. 59 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/split/ComponentManager.kt
  46. 36 0
      common/src/main/code/com/wdkl/ncs/android/lib/core/split/ComponentManagerImpl.kt
  47. 15 0
      common/src/main/code/com/wdkl/ncs/android/lib/jni/CommonJNI.kt
  48. 466 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/AppTool.kt
  49. 47 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/AutoClearHelper.kt
  50. 69 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/AutoClearValue.kt
  51. 53 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/BaseRecyclerViewHolder.kt
  52. 46 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/ChineseSortHelper.kt
  53. 144 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/ConnectionObserver.kt
  54. 66 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/ConnectionQualityMonitor.kt
  55. 374 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/Do.kt
  56. 113 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/EcodeHelper.kt
  57. 743 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/ExtendMethods.kt
  58. 314 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/GalleryHelper.kt
  59. 31 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/ImageWatchLoader.kt
  60. 45 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/JsonTranforHelper.kt
  61. 47 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/MD5Util.kt
  62. 51 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/NetReceiver.kt
  63. 614 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/NoAlphaItemAnimator.kt
  64. 39 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/OnClickListenerAntiViolence.kt
  65. 57 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/OnItemClickListenerAntiViolence.kt
  66. 338 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/RecycleViewScrollHelper.kt
  67. 305 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/ReflexHelper.kt
  68. 26 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/RegularHelper.kt
  69. 18 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/RxExtra.kt
  70. 156 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/SmartHideViewHelper.kt
  71. 165 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/TangramPlugin.kt
  72. 226 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/TimeEngine.kt
  73. 62 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/TimeHandle.kt
  74. 60 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/UUID.kt
  75. 38 0
      common/src/main/code/com/wdkl/ncs/android/lib/utils/VlayoutHelper.kt
  76. 9 0
      common/src/main/code/com/wdkl/ncs/android/lib/vo/MenuVo.kt
  77. 26 0
      common/src/main/code/com/wdkl/ncs/android/lib/vo/NetModel.kt
  78. 221 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/ArcView.kt
  79. 173 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/AutoSizeTextView.kt
  80. 929 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/CommonActionBar.kt
  81. 64 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/DialogBackGroundView.kt
  82. 105 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/EditTextCompatibleScrollView.kt
  83. 149 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/LetterView.kt
  84. 168 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/LineView.kt
  85. 208 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/MenuPopWindow.kt
  86. 395 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/PopCommonView.kt
  87. 70 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/PopWindowCompatible.kt
  88. 304 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/SaleProgressView.kt
  89. 207 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/StarView.kt
  90. 110 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/VcodeDialog.kt
  91. 399 0
      common/src/main/code/com/wdkl/ncs/android/lib/widget/VerificationCodeView.kt
  92. 9 0
      common/src/main/res/drawable/icon_cancle_gray.xml
  93. 二進制
      common/src/main/res/drawable/javashop_icon_star_nomal.png
  94. 二進制
      common/src/main/res/drawable/javashop_icon_star_selected.png
  95. 二進制
      common/src/main/res/drawable/sale_progress_view_bg.png
  96. 二進制
      common/src/main/res/drawable/sale_progress_view_fg.png
  97. 8 0
      common/src/main/res/drawable/shape_divider_identifying.xml
  98. 14 0
      common/src/main/res/drawable/shape_icv_et_bg_focus.xml
  99. 14 0
      common/src/main/res/drawable/shape_icv_et_bg_normal.xml
  100. 0 0
      common/src/main/res/layout/auto_size_tv.xml

+ 10 - 0
.gitignore

@@ -0,0 +1,10 @@
+*.iml
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+/gradle
+.externalNativeBuild
+/.gradle

+ 1 - 0
app/.gitignore

@@ -0,0 +1 @@
+/build

+ 124 - 0
app/build.gradle

@@ -0,0 +1,124 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt'
+//apply plugin: 'com.enation.javashop.aspectjrt'
+
+kapt {
+    arguments {
+        arg("moduleName", project.getName())
+    }
+}
+android {
+    compileSdkVersion target_sdk_version
+    buildToolsVersion build_tools_version
+    aaptOptions.cruncherEnabled = false
+    aaptOptions.useNewCruncher = false
+    defaultConfig {
+        applicationId "com.enation.app.javashop"
+        minSdkVersion min_sdk_version
+        targetSdkVersion target_sdk_version
+        versionCode app_version_code
+        versionName app_version
+        multiDexEnabled true
+        dataBinding {
+            enabled = true
+        }
+        ndk {
+            //选择要添加的对应cpu类型的.so库。
+            abiFilters 'armeabi', 'armeabi-v7a', 'armeabi-v8a' ,'x86', 'x86_64', 'mips', 'mips64'
+        }
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+        debug {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+    sourceSets {
+        main.java.srcDirs += 'src/main/code'
+    }
+    lintOptions{
+        checkReleaseBuilds false
+        abortOnError false
+    }
+    dexOptions {
+
+        javaMaxHeapSize "4g"
+
+        jumboMode=true
+
+        preDexLibraries=true
+
+        threadCount=8
+    }
+}
+
+dependencies {
+    compile fileTree(include: ['*.jar'], dir: 'libs')
+    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+        exclude group: 'com.android.support', module: 'support-annotations'
+    })
+    /**
+     * 单元测试
+     */
+    testCompile 'junit:junit:4.12'
+    /**
+     * Dagger编译依赖
+     */
+    kapt 'com.google.dagger:dagger-compiler:2.7'
+    /**
+     * 内存泄漏监控
+     */
+    debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
+    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
+    testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
+    /**
+     * Kotlin依赖
+     */
+    kapt 'com.android.databinding:compiler:2.3.3'
+    /**
+     * 路由注解处理器
+     */
+    kapt "com.enation.geamtear:jrouter-compiler:$router_version"
+    /**
+     * 外部化Moudle配置
+     * moudle独立编译配置
+     */
+    if (!componentTag) {
+        compile project(':welcome') // ===> 开始模块  建议在模块内添加广告 欢迎页 等页面
+        compile project(':home')   // ===> 主页模块  里面一般是App的首页 分类楼层页面
+        compile project(':shop')      // ===> 店铺模块 店铺列表 详细 等
+        compile project(':setting')   // ===> 设置模块 设置 缓存 App分享等
+        compile project(':extra')    // ===> 额外的一些页面 比如二维码扫描等一些附加功能
+        compile project(':hello')
+    }
+    /**
+     * JavaShopAndroid 中间件依赖库
+     */
+    compile project(':middleware')
+
+    /**
+     *  constraint-layout布局依赖
+     */
+    compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'
+
+}
+
+///**
+// * kawo组件化框架配置
+// */
+//kawo {
+//    /**
+//     * Aop注解排除Jar
+//     */
+//    aspectExcludeJarFilter 'com.enation.geamtear.pay','AlipaySdk'
+//}
+//
+

+ 592 - 0
app/proguard-rules.pro

@@ -0,0 +1,592 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/Android/MAC_SDK/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+#############################################
+#
+# 对于一些基本指令的添加
+#
+#############################################
+# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
+-optimizationpasses 5
+
+# 混合时不使用大小写混合,混合后的类名为小写
+-dontusemixedcaseclassnames
+
+# 指定不去忽略非公共库的类
+-dontskipnonpubliclibraryclasses
+
+# 这句话能够使我们的项目混淆后产生映射文件
+# 包含有类名->混淆后类名的映射关系
+-verbose
+
+# 指定不去忽略非公共库的类成员
+-dontskipnonpubliclibraryclassmembers
+
+# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
+-dontpreverify
+
+# 保留Annotation不混淆
+-keepattributes *Annotation*,InnerClasses
+
+# 避免混淆泛型
+-keepattributes Signature
+
+# 抛出异常时保留代码行号
+-keepattributes SourceFile,LineNumberTable
+
+# 指定混淆是采用的算法,后面的参数是一个过滤器
+# 这个过滤器是谷歌推荐的算法,一般不做更改
+-optimizations !code/simplification/cast,!field/*,!class/merging/*
+
+
+#############################################
+#
+# Android开发中一些需要保留的公共部分
+#
+#############################################
+
+# 保留我们使用的四大组件,自定义的Application等等这些类不被混淆
+# 因为这些子类都有可能被外部调用
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Appliction
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class * extends android.view.View
+-keep public class com.android.vending.licensing.ILicensingService
+
+
+# 保留support下的所有类及其内部类
+-keep class android.support.** {*;}
+
+# 保留继承的
+-keep public class * extends android.support.v4.**
+-keep public class * extends android.support.v7.**
+-keep public class * extends android.support.annotation.**
+
+# 保留R下面的资源
+-keep class **.R$* {*;}
+
+# 保留本地native方法不被混淆
+-keepclasseswithmembernames class * {
+    native <methods>;
+}
+
+# 保留在Activity中的方法参数是view的方法,
+# 这样以来我们在layout中写的onClick就不会被影响
+-keepclassmembers class * extends android.app.Activity{
+    public void *(android.view.View);
+}
+
+# 保留枚举类不被混淆
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+# 保留我们自定义控件(继承自View)不被混淆
+-keep public class * extends android.view.View{
+    *** get*();
+    void set*(***);
+    public <init>(android.content.Context);
+    public <init>(android.content.Context, android.util.AttributeSet);
+    public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+# 保留Parcelable序列化类不被混淆
+-keep class * implements android.os.Parcelable {
+    public static final android.os.Parcelable$Creator *;
+}
+
+# 保留Serializable序列化的类不被混淆
+-keepnames class * implements java.io.Serializable
+-keepclassmembers class * implements java.io.Serializable {
+    static final long serialVersionUID;
+    private static final java.io.ObjectStreamField[] serialPersistentFields;
+    !static !transient <fields>;
+    !private <fields>;
+    !private <methods>;
+    private void writeObject(java.io.ObjectOutputStream);
+    private void readObject(java.io.ObjectInputStream);
+    java.lang.Object writeReplace();
+    java.lang.Object readResolve();
+}
+
+# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
+-keepclassmembers class * {
+    void *(**On*Event);
+    void *(**On*Listener);
+}
+
+# webView处理,项目中没有使用到webView忽略即可
+-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+    public *;
+}
+-keepclassmembers class * extends android.webkit.webViewClient {
+    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
+    public boolean *(android.webkit.WebView, java.lang.String);
+}
+-keepclassmembers class * extends android.webkit.webViewClient {
+    public void *(android.webkit.webView, jav.lang.String);
+}
+
+# 移除Log类打印各个等级日志的代码,打正式包的时候可以做为禁log使用,这里可以作为禁止log打印的功能使用
+# 记得proguard-android.txt中一定不要加-dontoptimize才起作用
+# 另外的一种实现方案是通过BuildConfig.DEBUG的变量来控制
+#-assumenosideeffects class android.util.Log {
+#    public static int v(...);
+#    public static int i(...);
+#    public static int w(...);
+#    public static int d(...);
+#    public static int e(...);
+#}
+
+#############################################
+#
+# 项目中特殊处理部分
+#
+#############################################
+
+#-----------处理反射类---------------
+
+
+
+#-----------处理js交互---------------
+
+
+
+#-----------处理实体类---------------
+# 在开发的时候我们可以将所有的实体类放在一个包内,这样我们写一次混淆就行了。
+-keep class com.wdkl.ncs.android.middleware.model.**{ *; }
+
+-keep class com.enation.app.javashop.**{ *; }
+
+-keep class com.enation.app.javashop.**{ *; }
+
+-keep class com.enation.javashop.android.component.member.adapterPostCommentGoodsAdapter
+-keep class com.wdkl.ncs.android.component.shop.adapter.ShopAllGoodsAdapter
+-keep class com.enation.javashop.android.component.member.adapter.CouponAdapter
+-keep class com.enation.javashop.android.component.order.adapter.OrderItemAdapter
+
+
+#-----------处理第三方依赖库---------
+
+
+
+# AndroidEventBus
+-keep class org.simple.** { *; }
+-keep interface org.simple.** { *; }
+-keepclassmembers class * {
+    @org.simple.eventbus.Subscriber <methods>;
+}
+
+
+# BRVAH
+-keep class com.chad.library.adapter.** { *; }
+-keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
+-keep public class * extends com.chad.library.adapter.base.BaseViewHolder
+-keepclassmembers public class * extends com.chad.library.adapter.base.BaseViewHolder {
+    <init>(android.view.View);
+}
+
+
+# Bugly
+-dontwarn com.tencent.bugly.**
+-keep class com.tencent.bugly.** {*;}
+
+
+# ButterKnife
+-keep public class * implements butterknife.Unbinder {
+    public <init>(**, android.view.View);
+}
+-keep class butterknife.*
+-keepclasseswithmembernames class * {
+    @butterknife.* <methods>;
+}
+-keepclasseswithmembernames class * {
+    @butterknife.* <fields>;
+}
+
+
+# Dagger2
+-dontwarn com.google.errorprone.annotations.*
+
+
+# EventBus
+-keepattributes *Annotation*
+-keepclassmembers class ** {
+    @org.greenrobot.eventbus.Subscribe <methods>;
+}
+-keep enum org.greenrobot.eventbus.ThreadMode { *; }
+
+
+# Facebook
+-keep class com.facebook.** {*;}
+-keep interface com.facebook.** {*;}
+-keep enum com.facebook.** {*;}
+
+
+# FastJson
+-dontwarn com.alibaba.fastjson.**
+-keep class com.alibaba.fastjson.** { *; }
+-keepattributes Signature
+-keepattributes *Annotation*
+
+
+# Fresco
+-keep class com.facebook.fresco.** {*;}
+-keep interface com.facebook.fresco.** {*;}
+-keep enum com.facebook.fresco.** {*;}
+
+
+# 高德相关依赖
+# 集合包:3D地图3.3.2 导航1.8.0 定位2.5.0
+-dontwarn com.amap.api.**
+-dontwarn com.autonavi.**
+-keep class com.amap.api.**{*;}
+-keep class com.autonavi.**{*;}
+# 地图服务
+-dontwarn com.amap.api.services.**
+-keep class com.map.api.services.** {*;}
+# 3D地图
+-dontwarn com.amap.api.mapcore.**
+-dontwarn com.amap.api.maps.**
+-dontwarn com.autonavi.amap.mapcore.**
+-keep class com.amap.api.mapcore.**{*;}
+-keep class com.amap.api.maps.**{*;}
+-keep class com.autonavi.amap.mapcore.**{*;}
+# 定位
+-dontwarn com.amap.api.location.**
+-dontwarn com.aps.**
+-keep class com.amap.api.location.**{*;}
+-keep class com.aps.**{*;}
+# 导航
+-dontwarn com.amap.api.navi.**
+-dontwarn com.autonavi.**
+-keep class com.amap.api.navi.** {*;}
+-keep class com.autonavi.** {*;}
+
+
+# Glide
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
+  **[] $VALUES;
+  public *;
+}
+
+
+### greenDAO 3
+-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
+    public static java.lang.String TABLENAME;
+}
+-keep class **$Properties
+
+# If you do not use SQLCipher:
+-dontwarn org.greenrobot.greendao.database.**
+# If you do not use RxJava:
+-dontwarn rx.**
+
+
+# Gson
+-keepattributes Signature
+-keepattributes *Annotation*
+-keep class sun.misc.Unsafe { *; }
+-keep class com.google.gson.stream.** { *; }
+# 使用Gson时需要配置Gson的解析对象及变量都不混淆。不然Gson会找不到变量。
+# 将下面替换成自己的实体类
+#-keep class com.example.bean.** { *; }
+
+
+# Jackson
+-dontwarn org.codehaus.jackson.**
+-dontwarn com.fasterxml.jackson.databind.**
+-keep class org.codehaus.jackson.** { *;}
+-keep class com.fasterxml.jackson.** { *; }
+
+
+# 极光推送
+-dontoptimize
+-dontpreverify
+-dontwarn cn.jpush.**
+-keep class cn.jpush.** { *; }
+
+
+# OkHttp
+-dontwarn okio.**
+-dontwarn okhttp3.**
+-dontwarn javax.annotation.Nullable
+-dontwarn javax.annotation.ParametersAreNonnullByDefault
+
+
+# Okio
+-dontwarn com.squareup.**
+-dontwarn okio.**
+-keep public class org.codehaus.* { *; }
+-keep public class java.nio.* { *; }
+
+
+# OrmLite
+-keepattributes *DatabaseField*
+-keepattributes *DatabaseTable*
+-keepattributes *SerializedName*
+-keep class com.j256.**
+-keepclassmembers class com.j256.** { *; }
+-keep enum com.j256.**
+-keepclassmembers enum com.j256.** { *; }
+-keep interface com.j256.**
+-keepclassmembers interface com.j256.** { *; }
+
+
+# Realm
+-keep class io.realm.annotations.RealmModule
+-keep @io.realm.annotations.RealmModule class *
+-keep class io.realm.internal.Keep
+-keep @io.realm.internal.Keep class * { *; }
+-dontwarn javax.**
+-dontwarn io.realm.**
+
+
+# Retrofit
+-keep class retrofit2.** { *; }
+-dontwarn retrofit2.**
+-keepattributes Signature
+-keepattributes Exceptions
+-dontwarn okio.**
+-dontwarn javax.annotation.**
+
+
+# Retrolambda
+-dontwarn java.lang.invoke.*
+
+
+# RxJava RxAndroid
+-dontwarn sun.misc.**
+-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
+    long producerIndex;
+    long consumerIndex;
+}
+-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
+    rx.internal.util.atomic.LinkedQueueNode producerNode;
+}
+-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
+    rx.internal.util.atomic.LinkedQueueNode consumerNode;
+}
+-dontnote rx.internal.util.PlatformDependent
+
+
+
+# 微信支付
+-dontwarn com.tencent.mm.**
+-dontwarn com.tencent.wxop.stat.**
+-keep class com.tencent.mm.** {*;}
+-keep class com.tencent.wxop.stat.**{*;}
+
+
+# 信鸽
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep class com.tencent.android.tpush.**  {* ;}
+-keep class com.tencent.mid.**  {* ;}
+-keepattributes *Annotation*
+
+
+# 新浪微博
+-keep class com.sina.weibo.sdk.* { *; }
+-keep class android.support.v4.* { *; }
+-keep class com.tencent.* { *; }
+-keep class com.baidu.* { *; }
+-keep class lombok.ast.ecj.* { *; }
+-dontwarn android.support.v4.**
+-dontwarn com.tencent.**s
+-dontwarn com.baidu.**
+
+
+# XLog
+-keep class com.tencent.mars.** { *; }
+-keepclassmembers class com.tencent.mars.** { *; }
+-dontwarn com.tencent.mars.**
+
+
+# 讯飞语音
+-dontwarn com.iflytek.**
+-keep class com.iflytek.** {*;}
+
+
+# 银联
+-dontwarn com.unionpay.**
+-keep class com.unionpay.** { *; }
+
+
+# 友盟统计分析
+-keepclassmembers class * { public <init>(org.json.JSONObject); }
+-keepclassmembers enum com.umeng.analytics.** {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+
+# 友盟自动更新
+-keepclassmembers class * { public <init>(org.json.JSONObject); }
+-keep public class cn.irains.parking.cloud.pub.R$*{ public static final int *; }
+-keep public class * extends com.umeng.**
+-keep class com.umeng.** { *; }
+
+
+# 支付宝钱包
+-dontwarn com.alipay.**
+-dontwarn HttpUtils.HttpFetcher
+-dontwarn com.ta.utdid2.**
+-dontwarn com.ut.device.**
+-keep class com.alipay.android.app.IAlixPay{*;}
+-keep class com.alipay.android.app.IAlixPay$Stub{*;}
+-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
+-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
+-keep class com.alipay.sdk.app.PayTask{ public *;}
+-keep class com.alipay.sdk.app.AuthTask{ public *;}
+-keep class com.alipay.mobilesecuritysdk.*
+-keep class com.ut.*
+
+
+
+#解决使用Retrofit+rxJava联网时,在6.0系统出现java.lang.InternalError奔溃的问题:http://blog.csdn.net/mp624183768/article/details/79242147
+-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
+    long producerIndex;
+    long consumerIndex;
+}
+-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
+    rx.internal.util.atomic.LinkedQueueNode producerNode;
+}
+-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
+    rx.internal.util.atomic.LinkedQueueNode consumerNode;
+}
+
+-keep class com.tencent.mm.opensdk.** {
+*;
+}
+-keep class com.tencent.wxop.** {
+*;
+}
+-keep class com.tencent.mm.sdk.** {
+*;
+}
+-keep class com.umeng.commonsdk.** {*;}
+-keepclassmembers class * {
+   public <init> (org.json.JSONObject);
+}
+-keep public class [com.zongxueguan.naochanle_android].R$*{
+public static final int *;
+}
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+-dontshrink
+ -dontoptimize
+ -dontwarn com.google.android.maps.**
+ -dontwarn android.webkit.WebView
+ -dontwarn com.umeng.**
+ -dontwarn com.tencent.weibo.sdk.**
+ -dontwarn com.facebook.**
+ -keep public class javax.**
+ -keep public class android.webkit.**
+ -dontwarn android.support.v4.**
+ -keep enum com.facebook.**
+ -keepattributes Exceptions,InnerClasses,Signature
+ -keepattributes *Annotation*
+ -keepattributes SourceFile,LineNumberTable
+
+ -keep public interface com.facebook.**
+ -keep public interface com.tencent.**
+ -keep public interface com.umeng.socialize.**
+ -keep public interface com.umeng.socialize.sensor.**
+ -keep public interface com.umeng.scrshot.**
+
+ -keep public class com.umeng.socialize.* {*;}
+
+
+ -keep class com.facebook.**
+ -keep class com.facebook.** { *; }
+ -keep class com.umeng.scrshot.**
+ -keep public class com.tencent.** {*;}
+ -keep class com.umeng.socialize.sensor.**
+ -keep class com.umeng.socialize.handler.**
+ -keep class com.umeng.socialize.handler.*
+ -keep class com.umeng.weixin.handler.**
+ -keep class com.umeng.weixin.handler.*
+ -keep class com.umeng.qq.handler.**
+ -keep class com.umeng.qq.handler.*
+ -keep class UMMoreHandler{*;}
+ -keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;}
+ -keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;}
+ -keep class im.yixin.sdk.api.YXMessage {*;}
+ -keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;}
+ -keep class com.tencent.mm.sdk.** {
+    *;
+ }
+ -keep class com.tencent.mm.opensdk.** {
+    *;
+ }
+ -keep class com.tencent.wxop.** {
+    *;
+ }
+ -keep class com.tencent.mm.sdk.** {
+    *;
+ }
+ -dontwarn twitter4j.**
+ -keep class twitter4j.** { *; }
+
+ -keep class com.tencent.** {*;}
+ -dontwarn com.tencent.**
+ -keep class com.kakao.** {*;}
+ -dontwarn com.kakao.**
+ -keep public class com.umeng.com.umeng.soexample.R$*{
+     public static final int *;
+ }
+ -keep public class com.linkedin.android.mobilesdk.R$*{
+     public static final int *;
+ }
+ -keepclassmembers enum * {
+     public static **[] values();
+     public static ** valueOf(java.lang.String);
+ }
+
+ -keep class com.tencent.open.TDialog$*
+ -keep class com.tencent.open.TDialog$* {*;}
+ -keep class com.tencent.open.PKDialog
+ -keep class com.tencent.open.PKDialog {*;}
+ -keep class com.tencent.open.PKDialog$*
+ -keep class com.tencent.open.PKDialog$* {*;}
+ -keep class com.umeng.socialize.impl.ImageImpl {*;}
+ -keep class com.sina.** {*;}
+ -dontwarn com.sina.**
+ -keep class  com.alipay.share.sdk.** {
+    *;
+ }
+
+ -keepnames class * implements android.os.Parcelable {
+     public static final ** CREATOR;
+ }
+
+ -keep class com.linkedin.** { *; }
+ -keep class com.android.dingtalk.share.ddsharemodule.** { *; }
+ -keepattributes Signature
+
+-dontwarn okio.**
+-dontwarn javax.annotation.**

二進制
app/release/app-release.apk


+ 1 - 0
app/release/output.json

@@ -0,0 +1 @@
+[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1},"path":"app-release.apk","properties":{"packageId":"com.enation.app.javashop","split":"","minSdkVersion":"17"}}]

+ 26 - 0
app/src/androidTest/java/com/enation/javashop/android/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
+package com.enation.javashop.android;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() throws Exception {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getTargetContext();
+
+        assertEquals("com.enation.javashop.android", appContext.getPackageName());
+    }
+}

+ 80 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="com.wdkl.app.ncs">
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
+
+    <uses-permission android:name ="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/launcher"
+        android:label="@string/javashop_app_name"
+        android:supportsRtl="true"
+        tools:replace="android:label"
+        android:networkSecurityConfig="@xml/network_security_config"
+        android:name="com.wdkl.app.ncs.application.Application"
+        android:theme="@style/MyAppTheme">
+        <meta-data
+            android:name="com.enation.javashop.imagepluin.cache.MyGlideModule"
+            android:value="GlideModule" />
+        <meta-data
+            android:name="design_width_in_dp"
+            android:value="360"/>
+        <meta-data
+            android:name="design_height_in_dp"
+            android:value="640"/>
+
+        <activity android:name="com.wdkl.ncs.android.component.welcome.activity.WelcomeActivity"
+            >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:name="com.wdkl.app.ncs.activity.SchemeActivity">
+
+            <!-- Schame -->
+            <intent-filter>
+                <data
+                    android:host="m.wdkl.com"
+                    android:scheme="wdkl"/>
+
+                <action android:name="android.intent.action.VIEW"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.BROWSABLE"/>
+            </intent-filter>
+
+            <!-- App Links -->
+            <intent-filter android:autoVerify="true">
+                <action android:name="android.intent.action.VIEW"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.BROWSABLE"/>
+
+                <data
+                    android:host="m.wdkl.com"
+                    android:scheme="http"/>
+                <data
+                    android:host="m.wdkl.com"
+                    android:scheme="https"/>
+            </intent-filter>
+        </activity>
+        <meta-data
+            android:name="android.max_aspect"
+            android:value="2.2" />
+    </application>
+
+</manifest>

+ 4 - 0
app/src/main/assets/config.javashop

@@ -0,0 +1,4 @@
+{
+    "TestMode" : false ,
+    "TestPath" : "/order/create"
+}

+ 24 - 0
app/src/main/code/com/wdkl/app/ncs/activity/SchemeActivity.kt

@@ -0,0 +1,24 @@
+package com.wdkl.app.ncs.activity
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import com.enation.javashop.android.jrouter.JRouter
+import com.enation.javashop.android.jrouter.logic.datainfo.Postcard
+import com.enation.javashop.android.jrouter.logic.listener.NavListener
+
+/**
+ * Created by LDD on 2017/9/10.
+ */
+class SchemeActivity:AppCompatActivity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        val uri = intent.data
+        JRouter.prepare().create(uri).seek(this,object:NavListener(){
+            override fun onArrival(postcard: Postcard?) {
+                finish()
+            }
+        })
+    }
+
+}

+ 81 - 0
app/src/main/code/com/wdkl/app/ncs/application/Application.kt

@@ -0,0 +1,81 @@
+package com.wdkl.app.ncs.application
+
+import com.enation.javashop.android.jrouter.JRouter
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.enation.javashop.net.engine.config.NetEngineConfig
+import com.enation.javashop.net.engine.plugin.exception.RestfulExceptionInterceptor
+import com.enation.javashop.utils.base.config.BaseConfig
+
+/**
+ * @author LDD
+ * @Date   2018/1/11 下午12:48
+ * @From   com.enation.javashop.android.application
+ * @Note   应用Application
+ */
+class Application : BaseApplication() {
+
+
+    /**
+     * @author LDD
+     * @From   Application
+     * @Date   2018/1/11 下午12:50
+     * @Note   应用启动时调用
+     */
+    override fun onCreate() {
+        super.onCreate()
+        initRouter()
+        initFrame()
+        initLeaks()
+    }
+
+    /**
+     * @author  LDD
+     * @From    Application
+     * @Date   2018/1/11 下午12:50
+     * @Note   初始化路由
+     * @return rx观察者
+     */
+    private fun initRouter() {
+        JRouter.init(this)
+        JRouter.openDebug()
+        JRouter.openLog()
+        JRouter.prepare().create("/welcome/launch").seek()
+        JRouter.prepare().create("/home/launch").seek()
+        JRouter.prepare().create("/setting/launch").seek()
+        JRouter.prepare().create("/shop/launch").seek()
+        JRouter.prepare().create("/extra/launch").seek()
+
+        JRouter.prepare().create("/hello/launch").seek()
+    }
+
+    /**
+     * @author  LDD
+     * @From    Application
+     * @Date   2018/1/11 下午12:50
+     * @Note   初始化内存检测器
+     * @return rx观察者
+     */
+    private fun initLeaks() {
+//        if (JavaShopConfigCenter.INSTANCE.APP_DEV) {
+//            LeakCanary.install(this)
+//        }
+    }
+
+    /**
+     * @author  LDD
+     * @From    Application
+     * @Date   2018/1/11 下午12:50
+     * @Note   初始化内部框架
+     * @return rx观察者
+     */
+    private fun initFrame() {
+        if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIPOP) {
+            BaseConfig.getInstance().addActivity("WelcomeActivity", "HomeActivity")
+        } else {
+            BaseConfig.getInstance().closeScrollBack()
+        }
+        NetEngineConfig.init(baseContext)
+                .openLogger()
+                .addNetInterceptor(RestfulExceptionInterceptor())
+    }
+}

+ 63 - 0
app/src/main/res/layout/notification_lay.xml

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:background="#88000000"
+              android:orientation="horizontal"
+              android:paddingLeft="15dp"
+              android:paddingRight="15dp"
+              android:layout_width="match_parent"
+              android:layout_height="64dp">
+    <ImageView
+        android:layout_width="64dp"
+        android:src="@mipmap/launcher"
+        android:padding="5dp"
+        android:layout_gravity="center_vertical"
+        android:layout_height="64dp"/>
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_weight="1.5"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <TextView
+                android:id="@+id/notification_title"
+                android:text="WdklNCS"
+                android:textColor="#fff"
+                android:gravity="bottom"
+                android:textSize="15dp"
+                android:maxLines="1"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"/>
+            <TextView
+                android:id="@+id/notification_time"
+                android:layout_marginLeft="10dp"
+                android:textSize="12dp"
+                android:text="21-01-07"
+                android:maxLines="1"
+                android:textColor="#99ffffff"
+                android:gravity="bottom"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"/>
+        </LinearLayout>
+        <LinearLayout
+            android:layout_marginBottom="5dp"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <TextView
+                android:id="@+id/notification_content"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:textSize="12dp"
+                android:textColor="#99ffffff"
+                android:gravity="top"
+                android:maxLines="2"
+                android:ellipsize="end"
+                android:layout_marginBottom="5dp"
+                android:text="@string/app_name"
+                />
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>

+ 17 - 0
app/src/test/java/com/enation/javashop/android/ExampleUnitTest.java

@@ -0,0 +1,17 @@
+package com.enation.javashop.android;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() throws Exception {
+        assertEquals(4, 2 + 2);
+    }
+}

+ 113 - 0
build.gradle

@@ -0,0 +1,113 @@
+buildscript {
+    /**
+     * Kotlin统一版本
+     */
+    ext.kotlin_version = '1.3.21'
+
+    /**
+     * Aop编制版本
+     */
+    ext.aspectj_version = '1.8.9'
+
+    /**
+     * 是否开启单独Module编译
+     */
+    ext.componentTag = false
+
+    /**
+     * 路由注解处理器版本
+     */
+    ext.router_version = '1.0.2'
+
+    /**
+     * kawo组件化框架版本
+     */
+    ext.kawo_version = '1.0.9'
+
+    /**
+     * SDK最小支持版本
+     */
+    ext.min_sdk_version = 17
+
+    /**
+     * SDK目标支持版本
+     */
+    ext.target_sdk_version = 28
+
+    /**
+     * SDK编译版本
+     */
+    ext.build_tools_version = "26.0.2"
+
+    /**
+     * 支持库版本
+     */
+    ext.support_library_version = "26.0.1"
+
+    /**
+     * APP版本码
+     */
+    ext.app_version_code = 1
+
+    /**
+     * APP版本号
+     */
+    ext.app_version = "1.0"
+
+    /**
+     * 项目依赖库
+     */
+    dependencies {
+        repositories {
+            /**
+             * 依赖仓储
+             */
+            jcenter()
+            mavenCentral()
+            google()
+        }
+        /**
+         * Gradle插件
+         */
+        classpath 'com.android.tools.build:gradle:3.0.1'
+
+        /**
+         * Kawo组件化插件
+         */
+        classpath "com.enation.geamtear.gradle:kawo:$kawo_version"
+
+        /**
+         * KotlinGradle插件
+         */
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+        /**
+         * Kotlin辅助工具
+         */
+        classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
+
+        /**
+         * Aop埋点相关
+         */
+        classpath "org.aspectj:aspectjtools:$aspectj_version"
+    }
+}
+/**
+ * 统一依赖仓储
+ */
+allprojects {
+    repositories {
+        google()
+        jcenter()
+        mavenCentral()
+        maven { url 'https://dl.bintray.com/geamtear/maven' }
+        maven { url "https://jitpack.io" }
+    }
+}
+
+/**
+ *  清除Build配置时 删除根目录Build文件夹
+ */
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}

+ 1 - 0
common/.gitignore

@@ -0,0 +1 @@
+/build

+ 262 - 0
common/build.gradle

@@ -0,0 +1,262 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-kapt'
+android {
+    compileSdkVersion target_sdk_version
+    buildToolsVersion build_tools_version
+
+    defaultConfig {
+        minSdkVersion min_sdk_version
+        targetSdkVersion target_sdk_version
+        versionCode app_version_code
+        versionName app_version
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        dataBinding {
+            enabled = true
+        }
+//        ndk{
+//            moduleName "JavaShopCommonNDK"       //生成的so文件名字,调用C程序的代码中会用到该名字
+//            abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种平台下的so库
+//        }
+    }
+    lintOptions {
+        abortOnError false
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+//        debug {
+//            jniDebuggable true
+//        }
+    }
+    sourceSets {
+        main.java.srcDirs += 'src/main/code'
+//        main.jni.srcDirs = []
+//        main.jniLibs.srcDir 'src/main/libs'
+    }
+}
+
+dependencies {
+    compile fileTree(include: ['*.jar'], dir: 'libs')
+    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+        exclude group: 'com.android.support', module: 'support-annotations'
+    })
+
+    /**
+     * UI适配
+     */
+    compile 'me.jessyan:autosize:1.1.1'
+
+    /**
+     *  圆形ImageView
+     */
+    compile 'de.hdodenhof:circleimageview:2.2.0'
+
+    /**
+     *  JavaShop_Android 基础工具库
+     */
+    compile 'com.enation.geamtear.util:base:1.1.4'
+
+    /**
+     *  JavaShop_Android 网络库
+     */
+    compile 'com.enation.geamtear.net:engine:1.1.5'
+
+    /**
+     *  JavaShop_Android 图片加载库
+     */
+    compile 'com.enation.geamtear.image:glidepluin:1.0.2'
+
+    /**
+     *  JavaShop_Android 第三方工具库
+     */
+    compile 'com.enation.geamtear.widget:ConnectView:1.1.1'
+
+    /**
+     *  JavaShop_Android 地区选择工具库
+     */
+    compile 'com.enation.geamtear.widget:districtselectorview:1.0.6'
+
+    /**
+     *  JavaShop_Android 导航View
+     */
+    compile 'com.enation.geamtear.widget:NavigationView:1.1.0'
+
+    /**
+     *  JavaShop_Android 路由
+     */
+    compile 'com.enation.geamtear:jrouter-logic:1.0.3'
+
+    /**
+     *  JavaShop_Android 图片选择工具库
+     */
+    compile('com.enation.geamtear.photo:takephoto:1.0.2') {
+        exclude group: 'com.github.bumptech.glide'
+        exclude group: 'io.reactivex.rxjava2'
+    }
+
+    /**
+     *  JavaShop_Android Log日志库
+     */
+    compile 'com.enation.geamtear.util:logger:1.0.7'
+
+    /**
+     *   Android基础依赖库
+     */
+    compile "com.android.support:design:$support_library_version"
+    compile "com.android.support:support-v4:$support_library_version"
+    compile "com.android.support:cardview-v7:$support_library_version"
+    testCompile 'junit:junit:4.12'
+
+    /**
+     *   突破方法数限制
+     */
+    compile 'com.android.support:multidex:1.0.2'
+
+
+    compile 'com.github.1002326270xc:LayoutManager-FlowLayout:v1.7'
+
+    /**
+     *   刷新数据控件
+     */
+    compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-18'
+
+    /**
+     *   动画框架 巨牛逼
+     */
+    compile 'com.airbnb.android:lottie:1.5.3'
+
+    /**
+     *  Kotlin依赖
+     */
+    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+    compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.27.0'
+
+    /**
+     *  Databinding
+     */
+    kapt "com.android.databinding:compiler:2.3.3"
+
+    /**
+     *  Dagger依赖
+     */
+    compile 'com.google.dagger:dagger:2.7'
+
+    /**
+     *  Dagger编译依赖
+     */
+    kapt 'com.google.dagger:dagger-compiler:2.7'
+
+    /**
+     *  七巧板框架
+     */
+    compile 'com.alibaba.android:tangram:2.0.0@aar'
+    compile('com.alibaba.android:vlayout:1.2.6.1@aar') {
+        changing = true
+    }
+    compile 'com.alibaba.android:ultraviewpager:1.0.6.5@aar'
+    compile('me.everything:overscroll-decor-android:1.0.1@aar') {
+        transitive true
+        exclude group: 'com.android.support', module: 'recyclerview-v7'
+    }
+    compile('com.alibaba.android:virtualview:1.0.2@aar') {
+        transitive true
+        exclude group: 'com.android.support', module: 'appcompat-v7'
+        exclude group: 'com.tmall.android', module: 'tmallandroid_mui'
+        exclude group: 'com.google.android', module: 'support-v7-recyclerview'
+        exclude group: 'com.android.support', module: 'support-v4'
+        exclude group: 'com.android.support', module: 'support-annotations'
+    }
+
+    //compile 'com.alibaba.android:tangram:2.2.1@aar'
+
+    /**
+     *  Aop埋点
+     */
+    compile "org.aspectj:aspectjrt:$aspectj_version"
+
+    /**
+     *  constraint-layout布局依赖
+     */
+    compile 'com.android.support.constraint:constraint-layout:1.1.0-beta5'
+
+    /**
+     * 指示器
+     */
+    compile 'com.github.hackware1993:magicindicator:1.5.0'
+
+    /**
+     * 汉字辅助
+     */
+    compile files('libs/chinese2py.jar')
+
+    /**
+     * 二维码扫描
+     */
+    compile 'cn.yipianfengye.android:zxing-library:2.2'
+
+    /**
+     * GLIDE 图片处理器
+     */
+    compile ('jp.wasabeef:glide-transformations:2.0.1') {
+        exclude group: 'com.github.bumptech.glide'
+    }
+
+    /**
+     * 时间选择器
+     */
+    compile 'com.contrarywind:Android-PickerView:4.1.6'
+
+    /**
+     * 图片查看器
+     */
+    compile 'com.github.iielse:ImageWatcher:1.1.5'
+
+    /**
+     * 权限控制
+     */
+    compile 'pub.devrel:easypermissions:0.2.0'
+
+
+    compile 'com.github.pinguo-zhouwei:MZBannerView:v2.0.2'
+}
+
+//tasks.withType(JavaCompile) {
+//    compileTask -> compileTask.dependsOn ndkBuild
+//}
+//
+//task ndkBuild(type: Exec) {
+//    workingDir file('src/main/jni')
+//    commandLine getNdkBuildCmd()
+//}
+//
+//task cleanNative(type: Exec){
+//    workingDir file('src/main/jni')
+//    commandLine getNdkBuildCmd(), 'clean'
+//}
+//
+//clean.dependsOn cleanNative
+//
+//def getNdkDir() {
+//    if (System.env.ANDROID_NDK_ROOT != null)
+//        return System.env.ANDROID_NDK_ROOT
+//    Properties properties = new Properties()
+//    properties.load(project.rootProject.file('local.properties').newDataInputStream())
+//    def ndkdir = properties.getProperty('ndk.dir', null)
+//    if (ndkdir == null)
+//        throw new GradleException("NDK location not found. Define location with ndk.dir in the local.properties file or with an ANDROID_NDK_ROOT environment variable.")
+//    return ndkdir
+//}
+//
+//def getNdkBuildCmd() {
+//    def ndkbuild = getNdkDir() + "/ndk-build"
+//    //Window下需要加.cmd后缀,Mac下则不需要
+//    ndkbuild += ""
+//    return ndkbuild
+//}
+
+

二進制
common/libs/chinese2py.jar


+ 17 - 0
common/proguard-rules.pro

@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/Android/MAC_SDK/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}

+ 26 - 0
common/src/androidTest/java/com/enation/javashop/android/lib/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
+package com.wdkl.ncs.android.lib;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() throws Exception {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getTargetContext();
+
+        assertEquals("com.wdkl.ncs.android.lib.test", appContext.getPackageName());
+    }
+}

+ 18 - 0
common/src/main/AndroidManifest.xml

@@ -0,0 +1,18 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.wdkl.ncs.android.lib">
+
+    <application android:allowBackup="true"
+                 android:label="@string/app_name"
+                 android:supportsRtl="true"
+    >
+        <receiver android:name=".utils.NetReceiver" >
+            <intent-filter>
+                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
+            </intent-filter>
+        </receiver>
+    </application>
+
+    <uses-permission android:name="android.permission.VIBRATE"></uses-permission>
+    <uses-permission android:name="android.permission.FLASHLIGHT"></uses-permission>
+
+</manifest>

+ 156 - 0
common/src/main/code/com/wdkl/ncs/android/lib/adapter/BaseDelegateAdapter.kt

@@ -0,0 +1,156 @@
+package com.wdkl.ncs.android.lib.adapter
+
+import android.support.v7.widget.RecyclerView
+import android.widget.ImageView
+import com.alibaba.android.vlayout.DelegateAdapter
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.engine.DiskCacheStrategy
+import com.wdkl.ncs.android.lib.utils.dpToPx
+import com.wdkl.ncs.android.lib.utils.more
+import com.enation.javashop.imagepluin.R
+import jp.wasabeef.glide.transformations.CropSquareTransformation
+import jp.wasabeef.glide.transformations.RoundedCornersTransformation
+
+/**
+ * @author LDD
+ * @Date   2018/1/30 上午11:46
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   DelegateAdapter基类 添加了点击长按事件
+ */
+abstract class BaseDelegateAdapter<VH : RecyclerView.ViewHolder, out DataType> : DelegateAdapter.Adapter<VH>() {
+
+    /**
+     * @Name  tag
+     * @Type  Any
+     * @Note  标识Adapter的标签 同一个列表内 不可使用重复Tag 否则会造成查找失败
+     */
+    var tag : Any? = null
+
+    /**
+     * @Name  itemClickListener
+     * @Type  ((data:DataType, position:Int)->(Unit))?
+     * @Note  点击事件
+     */
+    private var itemClickListener :((data:DataType, position:Int)->(Unit))? = null
+
+    /**
+     * @Name  itemClickListener
+     * @Type  ((data:DataType, position:Int)->(Unit))?
+     * @Note  长按事件
+     */
+    private var itemLongClickListener :((data:DataType, position:Int)->(Unit))? = null
+
+    /**
+     * @author LDD
+     * @From   BaseDelegateAdapter
+     * @Date   2018/2/6 上午10:40
+     * @Note   数据提供者
+     * @return 数据源
+     */
+    abstract fun dataProvider():Any
+
+    /**
+     * @author LDD
+     * @From   BaseDelegateAdapter
+     * @Date   2018/2/6 上午10:40
+     * @Note   数据源处理器 判断是单个数据 还是数据集合
+     * @return 全部转换为数据集合
+     */
+    private fun dataProcessor():List<DataType>{
+        return if (dataProvider() is List<*> || dataProvider() is ArrayList<*>){
+            dataProvider() as List<DataType>
+        }else{
+            listOf(dataProvider() as DataType)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseDelegateAdapter
+     * @Date   2018/1/30 上午11:54
+     * @Note   设置item点击事件
+     * @param  itemClickListener 点击回调
+     */
+    fun setOnItemClickListener(itemClickListener:(data:DataType,position:Int)->(Unit)){
+        this.itemClickListener = itemClickListener
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseDelegateAdapter
+     * @Date   2018/1/30 上午11:54
+     * @Note   设置item点击事件
+     * @param  itemLongClickListener 长按回调
+     */
+    fun setOnItemLongClickListener(itemLongClickListener: (data:DataType,position:Int)->(Unit)){
+        this.itemLongClickListener = itemLongClickListener
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseDelegateAdapter
+     * @Date   2018/1/30 上午11:55
+     * @Note   重写该方法 对item进行事件配置
+     */
+    override fun onBindViewHolderWithOffset(holder: VH, position: Int, offsetTotal: Int) {
+        super.onBindViewHolderWithOffset(holder, position, offsetTotal)
+        if (itemFilter(position)){
+            itemClickListener?.more {
+                self ->
+                holder.itemView.setOnClickListener {
+                    self.invoke(dataProcessor()[position],position)
+                }
+            }
+            itemLongClickListener?.more {
+                self ->
+                holder.itemView.setOnLongClickListener {
+                    self.invoke(dataProcessor()[position],position)
+                    return@setOnLongClickListener true
+                }
+            }
+        }else{
+            holder.itemView.setOnLongClickListener{true}
+            holder.itemView.setOnClickListener{}
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseDelegateAdapter
+     * @Date   2018/2/9 下午2:18
+     * @Note   获取item对应数据
+     * @param  item坐标
+     */
+    open fun getItem(position: Int):DataType{
+        return dataProcessor()[position]
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseDelegateAdapter
+     * @Date   2018/1/30 上午11:56
+     * @Note   用来拦截是否为该item配置响应事件
+     * @param  position item坐标
+     */
+    abstract fun itemFilter(position: Int):Boolean
+
+
+    fun loadImage(url :String,imageView :ImageView){
+        Glide.with(imageView.context)
+                .load(url)
+                .thumbnail(0.1f)
+                .diskCacheStrategy(DiskCacheStrategy.ALL)
+                .placeholder(R.drawable.image_loading)
+                .error(R.drawable.image_error)
+                .into(imageView)
+    }
+
+    fun loadImageRound(url :String,imageView: ImageView,cornerType: RoundedCornersTransformation.CornerType = RoundedCornersTransformation.CornerType.ALL){
+        Glide.with(imageView.context)
+                .load(url)
+                .thumbnail(0.1f)
+                .bitmapTransform(RoundedCornersTransformation(imageView.context,3.dpToPx(),0,cornerType))
+                .into(imageView)
+    }
+
+}

+ 114 - 0
common/src/main/code/com/wdkl/ncs/android/lib/adapter/ListViewBaseAdapter.kt

@@ -0,0 +1,114 @@
+package com.wdkl.ncs.android.lib.adapter
+
+import android.content.Context
+import android.databinding.ViewDataBinding
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseAdapter
+import android.databinding.DataBindingUtil
+import android.view.LayoutInflater
+
+/**
+ * @author LDD
+ * @Date   2018/1/30 上午11:33
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   listView单一种类Item 快速适配器
+ */
+abstract class ListViewBaseAdapter<DataType, in BindingType:ViewDataBinding>constructor(private val context: Context, private val layout:Int, var datas : List<DataType>) : BaseAdapter() {
+
+    /**
+     * @Name  binding
+     * @Type  BindingType
+     * @Note  databinding工具类
+     */
+    private lateinit var binding : BindingType
+
+    /**
+     * @author LDD
+     * @From   ListViewBaseAdapter
+     * @Date   2018/1/30 上午11:35
+     * @Note   获取View
+     * @param  position 坐标
+     * @param  convertView item
+     * @param  parent  父容器
+     */
+    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
+        var currentView = convertView
+        if (currentView == null) {
+            binding = DataBindingUtil.inflate(LayoutInflater.from(context), layout, parent, false)
+            currentView = binding.root
+            reSize(currentView)
+            currentView.tag = binding
+        } else {
+            binding = currentView.tag as BindingType
+        }
+        fillItem(binding,datas.get(position),position)
+        binding.root.setOnClickListener {
+            itemClick(datas.get(position),position)
+        }
+        return currentView!!
+    }
+
+    /**
+     * @author LDD
+     * @From   ListViewBaseAdapter
+     * @Date   2018/1/30 上午11:36
+     * @Note   获取item数据
+     * @param  position 坐标
+     */
+    override fun getItem(position: Int): DataType {
+        return datas.get(position)
+    }
+
+    /**
+     * @author LDD
+     * @From   ListViewBaseAdapter
+     * @Date   2018/1/30 上午11:36
+     * @Note   获取ItemID
+     * @param  position 坐标
+     */
+    override fun getItemId(position: Int): Long {
+        return position.toLong()
+    }
+
+    /**
+     * @author LDD
+     * @From   ListViewBaseAdapter
+     * @Date   2018/1/30 上午11:37
+     * @Note   获取item总数
+     * @return item总数
+     */
+    override fun getCount(): Int {
+        return datas.count()
+    }
+
+    /**
+     * @author LDD
+     * @From   ListViewBaseAdapter
+     * @Date   2018/1/30 上午11:37
+     * @Note   抽象方法 填充数据
+     * @param  binding databinding
+     * @param  data 数据
+     * @param  position 坐标
+     */
+    abstract fun fillItem(binding: BindingType , data:DataType ,position: Int)
+
+    /**
+     * @author LDD
+     * @From   ListViewBaseAdapter
+     * @Date   2018/1/30 上午11:39
+     * @Note   重新设置item大小
+     * @param  convertView item
+     */
+    open fun reSize(convertView: View){}
+
+    /**
+     * @author LDD
+     * @From   ListViewBaseAdapter
+     * @Date   2018/1/30 上午11:39
+     * @Note   item点击事件
+     * @param  data itemData
+     * @param  position 坐标
+     */
+    open fun itemClick(data:DataType ,position: Int){}
+}

+ 171 - 0
common/src/main/code/com/wdkl/ncs/android/lib/adapter/TextViewDelegateAdapter.kt

@@ -0,0 +1,171 @@
+package com.wdkl.ncs.android.lib.adapter
+
+import android.graphics.Color
+import android.view.ViewGroup
+import com.alibaba.android.vlayout.LayoutHelper
+import com.alibaba.android.vlayout.layout.LinearLayoutHelper
+import com.wdkl.ncs.android.lib.R
+import com.wdkl.ncs.android.lib.databinding.TextAdapterLayBinding
+import com.wdkl.ncs.android.lib.utils.BaseRecyclerViewHolder
+import com.wdkl.ncs.android.lib.utils.then
+
+/**
+ * @author LDD
+ * @Date   2018/4/19 下午2:12
+ * @From   com.wdkl.ncs.android.lib.adapter
+ * @Note   文字视图Item适配器
+ */
+class TextViewDelegateAdapter(val text :String,val textLineCount :Int ,val textColor :Int ,val top : Int = 0 ,val bottom : Int = 0 ,val left : Int = 0 ,val right : Int = 0,val bgColor:Int = Color.WHITE) :BaseDelegateAdapter<BaseRecyclerViewHolder<TextAdapterLayBinding>,Int>(){
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:17
+     * @Note   数据提供者
+     */
+    override fun dataProvider(): Any {
+        return -1
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:17
+     * @Note   item点击过滤
+     * @param  position item坐标
+     */
+    override fun itemFilter(position: Int): Boolean {
+        return true
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:18
+     * @Note   构建ViewHolder
+     */
+    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): BaseRecyclerViewHolder<TextAdapterLayBinding> {
+        return BaseRecyclerViewHolder.build(parent, R.layout.text_adapter_lay)
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:19
+     * @Note   获取Item总数
+     */
+    override fun getItemCount(): Int {
+        return 1
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:19
+     * @Note   构建LayoutHelper
+     */
+    override fun onCreateLayoutHelper(): LayoutHelper {
+        return LinearLayoutHelper(0,1).then {
+            self ->
+            self.setMargin(left,top,right,bottom)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:20
+     * @Note   绑定数据
+     */
+    override fun onBindViewHolder(holder: BaseRecyclerViewHolder<TextAdapterLayBinding>?, position: Int) {
+
+        holder?.bind {
+            binding ->
+            binding.count = textLineCount
+            binding.textview.setTextColor(textColor)
+            binding.text = text
+            binding.root.setBackgroundColor(bgColor)
+        }
+
+    }
+
+}
+
+
+
+
+class TextViewListDelegateAdapter(val text :ArrayList<String>,val textLineCount :Int ,val textColor :Int ,val top : Int = 0 ,val bottom : Int = 0 ,val left : Int = 0 ,val right : Int = 0,val bgColor:Int = Color.WHITE) :BaseDelegateAdapter<BaseRecyclerViewHolder<TextAdapterLayBinding>,String>(){
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:17
+     * @Note   数据提供者
+     */
+    override fun dataProvider(): Any {
+        return text
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:17
+     * @Note   item点击过滤
+     * @param  position item坐标
+     */
+    override fun itemFilter(position: Int): Boolean {
+        return true
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:18
+     * @Note   构建ViewHolder
+     */
+    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): BaseRecyclerViewHolder<TextAdapterLayBinding> {
+        return BaseRecyclerViewHolder.build(parent, R.layout.text_adapter_lay)
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:19
+     * @Note   获取Item总数
+     */
+    override fun getItemCount(): Int {
+        return text.count()
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:19
+     * @Note   构建LayoutHelper
+     */
+    override fun onCreateLayoutHelper(): LayoutHelper {
+        return LinearLayoutHelper(0,1).then {
+            self ->
+            self.setMargin(left,top,right,bottom)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   TextViewDelegateAdapter
+     * @Date   2018/4/19 下午3:20
+     * @Note   绑定数据
+     */
+    override fun onBindViewHolder(holder: BaseRecyclerViewHolder<TextAdapterLayBinding>?, position: Int) {
+
+        holder?.bind {
+            binding ->
+            binding.count = textLineCount
+            binding.textview.setTextColor(textColor)
+            binding.text = getItem(position)
+            binding.root.setBackgroundColor(bgColor)
+        }
+
+    }
+
+}

+ 74 - 0
common/src/main/code/com/wdkl/ncs/android/lib/adapter/VlayoutHolderAdapter.kt

@@ -0,0 +1,74 @@
+package com.wdkl.ncs.android.lib.adapter
+
+import android.support.v7.widget.RecyclerView
+import android.view.View
+import android.view.ViewGroup
+import com.alibaba.android.vlayout.DelegateAdapter
+import com.alibaba.android.vlayout.LayoutHelper
+
+const val  VlayoutItemType   = 7321
+
+class VlayoutHolderAdapter(val callBack : HolderCallBack) : DelegateAdapter.Adapter<RecyclerView.ViewHolder>() {
+
+    /**
+     * @author LDD
+     * @From   CategoryPlaceHolderAdapter
+     * @Date   2018/1/30 下午2:42
+     * @Note   ViewHolder创建
+     */
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+        return callBack.viewHolderProvider(parent)
+    }
+
+    /**
+     * @author LDD
+     * @From   CategoryPlaceHolderAdapter
+     * @Date   2018/1/30 下午2:42
+     * @Note   Item总数
+     */
+    override fun getItemCount(): Int {
+        return onCreateLayoutHelper().itemCount
+    }
+
+    override fun getItemViewType(position: Int): Int {
+        return VlayoutItemType
+    }
+
+    /**
+     * @author LDD
+     * @From   CategoryPlaceHolderAdapter
+     * @Date   2018/1/30 下午2:42
+     * @Note   提供LayoutHelper
+     */
+    override fun onCreateLayoutHelper(): LayoutHelper {
+        return callBack.layoutHelperProvider()
+    }
+
+    /**
+     * @author LDD
+     * @From   CategoryPlaceHolderAdapter
+     * @Date   2018/1/30 下午2:42
+     * @Note   绑定ViewHolder
+     */
+    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+        callBack.bindView(holder)
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/1/30 下午2:44
+     * @From   CategoryPlaceHolderAdapter
+     * @Note   viewHolder
+     */
+    class PlaceHolder constructor(view : View) : RecyclerView.ViewHolder(view)
+
+
+    interface HolderCallBack{
+
+        fun bindView(holder: RecyclerView.ViewHolder)
+
+        fun layoutHelperProvider():LayoutHelper
+
+        fun viewHolderProvider(parent: ViewGroup):RecyclerView.ViewHolder
+    }
+}

+ 302 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/BaseActivity.kt

@@ -0,0 +1,302 @@
+package com.wdkl.ncs.android.lib.base
+
+import android.content.Context
+import android.content.Intent
+import android.databinding.DataBindingUtil
+import android.databinding.ViewDataBinding
+import android.os.Bundle
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import com.enation.javashop.android.jrouter.JRouter
+import com.wdkl.ncs.android.lib.R
+import com.wdkl.ncs.android.lib.utils.debugLog
+import com.wdkl.ncs.android.lib.utils.errorLog
+import com.enation.javashop.utils.base.tool.BaseToolActivity
+import com.enation.javashop.utils.base.tool.CommonTool
+import com.enation.javashop.utils.base.widget.LoadingDialog
+import kotlinx.android.synthetic.main.custom_loading.view.*
+import java.lang.reflect.Field
+import javax.inject.Inject
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午9:26
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   Activity基类
+ */
+abstract class BaseActivity<PresenterType : BaseContract.BasePresenter, DataBindingType : ViewDataBinding> : BaseToolActivity(),BaseControl {
+
+    /**
+     * @Name  presenter
+     * @Type  T : BaseContract.BasePresenter
+     * @Note  Activity中Presenter Dagger自动注入
+     */
+    @Inject
+    protected lateinit var presenter: PresenterType
+
+    /**
+     * @Name  presenter
+     * @Type  T2 : ViewDataBinding
+     * @Note  DataBinding对象
+     */
+    protected lateinit var mViewBinding: DataBindingType
+
+    /**
+     * @Name  lifecycleCalls
+     * @Type  ArrayList<((state :Int) ->Unit)>
+     * @Note  回调集合
+     */
+    private val lifecycleCalls by lazy { ArrayList<((state :Int) ->Unit)>() }
+
+    /**
+     * @Name  disposableManager
+     * @Type  DisposableManager
+     * @Note  Rx索引管理
+     */
+    protected val disposableManager by lazy { DisposableManager() }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:30
+     * @Note   Activity创建时进行相关的配置
+     */
+    override fun onCreate(savedInstanceState: Bundle?) {
+        try {
+            JRouter.prepare().inject(this)
+        }catch (e :Exception){
+            debugLog("Init","首页初始化完毕")
+        }
+        /**父类初始化*/
+        super.onCreate(savedInstanceState)
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_CREATE)
+        /**创建根视图*/
+        val rootView = layoutInflater.inflate(getLayId(), null, false)
+        /**初始化Databinding对象*/
+        mViewBinding = DataBindingUtil.bind(rootView)
+        /**设置根视图到Activity*/
+        setContentView(rootView)
+        /**执行抽象方法初始化Dagger相应操作*/
+        bindDagger()
+        /**Presenter绑定View*/
+        attachView()
+        /**执行初始化操作*/
+        init()
+        /**执行绑定event操作*/
+        bindEvent()
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:46
+     * @Note   执行生命周期监听 恢复
+     */
+    override fun onResume() {
+        super.onResume()
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_RESUME)
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:46
+     * @Note   执行生命周期监听 暂停
+     */
+    override fun onPause() {
+        super.onPause()
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_PAUSE)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:34
+     * @Note   Activity销毁回调
+     */
+    override fun onDestroy() {
+        super.onDestroy()
+        /**Presenter解除绑定*/
+        detachView()
+        /**DataBinding解除绑定*/
+        mViewBinding.unbind()
+        /**执行抽象方法destory()*/
+        destory()
+        /**解除RX引用*/
+        disposableManager.unDisposable()
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_DESTORY)
+        /**清除声明周期监听引用*/
+        removeAllCallBack()
+        /**处理android4.4.2 底层内存泄漏*/
+        fixInputMethodManagerLeak(activity)
+        errorLog("PageDestory","页面销毁======>$localClassName")
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:39
+     * @Note   获取Activity_LayoutId
+     */
+    protected abstract fun getLayId(): Int
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:44
+     * @Note   执行绑定Dagger操作
+     */
+    protected abstract fun bindDagger()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:45
+     * @Note   执行初始化操作
+     */
+    protected abstract fun init()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:45
+     * @Note   执行绑定事件操作
+     */
+    protected abstract fun bindEvent()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:46
+     * @Note   执行销毁相关操作
+     */
+    protected abstract fun destory()
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/1/19 下午6:03
+     * @Note   绑定View接口
+     */
+    protected open fun attachView() {
+       presenter.attachView(this )
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/5/10 下午3:17
+     * @Note   解绑View接口
+     */
+    protected open fun detachView(){
+        presenter.detachView()
+    }
+
+
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:37
+     * @Note   添加callBack
+     * @param  listener 监听回调
+     */
+    override fun addLifeCycleListener(listener: (state: Int) -> Unit) {
+        lifecycleCalls.add(listener)
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:43
+     * @Note   清除生命周期监听
+     */
+    private fun removeAllCallBack(){
+        lifecycleCalls.clear()
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:44
+     * @Note   在各个生命周期监听执行
+     * @param  state 生命周期状态
+     */
+    private fun lifeCycleDo(state :Int){
+        lifecycleCalls.forEach {
+            item ->
+            item.invoke(state)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/5/27 下午1:22
+     * @Note   页面返回数据
+     * @param  resultCode 返回码
+     * @param  data       数据
+     */
+    open fun resultHandle(resultCode: Int,data: Intent?){
+
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/5/27 下午1:22
+     * @Note   页面返回数据回调
+     */
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        resultHandle(resultCode,data)
+    }
+
+//    /**
+//     * 修改默认加载Dialog
+//     */
+//    override fun loadingDialogProvider(): LoadingDialog {
+//        return CommonTool.createLoadingDialog(this, R.layout.custom_loading,R.id.loadding_image)
+//    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:50
+     * @Note   处理4.4.2 Android底层内存泄漏
+     * @param  destContext 上下文
+     */
+    private fun fixInputMethodManagerLeak(destContext: Context?) {
+        if (destContext == null) {
+            return
+        }
+        val imm = destContext!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager ?: return
+        val arr = arrayOf("mCurRootView", "mServedView", "mNextServedView")
+        var f: Field?
+        var obj_get: Any?
+        arr.indices
+                .asSequence()
+                .map { arr[it] }
+                .forEach {
+                    try {
+                        f = imm.javaClass.getDeclaredField(it)
+                        if (f!!.isAccessible === false) {
+                            f!!.isAccessible = true
+                        }
+                        obj_get = f!!.get(imm)
+                        if (obj_get != null && obj_get is View) {
+                            val v_get = obj_get as View?
+                            if (v_get!!.getContext() === destContext) { // 被InputMethodManager持有引用的context是想要目标销毁的
+                                f!!.set(imm, null) // 置空,破坏掉path to gc节点
+                            }
+                        }
+                    } catch (t: Throwable) {
+                        t.printStackTrace()
+                    }
+                }
+    }
+}

+ 99 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/BaseApplication.kt

@@ -0,0 +1,99 @@
+package com.wdkl.ncs.android.lib.base
+
+import android.annotation.SuppressLint
+import android.app.Application
+import android.content.Context
+import android.content.Intent
+import android.support.multidex.MultiDexApplication
+import com.wdkl.ncs.android.lib.core.framework.Framework
+import com.wdkl.ncs.android.lib.core.hack.AndroidHack
+import com.wdkl.ncs.android.lib.core.runtime.ClassNotFoundInterceptor
+import com.wdkl.ncs.android.lib.utils.AppTool
+import com.enation.javashop.utils.logger.LoggerFactory
+import com.uuzuche.lib_zxing.activity.ZXingLibrary
+
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午9:51
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   Application基类
+ */
+open class BaseApplication : MultiDexApplication() {
+
+    /**
+     * 伴生对象
+     */
+    companion object {
+
+        /**
+         * @Name  appContext
+         * @Type  android.support.multidex.MultiDexApplication()
+         * @Note  应用Application对象(单例)
+         */
+        @SuppressLint("StaticFieldLeak")
+        lateinit var appContext: Application
+
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseApplication
+     * @Data   2017/12/26 上午10:06
+     * @Note   Application创建时调用
+     * @param  ...
+     */
+    override fun onCreate() {
+        super.onCreate()
+        closeAndroidPDialog()
+        AppTool.SystemUI.initStatusBarHeight(applicationContext)
+        /**Logger初始化*/
+        LoggerFactory.create(baseContext)
+                     .diskCache()
+                     .setTag("WdklLog")
+                     .build()
+        /**初始化Application对象*/
+        appContext = this
+        /**开始Activity生命周期监听,并启动AutoClearHelper*/
+        Framework.initActivityLifeController(this)
+        /**注入ClassNotFound异常拦截处理器*/
+        Framework.classNotFoundInterceptor = object : ClassNotFoundInterceptor {
+            override fun call(context: Context, intent: Intent?): Intent? {
+
+                return intent
+            }
+        }
+        /**对Instrumentation进行Hook替换成自定义Instrumentation*/
+        AndroidHack.hookInstrumentation()
+
+        /** 初始化Zxing */
+        ZXingLibrary.initDisplayOpinion(this)
+
+    }
+
+
+    private fun closeAndroidPDialog() {
+        try {
+            val aClass = Class.forName("android.content.pm.PackageParser\$Package")
+            val declaredConstructor = aClass.getDeclaredConstructor(String::class.java)
+            declaredConstructor.isAccessible = true
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+
+        try {
+            val cls = Class.forName("android.app.ActivityThread")
+            val declaredMethod = cls.getDeclaredMethod("currentActivityThread")
+            declaredMethod.isAccessible = true
+            val activityThread = declaredMethod.invoke(null)
+            val mHiddenApiWarningShown = cls.getDeclaredField("mHiddenApiWarningShown")
+            mHiddenApiWarningShown.isAccessible = true
+            mHiddenApiWarningShown.setBoolean(activityThread, true)
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+
+    }
+
+
+}

+ 84 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/BaseContract.kt

@@ -0,0 +1,84 @@
+package com.wdkl.ncs.android.lib.base
+
+import com.enation.javashop.net.engine.model.NetState
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午10:08
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   基础Mvp控制接口
+ */
+interface BaseContract {
+
+    /**
+     * @author  LDD
+     * @Data   2017/12/26 上午10:08
+     * @From   com.wdkl.ncs.android.lib.base.BaseContract
+     * @Note   基础Presenter接口
+     */
+    interface BasePresenter {
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.base.BaseContract.BasePresenter
+         * @Data   2017/12/26 上午10:23
+         * @Note   绑定View
+         * @param  view View
+         * @param  api  Api
+         */
+        fun attachView(view: Any)
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.base.BaseContract.BasePresenter
+         * @Data   2017/12/26 上午10:25
+         * @Note   销毁操作
+         */
+        fun detachView()
+    }
+
+    /**
+     * @author  LDD
+     * @Data   2017/12/26 上午10:26
+     * @From   com.wdkl.ncs.android.lib.base.BaseContract
+     * @Note   View控制类基类
+     */
+    interface BaseView {
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.base.BaseContract.BaseView
+         * @Data   2017/12/26 上午10:27
+         * @Note   展示错误信息
+         * @param  message 错误信息
+         */
+        fun onError(message: String, type :Int = -1)
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.base.BaseContract.BaseView
+         * @Data   2017/12/26 上午10:28
+         * @Note   网络请求完成
+         * @param  message  提示信息
+         */
+        fun complete(message: String = "", type :Int = -1)
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.base.BaseContract.BaseView
+         * @Data   2017/12/26 上午11:00
+         * @Note   网络请求开始
+         */
+        fun start()
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.base.BaseContract.BaseView
+         * @Data   2017/12/26 上午11:01
+         * @Note   网络监听
+         * @param  state 网络状态
+         */
+        fun networkMonitor(state: NetState)
+
+    }
+}

+ 32 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/BaseControl.kt

@@ -0,0 +1,32 @@
+package com.wdkl.ncs.android.lib.base
+
+/**
+ * @author LDD
+ * @Date   2018/3/29 上午11:32
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   基础控制器
+ */
+interface BaseControl {
+
+    /**
+     * @author LDD
+     * @From   BaseControl
+     * @Date   2018/3/29 上午11:33
+     * @Note   添加生命周期监听
+     * @param  listener 监听
+     */
+    fun addLifeCycleListener(listener :((state :Int) ->Unit))
+
+}
+
+/**创建*/
+const val LIFE_CYCLE_CREATE = 1
+
+/**恢复*/
+const val LIFE_CYCLE_RESUME = 2
+
+/**暂停*/
+const val LIFE_CYCLE_PAUSE = 3
+
+/**销毁*/
+const val LIFE_CYCLE_DESTORY = 4

+ 274 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/BaseFragment.kt

@@ -0,0 +1,274 @@
+package com.wdkl.ncs.android.lib.base
+
+import android.databinding.DataBindingUtil
+import android.databinding.ViewDataBinding
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.wdkl.ncs.android.lib.utils.errorLog
+import com.enation.javashop.utils.base.tool.BaseInterface
+import com.enation.javashop.utils.base.tool.BaseToolActivity
+import javax.inject.Inject
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午11:26
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   Fragment基类
+ */
+  abstract class BaseFragment<PresenterType : BaseContract.BasePresenter, DataBindingType : ViewDataBinding> : Fragment(),BaseControl {
+
+    /**
+     * @Name  layout
+     * @Type  android.view.View
+     * @Note  View根视图
+     */
+    private var layout: View? = null
+
+    /**
+     * @Name  activity
+     * @Type  com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Note  Fragment宿主Activity
+     */
+    protected lateinit var activity: BaseToolActivity
+
+    /**
+     * @Name  mViewDataBinding
+     * @Type  T2 : ViewDataBinding
+     * @Note  DataBinding对象
+     */
+    protected lateinit var mViewDataBinding: DataBindingType
+
+    /**
+     * @Name  lifecycleCalls
+     * @Type  ArrayList<((state :Int) ->Unit)>
+     * @Note  回调集合
+     */
+    private val lifecycleCalls by lazy { ArrayList<((state :Int) ->Unit)>() }
+
+    /**
+     * @Name  presenter
+     * @Type  T : BaseContract.BasePresenter
+     * @Note  Fargment的Presenter Dagger自动注入
+     */
+    @Inject
+    protected lateinit var presenter: PresenterType
+
+    /**
+     * @Name  disposableManager
+     * @Type  DisposableManager
+     * @Note  Rx索引管理
+     */
+    protected val disposableManager by lazy { DisposableManager() }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:38
+     * @Note   Fragment创建时调用
+     */
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+        /**初始化根视图及DataBinding*/
+        if (layout == null) {
+            layout = inflater.inflate(getLayId(), null)
+            mViewDataBinding = DataBindingUtil.bind(layout)
+        }
+
+        /**初始化宿主Activity*/
+        activity = getActivity() as BaseToolActivity
+        return layout
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:43
+     * @Note   在Fragment视图创建完毕后调用
+     */
+    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_CREATE)
+
+        /**绑定Dagger*/
+        bindDagger()
+
+        /**绑定视图*/
+        attachView()
+
+        /**执行其他初始化操作*/
+        init()
+
+        /**初始化响应事件*/
+        bindEvent()
+
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:46
+     * @Note   执行生命周期监听 恢复
+     */
+    override fun onResume() {
+        super.onResume()
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_RESUME)
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:46
+     * @Note   执行生命周期监听 暂停
+     */
+    override fun onPause() {
+        super.onPause()
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_PAUSE)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:45
+     * @Note   在Fragment销毁时调用
+     */
+    override fun onDestroyView() {
+
+        /**调用父类方法*/
+        super.onDestroyView()
+
+        /**Presenter解除绑定*/
+        detachView()
+
+        /**ViewBinding解除绑定*/
+        mViewDataBinding.unbind()
+
+        /**执行其他销毁操作*/
+        destory()
+
+        /**解除RX引用*/
+        disposableManager.unDisposable()
+
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_DESTORY)
+
+        /**清除生命周期监听引用*/
+        removeAllCallBack()
+
+        errorLog("FragmentDestory","页面销毁======>${javaClass.name}")
+
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:37
+     * @Note   添加callBack
+     * @param  listener 监听回调
+     */
+    override fun addLifeCycleListener(listener: (state: Int) -> Unit) {
+        lifecycleCalls.add(listener)
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:43
+     * @Note   清除生命周期监听
+     */
+    private fun removeAllCallBack(){
+        lifecycleCalls.clear()
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:44
+     * @Note   在各个生命周期监听执行
+     * @param  state 生命周期状态
+     */
+    private fun lifeCycleDo(state :Int){
+        lifecycleCalls.forEach {
+            item ->
+            item.invoke(state)
+        }
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:47
+     * @Note   获取根视图LayoutId
+     * @return LayoutId
+     */
+    protected abstract fun getLayId(): Int
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:47
+     * @Note   绑定Dagger
+     */
+    protected abstract fun bindDagger()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:50
+     * @Note   初始化其他操作
+     */
+    protected abstract fun init()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:50
+     * @Note   绑定事件
+     */
+    protected abstract fun bindEvent()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:50
+     * @Note   其他销毁操作
+     */
+    protected abstract fun destory()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:52
+     * @Note   销毁View操作
+     */
+    protected open fun attachView() {
+        presenter.attachView(this)
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/5/10 下午3:17
+     * @Note   解绑View接口
+     */
+    protected open fun detachView(){
+        presenter.detachView()
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseFragment
+     * @Data   2017/12/26 上午11:57
+     * @Note   获取工具对象
+     * @return 工具对象
+     */
+    protected fun getUtils(): BaseInterface {
+
+        return activity
+    }
+}

+ 41 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/BaseLaunch.kt

@@ -0,0 +1,41 @@
+package com.wdkl.ncs.android.lib.base
+
+import android.content.Context
+import com.enation.javashop.android.jrouter.logic.template.BaseProvider
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午11:59
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   模块初始化类
+ */
+abstract class BaseLaunch :BaseProvider {
+
+    /**
+     * @Name  context
+     * @Type  android.content.Context
+     * @Note  上下文
+     */
+    protected var context :Context? = null
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseLaunch
+     * @Data   2017/12/26 下午12:02
+     * @Note   执行初始化操作
+     * @param  context 上下文
+     */
+    override fun init(context: Context) {
+        this.context = context
+        moduleInit()
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseLaunch
+     * @Data   2017/12/26 下午12:03
+     * @Note   子类初始化操作
+     */
+    abstract fun moduleInit()
+
+}

+ 49 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/DisposableManager.kt

@@ -0,0 +1,49 @@
+package com.wdkl.ncs.android.lib.base
+
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.disposables.Disposable
+
+/**
+ * @author LDD
+ * @Date   2018/4/11 下午4:33
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   RX引用管理器
+ */
+open class DisposableManager {
+
+    /**
+     * @Name  compositeDisposable
+     * @Type  io.reactivex.disposables.CompositeDisposable
+     * @Note  Disposable管理器
+     */
+    protected var compositeDisposable: CompositeDisposable? = null
+
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.DisposableManager
+     * @Data   2017/12/26 下午12:28
+     * @Note   移除监听
+     */
+    fun unDisposable() {
+        if (compositeDisposable != null) {
+            compositeDisposable!!.dispose()
+        }
+
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.DisposableManager
+     * @Data   2017/12/26 下午12:29
+     * @Note   添加Disposable
+     * @param  disposable 监听引用
+     */
+    fun addDisposable(disposable: Disposable) {
+        if (compositeDisposable == null) {
+            compositeDisposable = CompositeDisposable()
+        }
+        compositeDisposable!!.add(disposable)
+    }
+
+}

+ 384 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/GalleryActivity.kt

@@ -0,0 +1,384 @@
+package com.wdkl.ncs.android.lib.base
+
+import android.content.Context
+import android.content.Intent
+import android.databinding.DataBindingUtil
+import android.databinding.ViewDataBinding
+import android.os.Bundle
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import com.enation.javashop.android.jrouter.JRouter
+import com.wdkl.ncs.android.lib.utils.debugLog
+import com.enation.javashop.photoutils.app.TakePhoto
+import com.enation.javashop.photoutils.app.TakePhotoImpl
+import com.enation.javashop.photoutils.model.InvokeParam
+import com.enation.javashop.photoutils.model.TContextWrap
+import com.enation.javashop.photoutils.model.TResult
+import com.enation.javashop.photoutils.permission.InvokeListener
+import com.enation.javashop.photoutils.permission.PermissionManager
+import com.enation.javashop.photoutils.permission.TakePhotoInvocationHandler
+import com.enation.javashop.photoutils.uitl.TakePhotoinf
+import com.enation.javashop.utils.base.tool.BaseToolActivity
+import java.lang.reflect.Field
+import javax.inject.Inject
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 下午12:07
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   带有相册功能的Activity基类
+ */
+ abstract class GalleryActivity<PresenterType : BaseContract.BasePresenter, DataBindingType : ViewDataBinding>: BaseToolActivity(),BaseControl , TakePhoto.TakeResultListener, InvokeListener, TakePhotoinf {
+
+
+    /**
+     * @Name  takePhoto
+     * @Type  com.enation.javashop.photoutils.app.TakePhoto
+     * @Note  TakePhoto对象
+     */
+    private  var takePhoto : TakePhoto? = null
+
+    /**
+     * @Name  invokeparam
+     * @Type  com.enation.javashop.photoutils.model.InvokeParam
+     * @Note  invokeparam
+     */
+    private  var invokeparam: InvokeParam? = null
+
+    /**
+     * @Name  presenter
+     * @Type  T : BaseContract.BasePresenter
+     * @Note  Activity中Presenter Dagger自动注入
+     */
+    @Inject
+    protected lateinit var presenter: PresenterType
+
+    /**
+     * @Name  presenter
+     * @Type  T2 : ViewDataBinding
+     * @Note  DataBinding对象
+     */
+    protected lateinit var mViewBinding: DataBindingType
+
+    /**
+     * @Name  lifecycleCalls
+     * @Type  ArrayList<((state :Int) ->Unit)>
+     * @Note  回调集合
+     */
+    private val lifecycleCalls by lazy { ArrayList<((state :Int) ->Unit)>() }
+
+    /**
+     * @Name  disposableManager
+     * @Type  DisposableManager
+     * @Note  Rx索引管理
+     */
+    protected val disposableManager by lazy { DisposableManager() }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:30
+     * @Note   Activity创建时进行相关的配置
+     */
+    override fun onCreate(savedInstanceState: Bundle?) {
+        getTakePhoto()!!.onCreate(savedInstanceState)
+        try {
+            JRouter.prepare().inject(this)
+        }catch (e :Exception){
+            debugLog("Init","首页初始化完毕")
+        }
+        /**父类初始化*/
+        super.onCreate(savedInstanceState)
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_CREATE)
+        /**创建根视图*/
+        val rootView = layoutInflater.inflate(getLayId(), null, false)
+        /**初始化Databinding对象*/
+        mViewBinding = DataBindingUtil.bind(rootView)
+        /**设置根视图到Activity*/
+        setContentView(rootView)
+        /**执行抽象方法初始化Dagger相应操作*/
+        bindDagger()
+        /**Presenter绑定View*/
+        attachView()
+        /**执行初始化操作*/
+        init()
+        /**执行绑定event操作*/
+        bindEvent()
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:46
+     * @Note   执行生命周期监听 恢复
+     */
+    override fun onResume() {
+        super.onResume()
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_RESUME)
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:46
+     * @Note   执行生命周期监听 暂停
+     */
+    override fun onPause() {
+        super.onPause()
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_PAUSE)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:34
+     * @Note   Activity销毁回调
+     */
+    override fun onDestroy() {
+        super.onDestroy()
+        /**初始化相机*/
+        takePhoto = null
+        /**Presenter解除绑定*/
+        detachView()
+        /**DataBinding解除绑定*/
+        mViewBinding.unbind()
+        /**执行抽象方法destory()*/
+        destory()
+        /**解除RX引用*/
+        disposableManager.unDisposable()
+        /**执行生命周期监听*/
+        lifeCycleDo(LIFE_CYCLE_DESTORY)
+        /**清除声明周期监听引用*/
+        removeAllCallBack()
+        /**处理android4.4.2 底层内存泄漏*/
+        fixInputMethodManagerLeak(activity)
+        debugLog("PageDestory","页面销毁======>$localClassName")
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:39
+     * @Note   获取Activity_LayoutId
+     */
+    protected abstract fun getLayId(): Int
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:44
+     * @Note   执行绑定Dagger操作
+     */
+    protected abstract fun bindDagger()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:45
+     * @Note   执行初始化操作
+     */
+    protected abstract fun init()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:45
+     * @Note   执行绑定事件操作
+     */
+    protected abstract fun bindEvent()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:46
+     * @Note   执行销毁相关操作
+     */
+    protected abstract fun destory()
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/1/19 下午6:03
+     * @Note   绑定View接口
+     */
+    protected open fun attachView() {
+        presenter.attachView(this )
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/5/10 下午3:17
+     * @Note   解绑View接口
+     */
+    protected open fun detachView(){
+        presenter.detachView()
+    }
+
+
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:37
+     * @Note   添加callBack
+     * @param  listener 监听回调
+     */
+    override fun addLifeCycleListener(listener: (state: Int) -> Unit) {
+        lifecycleCalls.add(listener)
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:43
+     * @Note   清除生命周期监听
+     */
+    private fun removeAllCallBack(){
+        lifecycleCalls.clear()
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/3/29 上午11:44
+     * @Note   在各个生命周期监听执行
+     * @param  state 生命周期状态
+     */
+    private fun lifeCycleDo(state :Int){
+        lifecycleCalls.forEach {
+            item ->
+            item.invoke(state)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/5/27 下午1:22
+     * @Note   页面返回数据
+     * @param  resultCode 返回码
+     * @param  data       数据
+     */
+    open fun resultHandle(resultCode: Int,data: Intent?){
+
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseActivity
+     * @Date   2018/5/27 下午1:22
+     * @Note   页面返回数据回调
+     */
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        getTakePhoto()!!.onActivityResult(requestCode, resultCode, data)
+        resultHandle(resultCode,data)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.BaseActivity
+     * @Data   2017/12/26 上午9:50
+     * @Note   处理4.4.2 Android底层内存泄漏
+     * @param  destContext 上下文
+     */
+    private fun fixInputMethodManagerLeak(destContext: Context?) {
+        if (destContext == null) {
+            return
+        }
+        val imm = destContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+                ?: return
+        val arr = arrayOf("mCurRootView", "mServedView", "mNextServedView")
+        var f: Field?
+        var obj_get: Any?
+        arr.indices
+                .asSequence()
+                .map { arr[it] }
+                .forEach {
+                    try {
+                        f = imm.javaClass.getDeclaredField(it)
+                        if (!f!!.isAccessible) {
+                            f!!.isAccessible = true
+                        }
+                        obj_get = f!!.get(imm)
+                        if (obj_get != null && obj_get is View) {
+                            val v_get = obj_get as View?
+                            if (v_get!!.context === destContext) { // 被InputMethodManager持有引用的context是想要目标销毁的
+                                f!!.set(imm, null) // 置空,破坏掉path to gc节点
+                            }
+                        }
+                    } catch (t: Throwable) {
+                        t.printStackTrace()
+                    }
+                }
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryActivity
+     * @Data   2017/12/26 下午12:12
+     * @Note   保存参数,防止丢失
+     */
+    override fun onSaveInstanceState(outState: Bundle?) {
+        getTakePhoto()!!.onSaveInstanceState(outState)
+        super.onSaveInstanceState(outState)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryActivity
+     * @Data   2017/12/26 下午12:12
+     * @Note   获取相机返回数据
+     */
+    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+        val type = PermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
+        PermissionManager.handlePermissionsResult(this, type, invokeparam, this)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryActivity
+     * @Data   2017/12/26 下午12:15
+     * @Note   鉴权
+     */
+    override fun invoke(invokeParam: InvokeParam?): PermissionManager.TPermissionType {
+        val type = PermissionManager.checkPermission(TContextWrap.of(this), invokeParam!!.getMethod())
+        if (PermissionManager.TPermissionType.WAIT == type) {
+            this.invokeparam = invokeParam
+        }
+        return type
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryActivity
+     * @Data   2017/12/26 下午12:15
+     * @Note   获取TakePhoto实例
+     */
+    override fun getTakePhoto(): TakePhoto? {
+        if (takePhoto == null) {
+            takePhoto = TakePhotoInvocationHandler.of(this).bind(TakePhotoImpl(this, this)) as TakePhoto
+        }
+        return takePhoto
+    }
+
+    /**
+     * 实现获取照片成功接口 子类自由复写
+     */
+    override fun takeSuccess(result: TResult) {}
+
+    /**
+     * 实现获取照片取消接口 子类自由复写
+     */
+    override fun takeCancel() {}
+
+    /**
+     * 实现获取照片失败接口 子类自由复写
+     */
+    override fun takeFail(result: TResult?, msg: String?) {}
+}

+ 136 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/GalleryFragment.kt

@@ -0,0 +1,136 @@
+package com.wdkl.ncs.android.lib.base
+
+import android.content.Intent
+import android.databinding.ViewDataBinding
+import android.os.Bundle
+import com.enation.javashop.photoutils.app.TakePhoto
+import com.enation.javashop.photoutils.app.TakePhotoImpl
+import com.enation.javashop.photoutils.model.InvokeParam
+import com.enation.javashop.photoutils.model.TContextWrap
+import com.enation.javashop.photoutils.model.TResult
+import com.enation.javashop.photoutils.permission.InvokeListener
+import com.enation.javashop.photoutils.permission.PermissionManager
+import com.enation.javashop.photoutils.permission.TakePhotoInvocationHandler
+import com.enation.javashop.photoutils.uitl.TakePhotoinf
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 下午12:07
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   带有相册功能的Fragment基类
+ */
+ abstract class GalleryFragment<PresenterType : BaseContract.BasePresenter, DataBindingType : ViewDataBinding> : BaseFragment<PresenterType,DataBindingType>(), TakePhoto.TakeResultListener, InvokeListener, TakePhotoinf {
+
+    /**
+     * @Name  takePhoto
+     * @Type  com.enation.javashop.photoutils.app.TakePhoto
+     * @Note  TakePhoto对象
+     */
+    private  var takePhoto : TakePhoto? = null
+
+    /**
+     * @Name  invokeparam
+     * @Type  com.enation.javashop.photoutils.model.InvokeParam
+     * @Note  invokeparam
+     */
+    private  var invokeparam: InvokeParam? = null
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryFragment
+     * @Data   2017/12/26 下午12:09
+     * @Note   Activity创建时调用 相册对象注册初始化生命周期
+     */
+    override fun onCreate(savedInstanceState: Bundle?) {
+        getTakePhoto()!!.onCreate(savedInstanceState)
+        super.onCreate(savedInstanceState)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryFragment
+     * @Data   2017/12/26 下午12:12
+     * @Note   保存参数,防止丢失
+     */
+    override fun onSaveInstanceState(outState: Bundle?) {
+        getTakePhoto()!!.onSaveInstanceState(outState)
+        super.onSaveInstanceState(outState)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryFragment
+     * @Data   2017/12/26 下午12:12
+     * @Note   获取相机返回数据
+     */
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        getTakePhoto()!!.onActivityResult(requestCode, resultCode, data)
+        super.onActivityResult(requestCode, resultCode, data)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryFragment
+     * @Data   2017/12/26 下午12:12
+     * @Note   获取相机返回数据
+     */
+    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+        val type = PermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
+        PermissionManager.handlePermissionsResult(getActivity(), type, invokeparam, this)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryFragment
+     * @Data   2017/12/26 下午12:13
+     * @Note   Activity销毁时调用
+     */
+    override fun onDestroyView() {
+        takePhoto=null
+        super.onDestroyView()
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryFragment
+     * @Data   2017/12/26 下午12:15
+     * @Note   获取TakePhoto实例
+     */
+    override fun getTakePhoto(): TakePhoto? {
+        if (takePhoto == null) {
+            takePhoto = TakePhotoInvocationHandler.of(this).bind(TakePhotoImpl(this, this)) as TakePhoto
+        }
+        return takePhoto
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.GalleryFragment
+     * @Data   2017/12/26 下午12:15
+     * @Note   鉴权
+     */
+    override fun invoke(invokeParam: InvokeParam?): PermissionManager.TPermissionType {
+        val type = PermissionManager.checkPermission(TContextWrap.of(this), invokeParam!!.getMethod())
+        if (PermissionManager.TPermissionType.WAIT == type) {
+            this.invokeparam = invokeParam!!
+        }
+        return type
+    }
+
+
+    /**
+     * 实现获取照片成功接口 子类自由复写
+     */
+    override fun takeSuccess(result: TResult?) {}
+
+    /**
+     * 实现获取照片取消接口 子类自由复写
+     */
+    override fun takeCancel() {}
+
+    /**
+     * 实现获取照片失败接口 子类自由复写
+     */
+    override fun takeFail(result: TResult?, msg: String?) {}
+}

+ 81 - 0
common/src/main/code/com/wdkl/ncs/android/lib/base/RxPresenter.kt

@@ -0,0 +1,81 @@
+package com.wdkl.ncs.android.lib.base
+
+import com.wdkl.ncs.android.lib.utils.errorLog
+import com.wdkl.ncs.android.lib.utils.getEventCenter
+import com.wdkl.ncs.android.lib.utils.to
+import com.wdkl.ncs.android.lib.vo.NetStateEvent
+import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.disposables.Disposable
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 下午12:22
+ * @From   com.wdkl.ncs.android.lib.base
+ * @Note   Presenter基类
+ */
+abstract class RxPresenter<out ViewType : BaseContract.BaseView> : DisposableManager() , BaseContract.BasePresenter {
+
+     /**
+      * @Name  mView
+      * @Type  T : BaseContract.BaseView
+      * @Note  View接口
+      */
+     private var mView: ViewType? = null
+
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.RxPresenter
+     * @Data   2017/12/26 下午12:31
+     * @Note   注入View接口和API 注册网络状态Event
+     * @param  view View接口
+     * @param  api  API
+     */
+    override fun attachView(view: Any) {
+        bindDagger()
+        /**注入View接口*/
+        try {
+            this.mView = view.to()
+        }catch (e :Exception){
+            errorLog("Interface Not Implement","Fragment/Activity 没有实现对应BaseView接口")
+            throw java.lang.Exception("Interface Not Implement : Fragment/Activity 没有实现对应BaseView接口")
+        }
+        /**注册网络状态事件*/
+        var disposable = getEventCenter().register(NetStateEvent::class.java) {
+            result ->
+            this.mView!!.networkMonitor(result.state)
+        }
+        addDisposable(disposable)
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.base.RxPresenter
+     * @Data   2017/12/26 下午12:35
+     * @Note   销毁操作
+     */
+    override fun detachView() {
+        this.mView = null
+        unDisposable()
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/1/19 下午6:16
+     * @From   com.wdkl.ncs.android.lib.base.RxPresenter
+     * @Note   依赖注入初始化
+     */
+    abstract fun bindDagger()
+
+    /**
+     * @author LDD
+     * @From   RxPresenter
+     * @Date   2018/1/19 下午6:16
+     * @Note   View接口提供者
+     * @return View接口
+     */
+    fun providerView():ViewType{
+        return mView!!
+    }
+
+}

+ 103 - 0
common/src/main/code/com/wdkl/ncs/android/lib/bind/BaseBindingHelper.kt

@@ -0,0 +1,103 @@
+package com.wdkl.ncs.android.lib.bind
+
+import android.databinding.BindingAdapter
+import android.os.Build
+import android.support.constraint.ConstraintLayout
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import android.text.style.AbsoluteSizeSpan
+import android.util.TypedValue
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.engine.DiskCacheStrategy
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.wdkl.ncs.android.lib.utils.errorLog
+import com.wdkl.ncs.android.lib.utils.getColorCompatible
+import com.wdkl.ncs.android.lib.utils.then
+import com.enation.javashop.imagepluin.R
+import com.enation.javashop.utils.base.tool.ScreenTool
+
+/**
+ * @author LDD
+ * @Date   2018/1/19 下午3:20
+ * @From   com.wdkl.ncs.android.lib.bind
+ * @Note   databinding辅助类
+ */
+object BaseBindingHelper {
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.binding.BindingHelper
+     * @Data   2017/12/26 上午9:23
+     * @Note   加载图片
+     * @param  imageView 需要加载图片的ImageView
+     * @param  url       图片Url
+     */
+    @BindingAdapter(value = ["bind:url"],requireAll = false)
+    @JvmStatic fun loadImage(imageView: ImageView?, url: String?) {
+        if(imageView == null || url == null ||url == ""){
+            return
+        }
+        Glide.with(imageView.context).load(url).thumbnail(0.1f).diskCacheStrategy(DiskCacheStrategy.ALL).placeholder(R.drawable.image_loading).error(R.drawable.image_error).into(imageView)
+    }
+
+    @BindingAdapter(value = ["bind:url_without_holder"],requireAll = false)
+    @JvmStatic fun loadImageWithoutHoldlder(imageView: ImageView?, url: String?) {
+        if(imageView == null || url == null ||url == ""){
+            return
+        }
+        Glide.with(imageView.context).load(url).thumbnail(0.1f).diskCacheStrategy(DiskCacheStrategy.ALL).error(R.drawable.image_error).into(imageView)
+    }
+    /**
+     * @author LDD
+     * @From   BaseBindingHelper
+     * @Date   2018/2/24 下午2:22
+     * @Note   显示价格大小
+     * @param  value 价格
+     */
+    @BindingAdapter(value = ["bind:price_text"], requireAll = false)
+    @JvmStatic
+    fun setPriceText(view: TextView, value: Double) {
+        view.text = SpannableStringBuilder("¥$value").then { self ->
+            self.setSpan(AbsoluteSizeSpan(ScreenTool.dip2px(view.context, 12f)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+            self.setSpan(AbsoluteSizeSpan(ScreenTool.dip2px(view.context, 15f)), 1, self.indexOf("."), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+            self.setSpan(AbsoluteSizeSpan(ScreenTool.dip2px(view.context, 12f)), self.indexOf("."), self.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+        }
+    }
+    /**
+     * @author LDD
+     * @From   HomeFragmentBindHelper
+     * @Date   2018/1/30 下午3:05
+     * @Note   透明渐变
+     */
+    @BindingAdapter(value = ["bind:alpha"],requireAll = false)
+    @JvmStatic fun backgroundGradient(view: ConstraintLayout, value:Int){
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            var alpha = value
+            if (alpha > 255) {
+                alpha = 255
+                if (view.background.alpha == 255) {
+                    return
+                }
+            }
+            view.background.alpha = alpha
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseBindingHelper
+     * @Date   2018/2/28 上午9:34
+     * @Note   解决ConstraintLayout 无法上色
+     */
+    @BindingAdapter(value = ["bind:backgroundColor"],requireAll = false)
+    @JvmStatic fun setBackgroundColor(view : View, value: Int){
+        view.setBackgroundColor(value)
+    }
+
+    @BindingAdapter(value = ["bind:text_count_for_line"],requireAll = true)
+    @JvmStatic fun setTextSize(tv :TextView , textCount :Int){
+        tv.setTextSize(TypedValue.COMPLEX_UNIT_PX,ScreenTool.getScreenWidth(BaseApplication.appContext)/textCount)
+    }
+}

+ 97 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/framework/ActivityLifeController.kt

@@ -0,0 +1,97 @@
+package com.wdkl.ncs.android.lib.core.framework
+
+import android.app.Activity
+import android.app.Application
+import android.os.Bundle
+import com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+import com.wdkl.ncs.android.lib.utils.AutoClearHelper
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午7:45
+ * @From   com.wdkl.ncs.android.lib.core.framework
+ * @Note   Activity生命周期回调
+ */
+class ActivityLifeController :Application.ActivityLifecycleCallbacks {
+
+    /**
+     * @Name  autoClearHelper
+     * @Type  com.wdkl.ncs.android.lib.utils.AutoClearHelper
+     * @Note  变量清理辅助类
+     */
+    private var isOpenAutoClear = false
+
+    /**
+     * @author  LDD
+     * @From    ActivityLifeController
+     * @Data   2017/12/26 上午7:48
+     * @Note   开启
+     */
+    fun withAutoValueHelper():ActivityLifeController{
+        isOpenAutoClear = true
+        return this
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework ActivityLifeController
+     * @Data   2017/12/26 上午8:22
+     * @Note   Activity处于不显示或者半透明状态
+     * @return Activity
+     */
+    override fun onActivityPaused(p0: Activity?) {
+
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework ActivityLifeController
+     * @Data   2017/12/26 上午8:22
+     * @Note   Activity处于完全显示状态
+     * @return Activity
+     */
+    override fun onActivityResumed(p0: Activity?) {
+
+    }
+
+    override fun onActivityStarted(p0: Activity?) {
+
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework ActivityLifeController
+     * @Data   2017/12/26 上午8:20
+     * @Note   Activity销毁方法
+     * @return 销毁的Activity
+     */
+    override fun onActivityDestroyed(p0: Activity?) {
+        if (p0 != null && isOpenAutoClear) {
+            AutoClearHelper.intance.destory(p0.localClassName)
+        }
+        if (p0 != null) {
+            JavaShopActivityTask.instance.popFromActivityStack(p0)
+        }
+    }
+
+    override fun onActivitySaveInstanceState(p0: Activity?, p1: Bundle?) {
+
+    }
+
+    override fun onActivityStopped(p0: Activity?) {
+
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework ActivityLifeController
+     * @Data   2017/12/26 上午8:25
+     * @Note   Activity创建回调
+     * @param  p0 创建的Activity
+     */
+    override fun onActivityCreated(p0: Activity?, p1: Bundle?) {
+        if (p0 != null) {
+            JavaShopActivityTask.instance.pushToActivityStack(p0)
+        }
+    }
+}

+ 67 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/framework/Framework.kt

@@ -0,0 +1,67 @@
+package com.wdkl.ncs.android.lib.core.framework
+
+import android.app.Application
+import com.wdkl.ncs.android.lib.core.runtime.ClassNotFoundInterceptor
+import com.wdkl.ncs.android.lib.core.split.ComponentManager
+import com.wdkl.ncs.android.lib.core.split.ComponentManagerImpl
+import com.wdkl.ncs.android.lib.utils.Do
+import java.io.File
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午8:28
+ * @From   com.wdkl.ncs.android.lib.core.framework
+ * @Note   JavaShop FrameWork层入口
+ */
+ class Framework {
+
+    /**
+     * @author  LDD
+     * @Data   2017/12/26 上午8:29
+     * @From   com.wdkl.ncs.android.lib.core.framework Framework
+     * @Note   Framework伴生对象
+     */
+    companion object {
+
+        /**
+         * @Name  com.wdkl.ncs.android.lib.core.framework.Framework.Companion.classNotFoundInterceptor
+         * @Type  com.wdkl.ncs.android.lib.core.runtime.ClassNotFoundInterceptor
+         * @Note  Class拦截器在Class文件查找失败时执行
+         */
+        var classNotFoundInterceptor : ClassNotFoundInterceptor? = null
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.core.framework.Framework Companion
+         * @Data   2017/12/26 上午8:32
+         * @Note   初始化Activity生命周期监听器
+         * @param  app  应用Application对象
+         */
+        fun initActivityLifeController(app:Application){
+            app.registerActivityLifecycleCallbacks(ActivityLifeController().withAutoValueHelper())
+        }
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.core.framework.Framework Companion
+         * @Data   2017/12/26 上午8:35
+         * @Note   Moudle安装
+         * @param  pakeageName    模块包名
+         * @param  moudleLocation 模块物理路径
+         */
+        fun installMoudle(pakeageName:String, moudleLocation:File){
+            ComponentManager.get().installMoudle(pakeageName,moudleLocation)
+        }
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.core.framework.Framework Companion
+         * @Data   2017/12/26 上午8:36
+         * @Note   Moudle卸载
+         * @param  pakeageName 根据包名进行卸载
+         */
+        fun unstallMoudle(pakeageName:String){
+            ComponentManager.get().unstallMoudle(pakeageName)
+        }
+    }
+}

+ 161 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/framework/InstallResourceHelper.kt

@@ -0,0 +1,161 @@
+package com.wdkl.ncs.android.lib.core.framework
+
+import android.content.Context
+
+
+/**
+ * @author LDD
+ * @Date   2018/1/17 上午10:15
+ * @From   com.wdkl.ncs.android.middleware.resource
+ * @Note   加载已安装资源
+ */
+class InstallResourceHelper {
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:15
+     * @Note   私有构造方法 防止外部实例化
+     */
+    private constructor()
+
+    /**
+     * @Name  install
+     * @Type  ResourceManager.Installed
+     * @Note  已安装资源
+     */
+    private lateinit var install :ResourceManager.Installed
+
+    /**
+     * @Name  CurrentPackageName
+     * @Type  String
+     * @Note  资源包名
+     */
+    private lateinit var CurrentPackageName : String
+
+    /**
+     * @author LDD
+     * @Date   2018/1/17 上午10:16
+     * @From   InstallResourceHelper
+     * @Note   伴生对象 实现单例
+     */
+    companion object {
+        /**
+         * @Name  com.wdkl.ncs.android.lib.core.framework.InstallResourceHelper.Companion.instance
+         * @Type  com.wdkl.ncs.android.lib.core.framework.InstallResourceHelper
+         * @Note  单例对象 懒加载
+         */
+        private val instance by lazy { InstallResourceHelper() }
+
+        /**
+         * @author LDD
+         * @From   Companion
+         * @Date   2018/1/17 上午10:17
+         * @Note   获取单例对象
+         * @return 已安装文件资源
+         */
+        fun get(): InstallResourceHelper {
+            return instance
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:18
+     * @Note   初始化
+     * @param  context 上下文 一般为Application
+     * @param  packageName 需要加在资源的包名
+     */
+    fun initInstalled(context :Context,packageName:String?){
+        CurrentPackageName = if (packageName == null) {context.applicationContext.packageName} else {packageName}
+        ResourceManager.init(context)
+        install = ResourceManager.installed()
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:19
+     * @Note   初始化 该方法一般用于加载本地资源 用于资源获取出错时使用
+     * @param  context 上下文 一般为Application
+     */
+    fun initInstalled(context: Context){
+        initInstalled(context,null)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取mipmap资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getMipmapId(name : String):Int{
+        return install.getResourceID(CurrentPackageName,"mipmap",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取drawble资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getDrawableId(name : String):Int{
+        return install.getResourceID(CurrentPackageName,"drawble",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取color资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getColorId(name : String):Int{
+
+        return install.getResourceID(CurrentPackageName,"color",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取style资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getStyleId(name : String):Int{
+
+        return install.getResourceID(CurrentPackageName,"style",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取string资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getStringId(name : String):Int{
+        return install.getResourceID(CurrentPackageName,"string",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取anim资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getAnimId(name : String):Int{
+        return install.getResourceID(CurrentPackageName,"anim",name)
+    }
+
+}

+ 75 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/framework/JavaShopInstrumentationHook.java

@@ -0,0 +1,75 @@
+package com.wdkl.ncs.android.lib.core.framework;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+import java.lang.reflect.Method;
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午8:38
+ * @From   com.wdkl.ncs.android.lib.core.framework
+ * @Note   Instrumentation 的自定义Hook
+ */
+public class JavaShopInstrumentationHook extends Instrumentation {
+
+    /**
+     * @Name  oldInstrumentation
+     * @Type  android.app.Instrumentation
+     * @Note  系统原始Instrumentation
+     */
+    public Instrumentation oldInstrumentation;
+
+    /**
+     * @Name  EXEC_START_ACTIVITY
+     * @Type  java.lang.String
+     * @Note  execStartActivity方法名 反射时使用
+     */
+    public static final String EXEC_START_ACTIVITY = "execStartActivity";
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework JavaShopInstrumentationHook
+     * @Data   2017/12/26 上午8:43
+     * @Note   构造方法 传入原始 Instrumentation
+     * @param  oldInstrumentation 原始 Instrumentation
+     */
+    public JavaShopInstrumentationHook(Instrumentation oldInstrumentation) {
+        this.oldInstrumentation = oldInstrumentation;
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework
+     * @Data   2017/12/26 上午8:42
+     * @Note   这个方法是由于原始方法里面的Instrumentation有execStartActivity方法来定的
+     */
+    public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
+                                            Intent intent, int requestCode, Bundle options) {
+        Method execStartActivity = null;
+        //由于这个方法是隐藏的,所以需要反射来调用,先找到这方法
+        try {
+            execStartActivity = Instrumentation.class.getDeclaredMethod(
+                    EXEC_START_ACTIVITY,
+                    Context.class, IBinder.class, IBinder.class, Activity.class,
+                    Intent.class, int.class, Bundle.class);
+            //因为该属性为私有 设置权限
+            execStartActivity.setAccessible(true);
+            return (ActivityResult) execStartActivity.invoke(oldInstrumentation, who,
+                    contextThread, token, target, intent, requestCode, options);
+        } catch (Exception e) {
+
+            try {
+                return (ActivityResult) execStartActivity.invoke(oldInstrumentation, who,
+                        contextThread, token, target, Framework.Companion.getClassNotFoundInterceptor().call(target,intent), requestCode, options);
+            } catch (Exception e1) {
+                Log.e("StartActivityError",e1.getMessage());
+                return null;
+            }
+        }
+    }
+}

+ 269 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/framework/ResourceManager.java

@@ -0,0 +1,269 @@
+package com.wdkl.ncs.android.lib.core.framework;
+
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import dalvik.system.DexClassLoader;
+
+public class ResourceManager {
+
+    private static final String TAG = "ResourceManager";
+
+    private ResourceManager() {
+    }
+
+    public static void init(Context context) {
+        UnInstalled.sManager.init(context);
+        Installed.sManager.init(context);
+    }
+
+    public static UnInstalled unInstalled() {
+        return UnInstalled.sManager;
+    }
+
+    public static Installed installed() {
+        return Installed.sManager;
+    }
+
+    /**
+     * 针对于未安装应用
+     */
+    public static class UnInstalled {
+
+        static final UnInstalled sManager = new UnInstalled();
+
+        private Context mContext;
+        private Map<String, LoadedResource> mRescources = new HashMap<String, LoadedResource>();
+        private String mDexDir;
+
+        private UnInstalled() {
+
+        }
+
+        /**
+         * 初始化
+         *
+         * @param context
+         */
+        public void init(Context context) {
+            mContext = context.getApplicationContext();
+            File dexDir = mContext.getDir("dex", Context.MODE_PRIVATE);
+            if (!dexDir.exists()) {
+                dexDir.mkdir();
+            }
+            mDexDir = dexDir.getAbsolutePath();
+        }
+
+        /**
+         * 获取未安装应用资源的ID
+         *
+         * @param packageName
+         * @param fieldName
+         * @return
+         */
+        public int getResourceID(String packageName, String type, String fieldName) {
+            int resID = 0;
+            LoadedResource recource = getUnInstalledRecource(packageName);
+            String rClassName = packageName + ".R$" + type;
+            Log.w(TAG, "resource class:" + rClassName + ",fieldName:" + fieldName);
+            try {
+                Class cls = recource.classLoader.loadClass(rClassName);
+                resID = (Integer) cls.getField(fieldName).get(null);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            return resID;
+        }
+
+        /**
+         * 获取未安装应用Drawable
+         *
+         * @param packageName
+         * @param fieldName
+         * @return
+         */
+        public Drawable getDrawable(String packageName, String fieldName) {
+            Drawable drawable = null;
+            int resourceID = getResourceID(packageName, "drawable", fieldName);
+            LoadedResource recource = getUnInstalledRecource(packageName);
+            if (recource != null) {
+                drawable = recource.resources.getDrawable(resourceID);
+            }
+            return drawable;
+        }
+
+        /**
+         * 加载未安装应用资源包
+         *
+         * @param resourcePath
+         * @return
+         */
+        public LoadedResource loadResource(String resourcePath) {
+
+            LoadedResource loadResource = null;
+
+            PackageInfo info = queryPackageInfo(resourcePath);    //    获取未安装APK的PackageInfo
+            if (info != null) {    //   获取成功
+                loadResource = mRescources.get(info.packageName);    // 先从缓存中取, 存在则直接返回, 不重复添加. 否则就搜索添加
+                if (loadResource == null) {
+                    try {
+                        AssetManager assetManager = AssetManager.class.newInstance();    // 创建AssetManager实例
+                        Class cls = AssetManager.class;
+                        Method method = cls.getMethod("addAssetPath", String.class);
+                        method.invoke(assetManager, resourcePath);    // 反射设置资源加载路径
+                        Resources resources = new Resources(assetManager, mContext.getResources().getDisplayMetrics(),
+                                mContext.getResources().getConfiguration());    // 构造出正确的Resource
+                        loadResource = new LoadedResource();
+                        loadResource.resources = resources;
+                        loadResource.packageName = info.packageName;
+                        loadResource.classLoader = new DexClassLoader(resourcePath, mDexDir, null,
+                                mContext.getClassLoader());    //    设置正确的类加载器, 因为需要去加载R文件
+                        mRescources.put(info.packageName, loadResource);    // 缓存
+                        Log.w(TAG, "build resource:" + resourcePath);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+
+            Log.w(TAG, "load resource:" + resourcePath);
+            return loadResource;
+
+        }
+
+        /**
+         * 获取未安装应用PackageInfo
+         *
+         * @param resourcePath
+         * @return
+         */
+        private PackageInfo queryPackageInfo(String resourcePath) {
+            return mContext.getPackageManager().getPackageArchiveInfo(resourcePath, PackageManager.GET_ACTIVITIES);
+        }
+
+        /**
+         * 获取未安装应用LoadResource
+         *
+         * @param packageName
+         * @return
+         */
+        public LoadedResource getUnInstalledRecource(String packageName) {
+            LoadedResource loadResource = mRescources.get(packageName);
+            if (loadResource == null) {
+                Log.w(TAG, "resource " + packageName + " not founded");
+            }
+            return loadResource;
+        }
+
+    }
+
+    /**
+     * 针对于已安装应用
+     */
+    public static class Installed {
+        static final Installed sManager = new Installed();
+
+        private Context mContext;
+        private Map<String, LoadedResource> mResources = new HashMap<String, LoadedResource>();
+
+        private Installed() {
+
+        }
+
+        /**
+         * 初始化
+         *
+         * @param context
+         */
+        public void init(Context context) {
+            mContext = context.getApplicationContext();
+        }
+
+        /**
+         * 获取已安装应用资源
+         *
+         * @param packageName
+         */
+        public LoadedResource getInstalledResource(String packageName) {
+
+            LoadedResource resource = mResources.get(packageName);    // 先从缓存中取, 没有就去加载
+
+            if (resource == null) {
+                try {
+                    Context context = mContext.createPackageContext(packageName,
+                            Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+                    resource = new LoadedResource();
+                    resource.packageName = packageName;
+                    resource.resources = context.getResources();
+                    resource.classLoader = context.getClassLoader();
+                    mResources.put(packageName, resource);    // 得到结果缓存起来
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+
+            return resource;
+        }
+
+        /**
+         * 获取资源ID
+         *
+         * @param packageName
+         * @param type
+         * @param fieldName
+         * @return
+         */
+        public int getResourceID(String packageName, String type, String fieldName) {
+
+            int resID = 0;
+            LoadedResource installedResource = getInstalledResource(packageName);    // 获取已安装APK的资源
+            if (installedResource != null) {
+                String rClassName = packageName + ".R$" + type;    // 根据匿名内部类的命名, 拼写出R文件的包名+类名
+                try {
+                    Class cls = installedResource.classLoader.loadClass(rClassName);    //  加载R文件
+                    resID = (Integer) cls.getField(fieldName).get(null);    //  反射获取R文件对应资源名的ID
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } else {
+                Log.w(TAG, "resource is null:" + packageName);
+            }
+            return resID;
+        }
+
+        /**
+         * 获取已加载应用Drawable
+         *
+         * @param packageName
+         * @param fieldName
+         * @return
+         */
+        public Drawable getDrawable(String packageName, String fieldName) {
+            Drawable drawable = null;
+            int resourceID = getResourceID(packageName, "drawable", fieldName);
+            LoadedResource installedResource = getInstalledResource(packageName);
+            if (installedResource != null) {
+                drawable = installedResource.resources.getDrawable(resourceID);
+            }
+            return drawable;
+        }
+    }
+    public static class LoadedResource {
+        public Resources resources;
+        public String packageName;
+        public ClassLoader classLoader;
+    }
+}
+
+
+

+ 141 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/framework/UnInstallResourceHelper.kt

@@ -0,0 +1,141 @@
+package com.wdkl.ncs.android.lib.core.framework
+
+import android.content.Context
+
+/**
+ * @author LDD
+ * @Date   2018/1/17 上午10:26
+ * @From   com.wdkl.ncs.android.middleware.resource
+ * @Note   加载未安装apk的资源文件
+ */
+class UnInstallResourceHelper {
+
+    /**
+     * @Name  resource
+     * @Type  ResourceManager.LoadedResource
+     * @Note  加载完成的资源
+     */
+    private lateinit var resource : ResourceManager.LoadedResource
+
+    /**
+     * @Name  packageName
+     * @Type  String
+     * @Note  资源包名
+     */
+    private lateinit var packageName : String
+
+    /**
+     * @author LDD
+     * @Date   2018/1/17 上午10:23
+     * @From   com.wdkl.ncs.android.middleware.resource
+     * @Note   伴生对象
+     */
+    companion object {
+
+        /**
+         * @Name  com.wdkl.ncs.android.lib.core.framework.UnInstallResourceHelper.Companion.instance
+         * @Type  com.wdkl.ncs.android.lib.core.framework.UnInstallResourceHelper
+         * @Note  单例
+         */
+        private val instance by lazy { UnInstallResourceHelper() }
+
+        /**
+         * @author LDD
+         * @From   Companion
+         * @Date   2018/1/17 上午10:25
+         * @Note   获取单例对象
+         * @return 未安装资源
+         */
+        fun get(): UnInstallResourceHelper {
+            return instance
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   UnInstallResourceHelper
+     * @Date   2018/1/17 上午10:22
+     * @Note   初始化
+     * @param  context 用户上下文
+     * @param  path    外部资源路径
+     */
+    fun init(context: Context,path:String){
+        ResourceManager.init(context)
+        resource = ResourceManager.unInstalled().loadResource(path)
+        packageName = resource.packageName
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取mipmap资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getMipmapId(name : String):Int{
+        return ResourceManager.unInstalled().getResourceID(packageName,"mipmap",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取drawable资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getDrawableId(name : String):Int{
+        return ResourceManager.unInstalled().getResourceID(packageName,"drawble",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取color资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getColorId(name : String):Int{
+
+        return ResourceManager.unInstalled().getResourceID(packageName,"color",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取style资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getStyleId(name : String):Int{
+
+        return ResourceManager.unInstalled().getResourceID(packageName,"style",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取string资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getStringId(name : String):Int{
+        return ResourceManager.unInstalled().getResourceID(packageName,"string",name)
+    }
+
+    /**
+     * @author LDD
+     * @From   InstallResourceHelper
+     * @Date   2018/1/17 上午10:20
+     * @Note   获取anim资源ID
+     * @param  name 资源名
+     * @return 资源ID
+     */
+    fun getAnimId(name : String):Int{
+        return ResourceManager.unInstalled().getResourceID(packageName,"anim",name)
+    }
+}

+ 68 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/hack/AndroidHack.kt

@@ -0,0 +1,68 @@
+package com.wdkl.ncs.android.lib.core.hack
+
+import android.app.Instrumentation
+import android.util.Log
+import com.wdkl.ncs.android.lib.core.framework.JavaShopInstrumentationHook
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午8:49
+ * @From   com.wdkl.ncs.android.lib.core.hack
+ * @Note   JavaShop Hack入口
+ */
+class AndroidHack {
+
+    /**
+     * 伴生对象
+     */
+    companion object {
+
+            /**
+             * @author  LDD
+             * @From   com.wdkl.ncs.android.lib.core.hack.AndroidHack Companion
+             * @Data   2017/12/26 上午8:50
+             * @Note   替换系统 hookInstrumentation 为null时自动进行JavaShopInstrumentationHook
+             * @param  instrumentationHook 需要进行hook的自定义Instrumentation
+             */
+            fun hookInstrumentation(instrumentationHook: Instrumentation?){
+
+                try {
+                    val mMainThreadClass = Class.forName("android.app.ActivityThread")
+
+                    //获取主线程
+                    val getMainThread = mMainThreadClass.getDeclaredMethod("currentActivityThread")
+                    //私有属性 设置访问权限
+                    getMainThread.isAccessible = true
+                    val currentActivityThread = getMainThread.invoke(null)
+
+                    // 获取mInstrumentation对象
+                    val mInstrumentationField = mMainThreadClass.getDeclaredField("mInstrumentation")
+                    //私有属性 设置访问权限
+                    mInstrumentationField.isAccessible = true
+                    //获取系统Instrumentation
+                    val instrumentation = mInstrumentationField.get(currentActivityThread) as Instrumentation
+                    // Hook Instrumentation 替换成我们自定义Instrumentation
+                    if (instrumentationHook==null){
+                        mInstrumentationField.set(currentActivityThread, JavaShopInstrumentationHook(instrumentation))
+                    }else{
+                        mInstrumentationField.set(currentActivityThread,instrumentationHook)
+                    }
+
+                    Log.i("InstrumentationHook", "JavaShop hook instrumentation success!")
+                } catch (ex: Exception) {
+                    Log.e("InstrumentationHook", "JavaShop hook instrumentation failed! [" + ex.message + "]")
+                }
+
+            }
+
+            /**
+             * @author  LDD
+             * @From   com.wdkl.ncs.android.lib.core.hack.AndroidHack Companion
+             * @Data   2017/12/26 上午8:53
+             * @Note   执行1参hookInstrumentation方法 直接使用JavaShopInstrumentationHook
+             */
+            fun hookInstrumentation(){
+                hookInstrumentation(null)
+            }
+        }
+}

+ 23 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/runtime/ClassNotFoundInterceptor.kt

@@ -0,0 +1,23 @@
+package com.wdkl.ncs.android.lib.core.runtime
+
+import android.content.Context
+import android.content.Intent
+
+/**
+ * @author  LDD
+ * @Data   2017/12/26 上午8:56
+ * @From   com.wdkl.ncs.android.lib.core.runtime
+ * @Note   拦截器接口
+ */
+interface ClassNotFoundInterceptor {
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.runtime ClassNotFoundInterceptor
+     * @Data   2017/12/26 上午8:57
+     * @Note   拦截器回调方法
+     * @param  context 上下文
+     * @param  intent  Intent
+     */
+    fun call(context:Context,intent :Intent?):Intent?
+}

+ 136 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/runtime/JavaShopActivityTask.kt

@@ -0,0 +1,136 @@
+package com.wdkl.ncs.android.lib.core.runtime
+
+import android.app.Activity
+import java.lang.ref.WeakReference
+import java.util.ArrayList
+
+ /**
+  * @author  LDD
+  * @Data   2017/12/26 上午9:00
+  * @From   com.wdkl.ncs.android.lib.core.runtime
+  * @Note   Activity栈
+  */
+ class JavaShopActivityTask {
+
+     /**
+      * @Name  activityList
+      * @Type  java.util.ArrayList
+      * @Note  Activity序列
+      */
+    private var activityList = ArrayList<WeakReference<Activity>>()
+
+     /**
+      * 伴生对象
+      */
+    companion object {
+         /**
+          * @Name  com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask.Companion.instance
+          * @Type  com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+          * @Note  单例
+          */
+         val instance = JavaShopActivityTask()
+    }
+
+     /**
+      * 构造方法私有化
+      */
+     private constructor()
+
+     /**
+      * @author  LDD
+      * @From   com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+      * @Data   2017/12/26 上午9:08
+      * @Note   获取当前应用Activity栈
+      * @return 当前应用Activity栈
+      */
+    fun getActivityArray(): ArrayList<WeakReference<Activity>>{
+        return activityList
+    }
+
+     /**
+      * @author  LDD
+      * @From   com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+      * @Data   2017/12/26 上午9:09
+      * @Note   获取当前栈顶Activity
+      * @return 当前栈顶Activity
+      */
+    fun peekTopActivity(): Activity? {
+        if (activityList != null && activityList.size > 0) {
+            val ref = activityList.get(activityList.size - 1)
+            if (ref != null && ref!!.get() != null) {
+                return ref!!.get()
+            }
+        }
+        return null
+    }
+
+     /**
+      * @author  LDD
+      * @From   com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+      * @Data   2017/12/26 上午9:13
+      * @Note   Activity创建时调用 添加activity到栈中
+      * @param  activity 新创建的Activity
+      */
+    fun pushToActivityStack(activity: Activity) {
+        activityList.add(WeakReference(activity))
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+     * @Data   2017/12/26 上午9:14
+     * @Note   activity销毁时调用 在栈中移除销毁的Activity
+     * @param  activity 销毁的Activity
+     */
+    fun popFromActivityStack(activity: Activity) {
+        for (x in activityList.indices) {
+            val ref = activityList.get(x)
+            if (ref != null && ref!!.get() != null && ref!!.get() === activity) {
+                activityList.remove(ref)
+                return
+            }
+        }
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+     * @Data   2017/12/26 上午9:16
+     * @Note   清除当前Activity栈
+     */
+    fun clearActivityStack() {
+        try {
+            for (ref in activityList) {
+                if (ref != null && ref!!.get() != null && !ref!!.get()!!.isFinishing()) {
+                    ref!!.get()!!.finish()
+                }
+            }
+        } catch (e: Throwable) {
+
+        } finally {
+            activityList.clear()
+        }
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+     * @Data   2017/12/26 上午9:17
+     * @Note   判断当前Activity栈是否为空
+     * @return Boolean 是否为空
+     */
+    fun isActivityStackEmpty(): Boolean {
+        return sizeOfActivityStack() == 0
+    }
+
+     /**
+      * @author  LDD
+      * @From   com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+      * @Data   2017/12/26 上午9:18
+      * @Note   获取当前Activity栈大小
+      * @return 当前Activity栈大小
+      */
+    fun sizeOfActivityStack(): Int {
+        return activityList.size
+    }
+}

+ 59 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/split/ComponentManager.kt

@@ -0,0 +1,59 @@
+package com.wdkl.ncs.android.lib.core.split
+
+import java.io.File
+
+/**
+ * @author  LDD
+ * @Date   2018/1/15 下午4:10
+ * @From   com.wdkl.ncs.android.lib.core.split
+ * @Note   组件控制器协议
+ */
+interface ComponentManager {
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework.Framework Companion
+     * @Data   2017/12/26 上午8:35
+     * @Note   Moudle安装
+     * @param  pakeageName    模块包名
+     * @param  moudleLocation 模块绝对路径
+     */
+    fun installMoudle(pakeageName:String, moudleLocation: File)
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework.Framework Companion
+     * @Data   2017/12/26 上午8:36
+     * @Note   Moudle卸载
+     * @param  pakeageName 根据包名进行卸载
+     */
+    fun unstallMoudle(pakeageName:String)
+
+
+    /**
+     * @author  LDD
+     * @Date   2018/1/15 下午4:08
+     * @From   ComponentManager
+     * @Note   伴生对象
+     */
+    companion object {
+
+        /**
+         * @Name  com.wdkl.ncs.android.lib.core.split.ComponentManagerImpl.Companion.INSTANCE
+         * @Type  com.wdkl.ncs.android.lib.core.split.ComponentManager
+         * @Note  组件控制器单例
+         */
+        private val INSTANCE:ComponentManager by lazy { ComponentManagerImpl() }
+
+        /**
+         * @author LDD
+         * @From   Companion
+         * @Date   2018/1/15 下午4:22
+         * @Note   获取单例
+         * @return 单例
+         */
+        fun get() :ComponentManager{
+            return INSTANCE
+        }
+    }
+}

+ 36 - 0
common/src/main/code/com/wdkl/ncs/android/lib/core/split/ComponentManagerImpl.kt

@@ -0,0 +1,36 @@
+package com.wdkl.ncs.android.lib.core.split
+
+import java.io.File
+
+/**
+ * @author  LDD
+ * @Date   2018/1/15 下午4:10
+ * @From   com.wdkl.ncs.android.lib.core.split
+ * @Note   组件控制器单例
+ */
+class ComponentManagerImpl : ComponentManager{
+
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework.Framework Companion
+     * @Date   2017/12/26 上午8:35
+     * @Note   Moudle安装
+     * @param  pakeageName    模块包名
+     * @param  moudleLocation 模块绝对路径
+     */
+    override fun installMoudle(pakeageName:String, moudleLocation: File){
+
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.core.framework.Framework Companion
+     * @Date   2017/12/26 上午8:36
+     * @Note   Moudle卸载
+     * @param  pakeageName 根据包名进行卸载
+     */
+    override fun unstallMoudle(pakeageName:String){
+
+    }
+}

+ 15 - 0
common/src/main/code/com/wdkl/ncs/android/lib/jni/CommonJNI.kt

@@ -0,0 +1,15 @@
+package com.wdkl.ncs.android.lib.jni
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午5:29
+ * @From   com.wdkl.ncs.android.lib.jni
+ * @Note   JavaShop通用JNI入口
+ */
+class CommonJNI {
+    init {
+        System.loadLibrary("JavaShopCommonNDK")
+    }
+
+    external fun sayHello(): String
+}

+ 466 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/AppTool.kt

@@ -0,0 +1,466 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.os.Build
+import android.os.Handler
+import android.provider.Settings
+import android.support.v4.widget.DrawerLayout
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.view.animation.AlphaAnimation
+import android.view.animation.Animation
+import android.view.animation.AnimationSet
+import android.view.animation.TranslateAnimation
+import android.view.inputmethod.InputMethodManager
+import android.widget.LinearLayout
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.enation.javashop.net.engine.utils.ThreadFromUtils
+import com.enation.javashop.utils.base.tool.ScreenTool
+import io.reactivex.BackpressureStrategy
+import io.reactivex.Flowable
+import io.reactivex.Observable
+import io.reactivex.disposables.Disposable
+import java.io.IOException
+import java.io.InputStream
+import java.net.HttpURLConnection
+import java.net.MalformedURLException
+import java.net.URL
+import java.nio.charset.Charset
+import java.text.NumberFormat
+import java.util.concurrent.TimeUnit
+
+/**
+ * @author  LDD
+ * @Date   2018/1/10 下午5:46
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   App通用工具类
+ */
+object AppTool {
+
+    /**
+     * @author LDD
+     * @Date   2018/3/15 上午11:03
+     * @From   AppTool
+     * @Note   动画工具类
+     */
+    object Anim {
+
+        /**
+         * @author LDD
+         * @From   Anim
+         * @Date   2018/3/15 上午11:04
+         * @Note   构建popwindow进入动画
+         * @param  context 上下文
+         * @param  fromYDelta 开始y点
+         * @param  duration 动画时间
+         */
+        @JvmStatic
+        fun createPopInAnimation(context: Context, fromYDelta: Float, duration: Long): Animation {
+            val set = AnimationSet(context, null)
+            set.setFillAfter(true)
+            val animation = TranslateAnimation(0f, 0f, fromYDelta, 0f)
+            animation.setDuration(duration)
+            set.addAnimation(animation)
+            val alphaAnimation = AlphaAnimation(0f, 1f)
+            alphaAnimation.setDuration(duration)
+            set.addAnimation(alphaAnimation)
+            return set
+        }
+
+        /**
+         * @author LDD
+         * @From   Anim
+         * @Date   2018/3/15 上午11:04
+         * @Note   构建popwindow进入动画
+         * @param  context 上下文
+         * @param  toYDelta 结束y点
+         * @param  duration 动画时间
+         */
+        @JvmStatic
+        fun createPopOutAnimation(context: Context, toYDelta: Float, duration: Long): Animation {
+            val set = AnimationSet(context, null)
+            set.setFillAfter(true)
+            val animation = TranslateAnimation(0f, 0f, 0f, toYDelta)
+            animation.duration = duration
+            set.addAnimation(animation)
+            val alphaAnimation = AlphaAnimation(1f, 0f)
+            alphaAnimation.duration = duration
+            set.addAnimation(alphaAnimation)
+            return set
+        }
+    }
+
+    /**
+     * @author  LDD
+     * @Date   2018/1/10 下午5:46
+     * @From   com.wdkl.ncs.android.lib.utils.AppTool
+     * @Note   网络工具类
+     */
+    object Net {
+
+        /**
+         * @author LDD
+         * @From   Net
+         * @Date   2018/1/16 下午1:07
+         * @Note   验证网速 并toast
+         * @param  bits 网速
+         */
+        @JvmStatic
+        fun verifyNetSpeed(bits: Double) {
+            if (bits < 100) {
+                showMessage("当前网络质量差")
+            }
+        }
+
+        /**
+         * @author LDD
+         * @From   Net
+         * @Date   2018/1/16 下午1:07
+         * @Note   验证网速 网络不好时执行回调  由使用者决定是否显示Toast信息
+         * @param  bits 网速
+         */
+        @JvmStatic
+        fun verifyNetSpeed(bits: Double, callBack: (() -> (Unit)) -> (Unit)) {
+            val toastCallBack = {
+                showMessage("当前网络质量差")
+            }
+            if (bits < 100) {
+                callBack.invoke(toastCallBack)
+            }
+        }
+    }
+
+    /**
+     * @author  LDD
+     * @Date   2018/1/10 下午5:46
+     * @From   com.wdkl.ncs.android.lib.utils.AppTool
+     * @Note   RxJava工具类
+     */
+    object Rx {
+
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/5/18 上午11:27
+     * @From   com.wdkl.ncs.android.lib.utils.AppTool
+     * @Note   文件工具类
+     */
+    object File {
+
+        /**
+         * @author LDD
+         * @From   File
+         * @Date   2018/5/18 上午11:33
+         * @Note   读取Assets文件夹下的配置信息
+         * @param  context  上下文
+         * @param  fileName 文件名
+         */
+        @JvmStatic
+        fun readAssetsText(context: Context, fileName: String): String {
+            try {
+                val ins = context.assets.open(fileName)
+                val size = ins.available()
+                var buffer = ByteArray(size)
+                ins.read(buffer)
+                ins.close()
+                var text = String(buffer, Charset.forName("utf-8"))
+                return text
+            } catch (e :IOException) {
+                return "读取错误,请检查文件名"
+            }
+        }
+
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/3/15 下午3:07
+     * @From   AppTool
+     * @Note   关于时间的操作
+     */
+    object Time {
+        private val handler by lazy { Handler() }
+
+        /**
+         * @author LDD
+         * @From   com.wdkl.ncs.android.lib.utils.AppTool.Rx
+         * @Date   2018/1/10 下午5:41
+         * @Note   Observable扩展方法 延时执行
+         * @param  milliSeconds 延时毫秒数
+         * @param  handlerProcessor     处理回调
+         */
+        @JvmStatic
+        fun delay(milliSeconds: Long, handlerProcessor: () -> (Unit)) {
+            handler.postDelayed(handlerProcessor, milliSeconds)
+        }
+    }
+
+    object Calculation{
+
+        /**
+         * @author LDD
+         * @From   Calculation
+         * @Date   2018/5/21 下午3:21
+         * @Note   获取百分比
+         * @param  total 总数
+         * @param  current 当前
+         */
+        @JvmStatic
+        fun getPercentage(total: Int, current: Int): Int {
+            val numberFormat = NumberFormat.getInstance()
+            // 设置精确到小数点后2位
+            numberFormat.maximumFractionDigits = 0
+            val result = numberFormat.format(current.toFloat() / total.toFloat() * 100)
+            return Integer.valueOf(result)!!
+        }
+
+    }
+
+
+    /**
+     * @author LDD
+     * @Date   2018/1/11 上午10:31
+     * @From   com.wdkl.ncs.android.lib.utils.AppTool
+     * @Note   关于设置
+     */
+    object Setting {
+
+        /**
+         * @author  LDD
+         * @From    com.wdkl.ncs.android.lib.utils.AppTool.Setting
+         * @Date    2018/1/11 上午10:31
+         * @Note    跳转网络设置
+         * @param   activity 调用页面
+         */
+        @JvmStatic
+        fun systemNetSetting(activity: AppCompatActivity) {
+            activity.startActivity(Intent(Settings.ACTION_WIRELESS_SETTINGS))
+        }
+
+        /**
+         * @author  LDD
+         * @From    com.wdkl.ncs.android.lib.utils.AppTool.Setting
+         * @Date    2018/1/11 上午10:31
+         * @Note    跳转WIFI设置
+         * @param   activity 调用页面
+         */
+        @JvmStatic
+        fun systemWifiSetting(activity: AppCompatActivity) {
+            activity.startActivity(Intent(Settings.ACTION_WIFI_SETTINGS))
+        }
+
+        /**
+         * @author  LDD
+         * @From    com.wdkl.ncs.android.lib.utils.AppTool.Setting
+         * @Date    2018/1/11 上午10:31
+         * @Note    跳转Mobile设置
+         * @param   activity 调用页面
+         */
+        @JvmStatic
+        fun systemMobileSetting(activity: AppCompatActivity) {
+            activity.startActivity(Intent(Settings.ACTION_DATA_ROAMING_SETTINGS))
+        }
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/4/2 下午3:12
+     * @From   AppTool
+     * @Note   图片工具类
+     */
+    object Image {
+
+        /**
+         * @author LDD
+         * @From   Image
+         * @Date   2018/4/2 下午3:23
+         * @Note   url获取Bitmap
+         * @param  url 图片URL
+         */
+        @JvmStatic
+        fun urlToBitmap(url: String): Observable<Bitmap> {
+            return Observable.create { subscriber ->
+                var fileUrl: URL? = null
+                val bitmap: Bitmap
+
+                try {
+                    fileUrl = URL(url)
+                } catch (e: MalformedURLException) {
+                    subscriber.onError(e)
+                }
+
+
+                try {
+                    val conn = fileUrl!!.openConnection() as HttpURLConnection
+                    conn.doInput = true
+                    conn.connect()
+                    val inStream = conn.inputStream
+                    bitmap = BitmapFactory.decodeStream(inStream)
+                    inStream.close()
+                    subscriber.onNext(bitmap)
+                } catch (e: IOException) {
+                    subscriber.onError(e)
+                }
+            }
+        }
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/4/2 下午3:12
+     * @From   AppTool
+     * @Note   系统UI工具类
+     */
+    object SystemUI {
+
+        private var statusBarHeight : Int = 0
+
+        @JvmStatic fun getStatusBarHeight() : Int{
+            return statusBarHeight
+        }
+
+        @JvmStatic fun initStatusBarHeight(context: Context){
+            val resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android")
+            if (resourceId > 0) {
+                statusBarHeight = context.getResources().getDimensionPixelSize(resourceId)
+            }
+        }
+
+
+        /**
+         * @author  LDD
+         * @From   SystemUI
+         * @Date   2018/1/12 下午4:09
+         * @Note   设置状态栏透明  4.4.2及以下 不可设置导航栏变色
+         * @param  activity 需要状态栏透明的页面
+         * @param  bottomColor  导航栏变色
+         */
+        @JvmStatic
+        fun ImmersiveWithBottomBarColor(activity: Activity, bottomColor: Int) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                    //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
+                    var window = activity.window
+                    var decorView = window.decorView
+                    //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间
+                    var option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    decorView.systemUiVisibility = option
+                    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
+                    window.statusBarColor = Color.TRANSPARENT
+                    //导航栏颜色也可以正常设置
+                    window.navigationBarColor = bottomColor
+                } else {
+                    var window = activity.window
+                    var attributes = window.attributes
+                    var flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+                    attributes.flags = flagTranslucentStatus
+                    window.attributes = attributes
+                }
+            }
+        }
+
+        /**
+         * @author LDD
+         * @From   SystemUI
+         * @Date   2018/1/15 下午2:07
+         * @Note   设置当页面有drawlayout时,让drawlayout也实现变色
+         * @param  activity  需要设置的也米娜
+         * @param  rid       当页内容视图
+         */
+        @JvmStatic
+        fun KitkatNavigationViewImmersive(activity: Activity, rid: Int) {
+            //要在内容布局增加状态栏,否则会盖在侧滑菜单上
+            val rootView = activity.findViewById<ViewGroup>(android.R.id.content) as ViewGroup
+            //DrawerLayout 则需要在第一个子视图即内容试图中添加padding
+            val parentView = rootView.getChildAt(0)
+            val linearLayout = LinearLayout(activity)
+            linearLayout.orientation = LinearLayout.VERTICAL
+            //侧滑菜单
+            val drawer = parentView as DrawerLayout
+            //内容视图
+            val content = activity.findViewById<View>(rid)
+            //将内容视图从 DrawerLayout 中移除
+            drawer.removeView(content)
+            //添加内容视图
+            linearLayout.addView(content, content.layoutParams)
+            //将带有占位状态栏的新的内容视图设置给 DrawerLayout
+            drawer.addView(linearLayout, 0)
+
+            if (parentView != null && Build.VERSION.SDK_INT >= 14) {
+                parentView.fitsSystemWindows = true
+                //布局预留状态栏高度的 padding
+                if (parentView is DrawerLayout) {
+                    //将主页面顶部延伸至status bar;虽默认为false,但经测试,DrawerLayout需显示设置
+                    parentView.clipToPadding = false
+                }
+            }
+        }
+
+
+        /**
+         * @author LDD
+         * @From   SystemUI
+         * @Date   2018/1/29 下午8:28
+         * @Note   显示或隐藏导航栏
+         * @param  activity 需要操作的activity
+         * @param  isShow   显示还是隐藏
+         */
+        @JvmStatic
+        fun showNavigationBar(activity: Activity, isShow: Boolean) {
+            if (isShow) {
+                activity.window.decorView.setOnSystemUiVisibilityChangeListener(null)
+                activity.window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)
+            } else {
+                activity.window.decorView.setOnSystemUiVisibilityChangeListener {
+                    activity.window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN)
+                }
+                activity.window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN)
+            }
+        }
+
+        /**
+         * @author LDD
+         * @From   SystemUI
+         * @Date   2018/4/17 下午1:44
+         * @Note   dp转px
+         * @param  dp dp大小
+         */
+        @JvmStatic
+        fun dpToPx(dp: Float): Int {
+            return ScreenTool.dip2px(BaseApplication.appContext, dp)
+        }
+
+        @JvmStatic
+        fun getNavigationBarHeight(activity: Activity): Int {
+            val resources = activity.getResources()
+            val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
+            val height = resources.getDimensionPixelSize(resourceId)
+            return height
+        }
+
+        /**
+         * @author LDD
+         * @From   SystemUI
+         * @Date   2018/5/15 下午4:47
+         * @Note   关闭软键盘
+         * @param  context 页面
+         */
+        @JvmStatic
+        fun hideKeyBoard(context: Activity) {
+            val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+            if (imm.isActive && context.currentFocus != null) {
+                if (context.currentFocus.windowToken != null) {
+                    imm.hideSoftInputFromWindow(context.currentFocus.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
+                }
+            }
+        }
+    }
+}

+ 47 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/AutoClearHelper.kt

@@ -0,0 +1,47 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.util.Log
+import java.util.IdentityHashMap
+
+
+/**
+ * @author  LDD
+ * @Data   2017/12/21 下午5:25
+ * @Note   自动清除数据辅助类 在Activity销毁时,自动处理其中参数,作用于该类
+ * {@link com.wdkl.ncs.android.lib.utils.AutoClearValue}
+ */
+class AutoClearHelper {
+
+    companion object {
+        val intance:AutoClearHelper by lazy {  AutoClearHelper() }
+    }
+
+    private constructor()
+
+    /**
+     * 储存
+     */
+    private var valueMap : IdentityHashMap<String, () -> Unit> = IdentityHashMap()
+
+    /**
+     * 创建
+     */
+    fun create(key:String,value:()->Unit){
+        valueMap.put(key,value)
+    }
+
+    /**
+     * Activity销毁时调用
+     */
+    fun destory(name :String){
+        valueMap.keys.filter { it == name }.forEach { valueMap[it]!!.invoke() }
+        valueMap.clear()
+    }
+
+    /**
+     * 获取当前AutoValuemap中Value总数
+     */
+    fun valueCount():Int{
+        return valueMap.size
+    }
+}

+ 69 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/AutoClearValue.kt

@@ -0,0 +1,69 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.app.Activity
+import android.support.v4.app.Fragment
+import android.support.v4.app.FragmentManager
+import android.util.Log
+
+/**
+ * @author  LDD
+ * @Data   2017/12/21 下午5:53
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   自动清理变量
+ */
+class AutoClearValue<ValueType> {
+
+    /**
+     * @Name  value
+     * @Type  ValueType
+     * @Note  自动处理的V安略
+     */
+    private var value : ValueType? = null
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils AutoClearValue
+     * @Data   2017/12/22 下午3:40
+     * @Note   在Fragment中使用的构造方法构造方法
+     * @param  fragment 所在的Fragment
+     */
+    constructor(fragment :Fragment , value: ValueType?) {
+        fragment.fragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks(){
+            override fun onFragmentDestroyed(fm: FragmentManager?, f: Fragment?) {
+                if (f == fragment) {
+                    this@AutoClearValue.value = null
+                    if (fm != null) {
+                        fm.unregisterFragmentLifecycleCallbacks(this)
+                    }
+                }
+            }
+        },false)
+        get()
+        this.value = value
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils AutoClearValue
+     * @Data   2017/12/22 下午3:41
+     * @Note   在Activity中使用的构造方法
+     * @param  activity 所在的Activity
+     */
+    constructor(activity: Activity,value:ValueType?){
+        AutoClearHelper.intance.create(activity.localClassName,{
+            this.value = null
+        })
+
+        this.value = value
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils AutoClearValue
+     * @Data   2017/12/21 下午5:53
+     * @Note   获取value
+     */
+    fun get() : ValueType?{
+        return value
+    }
+}

+ 53 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/BaseRecyclerViewHolder.kt

@@ -0,0 +1,53 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.databinding.DataBindingUtil
+import android.databinding.ViewDataBinding
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.ViewGroup
+
+/**
+ * @author LDD
+ * @Date   2018/2/2 下午4:02
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   RecyclerView ViewHolder 基类
+ */
+class BaseRecyclerViewHolder<out BindType:ViewDataBinding>(val databinding:BindType) :RecyclerView.ViewHolder(databinding.root) {
+
+    companion object {
+        /**
+         * @author LDD
+         * @From   BaseRecyclerViewHolder
+         * @Date   2018/4/10 上午11:18
+         * @Note   快速构建
+         * @param  parent   父容器
+         * @param  layoutId 布局ID
+         */
+        fun <BindType:ViewDataBinding>build(parent: ViewGroup?,layoutId : Int) : BaseRecyclerViewHolder<BindType>{
+            return BaseRecyclerViewHolder(DataBindingUtil.bind(LayoutInflater.from(parent?.context).inflate(layoutId,parent,false)))
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseRecyclerViewHolder
+     * @Date   2018/2/2 下午4:03
+     * @Note   获取viewbinding
+     * @return ViewDataBinding
+     */
+    fun getBinding():BindType{
+        return databinding
+    }
+
+    /**
+     * @author LDD
+     * @From   BaseRecyclerViewHolder
+     * @Date   2018/2/2 下午4:05
+     * @Note   绑定数据
+     * @param  block 绑定回调
+     */
+    inline fun bind(block :(binding : BindType)-> Unit){
+        block(databinding)
+    }
+
+}

+ 46 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/ChineseSortHelper.kt

@@ -0,0 +1,46 @@
+package com.wdkl.ncs.android.lib.utils
+
+import net.sourceforge.pinyin4j.PinyinHelper
+import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType
+import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat
+import net.sourceforge.pinyin4j.format.HanyuPinyinToneType
+import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination
+
+
+/**
+ * @author LDD
+ * @Date   2018/3/27 下午5:46
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   获取汉字首字母
+ */
+object ChineseSortHelper {
+    fun getFirstSpell(string: String): String {
+        val pybf = StringBuffer()
+        val arr = string.toCharArray()
+        val defaultFormat = HanyuPinyinOutputFormat()
+        defaultFormat.caseType = HanyuPinyinCaseType.LOWERCASE
+        defaultFormat.toneType = HanyuPinyinToneType.WITHOUT_TONE
+        for (i in arr.indices) {
+            if (arr[i].toInt() > 128) { //如果已经是字母就不用转换了
+                try {
+                    //获取当前汉字的全拼
+                    val temp = PinyinHelper.toHanyuPinyinStringArray(
+                            arr[i], defaultFormat)
+                    if (temp != null) {
+                        pybf.append(temp[0][0])// 取首字母
+                    }
+                } catch (e: BadHanyuPinyinOutputFormatCombination) {
+                    e.printStackTrace()
+                }
+
+            } else {
+                if (arr[i] in 'a'..'z') {
+                    arr[i].minus(32)
+                }
+                pybf.append(arr[i])
+            }
+        }
+        return pybf.toString().substring(0,1).toUpperCase()
+    }
+
+}

+ 144 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/ConnectionObserver.kt

@@ -0,0 +1,144 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.content.Context
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.enation.javashop.net.engine.plugin.connection.ConnectionQuality
+import com.enation.javashop.net.engine.plugin.exception.ExceptionHandle
+import com.enation.javashop.net.engine.utils.VoiNetTool
+import io.reactivex.Observer
+import io.reactivex.disposables.Disposable
+import org.json.JSONObject
+import retrofit2.HttpException
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午3:43
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   可以监听网络状态的观察者
+ */
+abstract class ConnectionObserver<T> : BaseObserver<T>(BaseApplication.appContext) {
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionObserver
+     * @Data   2017/12/22 下午3:44
+     * @Note   实现onStar方法 在此开始执行网络监听 并执行onStartWithConnection抽象方法
+     */
+    override fun onStart() {
+        ConnectionQualityMonitor.INSTANCE.startSample()
+        onStartWithConnection()
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionObserver
+     * @Data   2017/12/22 下午3:46
+     * @Note   实现onNext方法 在此停止网络监听 并执行onNextWithConnection
+     *           connectionBitsOfSecond方法 传递网络状态,网络速率
+     */
+    override fun onNext(p0: T) {
+        ConnectionQualityMonitor.INSTANCE.stopSample()
+        onNextWithConnection(p0,ConnectionQualityMonitor.INSTANCE.getConnectionQuanlity())
+        connectionBitsOfSecond(ConnectionQualityMonitor.INSTANCE.getConnectionBits())
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionObserver
+     * @Data   2017/12/22 下午3:50
+     * @Note   实现onError方法 传递网络状态,网络速率
+     */
+    override fun onError(p0: ExceptionHandle.ResponeThrowable) {
+        ConnectionQualityMonitor.INSTANCE.stopSample()
+        onErrorWithConnection(p0,ConnectionQualityMonitor.INSTANCE.getConnectionQuanlity())
+        connectionBitsOfSecond(ConnectionQualityMonitor.INSTANCE.getConnectionBits())
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionObserver
+     * @Data   2017/12/22 下午3:51
+     * @Note   传递当前网络速率 需要继承者重写
+     * @param  bits 网络速率
+     */
+    open fun connectionBitsOfSecond(bits: Double){}
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionObserver
+     * @Data   2017/12/22 下午3:53
+     * @Note   抽象方法,子类可以监听网络请求开始,并可以获得当前网络状态
+     */
+    abstract fun onStartWithConnection()
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionObserver
+     * @Data   2017/12/22 下午3:55
+     * @Note   抽象方法,子类可以监听网络请求成功,并获取当前网络状态
+     * @param  result 网络请求结果
+     * @param  connectionQuality 网络状态
+     */
+    abstract fun onNextWithConnection(result:T,connectionQuality :ConnectionQuality)
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionObserver
+     * @Data   2017/12/22 下午3:56
+     * @Note   抽象方法,子类可以监听网络请求失败,并获取当前网络状态
+     * @param  error 自定义网络错误
+     * @param  connectionQuality 当前网络状态
+     */
+    abstract fun onErrorWithConnection(error: ExceptionHandle.ResponeThrowable,connectionQuality :ConnectionQuality)
+}
+
+abstract class BaseObserver<T>(private val context: Context) : Observer<T> {
+
+    override fun onSubscribe(disposable: Disposable) {
+        if (VoiNetTool.getAPNType(this.context) == VoiNetTool.netType.noneNet) {
+            disposable.dispose()
+            this.onNoneNet()
+        } else {
+            this.onStart()
+            this.attachSubscribe(disposable)
+        }
+
+    }
+
+    override fun onError(e: Throwable) {
+        if (e is HttpException) {
+            var errorJSon = e.response().errorBody()!!.getJsonString()
+            if (errorJSon.contains("html")){
+                this.onError(ExceptionHandle.handleException(e))
+                return
+            }
+            val obj = JSONObject(errorJSon)
+            if (obj.has("code")){
+                val result = ExceptionHandle.ResponeThrowable(e,420)
+                result.customMessage = obj.getString("message")
+                this.onError(result)
+            }else{
+                this.onError(ExceptionHandle.handleException(e))
+            }
+        } else {
+            this.onError(ExceptionHandle.ResponeThrowable(e, 1000).then {
+                if (e.message == null) {
+                    it.customMessage = "加载失败!"
+                } else {
+                    it.customMessage = e.message
+                }
+            })
+        }
+
+    }
+
+    abstract fun onError(var1: ExceptionHandle.ResponeThrowable)
+
+    abstract fun onStart()
+
+    abstract fun attachSubscribe(var1: Disposable)
+
+    open fun onNoneNet() {}
+
+    override fun onComplete() {}
+}

+ 66 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/ConnectionQualityMonitor.kt

@@ -0,0 +1,66 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.util.Log
+import com.enation.javashop.net.engine.plugin.connection.ConnectionQuality
+import com.enation.javashop.net.engine.plugin.connection.ConnectionClassManager
+import com.enation.javashop.net.engine.plugin.connection.DeviceBandwidthSampler
+
+
+/**
+ * @Coder  LDD
+ * @Data   2017/12/22 下午3:58
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   网络状态监听
+ */
+class ConnectionQualityMonitor {
+
+    /**伴生对象,其中的方法相当于Java的静态方法*/
+    companion object {
+        /**单利设计模式 懒汉式*/
+        val INSTANCE:ConnectionQualityMonitor by lazy { ConnectionQualityMonitor() }
+    }
+
+    /**
+     * @Coder  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionQualityMonitor
+     * @Data   2017/12/22 下午3:59
+     * @Note   开始网络取样
+     */
+    fun startSample(){
+        DeviceBandwidthSampler.getInstance().startSampling()
+    }
+
+    /**
+     * @Coder  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionQualityMonitor
+     * @Data   2017/12/22 下午3:59
+     * @Note   停止网络取样
+     */
+    fun stopSample(){
+        DeviceBandwidthSampler.getInstance().stopSampling()
+    }
+
+    /**
+     * @Coder  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionQualityMonitor
+     * @Data   2017/12/22 下午4:00
+     * @Note   获取当前网络状态
+     * @return 当前网络状态
+     */
+    fun getConnectionQuanlity() :ConnectionQuality{
+        val quanlity = ConnectionClassManager.getInstance().currentBandwidthQuality
+        return quanlity
+    }
+
+    /**
+     * @Coder  LDD
+     * @From   com.wdkl.ncs.android.lib.utils ConnectionQualityMonitor
+     * @Data   2017/12/22 下午4:00
+     * @Note   获取当前网络速率
+     * @return 当前网络速率
+     */
+    fun getConnectionBits() :Double{
+      return  ConnectionClassManager.getInstance().downloadKBitsPerSecond
+    }
+
+}

+ 374 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/Do.kt

@@ -0,0 +1,374 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.os.Looper
+import java.util.concurrent.Executors
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午4:06
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   快速切换线程工具类 保证线程执行顺序
+ */
+  class Do :SendResultInterface,NomalResultInterface {
+
+    /**
+     * 伴生对象
+     */
+    companion object {
+
+        /**
+         * @author  LDD
+         * @From   com.wdkl.ncs.android.lib.utils.Do Companion
+         * @Data   2017/12/22 下午4:09
+         * @Note   初始化
+         */
+        fun prepare(): NomalResultInterface {
+            return Do()
+        }
+    }
+
+    /**
+     * @Name  threadPool
+     * @Type  ExecutorService
+     * @Note  可缓存线程池,用于处理非UI线程任务
+     */
+    private var threadPool = Executors.newFixedThreadPool(1)
+
+    /**
+     * @Name  threadQueue
+     * @Type  ArrayList<Any>
+     * @Note  任务序列
+     */
+    private var threadQueue : ArrayList<Any> = ArrayList()
+
+    /**
+     * @Name  onUI
+     * @Type  Int
+     * @Note  UI线程处理标记
+     */
+    private val onUI = 1
+
+    /**
+     * @Name  onThread
+     * @Type  Int
+     * @Note  非UI线程处理标记
+     */
+    private val onThread = 2
+
+    /**
+     * @Name  threadPool
+     * @Type  Handler
+     * @Note  UI任务处理Hander
+     */
+    private val uiThread = android.os.Handler(Looper.getMainLooper())
+
+    /**
+     * @Name  index
+     * @Type  int
+     * @Note  处理标记,编辑当前处理到第几个任务
+     */
+    private var index= 0
+
+    /**
+     * @Name  runFlag
+     * @Type  boolean
+     * @Note  标识当前任务序列是否执行完成
+     */
+    private var runFlag = false
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:16
+     * @Note   开始执行方法 递归处理事件队列
+     */
+    override fun execute(){
+        if (threadQueue.size>0){
+            val data = threadQueue[index]
+            if (runFlag){
+                execute()
+                return
+            }
+            runFlag = true
+            when (data) {
+                is DoModel -> {
+                    nomalDo()
+                }
+                is DoSendModel -> {
+                    sendDo()
+                }
+            }
+        }
+    }
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:17
+     * @Note   常规事件执行方法
+     */
+    private fun nomalDo(){
+        val data:DoModel = threadQueue[index] as DoModel
+        if (data.thread == onUI){
+            uiThread.post{
+                data.call.invoke {
+                    index+=1
+                    if (threadQueue.size > index){
+                        when (threadQueue[index]) {
+                            is DoModel -> {
+                                nomalDo()
+                            }
+                            is DoSendModel -> {
+                                sendDo()
+                            }
+                        }
+                    }else{
+                        clear()
+                    }
+                }
+            }
+        }else if(data.thread == onThread){
+            threadPool.execute {
+                data.call.invoke {
+                    index+=1
+                    if (threadQueue.size > index){
+                        when (threadQueue[index]) {
+                            is DoModel -> {
+                                nomalDo()
+                            }
+                            is DoSendModel -> {
+                                sendDo()
+                            }
+                        }
+                    }else{
+                        clear()
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:18
+     * @Note   发送参数事件处理方法
+     */
+    private fun sendDo(){
+        val data:DoSendModel = threadQueue[index] as DoSendModel
+        if (data.thread == onUI){
+            uiThread.post{
+                data.call.invoke {
+                    value ->
+                    index +=1
+                    if (threadQueue.size > index){
+                        when (threadQueue[index]) {
+                            is DoResultModel ->{
+                                resultDo(value)
+                            }
+                        }
+                    }else{
+                        clear()
+                    }
+                }
+            }
+        }else if(data.thread == onThread){
+            threadPool.execute {
+                data.call.invoke {
+                    value ->
+                    index +=1
+                    if (threadQueue.size > index){
+                        when (threadQueue[index]) {
+                            is DoResultModel ->{
+                                resultDo(value)
+                            }
+                        }
+                    }else{
+                        clear()
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:19
+     * @Note   接受参数事件处理方法
+     * @param  value 所接受的参数
+     */
+    private fun resultDo(value :Any){
+        val data:DoResultModel = threadQueue[index] as DoResultModel
+        if (data.thread == onUI){
+            uiThread.post{
+                data.call.invoke(value) {
+                    index +=1
+                    if (threadQueue.size > index){
+                        when (threadQueue[index]) {
+                            is DoModel -> {
+                                nomalDo()
+                            }
+                            is DoSendModel -> {
+                                sendDo()
+                            }
+                        }
+                    }else{
+                        clear()
+                    }
+                }
+            }
+        }else if(data.thread == onThread){
+            threadPool.execute {
+                data.call.invoke(value) {
+                    index +=1
+                    if (threadQueue.size > index){
+                        when (threadQueue[index]) {
+                            is DoModel -> {
+                                nomalDo()
+                            }
+                            is DoSendModel -> {
+                                sendDo()
+                            }
+                        }
+                    }else{
+                        clear()
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:20
+     * @Note   清除线程池 索引 复原运行标记
+     */
+    private fun clear(){
+        index = 0
+        threadQueue.clear()
+        runFlag = false
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:20
+     * @Note   在UI主线程执行普通方法
+     * @param  call 方法回调
+     */
+    override fun doOnUI(call: (call :() -> Unit) -> Unit):NomalResultInterface{
+        threadQueue.add(DoModel(onUI,call))
+        return this
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:33
+     * @Note   在非UI线程执行普通方法
+     * @param  call 方法回调
+     */
+    override fun doOnBack(call: (call :() -> Unit) -> Unit):NomalResultInterface{
+        threadQueue.add(DoModel(onThread,call))
+        return this
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:37
+     * @Note   在UI线程执行传递参数方法
+     * @param  call 方法回调
+     */
+    override fun onUISend(call: ((value :Any) -> Unit) -> Unit):SendResultInterface{
+        threadQueue.add(DoSendModel(onUI,call))
+        return this
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:37
+     * @Note   在非UI线程执行传递参数方法
+     * @param  call 方法回调
+     */
+    override fun onBackSend(call: ((value :Any) -> Unit) -> Unit):SendResultInterface{
+        threadQueue.add(DoSendModel(onThread,call))
+        return this
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:38
+     * @Note   在主线程执行接受参数方法
+     * @param  call 方法回调
+     */
+    override fun onUIResult(call: (Any,() -> Unit) -> Unit):NomalResultInterface{
+        threadQueue.add(DoResultModel(onUI,call))
+        return this
+    }
+
+    /**
+     * @author  LDD
+     * @From   com.wdkl.ncs.android.lib.utils Do
+     * @Data   2017/12/22 下午4:39
+     * @Note   在非UI线程执行结束参数方法
+     * @param  call 方法回调
+     */
+    override fun onBackResult(call: (Any,() -> Unit) -> Unit):NomalResultInterface{
+        threadQueue.add(DoResultModel(onThread,call))
+        return this
+    }
+
+}
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午4:42
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   执行完发送参数方法后 返回对应接口
+ */
+interface SendResultInterface {
+    fun onBackResult (call: (Any,() -> Unit) -> Unit):NomalResultInterface
+    fun onUIResult(call: (Any,() -> Unit) -> Unit):NomalResultInterface
+}
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午4:42
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   执行完普通方法和接受参数方法后 返回对应接口
+ */
+interface NomalResultInterface{
+    fun onBackSend(call: ((value :Any) -> Unit) -> Unit):SendResultInterface
+    fun onUISend(call: ((value :Any) -> Unit) -> Unit):SendResultInterface
+    fun doOnBack(call: (call :() -> Unit) -> Unit):NomalResultInterface
+    fun doOnUI(call: (call :() -> Unit) -> Unit):NomalResultInterface
+    fun execute()
+}
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午4:43
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   普通方法 Model
+ */
+data class DoModel constructor(var thread :Int, var call :(() -> Unit) -> Unit)
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午4:43
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   发送参数方法 Model
+ */
+data class DoSendModel constructor(var thread :Int, var call :((value : Any) -> Unit) -> Unit)
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午4:43
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   接收参数方法 Model
+ */
+data class DoResultModel constructor(var thread :Int, var call :(result :Any,() -> Unit) -> Unit)

+ 113 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/EcodeHelper.kt

@@ -0,0 +1,113 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import com.google.zxing.BarcodeFormat
+import com.google.zxing.EncodeHintType
+import com.google.zxing.WriterException
+import com.google.zxing.qrcode.QRCodeWriter
+import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
+import io.reactivex.Observable
+
+/**
+ * Created by LDD on 2018/11/9.
+ */
+class EcodeHelper {
+
+
+    fun rxCreateQRImage(content: String, heightPix: Int, logoBm: Bitmap?) :Observable<Bitmap>{
+        return Observable.create { observableEmitter ->
+            observableEmitter.onNext(createQRImage(content,heightPix,logoBm)!!)
+        }
+    }
+
+    fun createQRImage(content: String, heightPix: Int, logoBm: Bitmap?): Bitmap? {
+        try {
+            // if (content == null || "".equals(content)) {
+            // return false;
+            // }
+
+            //配置参数
+            val hints = HashMap<EncodeHintType, Any>()
+            hints.put(EncodeHintType.CHARACTER_SET, "utf-8")
+            //容错级别
+            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H)
+            //设置空白边距的宽度
+            // hints.put(EncodeHintType.MARGIN, 2); //default is 4
+
+            // 图像数据转换,使用了矩阵转换
+            val bitMatrix = QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, heightPix, heightPix, hints)
+            val pixels = IntArray(heightPix * heightPix)
+            // 下面这里按照二维码的算法,逐个生成二维码的图片,
+            // 两个for循环是图片横列扫描的结果
+            for (y in 0 until heightPix) {
+                for (x in 0 until heightPix) {
+                    if (bitMatrix.get(x, y)) {
+                        pixels[y * heightPix + x] = -0x1000000
+                    } else {
+                        pixels[y * heightPix + x] = -0x1
+                    }
+                }
+            }
+
+            // 生成二维码图片的格式,使用ARGB_8888
+            var bitmap: Bitmap? = Bitmap.createBitmap(heightPix, heightPix, Bitmap.Config.ARGB_8888)
+            bitmap!!.setPixels(pixels, 0, heightPix, 0, 0, heightPix, heightPix)
+
+            if (logoBm != null) {
+                bitmap = addLogo(bitmap, logoBm)
+            }
+
+            //必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大!
+            return bitmap
+        } catch (e: WriterException) {
+            e.printStackTrace()
+        }
+
+        return null
+    }
+
+    /**
+     * 在二维码中间添加Logo图案
+     */
+    private fun addLogo(src: Bitmap?, logo: Bitmap?): Bitmap? {
+        if (src == null) {
+            return null
+        }
+
+        if (logo == null) {
+            return src
+        }
+
+        //获取图片的宽高
+        val srcWidth = src.width
+        val srcHeight = src.height
+        val logoWidth = logo.width
+        val logoHeight = logo.height
+
+        if (srcWidth == 0 || srcHeight == 0) {
+            return null
+        }
+
+        if (logoWidth == 0 || logoHeight == 0) {
+            return src
+        }
+
+        //logo大小为二维码整体大小的1/5
+        val scaleFactor = srcWidth * 1.0f / 5f / logoWidth.toFloat()
+        var bitmap: Bitmap? = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888)
+        try {
+            val canvas = Canvas(bitmap)
+            canvas.drawBitmap(src, 0f, 0f, null)
+            canvas.scale(scaleFactor, scaleFactor, (srcWidth / 2).toFloat(), (srcHeight / 2).toFloat())
+            canvas.drawBitmap(logo, ((srcWidth - logoWidth) / 2).toFloat(), ((srcHeight - logoHeight) / 2).toFloat(), null)
+            canvas.save()
+            canvas.restore()
+        } catch (e: Exception) {
+            bitmap = null
+            e.stackTrace
+        }
+
+        return bitmap
+    }
+}

+ 743 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/ExtendMethods.kt

@@ -0,0 +1,743 @@
+package com.wdkl.ncs.android.lib.utils
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午4:45
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   扩展方法Koltin文件
+ */
+
+import android.app.Activity
+import android.app.Fragment
+import android.content.Context
+import android.content.Intent
+import android.databinding.ObservableField
+import android.os.Looper
+import android.support.v4.content.ContextCompat
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import android.view.ViewGroup
+import android.view.animation.Animation
+import android.widget.Toast
+import com.alibaba.android.vlayout.DelegateAdapter
+import com.alibaba.android.vlayout.VirtualLayoutManager
+import com.enation.javashop.android.jrouter.JRouter
+import com.enation.javashop.android.jrouter.logic.datainfo.Postcard
+import com.wdkl.ncs.android.lib.R
+import com.wdkl.ncs.android.lib.adapter.BaseDelegateAdapter
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.wdkl.ncs.android.lib.base.DisposableManager
+import com.enation.javashop.net.engine.plugin.rxbus.RxBus
+import com.enation.javashop.utils.base.tool.CommonTool
+import com.enation.javashop.utils.base.tool.ScreenTool
+import com.enation.javashop.utils.logger.LoggerFactory
+import io.reactivex.disposables.Disposable
+import okhttp3.ResponseBody
+import org.json.JSONArray
+import org.json.JSONObject
+import java.lang.RuntimeException
+import java.lang.ref.WeakReference
+import java.nio.charset.Charset
+import java.util.*
+import kotlin.collections.ArrayList
+
+/**
+ * 绑定字段 指定泛型
+ */
+typealias ObserableString = ObservableField<String>
+
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:47
+ * @Note   debug日志打印
+ * @param  tag 标记
+ * @param  message 日志信息
+ */
+fun debugLog(tag: String?, message: String?) {
+    val st = Throwable().stackTrace[1]
+    LoggerFactory.getLogger().i("【Tag -> $tag】 >>>>>>>>>>", "Message -> $message >>>>>>>>>>>>>>>>>>>>>>>>>> 【Location ->Class:${st.className} - Method:${st.methodName} - Line:${st.lineNumber}】 ")
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:47
+ * @Note   error日志打印
+ * @param  tag 标记
+ * @param  message 日志信息
+ */
+fun errorLog(tag: String, message: String) {
+    val st = Throwable().stackTrace[1]
+    LoggerFactory.getLogger().e("【Tag -> $tag】 >>>>>>>>>>", "Message -> $message >>>>>>>>>>>>>>>>>>>>>>>>>> 【Location ->Class:${st.className} - Method:${st.methodName} - Line:${st.lineNumber}】 ")
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:47
+ * @Note   显示Toast信息
+ * @param  message 需要显示的信息
+ */
+fun showMessage(message: String) {
+    if (message == ""){
+        return
+    }
+    val messageCallback = {
+        Toast.makeText(BaseApplication.appContext, message, Toast.LENGTH_SHORT).show()
+    }
+    try {
+        messageCallback.invoke()
+    } catch (runtime: RuntimeException) {
+        Looper.prepare()
+        messageCallback.invoke()
+    }
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:48
+ * @Note   数据类型转换
+ * @return 转换后的值
+ */
+fun <T> Any.to(): T {
+    return this as T
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:49
+ * @Note   通过JRouter框架检索对象,并实例化
+ * @param  path 对象注册到JRouter的路径
+ */
+fun <T> acquireInstance(path: String): T {
+    return JRouter.prepare().create(path).seek().to()
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:51
+ * @Note   跳转页面Activity扩展方法
+ * @param  path Activity注册到JRouter中的路径
+ * @param  _block 更多操作
+ * @param  requstCode 返回码
+ */
+fun AppCompatActivity.push(path: String, _block: ((Postcard) -> Unit)? = null, requstCode: Int = -1 , isNeedLogin :Boolean = false) {
+    if (isNeedLogin){
+        JRouter.prepare().create("/member/login/main").withTransition(R.anim.push_left_in, R.anim.push_left_out).then { postcard ->
+            _block?.invoke(postcard)
+        }.seek(this)
+        return
+    }
+    val engine = JRouter.prepare().create(path).withTransition(R.anim.push_left_in, R.anim.push_left_out).then { postcard ->
+        _block?.invoke(postcard)
+    }
+    if (requstCode == -1) {
+        engine.seek(this)
+    } else {
+        engine.seek(this, requstCode)
+    }
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:51
+ * @Note   跳转页面Activity扩展方法
+ * @param  path Activity注册到JRouter中的路径
+ * @param  _block 更多操作
+ * @param  requstCode 返回码
+ */
+fun Activity.push(path: String, _block: ((Postcard) -> Unit)? = null, requstCode: Int = -1 , isNeedLogin :Boolean = false) {
+    if (isNeedLogin){
+        JRouter.prepare().create("/member/login/main").withTransition(R.anim.push_left_in, R.anim.push_left_out).then { postcard ->
+            _block?.invoke(postcard)
+        }.seek(this)
+        return
+    }
+    val engine = JRouter.prepare().create(path).withTransition(R.anim.push_left_in, R.anim.push_left_out).then { postcard ->
+        _block?.invoke(postcard)
+    }
+    if (requstCode == -1) {
+        engine.seek(this)
+    } else {
+        engine.seek(this, requstCode)
+    }
+}
+
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:51
+ * @Note   跳转页面 V4 Fragment扩展方法
+ * @param  path Activity注册到JRouter中的路径
+ * @param  _block 更多操作
+ */
+fun android.support.v4.app.Fragment.push(path: String, _block: ((Postcard) -> Unit)? = null , isNeedLogin :Boolean = false) {
+    if (isNeedLogin){
+        JRouter.prepare().create("/member/login/main").withTransition(R.anim.push_left_in, R.anim.push_left_out).then { postcard ->
+            _block?.invoke(postcard)
+        }.seek(activity)
+        return
+    }
+    JRouter.prepare().create(path).withTransition(R.anim.push_left_in, R.anim.push_left_out).then { postcard ->
+        _block?.invoke(postcard)
+    }.seek(activity)
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:51
+ * @Note   跳转页面 V7 Fragment扩展方法
+ * @param  _block 更多操作
+ * @param  path Activity注册到JRouter中的路径
+ */
+fun Fragment.push(path: String, _block: ((Postcard) -> Unit)? = null , isNeedLogin :Boolean = false) {
+    if (isNeedLogin){
+        JRouter.prepare().create("/member/login/main").withTransition(R.anim.push_left_in, R.anim.push_left_out).then { postcard ->
+            _block?.invoke(postcard)
+        }.seek(activity)
+        return
+    }
+    JRouter.prepare().create(path).withTransition(R.anim.push_left_in, R.anim.push_left_out).then { postcard ->
+        _block?.invoke(postcard)
+    }.seek(activity)
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:53
+ * @Note   Activity 退出扩展方法
+ */
+fun AppCompatActivity.pop() {
+    finish()
+    overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out)
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午4:53
+ * @Note   用于代码规范化 有助于代码美观 一般用于配置对象时对代码格式化
+ *         示例: val linearLayout = LinearLayout(context).then {
+ *                  lay ->
+ *                  lay.orientation = LinearLayout.HORIZONTAL
+ *                  lay.setBackgroundColor(Color.RED)
+ *              }.removeAllViews()
+ * @param  _block 回调
+ */
+inline fun <T : Any> T.then(_block: (T) -> Unit): T {
+    _block.invoke(this)
+    return this
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午5:04
+ * @Note   用于代码格式化 与then不同的是 该方法不继续传递self 一般用于格式化对象初始化代码
+ *         示例: val view = View(context).more {
+ *                  self ->
+ *                  self.setBackgroundColor(Color.BLUE)
+ *                  self.setFadingEdgeLength(1)
+ *                  self.setOnClickListener{}
+ *              }
+ * @param  _block 回调
+ */
+inline fun <T : Any> T.more(_block: (T) -> Unit) {
+    _block.invoke(this)
+}
+
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午5:10
+ * @Note   获取事件序列中心
+ * @return RxBus事件中心
+ */
+fun getEventCenter(): RxBus {
+    return RxBus.getDefault()
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午5:13
+ * @Note   当变量为空时执行
+ * @param  _block 回调
+ */
+inline fun Any?.haventDo(_block: () -> Unit) {
+    if (this == null) {
+        _block.invoke()
+        return
+    } else if (this is String) {
+        if (this == "") {
+            _block.invoke()
+        }
+    }
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午5:15
+ * @Note   当一个序列 都为空时 执行该回调
+ * @param  array 需要判断空的序列
+ * @param  _block 回调
+ */
+inline fun haventDo(vararg array: Any?, _block: () -> Unit) {
+    var has = false
+    for (any in array) {
+        if (any != null) {
+            has = true
+            if (any is String) {
+                if (any == "") {
+                    has = false
+                }
+            }
+        } else {
+            has = false
+        }
+    }
+    if (!has) {
+        _block.invoke()
+    }
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午5:13
+ * @Note   当变量不为空时执行
+ * @param  _block 回调
+ */
+inline fun Any?.haveDo(_block: () -> Unit) {
+    if (this != null) {
+        if (this is String) {
+            if (this == "") {
+                return
+            }
+        }
+        _block.invoke()
+    }
+}
+
+/**
+ * @author  LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Data   2017/12/22 下午5:15
+ * @Note   当一个序列 都不为空时 执行该回调
+ * @param  array 需要判断空的序列
+ * @param  _block 回调
+ */
+inline fun haveDo(vararg array: Any?, _block: () -> Unit) {
+    var has = true
+    for (any in array) {
+        if (any == null) {
+            has = false
+        } else if (any is String) {
+            if (any == "") {
+                has = false
+            }
+        }
+    }
+    if (has) {
+        _block.invoke()
+    }
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/1/19 下午3:46
+ * @Note   通过context获取颜色
+ * @param  rid  颜色索引ID
+ */
+fun Context.getColorCompatible(rid: Int): Int {
+    return ContextCompat.getColor(this, rid)
+}
+
+/**
+ * @author LDD
+ * @Date   2018/1/19 下午3:51
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Note   非入侵式,setOnScrollListener兼容低版本实现
+ * @param  call 滑动回调
+ */
+inline fun View.setOnScrollObserver(crossinline call: (scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int) -> (Unit)) {
+    var oldScrollX = 0
+    var oldScrollY = 0
+    this.viewTreeObserver.addOnScrollChangedListener {
+        call.invoke(scrollX, scrollY, oldScrollX, oldScrollY)
+        oldScrollX = scrollX
+        oldScrollY = scrollY
+    }
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/1/29 下午4:00
+ * @Note   快速判断语法糖
+ * @param  trueDo  为true时调用
+ * @param  falseDo 为false时调用
+ */
+fun Boolean.judge(trueDo: (() -> (Unit))? = null, falseDo: (() -> (Unit))? = null) {
+    if (this) {
+        trueDo?.invoke()
+    } else {
+        falseDo?.invoke()
+    }
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/1/31 下午2:25
+ * @Note   快速判断语法糖
+ * @param  trueValue  为true时抛出
+ * @param  falseValue 为false时抛出
+ */
+fun <T> Boolean.judge(trueValue: T, falseValue: T): T {
+    return if (this) {
+        trueValue
+    } else {
+        falseValue
+    }
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/3/12 下午4:24
+ * @Note   快速重新定义LayoutParams重新布局
+ * @param  layout 重新布局回调
+ */
+inline fun <T : ViewGroup.LayoutParams> View.reLayout(layout: ((params: T) -> (Unit))) {
+    var params = (this.layoutParams as T)
+    layout(params)
+    this.layoutParams = params
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/3/13 上午11:09
+ * @Note   顺序执行补间动画 且可拦截
+ * @param  animList 动画列表
+ * @param  interceptor 拦截器
+ */
+fun View.animSequentialStart(animList: ArrayList<Animation>, interceptor: ((index: Int, state: Int) -> (Boolean))? = null) {
+
+    var index = 0
+
+    var listener = object : Animation.AnimationListener {
+        override fun onAnimationRepeat(animation: Animation?) {
+            val flag = interceptor?.invoke(index, 1)
+            flag?.judge(trueDo = {
+                animation?.cancel()
+            })
+        }
+
+        override fun onAnimationEnd(animation: Animation?) {
+            if (index != animList.size - 1) {
+                animList[index].cancel()
+            }
+            val flag = interceptor?.invoke(index, 2)
+            index += 1
+            flag?.judge(trueDo = {
+                animation?.cancel()
+            }, falseDo = {
+                if (index < animList.size) {
+                    animList[index].setAnimationListener(this)
+                    startAnimation(animList[index])
+                }
+            })
+        }
+
+        override fun onAnimationStart(animation: Animation?) {
+            val flag = interceptor?.invoke(index, 3)
+            flag?.judge(trueDo = {
+                animation?.cancel()
+            })
+        }
+    }
+    animList[index].setAnimationListener(listener)
+    startAnimation(animList[index])
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/3/15 下午3:57
+ * @Note   根据标记查找Adapter
+ * @param  tag 标记
+ */
+fun <T : BaseDelegateAdapter<*, *>> ArrayList<DelegateAdapter.Adapter<*>>.getAdapterByTag(tag: Any): T? {
+    this.forEach { item ->
+        if (item is BaseDelegateAdapter<*, *>) {
+            if (item.tag == tag) {
+                return item as T
+            }
+        }
+    }
+    return null
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/3/15 下午3:58
+ * @Note   根据标记移除Adapter
+ * @param  tag 标记
+ */
+fun <T : BaseDelegateAdapter<*, *>> ArrayList<DelegateAdapter.Adapter<*>>.removeAdapterByTag(tag: Any) {
+    remove(getAdapterByTag<T>(tag) as DelegateAdapter.Adapter<*>)
+}
+
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/3/15 下午4:25
+ * @Note   Vlayout获取屏幕上可见第一个Item的位置
+ */
+fun VirtualLayoutManager.getScollYDistance(): Int {
+    val position = findFirstVisibleItemPosition()
+    val firstVisiableChildView = findViewByPosition(position)
+    val itemHeight = firstVisiableChildView?.height
+    return position * (itemHeight ?: 0) - (firstVisiableChildView?.top ?: 0)
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/3/21 上午9:55
+ * @Note   转换弱引用
+ */
+fun <T : Any> T.weak(): WeakReference<T> {
+    return WeakReference(this)
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/4/12 上午8:56
+ * @Note   加入管理器
+ * @param  manager 管理器
+ */
+fun Disposable.joinManager(manager: DisposableManager) {
+    manager.addDisposable(this)
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/4/19 下午2:50
+ * @Note   dp转px
+ */
+fun Int.dpToPx(): Int {
+    return ScreenTool.dip2px(BaseApplication.appContext, this.toFloat())
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/4/19 下午2:50
+ * @Note   px转dp
+ */
+fun Int.pxToDp(): Int {
+    return ScreenTool.px2dip(BaseApplication.appContext, this.toFloat())
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/4/19 下午2:50
+ * @Note   dp转px
+ */
+fun Double.dpToPx(): Int {
+    return ScreenTool.dip2px(BaseApplication.appContext, this.toFloat())
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/4/19 下午2:50
+ * @Note   px转dp
+ */
+fun Double.pxToDp(): Int {
+    return ScreenTool.px2dip(BaseApplication.appContext, this.toFloat())
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/5/29 上午10:01
+ * @Note   获取对象
+ * @param  key
+ * @param  cls class对象
+ */
+fun <T> Intent.getObjectForGson(key: String, cls: Class<T>): T? {
+    return if (hasExtra(key)) {
+        val json = getStringExtra(key)
+        try {
+            JsonTranforHelper.toObject(json, cls)
+        } catch (e: Exception) {
+            null
+        }
+    } else {
+        null
+    }
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/5/29 上午10:03
+ * @Note   设置对象根据Gson
+ * @param  key 索引
+ * @param  value 值
+ */
+fun Intent.setObjectForGson(key: String, value: Any) {
+    putExtra(key, JsonTranforHelper.toJson(value))
+
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/5/29 下午4:13
+ * @Note   快速转换databinding字段
+ */
+fun <T> T.bindingParams(): ObservableField<T> {
+    return ObservableField(this)
+}
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.utils ExtendMethods.kt
+ * @Date   2018/8/13 上午10:13
+ * @Note   以流的方式获取Json的字符串
+ */
+fun ResponseBody.getJsonString() : String{
+    source().request(Long.MAX_VALUE)
+    val buffer = source().buffer()
+    return buffer.clone().readString(Charset.forName("UTF-8"))
+}
+
+fun ResponseBody.toJsonObject() :JSONObject{
+    val jsonString = getJsonString()
+    return if (jsonString.isEmpty()){
+        JSONObject()
+    }else{
+        JSONObject(jsonString)
+    }
+}
+
+fun ResponseBody.toJsonArray() :JSONArray{
+    val jsonString = getJsonString()
+    return if (jsonString.isEmpty()){
+        JSONArray()
+    }else{
+        JSONArray(jsonString)
+    }
+}
+
+
+/** 参数获取扩展方法 防止空值 */
+
+fun JSONObject.valueString(key: String) :String{
+    return if (has(key) &&  !isNull(key)){
+        getString(key)
+    }else{
+        ""
+    }}
+
+fun JSONObject.valueInt(key :String) :Int{
+    return if (has(key) &&  !isNull(key)){
+        getInt(key)
+    }else{
+        -1
+    }}
+
+fun JSONObject.valueBool(key: String) :Boolean{
+    return if (has(key) &&  !isNull(key)){
+        getBoolean(key)
+    }else{
+        false
+    }}
+
+fun JSONObject.valueDouble(key: String) :Double{
+    return if (has(key) &&  !isNull(key)){
+        getDouble(key)
+    }else{
+        -1.0
+    }
+}
+
+fun JSONObject.valueDate(key:String) :String{
+    return if(has(key) && !isNull(key)){
+        CommonTool.toString(Date(valueLong(key)*1000),null)
+    }else{
+        ""
+    }
+}
+
+fun JSONObject.valueLong(key: String) :Long{
+    return if (has(key) &&  !isNull(key)){
+        getLong(key)
+    }else{
+        -1
+    }
+}
+
+fun JSONObject.valueJsonObject(key :String) :JSONObject{
+    return if (has(key) &&  !isNull(key)){
+        getJSONObject(key)
+    }else{
+        JSONObject()
+    }
+}
+
+fun JSONObject.valueJsonArray(key :String) :JSONArray{
+    return if (has(key) &&  !isNull(key)){
+        getJSONArray(key)
+    }else{
+        JSONArray()
+    }
+}
+
+fun JSONArray.arrayObjects() : ArrayList<JSONObject>{
+
+    var result = ArrayList<JSONObject>()
+
+    for (i in 0..(this.length() - 1)){
+        result.add(getJSONObject(i))
+    }
+
+    return  result
+
+}
+
+/**=================================================*/
+
+fun View.visable(){
+    this.visibility = View.VISIBLE
+}
+
+fun View.gone(){
+    this.visibility = View.GONE
+}
+
+fun View.invisable(){
+    this.visibility = View.INVISIBLE
+}

+ 314 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/GalleryHelper.kt

@@ -0,0 +1,314 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.content.Context
+import android.media.Image
+import android.os.Handler
+import android.support.v4.view.PagerAdapter
+import android.support.v4.view.ViewPager
+import android.util.AttributeSet
+import android.util.SparseArray
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.engine.DiskCacheStrategy
+import com.enation.javashop.imagepluin.R
+import com.enation.javashop.imagepluin.utils.GlideUtils
+import java.lang.ref.WeakReference
+
+
+/**
+ * @author LDD
+ * @Date   2018/3/29 下午2:09
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   轮播辅助类
+ */
+class GalleryHelper<DataType> {
+
+    /**
+     * @Name  galleryList
+     * @Type  DataType  相册数据泛型
+     * @Note  相册数据
+     */
+    private lateinit var galleryList :ArrayList<DataType>
+
+    /**
+     * @Name  viewPager
+     * @Type  ViewPager弱引用
+     * @Note  ViewPager
+     */
+    private lateinit var viewPager :WeakReference<ViewPager>
+
+    /**
+     * @Name  autoScroll
+     * @Type  Boolean
+     * @Note  是否开启轮播
+     */
+    private var autoScroll = true
+
+    /**
+     * @Name  scrooIndex
+     * @Type  Int
+     * @Note  当前position
+     */
+    private var scrooIndex = 0
+
+    /**
+     * @Name  itemCallback
+     * @Type  block
+     * @Note  点击回调
+     */
+    private var itemCallback :((position :Int , imageView :ImageView) ->Unit)? = null
+
+    /**
+     * @Name  itemCallback
+     * @Type  block
+     * @Note  点击回调
+     */
+    private var itemCallback2 :((position :Int , imageView :ImageView , imageViews : SparseArray<ImageView>) ->Unit)? = null
+
+    /**
+     * @Name  dataTransform
+     * @Type  block
+     * @Note  数据转换回调
+     */
+    private lateinit var dataTransform :((data :DataType) ->String)
+
+    /**
+     * @Name  handler
+     * @Type  Hander
+     * @Note  处理器
+     */
+    private val handler by lazy { Handler(Handler.Callback { msg ->
+        if (!autoScroll){
+            return@Callback false
+        }
+        if (scrooIndex >= galleryList.size){
+            scrooIndex = 0
+            viewPager.get()?.setCurrentItem(scrooIndex,false)
+        }else{
+            viewPager.get()?.currentItem = scrooIndex
+        }
+        if (autoScroll){
+            pageScroll()
+        }
+        return@Callback false
+    }) }
+
+    /**
+     * @Name  galleryAdapter
+     * @Type  PagerAdapter
+     * @Note  相册适配器
+     */
+    private val galleryAdapter by lazy {
+        object : PagerAdapter() {
+
+            private var images = SparseArray<ImageView>()
+
+            override fun isViewFromObject(view: View?, data: Any?): Boolean {
+                return view === data as View
+            }
+
+            override fun getCount(): Int {
+                return galleryList.size
+            }
+
+            override fun destroyItem(container: ViewGroup?, position: Int, view: Any?) {
+                images.remove(position)
+                container?.removeView(view as View)
+            }
+
+            override fun instantiateItem(container: ViewGroup?, position: Int): Any {
+                val imageView = SquareImageView(viewPager.get()?.context!!)
+                imageView.scaleType = ImageView.ScaleType.CENTER_CROP
+                Glide.with(viewPager.get()?.context)
+                        .load(dataTransform.invoke(galleryList[position]))
+                        .diskCacheStrategy(DiskCacheStrategy.ALL)
+                        .placeholder(R.drawable.image_loading)
+                        .error(R.drawable.image_error)
+                        .into(imageView)
+                itemCallback?.more { call -> imageView.setOnClickListener(OnClickListenerAntiViolence({
+                    call.invoke(position,imageView)
+                }))}
+                itemCallback2?.more { call -> imageView.setOnClickListener(OnClickListenerAntiViolence({
+                    call.invoke(position,imageView,images)
+                }))}
+                container?.addView(imageView, 0)
+                images.append(position,imageView)
+                return imageView
+            }
+        }
+    }
+
+    companion object {
+
+        /**
+         * @author LDD
+         * @From   GalleryHelper
+         * @Date   2018/3/29 下午2:39
+         * @Note   构建入口
+         * @param  viewPager ViewPager弱引用
+         */
+        fun <DataType>build(viewPager :WeakReference<ViewPager>):GalleryHelper<DataType>{
+            return GalleryHelper(viewPager)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:40
+     * @Note   私有构造方法 防止外部直接实例化
+     * @param  viewPager ViewPager弱引用
+     */
+    private constructor(viewPager :WeakReference<ViewPager>){
+        this.viewPager = viewPager
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:40
+     * @Note   设置相册数据
+     * @param  galleryList 相册数据
+     */
+    fun setGallery(galleryList :ArrayList<DataType>):GalleryHelper<DataType>{
+        this.galleryList = galleryList
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:40
+     * @Note   设置item点击回调
+     * @param  itemCallback 点击回调
+     */
+    fun setItemCallBack(itemCallback :((position :Int, imageView :ImageView) ->Unit)):GalleryHelper<DataType>{
+        this.itemCallback = itemCallback
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:40
+     * @Note   设置item点击回调
+     * @param  itemCallback 点击回调
+     */
+    fun setItemCallBack(itemCallback :((position :Int, imageView :ImageView,imageViews : SparseArray<ImageView>) ->Unit)):GalleryHelper<DataType>{
+        this.itemCallback2 = itemCallback
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:41
+     * @Note   设置滑动回调
+     * @param  scrollCallBack 滑动回调
+     */
+    fun setScrollCallBack(scrollCallBack :((position :Int) ->Unit)):GalleryHelper<DataType>{
+        scrollCallBack.invoke(0)
+        viewPager.get()?.addOnPageChangeListener(object :ViewPager.OnPageChangeListener{
+            override fun onPageScrollStateChanged(state: Int) {
+
+            }
+
+            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
+
+            }
+
+            override fun onPageSelected(position: Int) {
+                initPageScroll()
+                scrollCallBack.invoke(position)
+            }
+        })
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:41
+     * @Note   设置数据转换器
+     * @param  dataTransform 数据转换器
+     */
+    fun setDataTransform(dataTransform :((data :DataType) ->String)):GalleryHelper<DataType>{
+        this.dataTransform = dataTransform
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:43
+     * @Note   开启自动轮播
+     * @param  context
+     */
+    fun autoScroll():GalleryHelper<DataType>{
+        autoScroll = true
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:47
+     * @Note   执行
+     */
+    fun execute(){
+        this.viewPager.get()?.adapter = galleryAdapter
+        if (autoScroll){
+            pageScroll()
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:51
+     * @Note   关闭滑动
+     */
+    fun offAutoScroll(){
+        autoScroll = false
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:52
+     * @Note   自动滑动
+     */
+    private fun pageScroll(){
+        initPageScroll()
+        handler.postDelayed({
+            handler.sendEmptyMessage(scrooIndex)
+        },3000)
+    }
+
+    /**
+     * @author LDD
+     * @From   GalleryHelper
+     * @Date   2018/3/29 下午2:52
+     * @Note   初始化滑动坐标
+     */
+    private fun initPageScroll(){
+        scrooIndex = viewPager.get()?.currentItem!! + 1
+    }
+
+}
+
+class SquareImageView: ImageView {
+
+    constructor(context: Context) : this(context,null)
+
+    constructor(context :Context,attrs : AttributeSet?) : super(context,attrs)
+
+    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        val widthSize = View.MeasureSpec.getSize(widthMeasureSpec)
+        setMeasuredDimension(widthSize, widthSize)
+    }
+}

+ 31 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/ImageWatchLoader.kt

@@ -0,0 +1,31 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.net.Uri
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.resource.drawable.GlideDrawable
+import com.bumptech.glide.request.RequestListener
+import com.enation.javashop.net.engine.utils.ThreadFromUtils
+import com.enation.javashop.net.engine.utils.ThreadUtils
+import com.github.ielse.imagewatcher.ImageWatcher
+import com.tmall.wireless.tangram.util.ImageUtils
+
+class ImageWatchLoader : ImageWatcher.Loader{
+    override fun load(p0: Context, p1: Uri, call: ImageWatcher.LoadCallback) {
+        call.onLoadStarted(null)
+        Glide.with(p0).load(p1).listener(object : RequestListener<Uri, GlideDrawable> {
+            override fun onException(p0: Exception, p1: Uri, p2:         com.bumptech.glide.request.target.Target
+            <GlideDrawable>, p3: Boolean): Boolean {
+                call.onLoadFailed(null)
+                return true
+            }
+
+            override fun onResourceReady(p0: GlideDrawable, p1: Uri, p2:         com.bumptech.glide.request.target.Target
+            <GlideDrawable>, p3: Boolean, p4: Boolean): Boolean {
+               call.onResourceReady(p0)
+                return true
+            }
+        }).into(1000,1000)
+    }
+}

+ 45 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/JsonTranforHelper.kt

@@ -0,0 +1,45 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.util.Log
+import com.google.gson.Gson
+
+/**
+ * @author LDD
+ * @Date   2018/5/8 上午11:51
+ * @From   com.wdkl.ncs.android.middleware.router
+ * @Note   Json转换辅助类
+ */
+object JsonTranforHelper {
+
+    /**
+     * @Name  com.wdkl.ncs.android.lib.utils.JsonTranforHelper.gson
+     * @Type  Gson
+     * @Note  静态Gson单例
+     */
+    @JvmStatic
+    private val gson = Gson()
+
+    /**
+     * @author LDD
+     * @From   JsonTranforHelper
+     * @Date   2018/5/8 上午11:53
+     * @Note   对象转Json
+     * @param  instance 对象
+     */
+    fun toJson(instance: Any): String {
+        return gson.toJson(instance)
+    }
+
+    /**
+     * @author LDD
+     * @From   JsonTranforHelper
+     * @Date   2018/5/8 上午11:53
+     * @Note   Json转对象
+     * @param  json json字符
+     * @param  cls  需要转换的对象的class
+     */
+    fun <T> toObject(json: String, cls: Class<T>): T {
+        return gson.fromJson(json, cls)
+    }
+
+}

+ 47 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/MD5Util.kt

@@ -0,0 +1,47 @@
+package com.wdkl.ncs.android.lib.utils
+
+import java.security.MessageDigest
+
+/**
+ *  Md5加密
+ */
+object MD5Util {
+
+
+    private val hexDigits = arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f")
+
+    private fun byteArrayToHexString(b: ByteArray): String {
+        val resultSb = StringBuffer()
+        for (i in b.indices)
+            resultSb.append(byteToHexString(b[i]))
+
+        return resultSb.toString()
+    }
+
+    private fun byteToHexString(b: Byte): String {
+        var n = b.toInt()
+        if (n < 0)
+            n += 256
+        val d1 = n / 16
+        val d2 = n % 16
+        return hexDigits[d1] + hexDigits[d2]
+    }
+
+    fun MD5Encode(origin: String, charsetname: String?): String? {
+        var resultString: String? = null
+        try {
+            resultString = origin
+            val md = MessageDigest.getInstance("MD5")
+            if (charsetname == null || "" == charsetname)
+                resultString = byteArrayToHexString(md.digest(resultString!!
+                        .toByteArray()))
+            else
+                resultString = byteArrayToHexString(md.digest(resultString!!
+                        .toByteArray(charset(charsetname))))
+        } catch (exception: Exception) {
+        }
+
+        return resultString
+    }
+
+}

+ 51 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/NetReceiver.kt

@@ -0,0 +1,51 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.net.ConnectivityManager
+import com.wdkl.ncs.android.lib.vo.NetStateEvent
+import com.enation.javashop.net.engine.model.NetState
+import com.enation.javashop.net.engine.utils.VoiNetTool
+
+/**
+ * @author  LDD
+ * @Data   2017/12/22 下午5:19
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   监听网络变化的 广播接收者
+ */
+class NetReceiver : BroadcastReceiver() {
+
+    companion object {
+        private var lastType :VoiNetTool.netType? = null
+    }
+
+    override fun onReceive(p0: Context, p1: Intent) {
+        // 如果相等的话就说明网络状态发生了变化
+        if (p1.action == ConnectivityManager.CONNECTIVITY_ACTION) {
+            val netWorkState  = VoiNetTool.getAPNType(p0)
+            if (lastType != null){
+                if (lastType != netWorkState){
+                    postEvent(netWorkState)
+                }
+            }else{
+                postEvent(netWorkState)
+            }
+        }
+    }
+
+    private fun postEvent(netType :VoiNetTool.netType){
+        lastType = netType
+        when (netType) {
+            VoiNetTool.netType.noneNet -> {
+                getEventCenter().post(NetStateEvent(NetState.NONE))
+            }
+            VoiNetTool.netType.wifi -> {
+                getEventCenter().post(NetStateEvent(NetState.WIFI))
+            }
+            else -> {
+                getEventCenter().post(NetStateEvent(NetState.MOBILE))
+            }
+        }
+    }
+}

+ 614 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/NoAlphaItemAnimator.kt

@@ -0,0 +1,614 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.TimeInterpolator
+import android.animation.ValueAnimator
+import android.support.v4.view.ViewCompat
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.SimpleItemAnimator
+import java.util.ArrayList
+
+/**
+ * @author LDD
+ * @Date   2018/3/21 上午8:59
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   ...
+ */
+class NoAlphaItemAnimator : SimpleItemAnimator() {
+    private val DEBUG = false
+
+    private var sDefaultInterpolator: TimeInterpolator? = null
+
+    private val mPendingRemovals = ArrayList<RecyclerView.ViewHolder>()
+    private val mPendingAdditions = ArrayList<RecyclerView.ViewHolder>()
+    private val mPendingMoves = ArrayList<MoveInfo>()
+    private val mPendingChanges = ArrayList<ChangeInfo>()
+
+    internal var mAdditionsList = ArrayList<ArrayList<RecyclerView.ViewHolder>>()
+    internal var mMovesList = ArrayList<ArrayList<MoveInfo>>()
+    internal var mChangesList = ArrayList<ArrayList<ChangeInfo>>()
+
+    internal var mAddAnimations = ArrayList<RecyclerView.ViewHolder>()
+    internal var mMoveAnimations = ArrayList<RecyclerView.ViewHolder>()
+    internal var mRemoveAnimations = ArrayList<RecyclerView.ViewHolder>()
+    internal var mChangeAnimations = ArrayList<RecyclerView.ViewHolder>()
+
+    class MoveInfo internal constructor(var holder: RecyclerView.ViewHolder, var fromX: Int, var fromY: Int, var toX: Int, var toY: Int)
+
+    class ChangeInfo private constructor(var oldHolder: RecyclerView.ViewHolder?, var newHolder: RecyclerView.ViewHolder?) {
+        var fromX: Int = 0
+        var fromY: Int = 0
+        var toX: Int = 0
+        var toY: Int = 0
+
+        internal constructor(oldHolder: RecyclerView.ViewHolder, newHolder: RecyclerView.ViewHolder,
+                             fromX: Int, fromY: Int, toX: Int, toY: Int) : this(oldHolder, newHolder) {
+            this.fromX = fromX
+            this.fromY = fromY
+            this.toX = toX
+            this.toY = toY
+        }
+
+        override fun toString(): String {
+            return ("ChangeInfo{"
+                    + "oldHolder=" + oldHolder
+                    + ", newHolder=" + newHolder
+                    + ", fromX=" + fromX
+                    + ", fromY=" + fromY
+                    + ", toX=" + toX
+                    + ", toY=" + toY
+                    + '}'.toString())
+        }
+    }
+
+    override fun runPendingAnimations() {
+        val removalsPending = !mPendingRemovals.isEmpty()
+        val movesPending = !mPendingMoves.isEmpty()
+        val changesPending = !mPendingChanges.isEmpty()
+        val additionsPending = !mPendingAdditions.isEmpty()
+        if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
+            // nothing to animate
+            return
+        }
+        // First, remove stuff
+        for (holder in mPendingRemovals) {
+            animateRemoveImpl(holder)
+        }
+        mPendingRemovals.clear()
+        // Next, move stuff
+        if (movesPending) {
+            val moves = ArrayList<MoveInfo>()
+            moves.addAll(mPendingMoves)
+            mMovesList.add(moves)
+            mPendingMoves.clear()
+            val mover = Runnable {
+                for (moveInfo in moves) {
+                    animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
+                            moveInfo.toX, moveInfo.toY)
+                }
+                moves.clear()
+                mMovesList.remove(moves)
+            }
+            if (removalsPending) {
+                val view = moves[0].holder.itemView
+                ViewCompat.postOnAnimationDelayed(view, mover, removeDuration)
+            } else {
+                mover.run()
+            }
+        }
+        // Next, change stuff, to run in parallel with move animations
+        if (changesPending) {
+            val changes = ArrayList<ChangeInfo>()
+            changes.addAll(mPendingChanges)
+            mChangesList.add(changes)
+            mPendingChanges.clear()
+            val changer = Runnable {
+                for (change in changes) {
+                    animateChangeImpl(change)
+                }
+                changes.clear()
+                mChangesList.remove(changes)
+            }
+            if (removalsPending) {
+                val holder = changes[0].oldHolder
+                ViewCompat.postOnAnimationDelayed(holder!!.itemView, changer, removeDuration)
+            } else {
+                changer.run()
+            }
+        }
+        // Next, add stuff
+        if (additionsPending) {
+            val additions = ArrayList<RecyclerView.ViewHolder>()
+            additions.addAll(mPendingAdditions)
+            mAdditionsList.add(additions)
+            mPendingAdditions.clear()
+            val adder = Runnable {
+                for (holder in additions) {
+                    animateAddImpl(holder)
+                }
+                additions.clear()
+                mAdditionsList.remove(additions)
+            }
+            if (removalsPending || movesPending || changesPending) {
+                val removeDuration = if (removalsPending) removeDuration else 0
+                val moveDuration = if (movesPending) moveDuration else 0
+                val changeDuration = if (changesPending) changeDuration else 0
+                val totalDelay = removeDuration + Math.max(moveDuration, changeDuration)
+                val view = additions[0].itemView
+                ViewCompat.postOnAnimationDelayed(view, adder, totalDelay)
+            } else {
+                adder.run()
+            }
+        }
+    }
+
+    override fun animateRemove(holder: RecyclerView.ViewHolder): Boolean {
+        resetAnimation(holder)
+        mPendingRemovals.add(holder)
+        return true
+    }
+
+    private fun animateRemoveImpl(holder: RecyclerView.ViewHolder) {
+        val view = holder.itemView
+        val animation = view.animate()
+        mRemoveAnimations.add(holder)
+        animation.setDuration(removeDuration).alpha(0f).setListener(
+                object : AnimatorListenerAdapter() {
+                    override fun onAnimationStart(animator: Animator) {
+                        dispatchRemoveStarting(holder)
+                    }
+
+                    override fun onAnimationEnd(animator: Animator) {
+                        animation.setListener(null)
+                        view.alpha = 1f
+                        dispatchRemoveFinished(holder)
+                        mRemoveAnimations.remove(holder)
+                        dispatchFinishedWhenDone()
+                    }
+                }).start()
+    }
+
+    override fun animateAdd(holder: RecyclerView.ViewHolder): Boolean {
+        resetAnimation(holder)
+        mPendingAdditions.add(holder)
+        return true
+    }
+
+    /**
+     * 关闭默认局部刷新动画
+     */
+    fun closeDefaultAnimator() :NoAlphaItemAnimator {
+        addDuration = 0
+        changeDuration = 0
+        moveDuration = 0
+        removeDuration = 0
+        (this as SimpleItemAnimator).supportsChangeAnimations = false
+        return this
+    }
+
+    internal fun animateAddImpl(holder: RecyclerView.ViewHolder) {
+        val view = holder.itemView
+        val animation = view.animate()
+        mAddAnimations.add(holder)
+        animation.setDuration(addDuration)
+                .setListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationStart(animator: Animator) {
+                        dispatchAddStarting(holder)
+                    }
+
+                    override fun onAnimationCancel(animator: Animator) {
+
+                    }
+
+                    override fun onAnimationEnd(animator: Animator) {
+                        animation.setListener(null)
+                        dispatchAddFinished(holder)
+                        mAddAnimations.remove(holder)
+                        dispatchFinishedWhenDone()
+                    }
+                }).start()
+    }
+
+    override fun animateMove(holder: RecyclerView.ViewHolder, fromX: Int, fromY: Int,
+                             toX: Int, toY: Int): Boolean {
+        var fromX = fromX
+        var fromY = fromY
+        val view = holder.itemView
+        fromX += holder.itemView.translationX.toInt()
+        fromY += holder.itemView.translationY.toInt()
+        resetAnimation(holder)
+        val deltaX = toX - fromX
+        val deltaY = toY - fromY
+        if (deltaX == 0 && deltaY == 0) {
+            dispatchMoveFinished(holder)
+            return false
+        }
+        if (deltaX != 0) {
+            view.translationX = (-deltaX).toFloat()
+        }
+        if (deltaY != 0) {
+            view.translationY = (-deltaY).toFloat()
+        }
+        mPendingMoves.add(MoveInfo(holder, fromX, fromY, toX, toY))
+        return true
+    }
+
+    internal fun animateMoveImpl(holder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int) {
+        val view = holder.itemView
+        val deltaX = toX - fromX
+        val deltaY = toY - fromY
+        if (deltaX != 0) {
+            view.animate().translationX(0f)
+        }
+        if (deltaY != 0) {
+            view.animate().translationY(0f)
+        }
+        // TODO: make EndActions end listeners instead, since end actions aren't called when
+        // vpas are canceled (and can't end them. why?)
+        // need listener functionality in VPACompat for this. Ick.
+        val animation = view.animate()
+        mMoveAnimations.add(holder)
+        animation.setDuration(moveDuration).setListener(object : AnimatorListenerAdapter() {
+            override fun onAnimationStart(animator: Animator) {
+                dispatchMoveStarting(holder)
+            }
+
+            override fun onAnimationCancel(animator: Animator) {
+                if (deltaX != 0) {
+                    view.translationX = 0f
+                }
+                if (deltaY != 0) {
+                    view.translationY = 0f
+                }
+            }
+
+            override fun onAnimationEnd(animator: Animator) {
+                animation.setListener(null)
+                dispatchMoveFinished(holder)
+                mMoveAnimations.remove(holder)
+                dispatchFinishedWhenDone()
+            }
+        }).start()
+    }
+
+    override fun animateChange(oldHolder: RecyclerView.ViewHolder, newHolder: RecyclerView.ViewHolder?,
+                               fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean {
+        if (oldHolder === newHolder) {
+            // Don't know how to run change animations when the same view holder is re-used.
+            // run a move animation to handle position changes.
+            return animateMove(oldHolder, fromX, fromY, toX, toY)
+        }
+        val prevTranslationX = oldHolder.itemView.translationX
+        val prevTranslationY = oldHolder.itemView.translationY
+        val prevAlpha = oldHolder.itemView.alpha
+        resetAnimation(oldHolder)
+        val deltaX = (toX.toFloat() - fromX.toFloat() - prevTranslationX).toInt()
+        val deltaY = (toY.toFloat() - fromY.toFloat() - prevTranslationY).toInt()
+        // recover prev translation state after ending animation
+        oldHolder.itemView.translationX = prevTranslationX
+        oldHolder.itemView.translationY = prevTranslationY
+        oldHolder.itemView.alpha = prevAlpha
+        if (newHolder != null) {
+            // carry over translation values
+            resetAnimation(newHolder)
+            newHolder.itemView.translationX = (-deltaX).toFloat()
+            newHolder.itemView.translationY = (-deltaY).toFloat()
+            newHolder.itemView.alpha = 0f
+        }
+        mPendingChanges.add(ChangeInfo(oldHolder, newHolder!!, fromX, fromY, toX, toY))
+        return true
+    }
+
+    internal fun animateChangeImpl(changeInfo: ChangeInfo) {
+        val holder = changeInfo.oldHolder
+        val view = holder?.itemView
+        val newHolder = changeInfo.newHolder
+        val newView = newHolder?.itemView
+        if (view != null) {
+            val oldViewAnim = view.animate().setDuration(
+                    changeDuration)
+            mChangeAnimations.add(changeInfo.oldHolder!!)
+            oldViewAnim.translationX((changeInfo.toX - changeInfo.fromX).toFloat())
+            oldViewAnim.translationY((changeInfo.toY - changeInfo.fromY).toFloat())
+            oldViewAnim.setListener(object : AnimatorListenerAdapter() {
+                override fun onAnimationStart(animator: Animator) {
+                    dispatchChangeStarting(changeInfo.oldHolder, true)
+                }
+
+                override fun onAnimationEnd(animator: Animator) {
+                    oldViewAnim.setListener(null)
+                    view.alpha = 1f
+                    view.translationX = 0f
+                    view.translationY = 0f
+                    dispatchChangeFinished(changeInfo.oldHolder, true)
+                    mChangeAnimations.remove(changeInfo.oldHolder!!)
+                    dispatchFinishedWhenDone()
+                }
+            }).start()
+        }
+        if (newView != null) {
+            val newViewAnimation = newView.animate()
+            mChangeAnimations.add(changeInfo.newHolder!!)
+            newViewAnimation.translationX(0f).translationY(0f).setDuration(changeDuration)
+                    .setListener(object : AnimatorListenerAdapter() {
+                        override fun onAnimationStart(animator: Animator) {
+                            dispatchChangeStarting(changeInfo.newHolder, false)
+                        }
+
+                        override fun onAnimationEnd(animator: Animator) {
+                            newViewAnimation.setListener(null)
+                            newView.alpha = 1f
+                            newView.translationX = 0f
+                            newView.translationY = 0f
+                            dispatchChangeFinished(changeInfo.newHolder, false)
+                            mChangeAnimations.remove(changeInfo.newHolder!!)
+                            dispatchFinishedWhenDone()
+                        }
+                    }).start()
+        }
+    }
+
+    private fun endChangeAnimation(infoList: MutableList<ChangeInfo>, item: RecyclerView.ViewHolder) {
+        for (i in infoList.indices.reversed()) {
+            val changeInfo = infoList[i]
+            if (endChangeAnimationIfNecessary(changeInfo, item)) {
+                if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
+                    infoList.remove(changeInfo)
+                }
+            }
+        }
+    }
+
+    private fun endChangeAnimationIfNecessary(changeInfo: ChangeInfo) {
+        if (changeInfo.oldHolder != null) {
+            endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder)
+        }
+        if (changeInfo.newHolder != null) {
+            endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder)
+        }
+    }
+
+    private fun endChangeAnimationIfNecessary(changeInfo: ChangeInfo, item: RecyclerView.ViewHolder?): Boolean {
+        var oldItem = false
+        if (changeInfo.newHolder === item) {
+            changeInfo.newHolder = null
+        } else if (changeInfo.oldHolder === item) {
+            changeInfo.oldHolder = null
+            oldItem = true
+        } else {
+            return false
+        }
+        item!!.itemView.alpha = 1f
+        item.itemView.translationX = 0f
+        item.itemView.translationY = 0f
+        dispatchChangeFinished(item, oldItem)
+        return true
+    }
+
+    override fun endAnimation(item: RecyclerView.ViewHolder) {
+        val view = item.itemView
+        // this will trigger end callback which should set properties to their target values.
+        view.animate().cancel()
+        // TODO if some other animations are chained to end, how do we cancel them as well?
+        for (i in mPendingMoves.indices.reversed()) {
+            val moveInfo = mPendingMoves[i]
+            if (moveInfo.holder === item) {
+                view.translationY = 0f
+                view.translationX = 0f
+                dispatchMoveFinished(item)
+                mPendingMoves.removeAt(i)
+            }
+        }
+        endChangeAnimation(mPendingChanges, item)
+        if (mPendingRemovals.remove(item)) {
+            view.alpha = 1f
+            dispatchRemoveFinished(item)
+        }
+        if (mPendingAdditions.remove(item)) {
+            view.alpha = 1f
+            dispatchAddFinished(item)
+        }
+
+        for (i in mChangesList.indices.reversed()) {
+            val changes = mChangesList[i]
+            endChangeAnimation(changes, item)
+            if (changes.isEmpty()) {
+                mChangesList.removeAt(i)
+            }
+        }
+        for (i in mMovesList.indices.reversed()) {
+            val moves = mMovesList[i]
+            for (j in moves.indices.reversed()) {
+                val moveInfo = moves[j]
+                if (moveInfo.holder === item) {
+                    view.translationY = 0f
+                    view.translationX = 0f
+                    dispatchMoveFinished(item)
+                    moves.removeAt(j)
+                    if (moves.isEmpty()) {
+                        mMovesList.removeAt(i)
+                    }
+                    break
+                }
+            }
+        }
+        for (i in mAdditionsList.indices.reversed()) {
+            val additions = mAdditionsList[i]
+            if (additions.remove(item)) {
+                view.alpha = 1f
+                dispatchAddFinished(item)
+                if (additions.isEmpty()) {
+                    mAdditionsList.removeAt(i)
+                }
+            }
+        }
+
+        // animations should be ended by the cancel above.
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        if (mRemoveAnimations.remove(item) && DEBUG) {
+            throw IllegalStateException("after animation is cancelled, item should not be in " + "mRemoveAnimations list")
+        }
+
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        if (mAddAnimations.remove(item) && DEBUG) {
+            throw IllegalStateException("after animation is cancelled, item should not be in " + "mAddAnimations list")
+        }
+
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        if (mChangeAnimations.remove(item) && DEBUG) {
+            throw IllegalStateException("after animation is cancelled, item should not be in " + "mChangeAnimations list")
+        }
+
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        if (mMoveAnimations.remove(item) && DEBUG) {
+            throw IllegalStateException("after animation is cancelled, item should not be in " + "mMoveAnimations list")
+        }
+        dispatchFinishedWhenDone()
+    }
+
+    private fun resetAnimation(holder: RecyclerView.ViewHolder) {
+        if (sDefaultInterpolator == null) {
+            sDefaultInterpolator = ValueAnimator().interpolator
+        }
+        holder.itemView.animate().interpolator = sDefaultInterpolator
+        endAnimation(holder)
+    }
+
+    override fun isRunning(): Boolean {
+        return (!mPendingAdditions.isEmpty()
+                || !mPendingChanges.isEmpty()
+                || !mPendingMoves.isEmpty()
+                || !mPendingRemovals.isEmpty()
+                || !mMoveAnimations.isEmpty()
+                || !mRemoveAnimations.isEmpty()
+                || !mAddAnimations.isEmpty()
+                || !mChangeAnimations.isEmpty()
+                || !mMovesList.isEmpty()
+                || !mAdditionsList.isEmpty()
+                || !mChangesList.isEmpty())
+    }
+
+    /**
+     * Check the state of currently pending and running animations. If there are none
+     * pending/running, call [.dispatchAnimationsFinished] to notify any
+     * listeners.
+     */
+    internal fun dispatchFinishedWhenDone() {
+        if (!isRunning) {
+            dispatchAnimationsFinished()
+        }
+    }
+
+    override fun endAnimations() {
+        var count = mPendingMoves.size
+        for (i in count - 1 downTo 0) {
+            val item = mPendingMoves[i]
+            val view = item.holder.itemView
+            view.translationY = 0f
+            view.translationX = 0f
+            dispatchMoveFinished(item.holder)
+            mPendingMoves.removeAt(i)
+        }
+        count = mPendingRemovals.size
+        for (i in count - 1 downTo 0) {
+            val item = mPendingRemovals[i]
+            dispatchRemoveFinished(item)
+            mPendingRemovals.removeAt(i)
+        }
+        count = mPendingAdditions.size
+        for (i in count - 1 downTo 0) {
+            val item = mPendingAdditions[i]
+            item.itemView.alpha = 1f
+            dispatchAddFinished(item)
+            mPendingAdditions.removeAt(i)
+        }
+        count = mPendingChanges.size
+        for (i in count - 1 downTo 0) {
+            endChangeAnimationIfNecessary(mPendingChanges[i])
+        }
+        mPendingChanges.clear()
+        if (!isRunning) {
+            return
+        }
+
+        var listCount = mMovesList.size
+        for (i in listCount - 1 downTo 0) {
+            val moves = mMovesList[i]
+            count = moves.size
+            for (j in count - 1 downTo 0) {
+                val moveInfo = moves[j]
+                val item = moveInfo.holder
+                val view = item.itemView
+                view.translationY = 0f
+                view.translationX = 0f
+                dispatchMoveFinished(moveInfo.holder)
+                moves.removeAt(j)
+                if (moves.isEmpty()) {
+                    mMovesList.remove(moves)
+                }
+            }
+        }
+        listCount = mAdditionsList.size
+        for (i in listCount - 1 downTo 0) {
+            val additions = mAdditionsList[i]
+            count = additions.size
+            for (j in count - 1 downTo 0) {
+                val item = additions[j]
+                val view = item.itemView
+                view.alpha = 1f
+                dispatchAddFinished(item)
+                additions.removeAt(j)
+                if (additions.isEmpty()) {
+                    mAdditionsList.remove(additions)
+                }
+            }
+        }
+        listCount = mChangesList.size
+        for (i in listCount - 1 downTo 0) {
+            val changes = mChangesList[i]
+            count = changes.size
+            for (j in count - 1 downTo 0) {
+                endChangeAnimationIfNecessary(changes[j])
+                if (changes.isEmpty()) {
+                    mChangesList.remove(changes)
+                }
+            }
+        }
+
+        cancelAll(mRemoveAnimations)
+        cancelAll(mMoveAnimations)
+        cancelAll(mAddAnimations)
+        cancelAll(mChangeAnimations)
+
+        dispatchAnimationsFinished()
+    }
+
+    internal fun cancelAll(viewHolders: List<RecyclerView.ViewHolder>) {
+        for (i in viewHolders.indices.reversed()) {
+            viewHolders[i].itemView.animate().cancel()
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     *
+     * If the payload list is not empty, DefaultItemAnimator returns `true`.
+     * When this is the case:
+     *
+     *  * If you override [.animateChange], both
+     * ViewHolder arguments will be the same instance.
+     *
+     *  *
+     * If you are not overriding [.animateChange],
+     * then DefaultItemAnimator will call [.animateMove] and
+     * run a move animation instead.
+     *
+     *
+     */
+    override fun canReuseUpdatedViewHolder(viewHolder: RecyclerView.ViewHolder,
+                                           payloads: List<Any>): Boolean {
+        return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads)
+    }
+}

+ 39 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/OnClickListenerAntiViolence.kt

@@ -0,0 +1,39 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.util.Log
+import android.view.View
+
+/**
+ * @author LDD
+ * @Data   2018/1/5 上午10:01
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note
+ */
+class OnClickListenerAntiViolence(val event:((view :View) -> Unit),val interval : Int = 1000) :View.OnClickListener {
+
+    /**
+     * @Name  time
+     * @Type  Long
+     * @Note  点击事件记录
+     */
+    private var time :Long = -12345678910
+
+
+    /**
+     * @author  LDD
+     * @From    OnClickListenerAntiViolence
+     * @Data   2018/1/5 上午10:04
+     * @Note   点击相应
+     * @param  view  所点击的View
+     */
+    override fun onClick(view: View) {
+
+        if (time == -12345678910){
+            time = System.currentTimeMillis()
+            event(view)
+        }else if (System.currentTimeMillis()-time > interval){
+            time = System.currentTimeMillis()
+            event(view)
+        }
+    }
+}

+ 57 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/OnItemClickListenerAntiViolence.kt

@@ -0,0 +1,57 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.view.View
+import android.widget.AdapterView
+
+/**
+ * @author  LDD
+ * @Data   2018/1/5 上午10:37
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   防暴力点击 ItemClickListener
+ */
+class OnItemClickListenerAntiViolence(val event :((adapterView: AdapterView<*>?, itemView: View?, position: Int, itemId: Long) -> Unit),val interval: Int = 1000) :AdapterView.OnItemClickListener {
+
+    /**
+     * @Name  time
+     * @Type  Long
+     * @Note  点击事件记录
+     */
+    private var time :Long = -12345678910
+
+    /**
+     * @Name  index
+     * @Type  Int
+     * @Note  点击下标记录
+     */
+    private var index :Int = -1
+
+    /**
+     * @author LDD
+     * @From   OnItemClickListenerAntiViolence
+     * @Data   2018/1/5 上午10:18
+     * @Note   Item点击事件
+     * @param  p0    列表视图
+     * @param  p1    所点击的视图
+     * @param  p2    position
+     * @param  p3    item ID
+     */
+    override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
+        if (index == p2){
+            if (time == -12345678910){
+                index = p2
+                event(p0,p1,p2,p3)
+                time = System.currentTimeMillis()
+            }else{
+                if (System.currentTimeMillis()-time >interval){
+                    index = p2
+                    event(p0,p1,p2,p3)
+                    time = System.currentTimeMillis()
+                }
+            }
+        }else{
+            index = p2
+            event(p0,p1,p2,p3)
+            time = System.currentTimeMillis()
+        }
+    }
+}

+ 338 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/RecycleViewScrollHelper.kt

@@ -0,0 +1,338 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.LinearLayoutManager
+
+
+/**
+ * @author LDD
+ * @Date   2018/3/15 下午3:59
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   RecycleView 滑动监听
+ */
+class RecycleViewScrollHelper
+/**
+ * recycleView的滑动监听事件,用于检测是否滑动到顶部或者滑动到底部.
+ *
+ * @param listener [OnScrollPositionChangedListener]滑动位置变动监听事件
+ */
+(listener: OnScrollPositionChangedListener) : RecyclerView.OnScrollListener() {
+    private var mRvScroll: RecyclerView? = null
+    private var mScrollDirectionChangedListener: OnScrollDirectionChangedListener? = null
+    //滑动位置变动的监听事件
+    private var mScrollPositionChangedListener: OnScrollPositionChangedListener? = null
+    //是否同时检测滑动到顶部及底部
+    private var mIsCheckTopBottomTogether = false
+    //检测滑动顶部/底部的优先顺序,默认先检测滑动到底部
+    private var mIsCheckTopFirstBottomAfter = false
+    //检测底部滑动时是否检测满屏状态
+    private var mIsCheckBottomFullRecycle = false
+    //检测顶部滑动时是否检测满屏状态
+    private var mIsCheckTopFullRecycle = false
+    //顶部满屏检测时允许的容差值
+    private var mTopOffsetFaultTolerance = 0
+    //底部满屏检测时允许的容差值
+    private var mBottomOffsetFaultTolerance = 0
+
+
+    private var mScrollDx = 0
+    private var mScrollDy = 0
+
+    init {
+        mScrollPositionChangedListener = listener
+    }
+
+    override fun onScrollStateChanged(recyclerView: RecyclerView?,
+                                      newState: Int) {
+        if (mScrollPositionChangedListener == null || recyclerView!!.adapter == null || recyclerView.childCount <= 0) {
+            return
+        }
+        val layoutManager = recyclerView.layoutManager
+        if (layoutManager is LinearLayoutManager) {
+            val lastItemPosition = layoutManager.findLastVisibleItemPosition()
+            val firstItemPosition = layoutManager.findFirstVisibleItemPosition()
+            val adapter = recyclerView.adapter
+            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+                //判断顶部/底部检测的优先顺序
+                if (!mIsCheckTopFirstBottomAfter) {
+                    //先检测底部
+                    if (this.checkIfScrollToBottom(recyclerView, lastItemPosition, adapter.itemCount)) {
+                        //若检测滑动到底部时,判断是否需要同时检测滑动到顶部
+                        if (mIsCheckTopBottomTogether) {
+                            //检测是否滑动到顶部
+                            this.checkIfScrollToTop(recyclerView, firstItemPosition)
+                            //不管是否滑动到顶部,已经触发了滑动到底部,所以直接返回,否则会调用滑动到未知位置的
+                            return
+                        } else {
+                            //若不需要同时检测,直接返回
+                            return
+                        }
+                    } else if (this.checkIfScrollToTop(recyclerView, firstItemPosition)) {
+                        //当未检测滑动到底部时,再检测是否滑动到顶部
+                        return
+                    }
+                } else {
+                    //先检测是否滑动到顶部
+                    if (this.checkIfScrollToTop(recyclerView, firstItemPosition)) {
+                        if (mIsCheckTopBottomTogether) {
+                            //检测是否滑动到底部
+                            this.checkIfScrollToBottom(recyclerView, lastItemPosition, adapter.itemCount)
+                            return
+                        } else {
+                            //若不需要同时检测,直接返回
+                            return
+                        }
+                    } else if (this.checkIfScrollToBottom(recyclerView, lastItemPosition, adapter.itemCount)) {
+                        //当未检测滑动到底部时,再检测是否滑动到底部
+                        return
+                    }
+                }
+            }
+        }
+        //其它任何情况
+        mScrollPositionChangedListener!!.onScrollToUnknown(false, false)
+    }
+
+    /**
+     * 检测是否滑动到了顶部item并回调事件
+     *
+     * @param recyclerView
+     * @param firstItemPosition 第一个可见itemView的position
+     * @return
+     */
+    private fun checkIfScrollToTop(recyclerView: RecyclerView, firstItemPosition: Int): Boolean {
+        if (firstItemPosition == 0) {
+            if (mIsCheckTopFullRecycle) {
+                val childCount = recyclerView.childCount
+                val firstChild = recyclerView.getChildAt(0)
+                val lastChild = recyclerView.getChildAt(childCount - 1)
+                val top = firstChild.top
+                val bottom = lastChild.bottom
+                //recycleView显示itemView的有效区域的top坐标Y
+                val topEdge = recyclerView.paddingTop - mTopOffsetFaultTolerance
+                //recycleView显示itemView的有效区域的bottom坐标Y
+                val bottomEdge = recyclerView.height - recyclerView.paddingBottom - mBottomOffsetFaultTolerance
+                //第一个view的顶部大于top边界值,说明第一个view已经完全显示在顶部
+                //同时最后一个view的底部应该小于bottom边界值,说明最后一个view的底部已经超出显示范围,部分或者完全移出了界面
+                if (top >= topEdge && bottom > bottomEdge) {
+                    mScrollPositionChangedListener!!.onScrollToTop()
+                    return true
+                } else {
+                    mScrollPositionChangedListener!!.onScrollToUnknown(true, false)
+                }
+            } else {
+                mScrollPositionChangedListener!!.onScrollToTop()
+                return true
+            }
+        }
+        return false
+    }
+
+    /**
+     * 检测是否滑动到底部item并回调事件
+     *
+     * @param recyclerView
+     * @param lastItemPosition 最后一个可见itemView的position
+     * @param itemCount        adapter的itemCount
+     * @return
+     */
+    private fun checkIfScrollToBottom(recyclerView: RecyclerView, lastItemPosition: Int, itemCount: Int): Boolean {
+        if (lastItemPosition + 1 == itemCount) {
+            //是否进行满屏的判断处理
+            //未满屏的情况下将永远不会被回调滑动到低部或者顶部
+            if (mIsCheckBottomFullRecycle) {
+                val childCount = recyclerView.childCount
+                //获取最后一个childView
+                val lastChildView = recyclerView.getChildAt(childCount - 1)
+                //获取第一个childView
+                val firstChildView = recyclerView.getChildAt(0)
+                val top = firstChildView.top
+                val bottom = lastChildView.bottom
+                //recycleView显示itemView的有效区域的bottom坐标Y
+                val bottomEdge = recyclerView.height - recyclerView.paddingBottom + mBottomOffsetFaultTolerance
+                //recycleView显示itemView的有效区域的top坐标Y
+                val topEdge = recyclerView.paddingTop + mTopOffsetFaultTolerance
+                //第一个view的顶部小于top边界值,说明第一个view已经部分或者完全移出了界面
+                //最后一个view的底部小于bottom边界值,说明最后一个view已经完全显示在界面
+                //若不处理这种情况,可能会存在recycleView高度足够高时,itemView数量很少无法填充一屏,但是滑动到最后一项时依然会发生回调
+                //此时其实并不需要任何刷新操作的
+                if (bottom <= bottomEdge && top < topEdge) {
+                    mScrollPositionChangedListener!!.onScrollToBottom()
+                    return true
+                } else {
+                    mScrollPositionChangedListener!!.onScrollToUnknown(false, true)
+                }
+            } else {
+                mScrollPositionChangedListener!!.onScrollToBottom()
+                return true
+            }
+        }
+        return false
+    }
+
+    override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
+        if (mScrollDirectionChangedListener != null) {
+            if (dx == 0 && dy == 0) {
+                mScrollDirectionChangedListener!!.onScrollDirectionChanged(0, 0)
+            } else if (dx == 0) {
+                val isUp = dy > 0
+                val isBeenUp = mScrollDy > 0
+                if (isUp != isBeenUp) {
+                    mScrollDx = dx
+                    mScrollDy = dy
+                    mScrollDirectionChangedListener!!.onScrollDirectionChanged(dx, dy)
+                }
+            } else if (dy == 0) {
+                val isLeft = dx > 0
+                val isBeenLeft = mScrollDx > 0
+                if (isLeft != isBeenLeft) {
+                    mScrollDx = dx
+                    mScrollDy = dy
+                    mScrollDirectionChangedListener!!.onScrollDirectionChanged(dx, dy)
+                }
+            }
+        }
+    }
+
+    //重置数据
+    private fun reset() {
+        mScrollDx = 0
+        mScrollDy = 0
+    }
+
+    /**
+     * 关联recycleView,当关联新的recycleView时,会自动移除上一个关联recycleView
+     *
+     * @param recyclerView
+     */
+    fun attachToRecycleView(recyclerView: RecyclerView?) {
+        if (recyclerView !== mRvScroll) {
+            unAttachToRecycleView()
+            mRvScroll = recyclerView
+            recyclerView?.addOnScrollListener(this)
+        }
+    }
+
+    /**
+     * 移除与recycleView的绑定
+     */
+    fun unAttachToRecycleView() {
+        if (mRvScroll != null) {
+            mRvScroll!!.removeOnScrollListener(this)
+        }
+        this.reset()
+    }
+
+    /**
+     * 设置滑动方向改变时的回调接口
+     *
+     * @param listener
+     */
+    fun setScrollDirectionChangedListener(listener: OnScrollDirectionChangedListener) {
+        mScrollDirectionChangedListener = listener
+    }
+
+    /**
+     * 设置顶部允许偏移的容差值,此值仅在允许检测满屏时有效,当[.setCheckIfItemViewFullRecycleViewForTop]设置为true 或者[.setCheckIfItemViewFullRecycleViewForBottom]设置为true 时有效.<br></br>
+     * 在检测底部滑动时,对顶部的检测会添加此容差值(更容易判断当前第一项childView已超出recycleView的显示范围),用于协助判断是否滑动到底部.
+     * 在检测顶部滑动时,对顶部的检测会添加此容差值(更容易判断为滑动到了顶部)
+     *
+     * @param offset 容差值,此值必须为0或正数
+     */
+    fun setTopOffsetFaultTolerance(offset: Int) {
+        mTopOffsetFaultTolerance = offset
+    }
+
+    /**
+     * 设置顶部允许偏移的容差值,此值仅在允许检测满屏时有效,当[.setCheckIfItemViewFullRecycleViewForTop]设置为true 或者[.setCheckIfItemViewFullRecycleViewForBottom]设置为true 时有效.<br></br>
+     * 在检测底部滑动时,对底部的检测会添加此容差值(更容易判断当前最后一项childView已超出recycleView的显示范围),用于协助判断是否滑动到顶部.
+     * 在检测顶部滑动时,对底部的检测会添加此容差值(更容易判断为滑动到了底部)
+     *
+     * @param offset 容差值,此值必须为0或正数
+     */
+    fun setBottomFaultTolerance(offset: Int) {
+        mBottomOffsetFaultTolerance = offset
+    }
+
+    /**
+     * 设置是否需要检测recycleView是否为满屏的itemView时才回调事件.<br></br>
+     *
+     *
+     * 当RecycleView的childView数量很少时,有可能RecycleView已经显示出所有的itemView,此时不存在向上滑动的可能.<br></br>
+     * 若设置当前值为true时,只有在RecycleView无法完全显示所有的itemView时,才会回调滑动到顶部的事件;否则将不处理;<br></br>
+     * 若设置为false则反之,不管任何时候只要滑动并顶部item显示时都会回调滑动事件
+     *
+     * @param isNeedToCheck true为当检测是否满屏显示;false不检测,直接回调事件
+     */
+    fun setCheckIfItemViewFullRecycleViewForTop(isNeedToCheck: Boolean) {
+        mIsCheckTopFullRecycle = isNeedToCheck
+    }
+
+    /**
+     * 设置是否需要检测recycleView是否为满屏的itemView时才回调事件.<br></br>
+     *
+     *
+     * 当RecycleView的childView数量很少时,有可能RecycleView已经显示o出所有的itemView,此时不存在向下滑动的可能.
+     * 若设置当前值为true时,只有在RecycleView无法完全显示所有的itemView时,才会回调滑动到底部的事件;否则将不处理;
+     * 若设置为false则反之,不管任何时候只要滑动到底部都会回调滑动事件
+     *
+     * @param isNeedToCheck true为当检测是否满屏显示;false不检测,直接回调事件
+     */
+    fun setCheckIfItemViewFullRecycleViewForBottom(isNeedToCheck: Boolean) {
+        mIsCheckBottomFullRecycle = isNeedToCheck
+    }
+
+    /**
+     * 设置是否先检测滑动到哪里.默认为false,先检测滑动到底部
+     *
+     * @param isTopFirst true为先检测滑动到顶部再检测滑动到底部;false为先检测滑动到底部再滑动到顶部
+     */
+    fun setCheckScrollToTopFirstBottomAfter(isTopFirst: Boolean) {
+        mIsCheckTopFirstBottomAfter = isTopFirst
+    }
+
+    /**
+     * 设置是否同时检测滑动到顶部及底部,默认为false,先检测到任何一个状态都会直接返回,不会再继续检测其它状态
+     *
+     * @param isCheckTogether true为两种状态都检测,即使已经检测到其中某种状态了.false为先检测到任何一种状态时将不再检测另一种状态
+     */
+    fun setCheckScrollToTopBottomTogether(isCheckTogether: Boolean) {
+        mIsCheckTopBottomTogether = isCheckTogether
+    }
+
+    /**
+     * 滑动位置改变监听事件,滑动到顶部/底部或者非以上两个位置时
+     */
+    interface OnScrollPositionChangedListener {
+        /**
+         * 滑动到顶部的回调事件
+         */
+        fun onScrollToTop()
+
+        /**
+         * 滑动到底部的回调事件
+         */
+        fun onScrollToBottom()
+
+        /**
+         * 滑动到未知位置的回调事件
+         *
+         * @param isTopViewVisible    当前位置顶部第一个itemView是否可见,这里是指adapter中的最后一个itemView
+         * @param isBottomViewVisible 当前位置底部最后一个itemView是否可见,这里是指adapter中的最后一个itemView
+         */
+        fun onScrollToUnknown(isTopViewVisible: Boolean, isBottomViewVisible: Boolean)
+    }
+
+    /**
+     * 滑动方向改变时监听事件
+     */
+    interface OnScrollDirectionChangedListener {
+        /**
+         * 滑动方向改变时监听事件,当两个参数值都为0时,数据变动重新layout
+         *
+         * @param scrollVertical   竖直方向的滑动方向,向上&lt;0,向下&gt;0,不动(水平滑动时)=0
+         * @param scrollHorizontal 水平方向的滑动方向,向左&lt;0,向右&gt;0,不动(竖直滑动时)=0
+         */
+        fun onScrollDirectionChanged(scrollHorizontal: Int, scrollVertical: Int)
+    }
+}

+ 305 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/ReflexHelper.kt

@@ -0,0 +1,305 @@
+package com.wdkl.ncs.android.lib.utils
+
+/**
+ * @author LDD
+ * @Date   2018/4/18 上午11:13
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   反射工具类
+ */
+class ReflexHelper private constructor(clsName :String){
+    
+    /**
+     * @author LDD
+     * @Date   2018/4/18 下午3:47
+     * @From   ReflexHelper
+     * @Note   用来避免在Kotlin中使用反射 Kotlin基础类型无法对应Java基础类型
+     */
+    data class ReflexFieldShell<T>(var value: T)
+
+    /**
+     * @Name  cls
+     * @Type  Class<*>
+     * @Note  查找到的Class对象
+     */
+    private val cls :Class<*> = Class.forName(clsName)
+
+    /**
+     * @Name  instance
+     * @Type  Any
+     * @Note  反射实例化出来的对象
+     */
+    private lateinit var instance :Any
+
+    /**
+     * @author LDD
+     * @Date   2018/4/19 下午2:29
+     * @From   ReflexHelper
+     * @Note   伴生对象用来静态build
+     */
+    companion object {
+
+        /**
+         * @author LDD
+         * @From   ReflexHelper
+         * @Date   2018/4/19 下午2:30
+         * @Note   静态构建
+         * @param  clsName 反射类对应全包名
+         */
+        fun build(clsName: String):ReflexHelper{
+            return ReflexHelper(clsName)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:30
+     * @Note   无参实例化
+     */
+    fun newInstance() :ReflexHelper{
+        instance = cls.newInstance()
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:32
+     * @Note   1参反射实例化
+     * @param  arg0 参数
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     */
+    fun newInstance(arg0 :Any,isPrivate :Boolean = false) :ReflexHelper{
+        val constructor = cls.getConstructor(arg0::class.java)
+        constructor.isAccessible = isPrivate
+        instance =  constructor.newInstance(arg0)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:32
+     * @Note   2参反射实例化
+     * @param  arg0 参数
+     * @param  arg1 参数
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     */
+    fun newInstance(arg0 :Any ,arg1 :Any,isPrivate :Boolean = false) :ReflexHelper{
+        val constructor = cls.getConstructor(arg0::class.java,arg1::class.java)
+        constructor.isAccessible = isPrivate
+        instance = constructor.newInstance(arg0,arg1)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:32
+     * @Note   3参反射实例化
+     * @param  arg0 参数
+     * @param  arg1 参数
+     * @param  arg2 参数
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     */
+    fun newInstance(arg0 :Any ,arg1 :Any ,arg2 :Any,isPrivate :Boolean = false) :ReflexHelper{
+        val constructor = cls.getConstructor(arg0::class.java,arg1::class.java,arg2::class.java)
+        constructor.isAccessible = isPrivate
+        instance = constructor.newInstance(arg0,arg1,arg2)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:32
+     * @Note   4参反射实例化
+     * @param  arg0 参数
+     * @param  arg1 参数
+     * @param  arg2 参数
+     * @param  arg3 参数
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     */
+    fun newInstance(arg0 :Any ,arg1 :Any ,arg2 :Any ,arg3 :Any ,isPrivate :Boolean = false) :ReflexHelper{
+        val constructor = cls.getConstructor(arg0::class.java,arg1::class.java,arg2::class.java,arg3::class.java)
+        constructor.isAccessible = isPrivate
+        instance = constructor.newInstance(arg0,arg1,arg2,arg3)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:32
+     * @Note   4参反射实例化
+     * @param  arg0 参数
+     * @param  arg1 参数
+     * @param  arg2 参数
+     * @param  arg3 参数
+     * @param  arg4 参数
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     */
+    fun newInstance( arg0 :Any ,arg1 :Any ,arg2 :Any ,arg3 :Any ,arg4 :Any ,isPrivate :Boolean = false) :ReflexHelper{
+        val constructor = cls.getConstructor(arg0::class.java,arg1::class.java,arg2::class.java,arg3::class.java,arg4::class.java)
+        constructor.isAccessible = isPrivate
+        instance = constructor.newInstance(arg0,arg1,arg2,arg3,arg4)
+        return this
+    }
+
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:37
+     * @Note   无参数方法反射调用
+     * @param  methodName 方法名
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     * @param  call      如果存在返回参数 实现该回调
+     */
+    fun callMethod(methodName :String ,call :((Any) ->Unit)? = null ,isPrivate :Boolean = false):ReflexHelper{
+        val method = cls.getMethod(methodName)
+        method.isAccessible = isPrivate
+        if (call == null){
+            method.invoke(instance)
+        }else{
+            call.invoke(method.invoke(instance))
+        }
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:37
+     * @Note   无参数方法反射调用
+     * @param  methodName 方法名
+     * @param  arg0  参数
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     * @param  call      如果存在返回参数 实现该回调
+     */
+    fun callMethod(methodName :String ,arg0: Any ,call :((Any) ->Unit)? = null ,isPrivate :Boolean = false):ReflexHelper{
+        val method = cls.getMethod(methodName,arg0::class.java)
+        method.isAccessible = isPrivate
+        if (call == null){
+            method.invoke(instance,arg0)
+        }else{
+            call.invoke(method.invoke(instance,arg0))
+        }
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:37
+     * @Note   无参数方法反射调用
+     * @param  arg0  参数
+     * @param  arg1  参数
+     * @param  methodName 方法名
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     * @param  call      如果存在返回参数 实现该回调
+     */
+    fun callMethod(methodName :String ,arg0: Any ,arg1: Any ,call :((Any) ->Unit)? = null,isPrivate :Boolean = false):ReflexHelper{
+        val method = cls.getMethod(methodName,arg0::class.java,arg1::class.java)
+        method.isAccessible = isPrivate
+        if (call == null){
+            method.invoke(instance,arg0,arg1)
+        }else{
+            call.invoke(method.invoke(instance,arg0,arg1))
+        }
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:37
+     * @Note   无参数方法反射调用
+     * @param  methodName 方法名
+     * @param  arg0  参数
+     * @param  arg1  参数
+     * @param  arg2  参数
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     * @param  call      如果存在返回参数 实现该回调
+     */
+    fun callMethod(methodName :String ,arg0: Any ,arg1: Any ,arg2: Any ,call :((Any) ->Unit)? = null,isPrivate :Boolean = false):ReflexHelper{
+        val method = cls.getMethod(methodName,arg0::class.java,arg1::class.java,arg2::class.java)
+        method.isAccessible = isPrivate
+        if (call == null){
+            method.invoke(instance,arg0,arg1,arg2)
+        }else{
+            call.invoke(method.invoke(instance,arg0,arg1,arg2))
+        }
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:37
+     * @Note   无参数方法反射调用
+     * @param  methodName 方法名
+     * @param  arg0  参数
+     * @param  arg1  参数
+     * @param  arg2  参数
+     * @param  arg3  参数
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     * @param  call      如果存在返回参数 实现该回调
+     */
+    fun callMethod(methodName :String ,arg0: Any ,arg1: Any ,arg2: Any ,arg3: Any ,call :((Any) ->Unit)? = null,isPrivate :Boolean = false):ReflexHelper{
+        val method = cls.getMethod(methodName,arg0::class.java,arg1::class.java,arg2::class.java,arg3::class.java)
+        method.isAccessible = isPrivate
+        if (call == null){
+            method.invoke(instance,arg0,arg1,arg2,arg3)
+        }else{
+            call.invoke(method.invoke(instance,arg0,arg1,arg2,arg3))
+        }
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:37
+     * @Note   无参数方法反射调用
+     * @param  methodName 方法名
+     * @param  arg0  参数
+     * @param  arg1  参数
+     * @param  arg2  参数
+     * @param  arg3  参数
+     * @param  arg4  参数
+     * @param  isPrivate 是否开启私有方法访问 违反封装规范
+     * @param  call      如果存在返回参数 实现该回调
+     */
+    fun callMethod(methodName :String ,arg0: Any ,arg1: Any ,arg2: Any ,arg3: Any ,arg4: Any ,call :((Any) ->Unit)? = null,isPrivate :Boolean = false):ReflexHelper{
+        val method = cls.getMethod(methodName,arg0::class.java,arg1::class.java,arg2::class.java,arg3::class.java,arg4::class.java)
+        method.isAccessible = isPrivate
+        if (call == null){
+            method.invoke(instance,arg0,arg1,arg2,arg3,arg4)
+        }else{
+            call.invoke(method.invoke(instance,arg0,arg1,arg2,arg3,arg4))
+        }
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:41
+     * @Note   获取反射成功的Class
+     */
+    fun <ValueType> getObjectClass() :Class<ValueType>{
+        return cls.to()
+    }
+
+    /**
+     * @author LDD
+     * @From   ReflexHelper
+     * @Date   2018/4/19 下午2:42
+     * @Note   获取反射成功的对象
+     */
+    fun <ValueType> getInstance() :ValueType{
+        return instance.to()
+    }
+
+}

+ 26 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/RegularHelper.kt

@@ -0,0 +1,26 @@
+package com.wdkl.ncs.android.lib.utils
+
+import java.util.regex.Pattern
+
+/**
+ * Created by LDD on 2018/11/16.
+ */
+class RegularHelper {
+
+    fun getMiddleString(content : String , start :String , endString: String , first :Boolean = false) : ArrayList<String>  {
+
+        val result = ArrayList<String>()
+
+        val pattern = Pattern.compile("$start(.*?)$endString")
+
+        val finder = pattern.matcher(content)
+
+        while (finder.find()){
+            result.add(finder.group(1))
+        }
+
+        return result
+
+    }
+
+}

+ 18 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/RxExtra.kt

@@ -0,0 +1,18 @@
+package com.wdkl.ncs.android.lib.utils
+
+import io.reactivex.Observable
+import okhttp3.ResponseBody
+
+/**
+ * Created by LDD on 2018/11/9.
+ */
+object RxExtra {
+
+    fun createNetErrorObservable (message :String) : Observable<ResponseBody>{
+        return  Observable.create { observableEmitter ->
+            observableEmitter.onError(Throwable(message))
+        }
+    }
+
+
+}

+ 156 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/SmartHideViewHelper.kt

@@ -0,0 +1,156 @@
+package com.wdkl.ncs.android.lib.utils
+
+import com.scwang.smartrefresh.layout.api.RefreshFooter
+import com.scwang.smartrefresh.layout.api.RefreshHeader
+import com.scwang.smartrefresh.layout.api.RefreshLayout
+import com.scwang.smartrefresh.layout.constant.RefreshState
+import com.scwang.smartrefresh.layout.listener.OnMultiPurposeListener
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.component.home.utils
+ * @Date   2018/1/30 下午3:06
+ * @Note   首页上滑topbar变幻辅助类
+ */
+
+class SmartHideViewHelper constructor(val refreshScrollStart: () -> Unit, val refreshEnd: () -> Unit) : OnMultiPurposeListener{
+
+    /**
+     * @Name  headerReleasing
+     * @Type  Boolean
+     * @Note  是否刷新
+     */
+    private  var headerReleasing =true
+
+
+    override fun onFooterMoving(footer: RefreshFooter?, isDragging: Boolean, percent: Float, offset: Int, footerHeight: Int, maxDragHeight: Int) {
+        refreshEnd.invoke()
+    }
+
+    override fun onHeaderStartAnimator(header: RefreshHeader?, headerHeight: Int, maxDragHeight: Int) {
+
+    }
+
+    override fun onFooterReleased(footer: RefreshFooter?, footerHeight: Int, maxDragHeight: Int) {
+        refreshEnd.invoke()
+    }
+
+    override fun onStateChanged(refreshLayout: RefreshLayout, oldState: RefreshState, newState: RefreshState) {
+        if (!headerReleasing){
+            refreshEnd.invoke()
+        }
+    }
+
+    override fun onHeaderMoving(header: RefreshHeader?, isDragging: Boolean, percent: Float, offset: Int, headerHeight: Int, maxDragHeight: Int) {
+        headerReleasing = true
+    }
+
+    override fun onFooterFinish(footer: RefreshFooter?, success: Boolean) {
+
+    }
+
+    override fun onFooterStartAnimator(footer: RefreshFooter?, footerHeight: Int, maxDragHeight: Int) {
+
+    }
+
+    override fun onHeaderReleased(header: RefreshHeader?, headerHeight: Int, maxDragHeight: Int) {
+        refreshScrollStart.invoke()
+    }
+
+    override fun onLoadMore(refreshLayout: RefreshLayout) {
+
+    }
+
+    override fun onRefresh(refreshLayout: RefreshLayout) {
+
+    }
+
+    override fun onHeaderFinish(header: RefreshHeader?, success: Boolean) {
+
+    }
+}
+
+//class SmartHideViewHelper : OnMultiPurposeListener {
+//
+//    override fun onFooterReleased(p0: RefreshFooter?, p1: Int, p2: Int) {
+//
+//    }
+//
+//    override fun onHeaderReleased(p0: RefreshHeader?, p1: Int, p2: Int) {
+//
+//    }
+//
+//    override fun onLoadMore(p0: RefreshLayout?) {
+//
+//    }
+//
+//    /**
+//     * @Name  headerReleasing
+//     * @Type  Boolean
+//     * @Note  是否刷新
+//     */
+//    private  var headerReleasing =true
+//
+//    /**
+//     * @Name  refreshScrollStart
+//     * @Type  block
+//     * @Note  开始刷新回调
+//     */
+//    private  var refreshScrollStart :()->(Unit)
+//
+//    /**
+//     * @Name  refreshEnd
+//     * @Type  block
+//     * @Note  刷新结束回调
+//     */
+//    private  var refreshEnd :()->(Unit)
+//
+//
+//    constructor(refreshScrollStart: () -> Unit, refreshEnd: () -> Unit) {
+//        this.refreshScrollStart = refreshScrollStart
+//        this.refreshEnd = refreshEnd
+//    }
+//
+//
+//    override fun onFooterPulling(footer: RefreshFooter?, percent: Float, offset: Int, footerHeight: Int, extendHeight: Int) {
+//        refreshEnd.invoke()
+//    }
+//
+//    override fun onHeaderReleasing(header: RefreshHeader?, percent: Float, offset: Int, headerHeight: Int, extendHeight: Int) {
+//        headerReleasing = true
+//    }
+//
+//    override fun onHeaderStartAnimator(header: RefreshHeader?, headerHeight: Int, extendHeight: Int) {
+//    }
+//
+//    override fun onStateChanged(refreshLayout: RefreshLayout?, oldState: RefreshState?, newState: RefreshState?) {
+//        if (!headerReleasing){
+//            refreshEnd.invoke()
+//        }
+//    }
+//
+//    override fun onFooterFinish(footer: RefreshFooter?, success: Boolean) {
+//
+//    }
+//
+//    override fun onFooterStartAnimator(footer: RefreshFooter?, footerHeight: Int, extendHeight: Int) {
+//
+//    }
+//
+//    override fun onFooterReleasing(footer: RefreshFooter?, percent: Float, offset: Int, footerHeight: Int, extendHeight: Int) {
+//        refreshEnd.invoke()
+//    }
+//
+//    override fun onHeaderPulling(header: RefreshHeader?, percent: Float, offset: Int, headerHeight: Int, extendHeight: Int) {
+//        refreshScrollStart.invoke()
+//    }
+//
+//    override fun onRefresh(refreshlayout: RefreshLayout?) {
+//
+//    }
+//
+//    override fun onHeaderFinish(header: RefreshHeader?, success: Boolean) {
+//
+//    }
+//
+//}

+ 165 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/TangramPlugin.kt

@@ -0,0 +1,165 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.app.Activity
+import android.support.v7.widget.RecyclerView
+import android.view.View
+import android.widget.ImageView
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.engine.DiskCacheStrategy
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.enation.javashop.imagepluin.R
+import com.tmall.wireless.tangram.TangramBuilder
+import com.tmall.wireless.tangram.TangramEngine
+import com.tmall.wireless.tangram.dataparser.concrete.Card
+import com.tmall.wireless.tangram.structure.BaseCell
+import com.tmall.wireless.tangram.structure.viewcreator.ViewHolderCreator
+import com.tmall.wireless.tangram.support.ExposureSupport
+import com.tmall.wireless.tangram.support.SimpleClickSupport
+import com.tmall.wireless.tangram.support.async.AsyncLoader
+import com.tmall.wireless.tangram.support.async.AsyncPageLoader
+import com.tmall.wireless.tangram.support.async.CardLoadSupport
+import com.tmall.wireless.tangram.util.IInnerImageSetter
+import org.json.JSONArray
+
+/**
+ * 七巧板辅助类
+ */
+class TangramPlugin :TangramIInter{
+
+    private lateinit var builder:TangramBuilder.InnerBuilder
+
+    private var engine:TangramEngine? = null
+
+    companion object {
+        fun initApplication(){
+            TangramBuilder.init(BaseApplication.appContext,object : IInnerImageSetter {
+                override fun <IMAGE : ImageView?> doLoadImageUrl(view: IMAGE, url: String?) {
+                    if (view != null) {
+                        Glide.with(view.context)
+                                .load(url)
+                                .fitCenter()
+                                .diskCacheStrategy(DiskCacheStrategy.ALL)
+                                .placeholder(R.drawable.image_loading)
+                                .error(R.drawable.image_error)
+                                .dontAnimate()
+                                .dontTransform()
+                                .into(view)
+                    }
+                }
+            }, ImageView::class.java)
+        }
+        fun prepare(context :Activity):TangramPlugin{
+            return TangramPlugin().build(context)
+        }
+    }
+
+    private fun build(context :Activity):TangramPlugin{
+        builder = TangramBuilder.newInnerBuilder(context)
+        return this
+    }
+
+    override fun <T : Card> registerCard(type :Int, cardClz :Class<T> ):TangramPlugin{
+        builder.registerCard(type,cardClz)
+        return this
+    }
+
+    override fun <T : View> registerCell(type :Int, view :Class<T> ):TangramPlugin{
+        builder.registerCell(type,view)
+        return this
+    }
+
+    override fun <V :View,C:BaseCell<V>>registerCell(type:Int,cellCls:Class<C>,viewCls:Class<V>):TangramPlugin{
+        builder.registerCell(type,cellCls,viewCls)
+        return this
+    }
+
+    override fun <V :View,C:BaseCell<V>,H: ViewHolderCreator.ViewHolder>registerCell(type:Int,cellCls:Class<C>,viewHolderCreator: ViewHolderCreator<H,V>):TangramPlugin{
+        builder.registerCell<V>(type,cellCls,viewHolderCreator)
+        return this
+    }
+
+    override fun setLoadListener(asyncLoader: AsyncLoader, asyncPageLoader: AsyncPageLoader): TangramPlugin {
+        initEngine()
+        engine?.addCardLoadSupport(CardLoadSupport(asyncLoader,asyncPageLoader))
+        return this
+    }
+
+    override fun getEngine(): TangramEngine {
+        initEngine()
+
+        return this!!.engine!!
+    }
+
+    override fun addClickSupport(support:SimpleClickSupport):TangramPlugin{
+        initEngine()
+        engine?.addSimpleClickSupport(support)
+        return this
+    }
+
+    override fun addExposureSupport(support: ExposureSupport):TangramPlugin{
+        initEngine()
+        engine?.addExposureSupport(support)
+        return this
+    }
+
+    override fun enableAutoLoadMore():TangramPlugin{
+        initEngine()
+        engine?.enableAutoLoadMore(true)
+        return this
+    }
+
+    override fun bindRecyclerView(view:RecyclerView):TangramPlugin{
+        initEngine()
+        engine?.bindView(view)
+        return this
+    }
+
+    override fun onScrolled():TangramPlugin{
+        initEngine()
+        engine?.contentView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+            override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
+                super.onScrolled(recyclerView, dx, dy)
+                engine?.onScrolled()
+            }
+        })
+        return this
+    }
+
+    override fun addDataSource(data :JSONArray):TangramPlugin{
+        initEngine()
+        engine?.setData(data)
+        return this
+    }
+    override fun addDataSource(data :List<Card>):TangramPlugin{
+        initEngine()
+        engine?.setData(data)
+        return this
+    }
+
+    override fun destory() {
+        engine?.destroy()
+    }
+
+    private fun initEngine(){
+        engine.haventDo {
+            engine = builder.build()
+        }
+    }
+}
+
+interface TangramIInter{
+    fun <T : Card> registerCard(type :Int, cardClz :Class<T> ):TangramPlugin
+    fun <T : View> registerCell(type :Int, view :Class<T> ):TangramPlugin
+    fun <V :View,C:BaseCell<V>>registerCell(type:Int,cellCls:Class<C>,viewCls:Class<V>):TangramPlugin
+    fun <V :View,C:BaseCell<V>,H: ViewHolderCreator.ViewHolder>registerCell(type:Int,cellCls:Class<C>,viewHolderCreator: ViewHolderCreator<H,V>):TangramPlugin
+    fun setLoadListener(asyncLoader: AsyncLoader,asyncPageLoader: AsyncPageLoader):TangramPlugin
+    fun getEngine ():TangramEngine
+    fun addClickSupport(support:SimpleClickSupport):TangramPlugin
+    fun addExposureSupport(support: ExposureSupport):TangramPlugin
+    fun enableAutoLoadMore():TangramPlugin
+    fun bindRecyclerView(view:RecyclerView):TangramPlugin
+    fun onScrolled():TangramPlugin
+    fun addDataSource(data :JSONArray):TangramPlugin
+    fun addDataSource(data :List<Card>):TangramPlugin
+    fun destory()
+}

+ 226 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/TimeEngine.kt

@@ -0,0 +1,226 @@
+package com.wdkl.ncs.android.lib.utils
+
+import java.sql.Time
+import java.util.concurrent.Executors
+
+/**
+ * @author LDD
+ * @Date   2018/5/9 下午6:19
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   倒计时工具类
+ */
+class TimeEngine {
+
+    companion object {
+        /**
+         * @author LDD
+         * @From   TimeEngine
+         * @Date   2018/5/10 上午8:46
+         * @Note   静态构建
+         * @param
+         */
+        fun build(timeLength: Long,current :Boolean = false) :TimeEngine{
+            return TimeEngine(timeLength,current)
+        }
+    }
+
+    private var isOnlySingleProcess = false
+
+    private var workState = false
+
+    fun needSingleProcess() : TimeEngine{
+        isOnlySingleProcess = true
+        return this
+    }
+
+
+
+    /**
+     * @Name  threadPool
+     * @Type  ExecutorService
+     * @Note  可缓存线程池,用于处理非UI线程任务
+     */
+    private var threadPool = Executors.newFixedThreadPool(1)
+
+    /**
+     * @Name  complete
+     * @Type  Block
+     * @Note  结束代码块
+     */
+    private var complete :(()->Unit)? = null
+
+    /**
+     * @Name  timeLong
+     * @Type  Long
+     * @Note  距离结束总时长
+     */
+    private var timeLength :Long
+
+    /**
+     * @Name  survival
+     * @Type  Boolean
+     * @Note  标记当前线程是否应该存活
+     */
+    private var survival = true
+
+    /**
+     * @Name  timeResult
+     * @Type  Int
+     * @Note  经过时间递减结果
+     */
+    private var timeResult :Long
+
+    /**
+     * @Name  current
+     * @Type  Boolean
+     * @Note  是否使用当前时间
+     */
+    private var current :Boolean
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:12
+     * @Note   构造
+     * @param  timeLength 时长 单位:秒
+     * @param  current  是否使用当前时间差
+     */
+    private constructor(timeLength: Long,current :Boolean = false) {
+        this.timeLength = timeLength
+        this.timeResult = timeLength
+        this.current = current
+    }
+
+    fun alive() :Boolean{
+        return survival
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:13
+     * @Note   开始执行
+     * @param  call 回调
+     */
+    fun execute(call :(day :Int,hour:Int,min:Int,sec :Int)->Unit , complete :(()->Unit)? = null){
+
+        var run = true
+
+        if (isOnlySingleProcess){
+            if (workState){
+                return
+            }
+        }
+
+        if (complete != null){
+            this.complete = complete
+        }
+
+        workState = true
+
+        threadPool.execute {
+            if (!run){
+                return@execute
+            }
+            while (survival && timeResult>0){
+                if (current){
+                    timeResult = (timeLength - System.currentTimeMillis() / 1000)
+                }else{
+                    timeResult-=1
+                }
+                call.invoke(getDay(timeResult),getHour(timeResult),getMinute(timeResult),getSecond(timeResult))
+                try {
+                    Thread.sleep(1000)
+                }catch (e :InterruptedException){
+                    debugLog("TimeEngine","线程池停止")
+                }
+                if (timeResult == 0L){
+                    this.complete?.invoke()
+                    workState = false
+                    run = false
+                }
+            }
+        }
+
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/21 下午3:01
+     * @Note   设置complete监听
+     * @param  complete 监听高级函数
+     */
+    fun setComplete(complete: (() -> Unit)){
+        this.complete = complete
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:29
+     * @Note   恢复初始状态
+     */
+    fun reset(){
+        timeResult = timeLength
+        survival = true
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:20
+     * @Note   获取小时
+     * @param  time 总时间
+     */
+    private fun getHour(time: Long): Int {
+        return (time % (60 * 60 * 24) / (60 * 60)).toInt()
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:21
+     * @Note   获取分钟
+     * @param  time 总时间
+     */
+    private fun getMinute(time: Long): Int {
+        return (time % (60 * 60 * 24) % (60 * 60) / 60).toInt()
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:21
+     * @Note   获取秒
+     * @param  time 总时长
+     */
+    private fun getSecond(time: Long): Int {
+        return (time % (60 * 60 * 24) % (60 * 60) % 60).toInt()
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:22
+     * @Note   获取天数
+     * @param  time 总时长
+     */
+    private fun getDay(time: Long): Int {
+        return (time / (60 * 60 * 24)).toInt()
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:14
+     * @Note   销毁TimeEngine
+     */
+    fun destory(){
+        if (survival){
+            workState = false
+            survival = false
+            threadPool.shutdownNow()
+        }
+    }
+}

+ 62 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/TimeHandle.kt

@@ -0,0 +1,62 @@
+package com.wdkl.ncs.android.lib.utils
+
+import java.util.*
+
+/**
+ *  事件处理器
+ */
+object TimeHandle {
+
+    fun getCurrentDay24Mill() :Long{
+        val cal = Calendar.getInstance()
+        cal.set(Calendar.HOUR_OF_DAY, 24)
+        cal.set(Calendar.SECOND, 0)
+        cal.set(Calendar.MINUTE, 0)
+        cal.set(Calendar.MILLISECOND, 0)
+        return cal.timeInMillis
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:20
+     * @Note   获取小时
+     * @param  time 总时间
+     */
+    fun getHour(time: Int): Int {
+        return time % (60 * 60 * 24) / (60 * 60)
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:21
+     * @Note   获取分钟
+     * @param  time 总时间
+     */
+    fun getMinute(time: Int): Int {
+        return time % (60 * 60 * 24) % (60 * 60) / 60
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:21
+     * @Note   获取秒
+     * @param  time 总时长
+     */
+    fun getSecond(time: Int): Int {
+        return time % (60 * 60 * 24) % (60 * 60) % 60
+    }
+
+    /**
+     * @author LDD
+     * @From   TimeEngine
+     * @Date   2018/5/10 上午9:22
+     * @Note   获取天数
+     * @param  time 总时长
+     */
+    fun getDay(time: Int): Int {
+        return time / (60 * 60 * 24)
+    }
+}

+ 60 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/UUID.kt

@@ -0,0 +1,60 @@
+package com.wdkl.ncs.android.lib.utils
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.Context.WIFI_SERVICE
+import android.net.wifi.WifiManager
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.enation.javashop.utils.base.cache.ACache
+
+
+/**
+ * @author LDD
+ * @Date   2018/8/9 下午4:31
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   UUID 工具类
+ */
+class UUID {
+
+    /**
+     * 伴生对象
+     */
+    companion object {
+
+        /*UUID*/
+        var uuid = get()
+
+        /**
+         * @author LDD
+         * @From   UUID
+         * @Date   2018/8/9 下午4:31
+         * @Note   获取UUID
+         * @param  uuid
+         */
+        @SuppressLint("MissingPermission", "WifiManagerLeak", "HardwareIds")
+        private fun get() : String{
+            //refreshUUID("abcd1234")
+            var macAddress = ACache.get(BaseApplication.appContext).getAsString("UUID")
+            if (macAddress == null){
+                val wifiManager :WifiManager? = BaseApplication.appContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
+                val info = wifiManager?.connectionInfo
+                if (!wifiManager!!.isWifiEnabled) {
+                    //必须先打开,才能获取到MAC地址
+                    wifiManager.isWifiEnabled = true
+                    wifiManager.isWifiEnabled = false
+                }
+                if (null != info) {
+                    macAddress = info.macAddress
+                }
+            }
+            return macAddress
+        }
+
+        fun refreshUUID(id : String){
+            uuid = id
+            ACache.get(BaseApplication.appContext).put("UUID", uuid)
+        }
+
+    }
+
+}

+ 38 - 0
common/src/main/code/com/wdkl/ncs/android/lib/utils/VlayoutHelper.kt

@@ -0,0 +1,38 @@
+package com.wdkl.ncs.android.lib.utils
+
+import com.alibaba.android.vlayout.layout.LinearLayoutHelper
+
+/**
+ * @author LDD
+ * @Date   2018/4/23 上午11:18
+ * @From   com.wdkl.ncs.android.lib.utils
+ * @Note   Vlayout工具类
+ */
+object VlayoutHelper {
+
+    /**
+     * @author LDD
+     * @From   VlayoutHelper
+     * @Date   2018/4/23 上午11:22
+     * @Note   快速构建列表Layhelper
+     * @param  diviHeight  间距
+     * @param  size  item总数
+     * @param  left   左侧margin  默认0
+     * @param  right  右侧margin  默认0
+     * @param  top    上方margin  默认10dp
+     * @param  bottom 下方margin  默认0
+     */
+    @JvmStatic
+    fun createLinearLayoutHelper(diviHeight : Int = 0 ,
+                                 size :Int = 1 ,
+                                 left :Int = 0,
+                                 right :Int = 0,
+                                 top :Int = AppTool.SystemUI.dpToPx(10F),
+                                 bottom :Int = 0):LinearLayoutHelper{
+        return LinearLayoutHelper(diviHeight,size).then {
+                self ->
+                self.setMargin(left,top,right,bottom)
+        }
+    }
+
+}

+ 9 - 0
common/src/main/code/com/wdkl/ncs/android/lib/vo/MenuVo.kt

@@ -0,0 +1,9 @@
+package com.wdkl.ncs.android.lib.vo
+
+/**
+ * @author LDD
+ * @Date   2018/4/12 下午4:25
+ * @From   com.wdkl.ncs.android.lib.vo
+ * @Note   菜单视图VO
+ */
+data class MenuVo(val name :String,val resId :Int ,val menuId : Int)

+ 26 - 0
common/src/main/code/com/wdkl/ncs/android/lib/vo/NetModel.kt

@@ -0,0 +1,26 @@
+package com.wdkl.ncs.android.lib.vo
+
+import com.enation.javashop.net.engine.model.NetState
+
+/**
+ * 网络监听事件实体类
+ */
+data class NetStateEvent constructor(val state: NetState)
+
+/**
+ * 【扩展】
+ *  类型过滤,相应类型执行相应方法
+ */
+fun NetState.filter(onMobile:()->Unit,onWifi:()->Unit,offline:()->Unit){
+    when (this) {
+        NetState.MOBILE -> {
+            onMobile.invoke()
+        }
+        NetState.WIFI -> {
+            onWifi.invoke()
+        }
+        NetState.NONE -> {
+            offline.invoke()
+        }
+    }
+}

+ 221 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/ArcView.kt

@@ -0,0 +1,221 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.*
+import android.media.Image
+import android.os.Build
+import android.util.AttributeSet
+import android.view.View
+import android.widget.ImageView
+import com.wdkl.ncs.android.lib.R
+
+
+
+
+/**
+ * @author LDD
+ * @Date   2018/2/26 上午10:30
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   弧形View
+ */
+class ArcView : ImageView {
+
+    /**
+     * @Name  arcHeight
+     * @Type  Int
+     * @Note  弧形高度
+     */
+    private var arcHeight = 0
+
+    /**
+     * @Name  arcShape
+     * @Type  ArcShape
+     * @Note  内部还是外部
+     */
+    private var arcShape = ArcShape.outSide
+
+    /**
+     * @Name  arcPosition
+     * @Type  ArcPosition
+     * @Note  弧形方向
+     */
+    private var arcPosition = ArcPosition.bottom
+
+    /**
+     * @author LDD
+     * @From   ArcView
+     * @Date   2018/2/27 上午9:10
+     * @Note   一参构造调用二餐
+     */
+    constructor(context: Context) : this(context,null)
+
+    /**
+     * @author LDD
+     * @From   ArcView
+     * @Date   2018/2/27 上午9:11
+     * @Note   二参调用三参
+     */
+    constructor(context: Context, attrs: AttributeSet?) : this(context,attrs,0)
+
+    /**
+     * @author LDD
+     * @From   ArcView
+     * @Date   2018/2/27 上午9:11
+     * @Note   实际调用的构造方法
+     */
+    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
+        val typeArray = context.obtainStyledAttributes(attrs, R.styleable.ArcView)
+        arcHeight = typeArray.getDimensionPixelSize(R.styleable.ArcView_arc_height,10)
+        typeArray.recycle()
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            setLayerType(View.LAYER_TYPE_SOFTWARE, null)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   ArcView
+     * @Date   2018/2/27 上午9:11
+     * @Note   绘制弧形
+     */
+    @SuppressLint("DrawAllocation")
+    override fun onDraw(canvas: Canvas) {
+        if (arcHeight > 0) {
+            val paint = Paint()
+            paint.isAntiAlias = true
+            paint.color = Color.WHITE
+            var saveCount = 0
+            saveCount = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                canvas.saveLayer(0F, 0F, width.toFloat(), height.toFloat(), null)
+            }else{
+                canvas.saveLayer(0F, 0F, width.toFloat(), height.toFloat(), null, Canvas.ALL_SAVE_FLAG)
+            }
+            super.onDraw(canvas)
+            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
+                paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)
+                canvas.drawPath(createClipPath(arcPosition,arcShape), paint)
+            }else{
+                paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)
+                val path = Path()
+                path.addRect(0F, 0F, width.toFloat(),height.toFloat(), Path.Direction.CW)
+                path.op(createClipPath(arcPosition,arcShape), Path.Op.DIFFERENCE)
+                canvas.drawPath(createClipPath(arcPosition,arcShape), paint)
+            }
+            canvas.restoreToCount(saveCount)
+            paint.xfermode = null
+        } else {
+            super.onDraw(canvas)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   ArcView
+     * @Date   2018/2/27 上午9:17
+     * @Note   绘制弧形
+     * @param  arcHeight 弧形高度
+     * @param  arcPosition 弧形方向
+     * @param  arcShape 内部外部
+     */
+    fun drawArc(arcHeight : Int , arcShape: ArcShape , arcPosition: ArcPosition){
+        this.arcHeight = arcHeight
+        this.arcPosition = arcPosition
+        this.arcShape = arcShape
+        invalidate()
+    }
+
+    /**
+     * @author LDD
+     * @From   ArcView
+     * @Date   2018/2/26 下午4:01
+     * @Note   构建弧形Path
+     * @param  arcPosition 方向
+     * @param  arcShape 内部还是外部
+     */
+    private fun createClipPath(arcPosition:ArcPosition , arcShape: ArcShape): Path {
+        val path = Path()
+
+        when (arcPosition) {
+            ArcPosition.bottom -> {
+                if (arcShape === ArcShape.inSide) {
+                    path.moveTo(0f, 0f)
+                    path.lineTo(0f, height.toFloat())
+                    path.quadTo((width / 2).toFloat(), (height - 2 * arcHeight).toFloat(), width.toFloat(), height.toFloat())
+                    path.lineTo(width.toFloat(), 0f)
+                    path.close()
+                } else {
+                    path.moveTo(0f, 0f)
+                    path.lineTo(0f, (height - arcHeight).toFloat())
+                    path.quadTo((width / 2).toFloat(), (height + arcHeight).toFloat(), width.toFloat(), (height - arcHeight).toFloat())
+                    path.lineTo(width.toFloat(), 0f)
+                    path.close()
+                }
+            }
+            ArcPosition.top -> if (arcShape === ArcShape.inSide) {
+                path.moveTo(0f, height.toFloat())
+                path.lineTo(0f, 0f)
+                path.quadTo((width / 2).toFloat(), (2 * arcHeight).toFloat(), width.toFloat(), 0F)
+                path.lineTo(width.toFloat(), height.toFloat())
+                path.close()
+            } else {
+                path.moveTo(0f, arcHeight.toFloat())
+                path.quadTo((width / 2).toFloat(), (-arcHeight).toFloat(), width.toFloat(), arcHeight.toFloat())
+                path.lineTo(width.toFloat(), height.toFloat())
+                path.lineTo(0F, height.toFloat())
+                path.close()
+            }
+            ArcPosition.left -> if (arcShape === ArcShape.inSide) {
+                path.moveTo(width.toFloat(), 0f)
+                path.lineTo(0f, 0f)
+                path.quadTo((arcHeight * 2).toFloat(), (height / 2).toFloat(), 0F, height.toFloat())
+                path.lineTo(width.toFloat(), height.toFloat())
+                path.close()
+            } else {
+                path.moveTo(width.toFloat(), 0f)
+                path.lineTo(arcHeight.toFloat(), 0f)
+                path.quadTo((-arcHeight).toFloat(), (height / 2).toFloat(), arcHeight.toFloat(), height.toFloat())
+                path.lineTo(width.toFloat(), height.toFloat())
+                path.close()
+            }
+            ArcPosition.right -> if (arcShape === ArcShape.inSide) {
+                path.moveTo(0f, 0f)
+                path.lineTo(width.toFloat(), 0f)
+                path.quadTo((width - arcHeight * 2).toFloat(), (height / 2).toFloat(), width.toFloat(), height.toFloat())
+                path.lineTo(0f, height.toFloat())
+                path.close()
+            } else {
+                path.moveTo(0f, 0f)
+                path.lineTo((width - arcHeight).toFloat(), 0f)
+                path.quadTo((width + arcHeight).toFloat(), (height / 2).toFloat(), (width - arcHeight).toFloat(), height.toFloat())
+                path.lineTo(0f, height.toFloat())
+                path.close()
+            }
+        }
+
+        return path
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/2/27 上午9:12
+     * @From   ArcView
+     * @Note   方向选择枚举
+     */
+    enum class ArcPosition {
+        top,
+        bottom,
+        left,
+        right
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/2/27 上午9:13
+     * @From   ArcView
+     * @Note   外部选择枚举
+     */
+    enum class ArcShape {
+        inSide, outSide
+    }
+}

+ 173 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/AutoSizeTextView.kt

@@ -0,0 +1,173 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import android.text.TextPaint
+import android.text.style.AbsoluteSizeSpan
+import android.text.style.StrikethroughSpan
+import android.util.AttributeSet
+import android.util.Log
+import android.view.Gravity
+import android.widget.TextView
+import com.wdkl.ncs.android.lib.R
+import com.wdkl.ncs.android.lib.utils.errorLog
+import com.wdkl.ncs.android.lib.utils.then
+import com.enation.javashop.utils.base.tool.ScreenTool
+
+
+/**
+ * @author LDD
+ * @Date   2018/3/19 上午11:44
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   自动改变文字大小的TextView
+ */
+class AutoSizeTextView : TextView {
+
+    private val mTextPaint by lazy {
+        TextPaint()
+    }
+    private var mMaxTextSize: Float = 100.toFloat() // 获取当前所设置文字大小作为最大文字大小
+    private var mMinTextSize = 8f    //最小的字体大小
+
+
+    private var priceType = false
+
+    private var autoSize = false
+
+    private var decimalHandle = 1
+
+    private val AlwaysRetain = 1
+
+    private var deleteLine = false
+
+    private val IfExistRetain = 2
+
+    private val AlwaysRemove = 3
+
+    constructor(context: Context) : this(context, null)
+    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
+    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
+        val typeArray = context.obtainStyledAttributes(attrs, R.styleable.AutoSizeTextView)
+
+        priceType = typeArray.getBoolean(R.styleable.AutoSizeTextView_price_type,false)
+
+        decimalHandle = typeArray.getInt(R.styleable.AutoSizeTextView_decimal_handle,AlwaysRetain)
+
+        autoSize = typeArray.getBoolean(R.styleable.AutoSizeTextView_auto_size,false)
+
+        deleteLine = typeArray.getBoolean(R.styleable.AutoSizeTextView_delete_line,false)
+
+        typeArray.recycle()
+    }
+
+    init {
+        gravity = gravity or Gravity.CENTER_VERTICAL // 默认水平居中
+        initialise()
+    }
+
+    private fun initialise() {
+        mTextPaint.set(this.paint)
+        //默认的大小是设置的大小,如果撑不下了 就改变
+        mMaxTextSize = this.textSize
+    }
+
+    override fun onTextChanged(text: CharSequence, start: Int, lengthBefore: Int, lengthAfter: Int) {
+
+        if (priceType) {
+            try {
+                text.toString().toDouble()
+            } catch (e: Exception) {
+                refitText(text.toString(), this.height, true)
+                return
+            }
+
+            when (decimalHandle) {
+                AlwaysRetain -> {
+                    val price = text.toString().toDouble()
+                    var maxSize = refitText(text.toString(), height, false)
+                    this.text = SpannableStringBuilder("¥$price").then { self ->
+                        if (deleteLine){
+                            self.setSpan(StrikethroughSpan(), 0,text.length+1 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                        }else{
+                            self.setSpan(AbsoluteSizeSpan((maxSize * 0.6).toInt()), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                            self.setSpan(AbsoluteSizeSpan((maxSize).toInt()), 1, self.indexOf("."), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                            self.setSpan(AbsoluteSizeSpan((maxSize * 0.6).toInt()), self.indexOf("."), self.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                        }
+                    }
+                }
+                IfExistRetain -> {
+                    val str = "${text.toString().toDouble()}"
+                    var decimal = str.substring(text.indexOf("."), text.length)
+                    var maxSize = refitText(text.toString(), height, false)
+                    if (decimal == ".00" || decimal == ".0"){
+                        this.text = SpannableStringBuilder("¥${str.removeRange(str.indexOf("."), str.length)}").then { self ->
+                            if (deleteLine){
+                                self.setSpan(StrikethroughSpan(), 0,text.length+1 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                            }else{
+                                self.setSpan(AbsoluteSizeSpan((maxSize * 0.6).toInt()), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                                self.setSpan(AbsoluteSizeSpan((maxSize).toInt()),1, self.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                            }
+                        }
+                    }else{
+                        this.text = SpannableStringBuilder("¥$str").then { self ->
+                            if (deleteLine){
+                                self.setSpan(StrikethroughSpan(), 0,text.length+1 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                            }else{
+                                self.setSpan(AbsoluteSizeSpan((maxSize * 0.6).toInt()), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                                self.setSpan(AbsoluteSizeSpan((maxSize).toInt()), 1, self.indexOf("."), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                                self.setSpan(AbsoluteSizeSpan((maxSize * 0.6).toInt()), self.indexOf("."), self.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                            }
+                        }
+                    }
+                }
+                AlwaysRemove -> {
+                    val str = "${text.toString().toDouble()}"
+                    var maxSize = refitText(text.toString(), height, false)
+                    this.text = SpannableStringBuilder("¥${str.removeRange(str.indexOf("."), str.length)}").then { self ->
+                        if (deleteLine){
+                            self.setSpan(StrikethroughSpan(), 0,text.length+1 , Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                        }else{
+                            self.setSpan(AbsoluteSizeSpan((maxSize * 0.6).toInt()), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                            self.setSpan(AbsoluteSizeSpan((maxSize).toInt()),1, self.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+                        }
+                    }
+                }
+            }
+        } else {
+            refitText(text.toString(), this.height, true)
+        }
+
+        super.onTextChanged(text, start, lengthBefore, lengthAfter)
+    }
+
+
+    private fun refitText(textString: String, height: Int, isSet: Boolean): Float {
+        if (height > 0) {
+            val availableHeight = (height - this.paddingTop - this.paddingBottom) / maxLines  //减去边距为字体的实际高度
+            var trySize = mMaxTextSize
+            mTextPaint.textSize = trySize
+            while (mTextPaint.descent() - mTextPaint.ascent() > availableHeight) {   //测量的字体高度过大,不断地缩放
+                trySize -= 1f  //字体不断地减小来适应
+                if (trySize <= mMinTextSize) {
+                    trySize = mMinTextSize  //最小为这个
+                    break
+                }
+                mTextPaint.textSize = trySize
+            }
+            if (isSet) {
+                textSize = ScreenTool.px2sp(context, trySize).toFloat()
+            }
+            return trySize
+        }
+        return 0f
+    }
+
+    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+        if (h != oldh) {
+            refitText(this.text.toString(), h, true)
+        }
+    }
+}

+ 929 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/CommonActionBar.kt

@@ -0,0 +1,929 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.res.TypedArray
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.support.annotation.*
+import android.support.annotation.IntRange
+import android.support.constraint.ConstraintLayout
+import android.support.v4.widget.TextViewCompat
+import android.util.AttributeSet
+import android.util.TypedValue
+import android.view.Gravity
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import com.wdkl.ncs.android.lib.R
+import android.support.constraint.ConstraintSet
+import android.view.LayoutInflater
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.engine.DiskCacheStrategy
+import com.wdkl.ncs.android.lib.utils.*
+import com.enation.javashop.utils.base.tool.ScreenTool
+import com.enation.javashop.utils.base.tool.SystemTool
+
+
+/**
+ * @author LDD
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Date   2018/3/7 上午10:14
+ * @Note   通用ActionBar
+ */
+class CommonActionBar : ConstraintLayout {
+
+    /**
+     * @Name  holderColor
+     * @Type  Int
+     * @Note  顶部Holder的颜色
+     */
+    private var holderColor: Int = -1
+
+    /**
+     * @Name  backgroundViewColor
+     * @Type  Int
+     * @Note  背景颜色
+     */
+    private var backgroundViewColor: Int = -1
+
+    /**
+     * @Name  titleText
+     * @Type  String
+     * @Note  标题
+     */
+    private lateinit var titleText: String
+
+    /**
+     * @Name  leftText
+     * @Type  String
+     * @Note  左侧文字
+     */
+    private lateinit var leftText: String
+
+    /**
+     * @Name  leftImageDrawable
+     * @Type  Drawable
+     * @Note  左侧图片
+     */
+    private var leftImageDrawable: Drawable? = null
+
+    /**
+     * @Name  rightText
+     * @Type  String
+     * @Note  右侧文字
+     */
+    private lateinit var rightText: String
+
+    /**
+     * @Name  rightImageDrawable
+     * @Type  Drawable
+     * @Note  右侧ImageView
+     */
+    private var rightImageDrawable: Drawable? = null
+
+    /**
+     * @Name  holderVisibility
+     * @Type  Boolean
+     * @Note  holder是否显示
+     */
+    private var holderVisibility: Boolean = true
+
+    /**
+     * @Name  titleImageDrawable
+     * @Type  Drawable
+     * @Note  标题图片
+     */
+    private var titleImageDrawable: Drawable? = null
+
+    /**
+     * @Name  backgroundImageDrawable
+     * @Type  Drawable
+     * @Note  北京图片
+     */
+    private var backgroundImageDrawable: Drawable? = null
+
+    /**
+     * @Name  leftTextColor
+     * @Type  Int
+     * @Note  左侧文字颜色
+     */
+    private var leftTextColor :Int = -1
+
+    /**
+     * @Name  rightTextColor
+     * @Type  Int
+     * @Note  右侧文字颜色
+     */
+    private var rightTextColor :Int = -1
+
+    /**
+     * @Name  titleTextColor
+     * @Type  Int
+     * @Note  标题文字颜色
+     */
+    private var titleTextColor:Int = -1
+
+    /**View ID 常量 =========================*/
+    private val TopHolderId = 222
+    private val TitleTextId = 333
+    private val TitleImageId = 444
+    private val LeftTextId = 555
+    private val LeftImageId = 666
+    private val LeftTouchId = 777
+    private val RightTextId = 888
+    private val RightImageId = 999
+    private val RightTouchViewId = 1111
+    private val BackgroundImageViewId = 2222
+    private val BottomLineId =3333
+    /**=====================================*/
+
+    /**
+     * @Name  applyConstraintSet
+     * @Type  ConstraintSet
+     * @Note  constraint布局辅助类
+     */
+    private val applyConstraintSet = ConstraintSet()
+
+    /**
+     * @Name  holderView
+     * @Type  View
+     * @Note  holder占位View
+     */
+    private val holderView by lazy {
+        return@lazy View(context).then { self ->
+            self.id = TopHolderId
+            self.setBackgroundColor(holderColor)
+            self.visibility = holderVisibility.judge(View.VISIBLE,View.INVISIBLE)
+        }
+    }
+
+    /**
+     * @Name  backgroundImageView
+     * @Type  ImageView
+     * @Note  背景ImageView
+     */
+    private val backgroundImageView by lazy {
+        return@lazy ImageView(context).then { self ->
+            self.id = BackgroundImageViewId
+            self.setBackgroundColor(Color.TRANSPARENT)
+            self.scaleType = ImageView.ScaleType.CENTER_CROP
+            backgroundImageDrawable.haveDo {
+                self.setImageDrawable(backgroundImageDrawable)
+            }
+            setBackgroundColor((backgroundViewColor == -1).judge(Color.WHITE,backgroundViewColor))
+        }
+    }
+
+    /**
+     * @Name  titleTextView
+     * @Type  TextView
+     * @Note  左侧TextView
+     */
+    private val titleTextView by lazy {
+        return@lazy  (LayoutInflater.from(context).inflate(R.layout.auto_size_tv,null) as TextView ).then { self ->
+            self.id = TitleTextId
+            self.gravity = Gravity.CENTER
+            self.visibility = View.INVISIBLE
+            self.text = titleText
+            self.setTextColor(titleTextColor)
+        }
+    }
+
+    /**
+     * @Name  titleImageView
+     * @Type  ImageView
+     * @Note  标题ImageView
+     */
+    private val titleImageView by lazy {
+        return@lazy ImageView(context).then { self ->
+            self.id = TitleImageId
+            self.setBackgroundColor(Color.parseColor("#00000000"))
+            self.scaleType = ImageView.ScaleType.FIT_CENTER
+            self.visibility = View.INVISIBLE
+            if (titleImageDrawable != null){
+                self.visibility = View.VISIBLE
+                self.setImageDrawable(titleImageDrawable)
+            }
+        }
+    }
+
+    /**
+     * @Name  leftTextView
+     * @Type  TextView
+     * @Note  左侧TextView
+     */
+    private val leftTextView by lazy {
+        return@lazy (LayoutInflater.from(context).inflate(R.layout.auto_size_tv,null) as TextView ).then { self ->
+            self.id = LeftTextId
+            self.gravity = Gravity.CENTER
+            TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(self, 10, 100, 2, TypedValue.COMPLEX_UNIT_SP)
+            TextViewCompat.setAutoSizeTextTypeWithDefaults(self, TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM)
+            self.visibility = View.INVISIBLE
+            self.text = leftText
+            self.setTextColor(leftTextColor)
+        }
+    }
+    /**
+     * @Name  leftImageView
+     * @Type  ImageView
+     * @Note  左侧ImageView
+     */
+    private val leftImageView by lazy {
+        return@lazy ImageView(context).then { self ->
+            self.id = LeftImageId
+            self.visibility = View.INVISIBLE
+            leftImageDrawable.haveDo {
+                self.setImageDrawable(leftImageDrawable)
+            }
+        }
+    }
+    /**
+     * @Name  leftTouchView
+     * @Type  View
+     * @Note  左侧点击视图
+     */
+    private val leftTouchView by lazy {
+        return@lazy View(context).then { self ->
+            self.id = LeftTouchId
+        }
+    }
+    /**
+     * @Name  rightTextView
+     * @Type  TextView
+     * @Note  右侧TextView
+     */
+    private val rightTextView by lazy {
+        return@lazy (LayoutInflater.from(context).inflate(R.layout.auto_size_tv,null) as TextView ).then { self ->
+            self.id = RightTextId
+            self.gravity = Gravity.CENTER
+            TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(self, 10, 100, 2, TypedValue.COMPLEX_UNIT_SP)
+            TextViewCompat.setAutoSizeTextTypeWithDefaults(self, TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM)
+            self.visibility = View.INVISIBLE
+            self.text = rightText
+            self.setTextColor(rightTextColor)
+        }
+    }
+    /**
+     * @Name  rightImageView
+     * @Type  ImageView
+     * @Note  右侧ImageView
+     */
+    private val rightImageView by lazy {
+        return@lazy ImageView(context).then { self ->
+            self.id = RightImageId
+            self.visibility = View.INVISIBLE
+            rightImageDrawable.haveDo {
+                self.setImageDrawable(rightImageDrawable)
+            }
+        }
+    }
+
+    /**
+     * @Name  rightTouchView
+     * @Type  View
+     * @Note  右侧点击视图
+     */
+    private val rightTouchView by lazy {
+        return@lazy View(context).then { self ->
+            self.id = RightTouchViewId
+        }
+    }
+
+    /**
+     * @Name  bottomLine
+     * @Type  View
+     * @Note  底部Line
+     */
+    private val bottomLine by lazy {
+        return@lazy View(context).then { self ->
+            self.id = BottomLineId
+            self.setBackgroundColor(Color.parseColor("#e4e6e5"))
+        }
+    }
+
+    /**
+     * @Name  imageLoader
+     * @Type  (url: String, imageView: ImageView) -> Unit
+     * @Note  图片加载器
+     */
+    private var imageLoader:(url: String, imageView: ImageView) -> Unit = { url : String, iv : ImageView ->
+        Glide.with(context)
+                .load(url)
+                .thumbnail(0.1f)
+                .centerCrop()
+                .diskCacheStrategy(DiskCacheStrategy.ALL)
+                .into(iv)
+    }
+
+
+    constructor(context: Context) : this(context, null)
+    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
+    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
+        setBackgroundColor(Color.TRANSPARENT)
+        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.CommonActionBar)
+        parameterInit(typedArray)
+        layoutInit()
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/3/7 上午10:14
+     * @Note   参数初始化
+     */
+    private fun parameterInit(typedArray: TypedArray) {
+        holderColor = typedArray.getColor(R.styleable.CommonActionBar_holder_color, Color.parseColor("#ff484848"))
+        leftTextColor = typedArray.getColor(R.styleable.CommonActionBar_left_text_color, Color.parseColor("#6e6c6f"))
+        rightTextColor = typedArray.getColor(R.styleable.CommonActionBar_right_text_color, Color.parseColor("#6e6c6f"))
+        titleTextColor = typedArray.getColor(R.styleable.CommonActionBar_title_text_color, Color.parseColor("#000000"))
+        titleText = typedArray.getString(R.styleable.CommonActionBar_title_text) ?: ""
+        leftText = typedArray.getString(R.styleable.CommonActionBar_left_text) ?: ""
+        leftImageDrawable = typedArray.getDrawable(R.styleable.CommonActionBar_left_image)
+        rightText = typedArray.getString(R.styleable.CommonActionBar_right_text) ?: ""
+        rightImageDrawable = typedArray.getDrawable(R.styleable.CommonActionBar_right_image)
+        holderVisibility = typedArray.getBoolean(R.styleable.CommonActionBar_holder_visibility, true)
+        titleImageDrawable = typedArray.getDrawable(R.styleable.CommonActionBar_title_image)
+        backgroundImageDrawable = typedArray.getDrawable(R.styleable.CommonActionBar_background_image)
+        backgroundViewColor = typedArray.getColor(R.styleable.CommonActionBar_background_color,-1)
+        typedArray.recycle()
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/3/7 下午1:25
+     * @Note   布局
+     */
+    @SuppressLint("ResourceType")
+    private fun layoutInit() {
+        applyConstraintSet.clone(this)
+
+        addView(backgroundImageView).then {
+            applyConstraintSet.connect(BackgroundImageViewId, ConstraintSet.LEFT, id, ConstraintSet.LEFT, 0)
+            applyConstraintSet.connect(BackgroundImageViewId, ConstraintSet.RIGHT, id, ConstraintSet.RIGHT, 0)
+            applyConstraintSet.connect(BackgroundImageViewId, ConstraintSet.TOP, id, ConstraintSet.TOP, 0 )
+            applyConstraintSet.connect(BackgroundImageViewId, ConstraintSet.BOTTOM, id, ConstraintSet.BOTTOM, 0)
+            applyConstraintSet.applyTo(this)
+        }
+        addView(holderView).then {
+            applyConstraintSet.connect(TopHolderId, ConstraintSet.LEFT, id, ConstraintSet.LEFT, 0)
+            applyConstraintSet.connect(TopHolderId, ConstraintSet.RIGHT, id, ConstraintSet.RIGHT, 0)
+            applyConstraintSet.connect(TopHolderId, ConstraintSet.TOP, id, ConstraintSet.TOP, 0)
+            applyConstraintSet.constrainWidth(TopHolderId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(TopHolderId, AppTool.SystemUI.getStatusBarHeight())
+            applyConstraintSet.applyTo(this)
+        }
+        addView(leftTextView).then {
+            applyConstraintSet.connect(LeftTextId, ConstraintSet.LEFT, id, ConstraintSet.LEFT, ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(LeftTextId, ConstraintSet.TOP, holderView.id, ConstraintSet.BOTTOM, 0)
+            applyConstraintSet.connect(LeftTextId, ConstraintSet.BOTTOM, id, ConstraintSet.BOTTOM, 0)
+            applyConstraintSet.constrainWidth(LeftTextId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(LeftTextId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainDefaultHeight(LeftTextId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainPercentHeight(LeftTextId,0.4F)
+            applyConstraintSet.setDimensionRatio(LeftTextId,"w,1:1")
+            applyConstraintSet.applyTo(this)
+        }
+        addView(leftImageView).then {
+            applyConstraintSet.connect(LeftImageId,ConstraintSet.LEFT,id,ConstraintSet.LEFT,ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(LeftImageId,ConstraintSet.TOP,TopHolderId,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.connect(LeftImageId,ConstraintSet.BOTTOM,id,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.constrainWidth(LeftImageId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(LeftImageId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainDefaultHeight(LeftImageId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainPercentHeight(LeftImageId,0.33f)
+            applyConstraintSet.setDimensionRatio(LeftImageId,"w,1:1")
+            applyConstraintSet.applyTo(this)
+        }
+
+        addView(leftTouchView).then {
+            applyConstraintSet.connect(LeftTouchId,ConstraintSet.LEFT,id,ConstraintSet.LEFT,ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(LeftTouchId,ConstraintSet.TOP,TopHolderId,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.connect(LeftTouchId,ConstraintSet.BOTTOM,id,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.constrainWidth(LeftTouchId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(LeftTouchId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainDefaultHeight(LeftTouchId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainPercentHeight(LeftTouchId,0.65f)
+            applyConstraintSet.setDimensionRatio(LeftTouchId,"w,1:1")
+            applyConstraintSet.applyTo(this)
+        }
+
+        addView(rightTextView).then {
+            applyConstraintSet.connect(RightTextId, ConstraintSet.RIGHT, id, ConstraintSet.RIGHT, ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(RightTextId, ConstraintSet.TOP, holderView.id, ConstraintSet.BOTTOM, 0)
+            applyConstraintSet.connect(RightTextId, ConstraintSet.BOTTOM, id, ConstraintSet.BOTTOM, 0)
+            applyConstraintSet.constrainWidth(RightTextId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(RightTextId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainDefaultHeight(RightTextId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainPercentHeight(RightTextId,0.4F)
+            applyConstraintSet.setDimensionRatio(RightTextId,"w,1:1")
+            applyConstraintSet.applyTo(this)
+        }
+
+        addView(rightImageView).then {
+            applyConstraintSet.connect(RightImageId,ConstraintSet.RIGHT,id,ConstraintSet.RIGHT,ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(RightImageId,ConstraintSet.TOP,TopHolderId,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.connect(RightImageId,ConstraintSet.BOTTOM,id,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.constrainWidth(RightImageId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(RightImageId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainDefaultHeight(RightImageId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainPercentHeight(RightImageId,0.33f)
+            applyConstraintSet.setDimensionRatio(RightImageId,"w,1:1")
+            applyConstraintSet.applyTo(this)
+        }
+
+        addView(rightTouchView).then {
+            applyConstraintSet.connect(RightTouchViewId,ConstraintSet.RIGHT,id,ConstraintSet.RIGHT,ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(RightTouchViewId,ConstraintSet.TOP,TopHolderId,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.connect(RightTouchViewId,ConstraintSet.BOTTOM,id,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.constrainWidth(RightTouchViewId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(RightTouchViewId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainDefaultHeight(RightTouchViewId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainPercentHeight(RightTouchViewId,0.65f)
+            applyConstraintSet.setDimensionRatio(RightTouchViewId,"w,1:1")
+            applyConstraintSet.applyTo(this)
+        }
+
+        addView(titleTextView).then {
+            applyConstraintSet.connect(TitleTextId,ConstraintSet.TOP,TopHolderId,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.connect(TitleTextId,ConstraintSet.LEFT,LeftTouchId,ConstraintSet.RIGHT,ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(TitleTextId,ConstraintSet.RIGHT,RightTouchViewId,ConstraintSet.LEFT,ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(TitleTextId,ConstraintSet.BOTTOM,id,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.constrainWidth(TitleTextId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(TitleTextId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainDefaultHeight(TitleTextId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainPercentHeight(TitleTextId,0.33F)
+            applyConstraintSet.applyTo(this)
+        }
+
+        addView(titleImageView).then{
+            applyConstraintSet.connect(TitleImageId,ConstraintSet.TOP,TopHolderId,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.connect(TitleImageId,ConstraintSet.LEFT,LeftTouchId,ConstraintSet.RIGHT,ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(TitleImageId,ConstraintSet.RIGHT,RightTouchViewId,ConstraintSet.LEFT,ScreenTool.dip2px(context,10f))
+            applyConstraintSet.connect(TitleImageId,ConstraintSet.BOTTOM,id,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.constrainWidth(TitleImageId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(TitleImageId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainDefaultHeight(TitleImageId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainPercentHeight(TitleImageId,0.33F)
+            applyConstraintSet.applyTo(this)
+        }
+
+        addView(bottomLine).then {
+            applyConstraintSet.connect(BottomLineId,ConstraintSet.BOTTOM,id,ConstraintSet.BOTTOM,0)
+            applyConstraintSet.constrainWidth(BottomLineId, ConstraintSet.MATCH_CONSTRAINT)
+            applyConstraintSet.constrainHeight(BottomLineId, ScreenTool.dip2px(context,1f))
+            applyConstraintSet.applyTo(this)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/1/31 下午4:56
+     * @From   CommonActionBar
+     * @Note   设置左侧资源图片
+     * @param  imageRes 图片资源
+     */
+    fun setLeftImage(@DrawableRes imageRes:Int):CommonActionBar{
+        leftImageView.setImageResource(imageRes)
+        leftImageView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午4:59
+     * @Note   设置左侧网络图片
+     * @param  imageUrl 网络图片URL
+     */
+    fun setLeftImage(imageUrl:String):CommonActionBar{
+        imageLoader(imageUrl,leftImageView)
+        leftImageView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:00
+     * @Note   设置右侧图片资源
+     * @param  imageRes 图片资源
+     */
+    fun setRightImage(@DrawableRes imageRes:Int):CommonActionBar{
+        rightImageView.setImageResource(imageRes)
+        rightImageView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:00
+     * @Note   设置右侧网络图片
+     * @param  imageUrl 网络图片URL
+     */
+    fun setRightImage(imageUrl:String):CommonActionBar{
+        imageLoader(imageUrl,rightImageView)
+        rightImageView.visibility = View.VISIBLE
+        return  this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:00
+     * @Note   设置左侧文字
+     * @param  text 文字
+     */
+    fun setLeftText(text:String):CommonActionBar{
+        leftTextView.text = text
+        leftTextView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:01
+     * @Note   设置左侧文字颜色
+     * @param  color 文字颜色
+     */
+    fun setLeftTextColor(@ColorRes color :Int):CommonActionBar{
+        leftTextView.setTextColor(context.getColorCompatible(color))
+        leftTextView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:02
+     * @Note   设置右侧文字
+     * @param  text 文字
+     */
+    fun setRightText(text:String):CommonActionBar{
+        rightTextView.text = text
+        rightTextView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:03
+     * @Note   设置右侧文字颜色
+     * @param  color 文字颜色
+     */
+    fun setRightTextColor(@ColorRes color :Int):CommonActionBar{
+        rightTextView.setTextColor(context.getColorCompatible(color))
+        rightTextView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:03
+     * @Note   设置标题
+     * @param  title 标题
+     */
+    fun setTitleText(title:String):CommonActionBar{
+        titleText = title
+        titleTextView.text = titleText
+        titleTextView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:04
+     * @Note   设置标题颜色
+     * @param  color 标题颜色
+     */
+    fun setTitleColor(@ColorRes color :Int):CommonActionBar{
+        titleTextView.setTextColor(context.getColorCompatible(color))
+        titleTextView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:04
+     * @Note   设置左侧文字大小
+     * @param  sizeLevel 设置文字大小 0.0到10.0之间随意调
+     */
+    fun setLeftTextSize(@FloatRange(from = 0.0,to = 10.0)sizeLevel:Float):CommonActionBar{
+        var layoutParams = leftTextView.layoutParams.to<ConstraintLayout.LayoutParams>()
+        layoutParams.matchConstraintPercentHeight = sizeLevel*0.1f*0.65f
+        leftTextView.layoutParams = layoutParams
+        leftTextView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:04
+     * @Note   设置右侧文字大小
+     * @param  sizeLevel 设置文字大小 0.0到10.0之间随意调
+     */
+    fun setRightTextSize(@FloatRange(from = 0.0,to = 10.0)sizeLevel:Float):CommonActionBar{
+        var layoutParams = rightTextView.layoutParams.to<ConstraintLayout.LayoutParams>()
+        layoutParams.matchConstraintPercentHeight = sizeLevel*0.1f*0.65f
+        rightTextView.layoutParams = layoutParams
+        rightTextView.visibility = View.VISIBLE
+        return this
+    }
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:06
+     * @Note   设置背景图
+     * @param  res 本地资源
+     */
+    fun setBackground(@DrawableRes res :Int):CommonActionBar{
+        backgroundImageView.setImageResource(res)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:07
+     * @Note   设置背景图 网络资源
+     * @param  imageUrl 网络图片URL
+     */
+    fun setBackground(imageUrl :String):CommonActionBar{
+        imageLoader(imageUrl,backgroundImageView)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:09
+     * @Note   设置背景透明度  0-255区间  当背景为image时 无效
+     * @param  aplha 透明度
+     */
+    fun setBackgroundAlpha(@IntRange(from = 0, to = 255) aplha:Int):CommonActionBar{
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+            backgroundImageView.imageAlpha = aplha
+        }
+        backgroundImageView.background?.alpha = aplha
+        backgroundImageView.drawable?.alpha =aplha
+        bottomLine.background.alpha = aplha
+        background?.alpha = aplha
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/5/21 下午6:10
+     * @Note   设置底线颜色
+     * @param  color 颜色
+     */
+    fun setLineBgColor(color: Int):CommonActionBar{
+        bottomLine.setBackgroundColor(color)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:10
+     * @Note   设置topbar占位视图背景颜色
+     * @param  res 颜色资源
+     */
+    fun setTopHolderColor(@DrawableRes res :Int):CommonActionBar{
+        holderView.setBackgroundColor(res)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:12
+     * @Note   设置占位View是否显示
+     * @param  isVisible 是否显示
+     */
+    fun setTopHolderVisibility(isVisible: Boolean): CommonActionBar{
+        holderView.visibility = isVisible.judge(View.VISIBLE,View.INVISIBLE)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:04
+     * @Note   设置左侧图片大小
+     * @param  sizeLevel 设置大小 0.0到10.0之间随意调
+     */
+    fun setLeftImageSize(@FloatRange(from = 0.0,to = 10.0)sizeLevel:Float):CommonActionBar{
+        var layoutParams = leftImageView.layoutParams.to<ConstraintLayout.LayoutParams>()
+        layoutParams.matchConstraintPercentHeight = sizeLevel*0.1f*0.65f
+        leftImageView.layoutParams = layoutParams
+        leftImageView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:04
+     * @Note   设置右侧图片大小
+     * @param  sizeLevel 设置大小 0.0到10.0之间随意调
+     */
+    fun setRightImageSize(@FloatRange(from = 0.0,to = 10.0)sizeLevel:Float):CommonActionBar{
+        var layoutParams = rightImageView.layoutParams.to<ConstraintLayout.LayoutParams>()
+        layoutParams.matchConstraintPercentHeight = sizeLevel*0.1f*0.65f
+        rightImageView.layoutParams = layoutParams
+        rightImageView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:04
+     * @Note   设置标题文字大小
+     * @param  sizeLevel 设置文字大小 0.0到10.0之间随意调
+     */
+    fun setTitleSize(@FloatRange(from = 0.0,to = 10.0)sizeLevel:Float):CommonActionBar{
+        var layoutParams = titleTextView.layoutParams.to<ConstraintLayout.LayoutParams>()
+        layoutParams.matchConstraintPercentHeight = sizeLevel*0.1f*0.65f
+        titleTextView.layoutParams = layoutParams
+        titleTextView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:04
+     * @Note   设置标题文字大小
+     * @param  sizeLevel 设置文字大小 0.0到10.0之间随意调
+     */
+    fun setTitleImageSize(@FloatRange(from = 0.0,to = 10.0)sizeLevel:Float):CommonActionBar{
+        var layoutParams = titleImageView.layoutParams.to<ConstraintLayout.LayoutParams>()
+        layoutParams.matchConstraintPercentHeight = sizeLevel*0.1f*0.65f
+        titleImageView.layoutParams = layoutParams
+        titleImageView.visibility = View.VISIBLE
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/3/8 下午1:40
+     * @Note   标题图片
+     */
+    fun setTitleImageRes(@DrawableRes res: Int):CommonActionBar{
+        titleImageView.setImageResource(res)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/3/8 下午1:42
+     * @Note   标题图片
+     * @param  imageUrl 图片URL
+     */
+    fun setTitleNetImage(imageUrl : String):CommonActionBar{
+        imageLoader(imageUrl,titleImageView)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:13
+     * @Note   设置左侧点击事件
+     * @param  listener 点击事件
+     */
+    fun setLeftClickListener(listener: (View) -> (Unit)):CommonActionBar{
+        leftTouchView.setOnClickListener(listener)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:14
+     * @Note   设置右侧点击事件
+     * @param  listener 点击事件
+     */
+    fun setRightClickListener(listener: (View) -> (Unit)):CommonActionBar{
+        rightTouchView.setOnClickListener(listener)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/1/31 下午5:14
+     * @Note   设置网络图片加载器
+     * @param  imageLoader  图片加载器  默认内置图片加载器
+     */
+    fun setImageLoader(imageLoader :(url : String , imageView :ImageView) -> (Unit)):CommonActionBar{
+        this.imageLoader = imageLoader
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/2/27 下午3:10
+     * @Note   设置标题显示与否
+     * @param  visibility 显示
+     */
+    fun setTitleVisibility(visibility : Boolean):CommonActionBar{
+        titleTextView.visibility = visibility.judge(View.VISIBLE,View.INVISIBLE)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/2/27 下午3:10
+     * @Note   设置右侧显示与否
+     * @param  visibility 显示
+     */
+    fun setRightVisibility(visibility : Boolean):CommonActionBar{
+        rightTextView.visibility = visibility.judge(View.VISIBLE,View.INVISIBLE)
+        rightImageView.visibility = visibility.judge(View.VISIBLE,View.INVISIBLE)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/2/28 上午9:17
+     * @Note   设置背景颜色
+     * @param  color ColorInt
+     */
+    fun setBgColor(@ColorInt color:Int):CommonActionBar{
+        setBackgroundColor(color)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/2/28 上午9:17
+     * @Note   设置背景颜色
+     * @param  color ColorRes
+     */
+    fun setBgResColor(@ColorRes color: Int):CommonActionBar{
+        setBackgroundColor(context.getColorCompatible(color))
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/2/28 上午10:31
+     * @Note   设置显示隐藏
+     * @param  visibility 是否显示
+     */
+    fun setVisibility(visibility: Boolean):CommonActionBar{
+        this.visibility = visibility.judge(View.VISIBLE, View.INVISIBLE)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/3/14 下午2:20
+     * @Note   重置设置topbar高度
+     * @param  height 重新设置的高度
+     */
+    fun reTobBarHeight(height : Int){
+
+        this.reLayout<ConstraintLayout.LayoutParams> {
+            params ->
+            if (height == -1){
+                params.height = (ScreenTool.getScreenHeight(context)*0.13).toInt()
+            }else{
+                params.height = height
+            }
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   CommonActionBar
+     * @Date   2018/4/19 下午12:22
+     * @Note   获占位View
+     */
+    fun holderViewProvider():View{
+        return holderView
+    }
+}
+
+

+ 64 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/DialogBackGroundView.kt

@@ -0,0 +1,64 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.content.Context
+import android.graphics.*
+import android.util.AttributeSet
+import android.view.View
+
+/**
+ * @author LDD
+ * @Date   2018/4/12 下午4:09
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   对话框Dilaog背景View
+ */
+class DialogBackGroundView : View {
+
+    /**
+     * @Name  paint
+     * @Type  Paint
+     * @Note  画笔
+     */
+    private val paint = Paint()
+
+    /**构造方法*/
+    constructor(context: Context?) : super(context)
+    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
+
+    /**
+     * @author LDD
+     * @From   DialogBackGroundView
+     * @Date   2018/4/12 下午3:53
+     * @Note   类初始化方法
+     */
+    init {
+        setBackgroundColor(Color.TRANSPARENT)
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        super.onDraw(canvas)
+        /**设置画笔颜色*/
+        paint.color = Color.parseColor("#bb000000")
+        /**设置粗体*/
+        paint.typeface = Typeface.DEFAULT_BOLD
+        /**设置抗锯齿*/
+        paint.isAntiAlias = true
+        /**矩形轮廓*/
+        val rectrf = RectF(0f, height.toFloat()/20, width.toFloat(), height.toFloat())
+        /**画矩形并且设置圆角*/
+        canvas.drawRoundRect(rectrf, (width/30).toFloat(), (height/30).toFloat(), paint)
+        /**初始化Patn*/
+        val path = Path()
+        /**移动到适合的点*/
+        path.moveTo((width - height.toFloat()*0.1).toFloat(),0f)
+        /**画线*/
+        path.lineTo((width - height.toFloat()*0.1 + height.toFloat()/20).toFloat(),height.toFloat()/20+0.2f)
+        path.lineTo((width - height.toFloat()*0.1 - height.toFloat()/20).toFloat(),height.toFloat()/20+0.2f)
+        /**闭合路径*/
+        path.close()
+        /**画Path*/
+        canvas.drawPath(path,paint)
+        paint.reset()
+    }
+
+}

+ 105 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/EditTextCompatibleScrollView.kt

@@ -0,0 +1,105 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.widget.EditText
+
+
+/**
+ * @author LDD
+ * @Date   2018/4/24 下午1:23
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   兼容滑动视图嵌套的EditText
+ */
+class EditTextCompatibleScrollView :EditText {
+
+
+    /**
+     * @Name  mOffsetHeight
+     * @Type  Int
+     * @Note  滑动距离的最大边界
+     */
+    private var mOffsetHeight: Int = 0
+
+    /**
+     * @Name  mBottomFlag
+     * @Type  Boolean
+     * @Note  是否到顶或者到底的标志
+     */
+    private var mBottomFlag = false
+
+    /**构造*/
+    constructor(context: Context?) : super(context)
+    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
+
+    /**
+     * @author LDD
+     * @From   EditTextCompatibleScrollView
+     * @Date   2018/4/24 下午1:24
+     * @Note   测量
+     */
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+
+        val mLayout = layout
+        val paddingTop: Int = totalPaddingTop
+        val paddingBottom: Int = totalPaddingBottom
+        val mHeight: Int = height
+        val mLayoutHeight: Int = mLayout.height
+
+        //计算滑动距离的边界
+        mOffsetHeight = mLayoutHeight + paddingTop + paddingBottom - mHeight
+    }
+
+
+    /**
+     * @author LDD
+     * @Date   2018/4/24 下午1:25
+     * @From   EditTextCompatibleScrollView
+     * @Note   消耗触摸事件
+     */
+    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
+        if (event.action == MotionEvent.ACTION_DOWN)
+        //如果是新的按下事件,则对mBottomFlag重新初始化
+            mBottomFlag = false
+        //如果已经不要这次事件,则传出取消的信号,这里的作用不大
+        if (mBottomFlag)
+            event.action = MotionEvent.ACTION_CANCEL
+        return super.dispatchTouchEvent(event)
+    }
+
+    /**
+     * @author LDD
+     * @From    EditTextCompatibleScrollView
+     * @Date   2018/4/24 下午1:25
+     * @Note   触摸处理
+     */
+    @SuppressLint("WrongConstant")
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        val result = super.onTouchEvent(event)
+        if (!mBottomFlag)
+            parent.requestDisallowInterceptTouchEvent(true)
+        return result
+    }
+
+    /**
+     * @author LDD
+     * @From   EditTextCompatibleScrollView
+     * @Date   2018/4/24 下午1:27
+     * @Note   滑动时的处理
+     */
+    override fun onScrollChanged(horiz: Int, vert: Int, oldHoriz: Int, oldVert: Int) {
+        super.onScrollChanged(horiz, vert, oldHoriz, oldVert)
+        if (vert == mOffsetHeight || vert == 0) {
+            //这里触发父布局或祖父布局的滑动事件
+            parent.requestDisallowInterceptTouchEvent(false)
+            mBottomFlag = true
+        }
+    }
+
+
+
+}

+ 149 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/LetterView.kt

@@ -0,0 +1,149 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Typeface
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import com.wdkl.ncs.android.lib.utils.errorLog
+
+
+/**
+ * @author LDD
+ * @Date   2018/3/23 上午10:54
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   首字母快速索引View
+ */
+class LetterView : View {
+
+    /**
+     * @Name  onTouchingLetterChangedListener
+     * @Type  Block
+     * @Note  触摸到字母时的回调
+     */
+    private var onTouchingLetterChangedListener: ((letter: String) -> Unit)? = null
+
+    /**
+     * @Name  letterList
+     * @Type  ArrayList<String>
+     * @Note  首字母集合
+     */
+    private var letterList = arrayListOf("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "#")
+
+    /**
+     * @Name  choose
+     * @Type  Int
+     * @Note  选中字母下标 为-1代表未选中
+     */
+    private var choose = -1
+
+    /**
+     * @Name  paint
+     * @Type  Paint
+     * @Note  画笔
+     */
+    private val paint = Paint()
+
+    /**构造事件*/
+    constructor(context: Context?) : super(context)
+    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
+    /**======*/
+
+    /**
+     * @author LDD
+     * @From   LetterView
+     * @Date   2018/3/23 上午10:59
+     * @Note   设置自定义首字母集合
+     * @param  letters 首字母集合
+     */
+    fun setLetter(letters: ArrayList<String>) {
+        letterList = letters
+        invalidate()
+    }
+
+    /**
+     * @author LDD
+     * @From   LetterView
+     * @Date   2018/3/23 上午11:00
+     * @Note   重写Draw方法绘制UI
+     * @param  canvas 画布
+     */
+    override fun onDraw(canvas: Canvas) {
+        super.onDraw(canvas)
+        /**获取单个字母高度 总高度/字母个数*/
+        val singleHeight = height / letterList.size
+
+        /**设置粗体*/
+        paint.typeface = Typeface.DEFAULT_BOLD
+        /**设置抗锯齿*/
+        paint.isAntiAlias = true
+
+        /**循环绘制首字母*/
+        for (i in letterList.indices) {
+            /**设置选中的字母为选中色*/
+            if (i == choose) {
+                paint.color = Color.parseColor("#f55158")
+                paint.isFakeBoldText = true
+                /**设置字体大小*/
+                paint.textSize = (width * 0.65).toFloat()
+            }else{
+                /**设置画笔颜色*/
+                paint.color = Color.BLACK
+                paint.isFakeBoldText = false
+                /**设置字体大小*/
+                paint.textSize = (width * 0.5).toFloat()
+            }
+            /**设置文字绘制坐标*/
+            val xPos = width / 2 - paint.measureText(letterList[i]) / 2
+            val yPos = (singleHeight * i + singleHeight / 2).toFloat()
+
+            /**绘制文字*/
+            canvas.drawText(letterList[i], xPos, yPos, paint)
+
+        }
+
+        /**重置画笔*/
+        paint.reset()
+    }
+
+    /**
+     * @author LDD
+     * @From   LetterView
+     * @Date   2018/3/23 上午11:08
+     * @Note   重新监听触摸事件
+     * @param  event 事件
+     */
+    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
+        /**获取触摸Y坐标*/
+        val y = event.y
+        /**获取上次选中坐标*/
+        val oldChoose = choose
+        /**点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数*/
+        val c = (y / height * letterList.size).toInt()
+        /**当action为down时设置设置相应 设置选中下标 并且绘制*/
+
+        if (oldChoose != c) {
+            if (c >= 0 && c < letterList.size) {
+                onTouchingLetterChangedListener?.invoke(letterList[c])
+                choose = c
+                invalidate()
+            }
+        }
+
+        return true
+    }
+
+    /**
+     * @author LDD
+     * @From   LetterView
+     * @Date   2018/3/23 上午11:13
+     * @Note   设置触摸事件
+     */
+    fun setOnTouchingLetterChangedListener(onTouchLetterCallBack: ((letter: String) -> Unit)) {
+        this.onTouchingLetterChangedListener = onTouchLetterCallBack
+    }
+}

+ 168 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/LineView.kt

@@ -0,0 +1,168 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.content.Context
+import android.graphics.*
+import android.os.Build
+import android.util.AttributeSet
+import android.view.View
+import com.wdkl.ncs.android.lib.R
+import com.wdkl.ncs.android.lib.utils.then
+
+/**
+ * @author LDD
+ * @Date   2018/3/5 下午12:47
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   绘制背景线条的View
+ */
+class LineView : View{
+
+    /**
+     * @Name  hornHieght
+     * @Type  Float
+     * @Note  角高度
+     */
+    private var hornHieght = 0.1f
+
+    /**
+     * @Name  linePosition
+     * @Type  Int
+     * @Note  Line坐标
+     */
+    private var linePosition =3
+
+    /**
+     * @Name  linePadding
+     * @Type  lineHeight
+     * @Note  线绘制高度
+     */
+    var lineHeight = 0.8f
+
+    /**
+     * @Name  PositionTop
+     * @Type  Int
+     * @Note  顶部对齐
+     */
+    private val PositionTop = 1
+
+    /**
+     * @Name  PositionBottom
+     * @Type  Int
+     * @Note  底部对齐
+     */
+    private val PositionBottom = 2
+
+    /**
+     * @Name  PositionCenter
+     * @Type  Int
+     * @Note  中心对戏
+     */
+    private val PositionCenter = 3
+
+    /**
+     * @Name  lineColor
+     * @Type  Int
+     * @Note  线条颜色
+     */
+    private var lineColor :Int  =Color.BLACK
+
+    /**
+     * @Name  topPosition
+     * @Type  Float
+     * @Note  顶部position
+     */
+    private val topPosition :Float by lazy {
+        var y = 0f
+        when (linePosition) {
+            PositionBottom -> y = height - height*lineHeight
+            PositionCenter -> y = (height-height*lineHeight)/2
+            PositionTop -> y = 0f
+        }
+        return@lazy y
+    }
+
+    /**
+     * @Name  bottomPosition
+     * @Type  Float
+     * @Note  底部Position
+     */
+    private val bottomPosition:Float by lazy {
+        var y = height.toFloat()
+        when (linePosition) {
+            PositionCenter -> y = height*lineHeight+(height-height*lineHeight)/2
+            PositionTop -> y = (height-height*lineHeight)/2
+        }
+        return@lazy y
+    }
+
+    /**
+     * @Name  hornCenterPostion
+     * @Type  Float
+     * @Note  中心店
+     */
+    private val hornCenterPostion:Float by lazy {
+        var y = 0f
+        when (linePosition) {
+            PositionCenter -> y = (height/2).toFloat()
+            PositionTop -> y = height*lineHeight/2
+            PositionBottom -> y = (height/2)+(height-height*lineHeight)/2
+        }
+            return@lazy y
+    }
+
+
+    constructor(context: Context) : this(context,null)
+
+    constructor(context: Context, attrs: AttributeSet?) :this(context,attrs,0)
+
+    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
+        val typeArray = context.obtainStyledAttributes(attrs, R.styleable.LineView)
+        lineHeight = typeArray.getFloat(R.styleable.LineView_line_height,0.8f)
+        hornHieght = typeArray.getFloat(R.styleable.LineView_horn_height,0.1f)
+        linePosition = typeArray.getInt(R.styleable.LineView_line_position,3)
+        lineColor = typeArray.getColor(R.styleable.LineView_line_color,Color.BLACK)
+        typeArray.recycle()
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            setLayerType(View.LAYER_TYPE_SOFTWARE, null)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   LineView
+     * @Date   2018/3/5 下午4:52
+     * @Note   绘制UI
+     */
+    override fun onDraw(canvas: Canvas) {
+        var paint = Paint()
+        paint.style = Paint.Style.STROKE
+        paint.strokeWidth = (width/40).toFloat()
+        paint.isAntiAlias = true
+        paint.color = lineColor
+        paint.strokeJoin = Paint.Join.ROUND
+        canvas.drawPath(createPath(), paint)
+    }
+
+
+    /**
+     * @author LDD
+     * @From   LineView
+     * @Date   2018/3/5 下午4:51
+     * @Note   构建Path
+     * @return Path
+     */
+    fun createPath():Path{
+        return Path().then {
+            path ->
+            path.moveTo((width/20).toFloat(),topPosition)
+            path.lineTo((width/20).toFloat(),hornCenterPostion-hornHieght*height/2)
+            path.moveTo((width/20).toFloat(),hornCenterPostion-hornHieght*height/2)
+            path.lineTo(hornHieght*height*0.7f+(width/20f),hornCenterPostion)
+            path.moveTo(hornHieght*height*0.7f+(width/20f),hornCenterPostion)
+            path.lineTo((width/20).toFloat(),hornCenterPostion+hornHieght*height/2)
+            path.moveTo((width/20).toFloat(),hornCenterPostion+hornHieght*height/2)
+            path.lineTo((width/20).toFloat(),bottomPosition)
+            path.close()
+        }
+    }
+
+}

+ 208 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/MenuPopWindow.kt

@@ -0,0 +1,208 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.app.Activity
+import android.graphics.drawable.BitmapDrawable
+import android.view.View
+import android.widget.ListView
+import android.widget.RelativeLayout
+import com.wdkl.ncs.android.lib.R
+import com.wdkl.ncs.android.lib.adapter.ListViewBaseAdapter
+import com.wdkl.ncs.android.lib.base.BaseApplication
+import com.wdkl.ncs.android.lib.databinding.MenuItemLayBinding
+import com.wdkl.ncs.android.lib.utils.AppTool
+import com.wdkl.ncs.android.lib.utils.animSequentialStart
+import com.wdkl.ncs.android.lib.utils.reLayout
+import com.wdkl.ncs.android.lib.vo.MenuVo
+import com.enation.javashop.utils.base.tool.ScreenTool
+
+/**
+ * @author LDD
+ * @Date   2018/4/12 下午1:57
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   点击菜单视图
+ */
+class MenuPopWindow constructor(val activity: Activity,val data :ArrayList<MenuVo>) :PopWindowCompatible((ScreenTool.getScreenWidth(BaseApplication.appContext)/3).toInt(), (if(data.size>5) 5 else data.size) * (ScreenTool.getScreenWidth(BaseApplication.appContext)/3/3.5).toInt()){
+
+
+
+    /**
+     * @Name  animIsEnd
+     * @Type  Boolean
+     * @Note  动画是否结束
+     */
+    private var animIsEnd = true
+
+    /**
+     * @Name  clickCallBack
+     * @Type  block
+     * @Note  点击回调
+     */
+    private var clickCallBack :((MenuVo) ->Unit)? = null
+
+    /**类初始化操作*/
+    init {
+        isFocusable = true
+        isOutsideTouchable = true
+        setBackgroundDrawable(BitmapDrawable())
+        createView()
+    }
+
+    companion object {
+        /**
+         * @author LDD
+         * @From   MenuPopWindow
+         * @Date   2018/4/13 上午9:43
+         * @Note   静态构建
+         * @param  activity 调用上下文
+         * @param  data     数据
+         */
+        fun build(activity: Activity,data :ArrayList<MenuVo>):MenuPopWindow{
+            return MenuPopWindow(activity,data)
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   MenuPopWindow
+     * @Date   2018/4/13 上午9:28
+     * @Note   创建视图
+     */
+    fun createView(){
+
+        /**声明父视图*/
+        var parent = RelativeLayout(activity)
+        /**设置父视图为PopWindow的内容视图*/
+        contentView = parent
+        /**初始化背景视图*/
+        val backView = DialogBackGroundView(activity)
+        /**添加进父视图*/
+        parent.addView(backView)
+        /**设置为父视图的大小*/
+        backView.reLayout<RelativeLayout.LayoutParams> {
+            params ->
+            params.height = height
+            params.width = width
+        }
+        /**初始化ListView*/
+        val listView = ListView(activity)
+        /**隐藏滑动条*/
+        listView.isVerticalScrollBarEnabled = false
+        /**添加父视图*/
+        parent.addView(listView)
+        /**设置列表视图大小*/
+        listView.reLayout<RelativeLayout.LayoutParams> {
+            params ->
+            params.height = (height*0.95).toInt()
+            params.width = width
+            params.setMargins(0,(height*0.05).toInt(),0,(height*0.05).toInt())
+        }
+        /**设置适配器*/
+        listView.adapter = object : ListViewBaseAdapter<MenuVo,MenuItemLayBinding>(activity, R.layout.menu_item_lay,data){
+
+            override fun fillItem(binding: MenuItemLayBinding, data: MenuVo, position: Int) {
+                binding.menuItemIv.setImageResource(data.resId)
+                binding.data = data
+            }
+
+            override fun itemClick(data: MenuVo, position: Int) {
+                dismiss({
+                    clickCallBack?.invoke(data)
+                })
+            }
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   MenuPopWindow
+     * @Date   2018/4/13 上午9:41
+     * @Note   设置点击事件
+     * @param  call 点击回调
+     */
+    fun setItemCallBack(call : (MenuVo) -> Unit):MenuPopWindow{
+        this.clickCallBack = call
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   MenuPopWindow
+     * @Date   2018/3/15 下午3:29
+     * @Note   显示
+     * @param  atView 显示在那个view下方
+     */
+    fun show(atView:View){
+
+        /**当动画未执行完毕 又或者筛选条件数量为0时 不显示*/
+        if (data.size == 0 || !animIsEnd){
+            return
+        }
+
+
+        /**将该View加载到页面之上*/
+
+        var baseLine = ScreenTool.getScreenWidth(BaseApplication.appContext) - width
+        var offset = -atView.width/3
+        var location = IntArray(2)
+        atView.getLocationOnScreen(location)
+        if (location[0] > baseLine){
+            offset -= (location[0] - baseLine).toInt()
+        }
+
+        showAsDropDown(atView,offset,-atView.height/3)
+
+        /**执行动画 起始y点为 -View.height 减去 Recly.height -button.height  */
+        contentView.animSequentialStart(arrayListOf(AppTool.Anim.createPopInAnimation(activity, (-height).toFloat(),300)),interceptor = {
+            index: Int, state: Int ->
+
+            /**动画结束 设置动画标记结束 显示Mask*/
+            if (state == 2){
+                animIsEnd = true
+            }
+
+            /**动画开始 重置动画标记*/
+            if (state == 3){
+                animIsEnd = false
+            }
+
+            /**当返回true时 代表拦截当前动画 不再往下执行*/
+            return@animSequentialStart false
+        })
+    }
+
+    /**
+     * @author LDD
+     * @From   MenuPopWindow
+     * @Date   2018/3/15 下午3:36
+     * @Note   重写dismiss事件
+     */
+    fun dismiss(complete :(()->Unit)? = null) {
+
+        /**动画未执行完毕 不执行下方代码*/
+        if (!animIsEnd){
+            return
+        }
+
+        /**执行动画 终点y轴为 -View.height*/
+        contentView.animSequentialStart(arrayListOf(AppTool.Anim.createPopOutAnimation(activity,-height.toFloat(),300)),interceptor = {
+            index: Int, state: Int ->
+
+            /**动画执行完毕 设置标记 隐藏View*/
+            if (state == 2){
+                animIsEnd = true
+                complete?.invoke()
+                super.dismiss()
+            }
+
+            /**动画开始执行 还原标记*/
+            if (state == 3){
+                animIsEnd = false
+            }
+
+            /**当返回true时 代表拦截当前动画 不再往下执行*/
+            return@animSequentialStart false
+        })
+    }
+    
+    
+}

+ 395 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/PopCommonView.kt

@@ -0,0 +1,395 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.app.Activity
+import android.databinding.DataBindingUtil
+import android.graphics.drawable.BitmapDrawable
+import android.support.v7.app.AppCompatActivity
+import android.util.DisplayMetrics
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import com.alibaba.android.vlayout.DelegateAdapter
+import com.alibaba.android.vlayout.VirtualLayoutManager
+import com.wdkl.ncs.android.lib.R
+import com.wdkl.ncs.android.lib.adapter.BaseDelegateAdapter
+import com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+import com.wdkl.ncs.android.lib.databinding.PopCommonLayBinding
+import com.wdkl.ncs.android.lib.utils.*
+import com.enation.javashop.utils.base.tool.ScreenTool
+
+/**
+ * @author LDD
+ * @Date   2018/4/19 下午12:38
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   通用列表对话框
+ */
+class PopCommonView : PopWindowCompatible{
+
+    /**
+     * @Name  activity
+     * @Type  Activity
+     * @Note  页面
+     */
+    private var activity : Activity
+
+    /**
+     * @author LDD
+     * @From   GoodsFirstMoreView
+     * @Date   2018/4/4 上午10:45
+     * @Note   数据绑定
+     */
+    private lateinit var binding : PopCommonLayBinding
+
+    /**
+     * @Name  virtualLayoutManager
+     * @Type  VirtualLayoutManager
+     * @Note  VLayoutManager
+     */
+    private lateinit var virtualLayoutManager: VirtualLayoutManager
+
+    /**
+     * @Name  delegateAdapter
+     * @Type  DelegateAdapter
+     * @Note  七巧板适配器
+     */
+    private lateinit var delegateAdapter: DelegateAdapter
+
+    /**
+     * @Name  confirmObserver
+     * @Type  ((GoodsFilterValue?)->Unit)?
+     * @Note  确定监听
+     */
+    private var confirmObserver :(()->Unit)? = null
+
+    /**
+     * @Name  dismissObserver
+     * @Type  (()->(Unit))?
+     * @Note  取消监听
+     */
+    private var dismissObserver : (()->(Unit))? = null
+
+    /**
+     * @Name  animIsEnd
+     * @Type  Boolean
+     * @Note  动画是否结束
+     */
+    private var animIsEnd = true
+
+    /**
+     * @author LDD
+     * @Date   2018/4/19 下午3:20
+     * @From   PopCommonView
+     * @Note   伴生对象
+     */
+    companion object {
+
+        fun getHeight() :Int{
+            var dis  = DisplayMetrics()
+            JavaShopActivityTask.instance.peekTopActivity()!!.windowManager.defaultDisplay.getRealMetrics(dis)
+            return dis.heightPixels - ScreenTool.getVirtualBarHeigh(JavaShopActivityTask.instance.peekTopActivity() as AppCompatActivity?)
+        }
+
+        /**
+         * @author LDD
+         * @From   PopCommonView
+         * @Date   2018/4/19 下午3:21
+         * @Note   静态构建
+         * @param  activity 页面
+         */
+        fun build(activity: Activity) :PopCommonView{
+            return PopCommonView(activity)
+        }
+    }
+
+    /**构造方法*/
+    private constructor(activity: Activity): super(ScreenTool.getScreenWidth(activity).toInt(), (PopCommonView.getHeight() - AppTool.SystemUI.getStatusBarHeight())){
+        this.activity = activity
+        isFocusable = true
+        isOutsideTouchable = true
+        setBackgroundDrawable(BitmapDrawable())
+        createUI()
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午3:21
+     * @Note   构建UI
+     */
+    private fun createUI(){
+        contentView = activity.layoutInflater.inflate(R.layout.pop_common_lay,null)
+        binding = DataBindingUtil.bind(contentView)
+        /**初始化LayoutMannager*/
+        virtualLayoutManager = VirtualLayoutManager(this.activity)
+        /**初始化适配器*/
+        delegateAdapter = DelegateAdapter(virtualLayoutManager)
+        binding.popCommonRv.layoutManager = virtualLayoutManager
+        binding.popCommonRv.adapter = delegateAdapter
+        binding.popCommonContentBg.setOnTouchListener{ _ , _ -> true }
+        binding.popCommonMask.setOnTouchListener { v, event ->
+            if (event.action == MotionEvent.ACTION_DOWN ){
+                dismiss()
+            }
+            return@setOnTouchListener true
+        }
+        binding.popCommonBackIv.setOnClickListener(OnClickListenerAntiViolence({
+            dismiss()
+        }))
+        binding.popCommonComfrimTv.setOnClickListener(OnClickListenerAntiViolence({
+            confirmObserver?.invoke()
+            dismiss()
+        }))
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午3:22
+     * @Note   设置标题
+     * @param  title 标题
+     */
+    fun setTitle(title:String):PopCommonView{
+        binding.popCommonTitleTv.text = title
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/4/19 下午4:04
+     * @From   PopCommonView
+     * @Note   设置标题文字颜色
+     * @param  colorInt 颜色
+     */
+    fun setTitleTextColor(colorInt :Int):PopCommonView{
+        binding.popCommonTitleTv.setTextColor(colorInt)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/4/19 下午4:04
+     * @From   PopCommonView
+     * @Note   设置标题背景颜色
+     * @param  colorInt 颜色
+     */
+    fun setTitleBackgroudColor(colorInt :Int):PopCommonView{
+        binding.popCommonTitleTv.setBackgroundColor(colorInt)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/4/19 下午4:04
+     * @From   PopCommonView
+     * @Note   设置确认文字颜色
+     * @param  colorInt 颜色
+     */
+    fun setConfirmTextColor(colorInt :Int):PopCommonView{
+        binding.popCommonComfrimTv.setTextColor(colorInt)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/4/19 下午4:04
+     * @From   PopCommonView
+     * @Note   设置确认按钮显示
+     * @param  visable 是否显示
+     */
+    fun setConfirmVisable(visable :Boolean):PopCommonView{
+        binding.popCommonComfrimTv.visibility = visable.judge(View.VISIBLE,View.GONE)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/4/19 下午4:04
+     * @From   PopCommonView
+     * @Note   设置确认背景颜色
+     * @param  colorInt 颜色
+     */
+    fun setConfirmBackgroundColor(colorInt :Int):PopCommonView{
+        binding.popCommonComfrimTv.setBackgroundColor(colorInt)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @Date   2018/4/19 下午4:04
+     * @From   PopCommonView
+     * @Note   设置背景颜色
+     * @param  colorInt 颜色
+     */
+    fun setBackgroundColor(colorInt: Int):PopCommonView{
+        binding.popCommonContentBg.setBackgroundColor(colorInt)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午3:22
+     * @Note   是否显示确认Button
+     * @param  isVisable 是否显示
+     */
+    fun confirmButtonVisable(isVisable :Boolean):PopCommonView{
+        binding.popCommonComfrimTv.visibility = isVisable.judge(View.VISIBLE,View.GONE)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午3:23
+     * @Note   设置确认提示
+     * @param  text 提示
+     */
+    fun setConfrimTitle(text :String):PopCommonView{
+        binding.popCommonComfrimTv.visibility = View.VISIBLE
+        binding.popCommonComfrimTv.text = text
+        return this
+    }
+
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午4:13
+     * @Note   设置确定事件
+     * @param  call 回调
+     */
+    fun setConfirmListener(call : ()->Unit):PopCommonView{
+        confirmObserver  = call
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午4:13
+     * @Note   设置取消事件
+     * @param  call 回调
+     */
+    fun setDismissListener(call : () ->Unit):PopCommonView{
+        dismissObserver = call
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午3:23
+     * @Note   添加适配器
+     * @param  adapters 适配器列表
+     */
+    fun setAdapters(vararg adapters : DelegateAdapter.Adapter<*>):PopCommonView{
+        delegateAdapter.addAdapters(adapters.asList())
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午3:23
+     * @Note   添加适配器
+     * @param  adapters 适配器列表
+     */
+    fun setAdapters(adapters: List<DelegateAdapter.Adapter<*>>): PopCommonView {
+        delegateAdapter.addAdapters(adapters)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午3:24
+     * @Note   设置适配器
+     * @param   adapters 适配器
+     */
+    fun setAdapters(adapters: ArrayList<DelegateAdapter.Adapter<*>>):PopCommonView{
+        delegateAdapter.addAdapters(adapters)
+        return this
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午3:25
+     * @Note   显示与该View之下
+     * @param  atView view
+     */
+    fun show(atView : View){
+        /**当动画未执行完毕 又或者筛选条件数量为0时 不显示*/
+        if (delegateAdapter.adaptersCount == 0 || !animIsEnd){
+            return
+        }
+
+        /**mask先隐藏掉*/
+        binding.popCommonMask.visibility = View.GONE
+
+        /**将该View加载到页面之上*/
+        showAsDropDown(atView)
+
+        /**执行动画 起始y点为 -View.height 减去 Recly.height -button.height  */
+        contentView.animSequentialStart(arrayListOf(AppTool.Anim.createPopInAnimation(activity, height.toFloat(),300)),interceptor = {
+            index: Int, state: Int ->
+
+            /**动画结束 设置动画标记结束 显示Mask*/
+            if (state == 2){
+                animIsEnd = true
+                binding.popCommonMask.visibility = View.VISIBLE
+            }
+
+            /**动画开始 重置动画标记*/
+            if (state == 3){
+                animIsEnd = false
+            }
+
+            /**当返回true时 代表拦截当前动画 不再往下执行*/
+            return@animSequentialStart false
+        })
+    }
+
+    /**
+     * @author LDD
+     * @From   PopCommonView
+     * @Date   2018/4/19 下午3:26
+     * @Note   销毁退出
+     */
+    override fun dismiss() {
+
+        /**动画未执行完毕 不执行下方代码*/
+        if (!animIsEnd){
+            return
+        }
+
+        /**延迟执行 优化操作体验*/
+        AppTool.Time.delay(250) {
+            dismissObserver?.invoke()
+        }
+
+        /**隐藏Mask*/
+        binding.popCommonMask.visibility = View.GONE
+
+        /**执行动画 终点y轴为 -View.height*/
+        contentView.animSequentialStart(arrayListOf(AppTool.Anim.createPopOutAnimation(activity, height.toFloat(),300)),interceptor = {
+            index: Int, state: Int ->
+
+            /**动画执行完毕 设置标记 隐藏View*/
+            if (state == 2){
+                animIsEnd = true
+                super.dismiss()
+            }
+
+            /**动画开始执行 还原标记*/
+            if (state == 3){
+                animIsEnd = false
+            }
+
+            /**当返回true时 代表拦截当前动画 不再往下执行*/
+            return@animSequentialStart false
+        })
+    }
+
+}

+ 70 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/PopWindowCompatible.kt

@@ -0,0 +1,70 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.app.Activity
+import android.graphics.Rect
+import android.os.Build
+import android.util.DisplayMetrics
+import android.view.View
+import android.view.ViewGroup
+import android.widget.PopupWindow
+import com.wdkl.ncs.android.lib.core.runtime.JavaShopActivityTask
+import com.wdkl.ncs.android.lib.utils.errorLog
+
+/**
+ * @author LDD
+ * @Date   2018/4/10 下午6:02
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   兼容android7.0以上
+ */
+open class PopWindowCompatible : PopupWindow {
+
+
+    constructor(width: Int, height: Int) : super(width, height)
+
+
+    override fun showAsDropDown(anchor: View, xoff: Int, yoff: Int) {
+        if (Build.VERSION.SDK_INT >= 24) {
+            val rect = Rect()
+            anchor.getGlobalVisibleRect(rect)
+            val realdis = DisplayMetrics()
+            if(isNavigationBarExist(anchor.context as Activity)){
+                JavaShopActivityTask.instance.peekTopActivity()!!.windowManager.defaultDisplay.getMetrics(realdis)
+            }else{
+                JavaShopActivityTask.instance.peekTopActivity()!!.windowManager.defaultDisplay.getRealMetrics(realdis)
+            }
+            val h = realdis.heightPixels - rect.bottom
+            height = h
+        }
+        super.showAsDropDown(anchor, xoff, yoff)
+    }
+
+    override fun showAsDropDown(anchor: View) {
+        if (Build.VERSION.SDK_INT >= 24) {
+            val rect = Rect()
+            anchor.getGlobalVisibleRect(rect)
+            var realdis  = DisplayMetrics()
+            if(isNavigationBarExist(anchor.context as Activity)){
+                JavaShopActivityTask.instance.peekTopActivity()!!.windowManager.defaultDisplay.getMetrics(realdis)
+            }else{
+                JavaShopActivityTask.instance.peekTopActivity()!!.windowManager.defaultDisplay.getRealMetrics(realdis)
+            }
+            val h = realdis.heightPixels - rect.bottom
+            height = h
+        }
+        super.showAsDropDown(anchor)
+    }
+
+
+    private val NAVIGATION = "navigationBarBackground"
+
+    fun isNavigationBarExist(activity: Activity): Boolean {
+        val vp = activity.window.decorView as ViewGroup
+            for (i in 0 until vp.childCount) {
+                vp.getChildAt(i).context.packageName
+                if (vp.getChildAt(i).id != -1 && NAVIGATION == activity.resources.getResourceEntryName(vp.getChildAt(i).id)) {
+                    return true
+                }
+            }
+        return false
+    }
+}

+ 304 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/SaleProgressView.kt

@@ -0,0 +1,304 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.content.Context
+import android.graphics.*
+import android.util.AttributeSet
+import android.view.View
+import com.wdkl.ncs.android.lib.R
+import java.text.DecimalFormat
+import android.R.attr.bitmap
+import android.opengl.ETC1.getHeight
+import android.opengl.ETC1.getWidth
+
+
+
+
+
+/**
+ * @author LDD
+ * @Date   2018/5/18 上午10:48
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   促销进度视图
+ */
+class SaleProgressView :View {
+
+    //商品总数
+    private var totalCount: Int = 0
+    //当前卖出数
+    private var currentCount: Int = 0
+    //动画需要的
+    private var progressCount: Int = 0
+    //售出比例
+    private var scale: Float = 0.toFloat()
+    //边框颜色
+    private var sideColor: Int = 0
+    //文字颜色
+    private var textColor: Int = 0
+    //边框粗细
+    private var sideWidth: Float = 0.toFloat()
+    //边框所在的矩形
+    private lateinit var sidePaint: Paint
+    //背景矩形
+    private var bgRectF: RectF? = null
+    private var radius: Float = 0.toFloat()
+    private var mWidth: Int = 0
+    private var mHeight: Int = 0
+    private var mPorterDuffXfermode: PorterDuffXfermode? = null
+    private lateinit var srcPaint: Paint
+    private var fgSrc: Bitmap? = null
+    private var bgSrc: Bitmap? = null
+    private var textHeader: String? = null
+    private var nearOverText: String? = null
+    private var overText: String? = null
+    private var textSize: Float = 0.toFloat()
+    private lateinit var textPaint: Paint
+    private var nearOverTextWidth: Float = 0.toFloat()
+    private var overTextWidth: Float = 0.toFloat()
+    private var baseLineY: Float = 0.toFloat()
+    private var bgBitmap: Bitmap? = null
+    private var isNeedAnim: Boolean = false
+    private var onlyColor: String? = null
+
+    constructor(context: Context) : this(context,null)
+    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs,0)
+    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
+        initAttrs(context,attrs)
+        initPaint()
+    }
+
+    private fun initAttrs(context: Context, attrs: AttributeSet?) {
+        val ta = context.obtainStyledAttributes(attrs, R.styleable.SaleProgressView)
+        sideColor = ta.getColor(R.styleable.SaleProgressView_sideColor, -0xc3ce)
+        textColor = ta.getColor(R.styleable.SaleProgressView_textColor, -0xc3ce)
+        sideWidth = ta.getDimension(R.styleable.SaleProgressView_sideWidth, dp2px(2f))
+        overText = ta.getString(R.styleable.SaleProgressView_overText)
+        textHeader = ta.getString(R.styleable.SaleProgressView_textHeader)
+        nearOverText = ta.getString(R.styleable.SaleProgressView_nearOverText)
+        textSize = ta.getDimension(R.styleable.SaleProgressView_textSize, sp2px(10f))
+        isNeedAnim = ta.getBoolean(R.styleable.SaleProgressView_isNeedAnim, true)
+        onlyColor = ta.getString(R.styleable.SaleProgressView_onlyColor)
+        ta.recycle()
+    }
+
+    private fun initPaint() {
+        sidePaint = Paint(Paint.ANTI_ALIAS_FLAG)
+        sidePaint.style = Paint.Style.STROKE
+        sidePaint.strokeWidth = sideWidth
+        sidePaint.color = sideColor
+        srcPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+        textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+        srcPaint.isAntiAlias = true
+        textPaint.style = Paint.Style.FILL
+        textPaint.textSize = textSize
+        mPorterDuffXfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
+        nearOverTextWidth = textPaint.measureText(nearOverText)
+        overTextWidth = textPaint.measureText(overText)
+    }
+
+    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+        super.onSizeChanged(w, h, oldw, oldh)
+
+        //获取View的宽高
+        mWidth = measuredWidth
+        mHeight = measuredHeight
+
+        //圆角半径
+        radius = mHeight / 2.0f
+
+        //留出一定的间隙,避免边框被切掉一部分
+        if (bgRectF == null) {
+            bgRectF = RectF(sideWidth, sideWidth, mWidth - sideWidth, mHeight - sideWidth)
+        }
+
+        if (baseLineY == 0.0f) {
+            val fm = textPaint.fontMetricsInt
+            baseLineY = (mHeight / 2 - (fm!!.descent / 2 + fm.ascent / 2)).toFloat()
+        }
+
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        super.onDraw(canvas)
+
+        if (!isNeedAnim) {
+            progressCount = currentCount
+        }
+
+        scale = if (totalCount == 0) {
+            0.0f
+        } else {
+            DecimalFormat("0.00").format(progressCount.toFloat() / totalCount.toFloat()).toFloat()
+        }
+
+        drawSide(canvas)
+        drawBg(canvas)
+        drawFg(canvas)
+        drawText(canvas)
+
+        //这里是为了演示动画方便,实际开发中进度只会增加
+        if (progressCount != currentCount) {
+            if (progressCount < currentCount) {
+                progressCount++
+            } else {
+                progressCount--
+            }
+            postInvalidate()
+        }
+
+    }
+
+    //绘制背景边框
+    private fun drawSide(canvas: Canvas) {
+        canvas.drawRoundRect(bgRectF, radius, radius, sidePaint)
+    }
+
+    //绘制背景
+    private fun drawBg(canvas: Canvas) {
+        if (bgBitmap == null) {
+            bgBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888)
+        }
+        val bgCanvas = Canvas(bgBitmap)
+        if (bgSrc == null) {
+            if (onlyColor != null) {
+                bgSrc = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
+                bgSrc?.eraseColor(Color.WHITE)
+            } else {
+                bgSrc = BitmapFactory.decodeResource(resources, R.drawable.sale_progress_view_bg)
+            }
+        }
+        bgCanvas.drawRoundRect(bgRectF, radius, radius, srcPaint)
+
+        srcPaint.xfermode = mPorterDuffXfermode
+
+        bgCanvas.drawBitmap(bgSrc, null, bgRectF, srcPaint)
+
+        canvas.drawBitmap(bgBitmap, 0f, 0f, null)
+
+        srcPaint.xfermode = null
+    }
+
+    //绘制进度条
+    private fun drawFg(canvas: Canvas) {
+        if (scale == 0.0f) {
+            return
+        }
+        val fgBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888)
+        val fgCanvas = Canvas(fgBitmap)
+        if (fgSrc == null) {
+            if (onlyColor != null) {
+                fgSrc = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888)
+                val color = Color.parseColor(onlyColor)
+                fgSrc?.eraseColor(color)
+                fgSrc = toRound(fgSrc!!)
+            } else {
+                fgSrc = BitmapFactory.decodeResource(resources, R.drawable.sale_progress_view_fg)
+            }
+        }
+
+        fgCanvas.drawRoundRect(
+                RectF(sideWidth, sideWidth, (mWidth - sideWidth) * scale, mHeight - sideWidth),
+                radius, radius, srcPaint)
+
+        srcPaint.xfermode = mPorterDuffXfermode
+        fgCanvas.drawBitmap(fgSrc, null, bgRectF, srcPaint)
+
+        canvas.drawBitmap(fgBitmap, 0f, 0f, null)
+        srcPaint.xfermode = null
+    }
+
+    //绘制文字信息
+    private fun drawText(canvas: Canvas) {
+        val scaleText = DecimalFormat("#%").format(scale)
+
+        val saleText = if (textHeader != null) {
+            textHeader + String.format("%s件", progressCount)
+        } else {
+            String.format("已抢%s件", progressCount)
+        }
+
+        val scaleTextWidth = textPaint.measureText(scaleText)
+
+        val textBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888)
+        val textCanvas = Canvas(textBitmap)
+        if (onlyColor != null) {
+            textPaint.color = Color.TRANSPARENT
+        } else {
+            textPaint.color = textColor
+        }
+
+        textPaint.textSize = (mHeight*0.6).toFloat()
+
+        if (scale < 0.8f) {
+            textCanvas.drawText(saleText, dp2px(10f), baseLineY, textPaint)
+            textCanvas.drawText(scaleText, mWidth - scaleTextWidth - dp2px(10f), baseLineY, textPaint)
+        } else if (scale < 1.0f) {
+            textCanvas.drawText(nearOverText, mWidth / 2 - nearOverTextWidth / 2, baseLineY, textPaint)
+            textCanvas.drawText(scaleText, mWidth - scaleTextWidth - dp2px(10f), baseLineY, textPaint)
+        } else {
+            textCanvas.drawText(overText, mWidth / 2 - overTextWidth / 2, baseLineY, textPaint)
+        }
+
+        textPaint.xfermode = mPorterDuffXfermode
+        if (onlyColor != null) {
+            textPaint.color = Color.TRANSPARENT
+        } else {
+            textPaint.color = Color.WHITE
+        }
+        if (onlyColor != null) {
+            textCanvas.drawRoundRect(
+                    RectF(sideWidth - 1, sideWidth, (mWidth - sideWidth) * scale + 1, mHeight - sideWidth),
+                    radius, radius, textPaint)
+        } else {
+            textCanvas.drawRoundRect(
+                    RectF(sideWidth, sideWidth, (mWidth - sideWidth) * scale, mHeight - sideWidth),
+                    radius, radius, textPaint)
+        }
+        canvas.drawBitmap(textBitmap, 0f, 0f, null)
+        textPaint.xfermode = null
+    }
+
+    private fun dp2px(dpValue: Float): Float {
+        val scale = context.resources.displayMetrics.density
+        return (dpValue * scale + 0.5f)
+    }
+
+    private fun sp2px(spValue: Float): Float {
+        val scale = context.resources.displayMetrics.scaledDensity
+        return (spValue * scale + 0.5f)
+    }
+
+    private fun toRound(bitmap: Bitmap):Bitmap{
+        val output = Bitmap.createBitmap(bitmap.width,
+                bitmap.height, Bitmap.Config.ARGB_8888)
+        val canvas = Canvas(output)
+
+        val color = -0xbdbdbe
+        val paint = Paint()
+        val rect = Rect(0, 0, bitmap.width, bitmap.height)
+        val rectF = RectF(rect)
+        val roundPx = bitmap.height/2f - sideWidth
+
+        paint.isAntiAlias = true
+        canvas.drawARGB(0, 0, 0, 0)
+        paint.color = color
+        canvas.drawRoundRect(rectF, roundPx, roundPx, paint)
+
+        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
+        canvas.drawBitmap(bitmap, rect, rect, paint)
+
+        return output
+    }
+
+    fun setTotalAndCurrentCount(totalCount: Int, currentCount: Int) {
+        this.totalCount = totalCount
+
+        if (currentCount > totalCount) {
+            this.currentCount = totalCount
+        }else{
+            this.currentCount = currentCount
+        }
+
+        postInvalidate()
+    }
+
+}

+ 207 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/StarView.kt

@@ -0,0 +1,207 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.content.Context
+import android.graphics.*
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import com.wdkl.ncs.android.lib.R
+import com.wdkl.ncs.android.lib.base.BaseControl
+import com.wdkl.ncs.android.lib.base.LIFE_CYCLE_DESTORY
+import com.wdkl.ncs.android.lib.utils.then
+import com.wdkl.ncs.android.lib.utils.to
+
+
+/**
+ * @author LDD
+ * @Date   2018/3/28 下午3:59
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   心形等级自定义View
+ */
+class StarView :View{
+
+    private var star = 0
+
+    private var nomalBitmap :Bitmap
+
+    private var starEvent :((Int) ->Unit)? = null
+
+    private var selectedBitmap :Bitmap
+
+    private val paint by lazy {
+        return@lazy Paint().then {
+            self ->
+            self.isAntiAlias = true
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   StarView
+     * @Date   2018/3/28 下午4:00
+     * @Note   星级自定义View构造方法
+     */
+    constructor(context: Context?) : this(context,null)
+    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs,0)
+    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
+        val typeArray = context?.obtainStyledAttributes(attrs, R.styleable.StarView)
+        star = typeArray?.getInt(R.styleable.StarView_star,5) ?: 5
+
+        if (typeArray?.hasValue(R.styleable.StarView_selectImage)!!){
+            selectedBitmap = drawableToBitmap(typeArray.getDrawable(R.styleable.StarView_selectImage))
+        }else{
+            selectedBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.javashop_icon_star_selected)
+        }
+        if (typeArray.hasValue(R.styleable.StarView_nomalImage)){
+            nomalBitmap = drawableToBitmap(typeArray.getDrawable(R.styleable.StarView_nomalImage))
+        }else{
+            nomalBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.javashop_icon_star_nomal)
+        }
+
+        if(context is BaseControl){
+            context.addLifeCycleListener { 
+                state ->
+                if (state == LIFE_CYCLE_DESTORY){
+                    selectedBitmap.recycle()
+                    nomalBitmap.recycle()
+                }
+            }
+        }
+    }
+
+    /**
+     * @author LDD
+     * @From   StarView
+     * @Date   2018/5/18 上午10:27
+     * @Note   设置星级
+     * @param  star 星级
+     */
+    fun setStar(star :Int){
+        this.star = star
+        invalidate()
+    }
+
+    /**
+     * @author LDD
+     * @From   StarView
+     * @Date   2018/5/18 上午10:27
+     * @Note   设置星级变化监听
+     * @param  event 回调
+     */
+    fun setStarEvent(event :(Int) ->Unit){
+        starEvent = event
+    }
+
+    /**
+     * @author LDD
+     * @From   StarView
+     * @Date   2018/5/18 上午10:28
+     * @Note   重写绘制
+     * @param  canvas 画板
+     */
+    override fun onDraw(canvas: Canvas?) {
+        var imageWidth = width/7
+        var space = imageWidth/2
+        if (imageWidth > height){
+            imageWidth = height
+            space = (width -(height*5))/4
+        }
+        nomalBitmap = setImgSize(nomalBitmap,imageWidth,imageWidth)
+        selectedBitmap = setImgSize(selectedBitmap,imageWidth,imageWidth)
+
+        var left = 0
+
+        for (i in 0..4){
+            if (i >= star){
+                canvas?.drawBitmap(nomalBitmap, left.toFloat(), 0f, paint)
+            }else{
+                canvas?.drawBitmap(selectedBitmap, left.toFloat(), 0f, paint)
+            }
+            left += imageWidth+space
+        }
+
+        paint.reset()
+    }
+
+
+    /**
+     * @author LDD
+     * @From   StarView
+     * @Date   2018/5/18 上午10:28
+     * @Note   在此做滑动操作
+     */
+    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
+
+        if (starEvent == null){
+            return false
+        }
+
+        val x = event.x
+
+        var width = width/7 + width/7/2
+
+        val newStar = if (x < width/3){
+            0
+        }else{
+            (x / width).toInt()+1
+        }
+        if (star != newStar){
+            star = newStar
+            invalidate()
+            starEvent?.invoke(star)
+        }
+        return true
+    }
+
+    /**
+     * @author LDD
+     * @From   StarView
+     * @Date   2018/5/18 上午10:28
+     * @Note   drawable转化Bitmap
+     * @param  drawable drawable资源
+     */
+    fun drawableToBitmap(drawable: Drawable): Bitmap {
+        // 取 drawable 的长宽
+        val w = drawable.intrinsicWidth
+        val h = drawable.intrinsicHeight
+
+        // 取 drawable 的颜色格式
+        val config = if (drawable.opacity != PixelFormat.OPAQUE)
+            Bitmap.Config.ARGB_8888
+        else
+            Bitmap.Config.RGB_565
+        // 建立对应 bitmap
+        val bitmap = Bitmap.createBitmap(w, h, config)
+        // 建立对应 bitmap 的画布
+        val canvas = Canvas(bitmap)
+        drawable.setBounds(0, 0, w, h)
+        // 把 drawable 内容画到画布中
+        drawable.draw(canvas)
+        return bitmap
+    }
+
+    /**
+     * @author LDD
+     * @From   StarView
+     * @Date   2018/5/18 上午10:29
+     * @Note   重新设置Image大小
+     * @param  bm  图片
+     * @param  newHeight 新的高度
+     * @param  newWidth 新的宽度
+     */
+    fun setImgSize(bm: Bitmap, newWidth: Int, newHeight: Int): Bitmap {
+        // 获得图片的宽高.
+        val width = bm.width
+        val height = bm.height
+        // 计算缩放比例.
+        val scaleWidth = newWidth.toFloat() / width
+        val scaleHeight = newHeight.toFloat() / height
+        // 取得想要缩放的matrix参数.
+        val matrix = Matrix()
+        matrix.postScale(scaleWidth, scaleHeight)
+        // 得到新的图片.
+        return Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true)
+    }
+}

+ 110 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/VcodeDialog.kt

@@ -0,0 +1,110 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.app.Dialog
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.EditText
+import android.widget.ImageView
+import com.wdkl.ncs.android.lib.R
+import com.wdkl.ncs.android.lib.utils.reLayout
+import com.wdkl.ncs.android.lib.utils.showMessage
+import com.enation.javashop.utils.base.tool.ScreenTool
+
+/**
+ * @author LDD
+ * @Date   2018/5/10 下午5:10
+ * @From   com.wdkl.ncs.android.lib.widget
+ * @Note   验证码对话框
+ */
+class VcodeDialog  {
+
+    /**
+     * @Name  context
+     * @Type  Context
+     * @Note  上下文
+     */
+    private val context :Context
+
+    /**
+     * @author LDD
+     * @Date   2018/5/10 下午5:13
+     * @From   VcodeDialog
+     * @Note   伴生对象
+     */
+    companion object {
+
+        /**
+         * @author LDD
+         * @From   VcodeDialog
+         * @Date   2018/5/10 下午5:13
+         * @Note   静态构建
+         * @param  context 上下文
+         */
+        fun build(context: Context):VcodeDialog{
+            return VcodeDialog(context)
+        }
+
+    }
+    
+    /**
+     * @author LDD
+     * @From   VcodeDialog
+     * @Date   2018/5/10 下午5:12
+     * @Note   构造
+     * @param  context 上下文
+     */
+    private constructor(context: Context) {
+        this.context = context
+    }
+
+    /**
+     * @author LDD
+     * @From   VcodeDialog
+     * @Date   2018/5/10 下午5:12
+     * @Note   构建
+     * @param  call 验证码回调
+     * @param  imageLoader 加载验证码回调
+     */
+    fun config(call :(String) ->Unit,imageLoader :(iv : ImageView) ->Unit ,cancleCall :(()->Unit)? = null) :Dialog{
+        val contentView = LayoutInflater.from(context).inflate(R.layout.vcode_dialog_lay, null)
+        val dialog = Dialog(context, R.style.Dialog)
+        dialog.setContentView(contentView)
+        contentView.reLayout<ViewGroup.LayoutParams> {
+            params ->
+            params.width = ScreenTool.getScreenWidth(context).toInt()
+            params.height = ScreenTool.getScreenHeight(context).toInt()
+        }
+        val yesTv = contentView.findViewById<View>(R.id.vcode_dialog_confrim)
+        val noTv = contentView.findViewById<View>(R.id.vcode_dialog_cancel)
+        val image = contentView.findViewById<ImageView>(R.id.vcode_dialog_iv)
+        val et = contentView.findViewById<EditText>(R.id.vcode_dialog_et)
+
+        imageLoader.invoke(image)
+
+        image.setOnClickListener {
+            imageLoader.invoke(image)
+        }
+
+        yesTv.setOnClickListener {
+            val text = et.text.toString().trim()
+            if (text == "") {
+                showMessage("请输入验证码!")
+                return@setOnClickListener
+            }
+            dialog.dismiss()
+            call.invoke(text)
+        }
+        noTv.setOnClickListener {
+            dialog.dismiss()
+            cancleCall?.invoke()
+        }
+        dialog.setCanceledOnTouchOutside(false)
+        dialog.setCancelable(false)
+        return dialog
+    }
+
+
+
+}

+ 399 - 0
common/src/main/code/com/wdkl/ncs/android/lib/widget/VerificationCodeView.kt

@@ -0,0 +1,399 @@
+package com.wdkl.ncs.android.lib.widget
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Paint.ANTI_ALIAS_FLAG
+import android.graphics.drawable.Drawable
+import android.support.v4.content.ContextCompat
+import android.support.v7.widget.AppCompatTextView
+import android.text.Editable
+import android.text.InputFilter
+import android.text.TextUtils
+import android.text.TextWatcher
+import android.util.AttributeSet
+import android.util.TypedValue
+import android.view.Gravity
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.RelativeLayout
+import com.wdkl.ncs.android.lib.R
+import com.enation.javashop.utils.base.tool.ScreenTool
+
+
+/**
+ * Created by LDD on 2018/5/9.
+ */
+class VerificationCodeView :RelativeLayout {
+
+    private lateinit var containerEt: LinearLayout
+
+    private lateinit var et: EditText
+    // 输入框数量
+    private var mEtNumber: Int = 0
+    // 输入框的宽度
+    private var mEtWidth: Int = 0
+    //输入框分割线
+    private var mEtDividerDrawable: Drawable? = null
+    //输入框文字颜色
+    private var mEtTextColor: Int = 0
+    //输入框文字大小
+    private var mEtTextSize: Float = 0.toFloat()
+    //输入框获取焦点时背景
+    private var mEtBackgroundDrawableFocus: Drawable? = null
+    //输入框没有焦点时背景
+    private var mEtBackgroundDrawableNormal: Drawable? = null
+    //是否是密码模式
+    private var mEtPwd: Boolean = false
+    //密码模式时圆的半径
+    private var mEtPwdRadius: Float = 0.toFloat()
+
+    private var heightPercent :Float = -1f
+
+    //存储TextView的数据 数量由自定义控件的属性传入
+    private lateinit var mPwdTextViews: Array<PwdTextView>
+
+    private val myTextWatcher = MyTextWatcher()
+
+
+    constructor(context: Context) : this(context,null)
+    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs,0)
+    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
+        init(context, attrs, defStyleAttr)
+    }
+
+
+
+    //初始化 布局和属性
+    private fun init(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {
+        LayoutInflater.from(context).inflate(R.layout.layout_identifying_code, this)
+        containerEt = this.findViewById(R.id.container_et) as LinearLayout
+        et = this.findViewById(R.id.et) as EditText
+
+        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView, defStyleAttr, 0)
+        mEtNumber = typedArray.getInteger(R.styleable.VerificationCodeView_vcode_number, 1)
+        mEtWidth = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_vcode_width, -1)
+        mEtDividerDrawable = typedArray.getDrawable(R.styleable.VerificationCodeView_vcode_divider_drawable)
+        mEtTextSize = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_vcode_text_size, -1).toFloat()
+        mEtTextColor = typedArray.getColor(R.styleable.VerificationCodeView_vcode_text_color, Color.BLACK)
+        mEtBackgroundDrawableFocus = typedArray.getDrawable(R.styleable.VerificationCodeView_vcode_bg_focus)
+        mEtBackgroundDrawableNormal = typedArray.getDrawable(R.styleable.VerificationCodeView_vcode_bg_normal)
+        mEtPwd = typedArray.getBoolean(R.styleable.VerificationCodeView_vcode_pwd, false)
+        mEtPwdRadius = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_vcode_pwd_radius, 0).toFloat()
+        heightPercent = typedArray.getFloat(R.styleable.VerificationCodeView_vcode_height_percent,-1f)
+        //释放资源
+        typedArray.recycle()
+
+
+        // 当xml中未配置时 这里进行初始配置默认图片
+        if (mEtDividerDrawable == null) {
+            mEtDividerDrawable = ContextCompat.getDrawable(context,R.drawable.shape_divider_identifying)
+        }
+
+        if (mEtBackgroundDrawableFocus == null) {
+            mEtBackgroundDrawableFocus =ContextCompat.getDrawable(context,R.drawable.shape_icv_et_bg_focus)
+        }
+
+        if (mEtBackgroundDrawableNormal == null) {
+            mEtBackgroundDrawableNormal =ContextCompat.getDrawable(context,R.drawable.shape_icv_et_bg_normal)
+        }
+
+        initUI()
+    }
+
+    // 初始UI
+    private fun initUI() {
+        initTextViews(context, mEtNumber, mEtWidth, mEtDividerDrawable, mEtTextSize, mEtTextColor)
+        initEtContainer(mPwdTextViews)
+        setListener()
+    }
+
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        // 设置当 高为 warpContent 模式时的默认值 为 50dp
+        var mHeightMeasureSpec = heightMeasureSpec
+
+        val heightMode = View.MeasureSpec.getMode(mHeightMeasureSpec)
+        if (heightMode == View.MeasureSpec.AT_MOST) {
+            mHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(dp2px(50f, context).toInt(), View.MeasureSpec.EXACTLY)
+        }
+
+        super.onMeasure(widthMeasureSpec, mHeightMeasureSpec)
+    }
+
+
+    //初始化TextView
+    private fun initTextViews(context: Context, etNumber: Int, etWidth: Int, etDividerDrawable: Drawable?, etTextSize: Float, etTextColor: Int) {
+        // 设置 editText 的输入长度
+        et.isCursorVisible = false//将光标隐藏
+        et.filters = arrayOf<InputFilter>(InputFilter.LengthFilter(etNumber)) //最大输入长度
+        // 设置分割线的宽度
+        if (etDividerDrawable != null) {
+            etDividerDrawable.setBounds(0, 0, etDividerDrawable.minimumWidth, etDividerDrawable.minimumHeight)
+            containerEt.dividerDrawable = etDividerDrawable
+        }
+
+        mPwdTextViews = Array(etNumber,{PwdTextView(context)})
+
+        for (i in mPwdTextViews.indices) {
+            val textView = PwdTextView(context)
+            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, if (etTextSize == -1f){
+                ((ScreenTool.getScreenHeight(context)*heightPercent)*0.7).toFloat()
+            }else{etTextSize})
+            textView.setTextColor(etTextColor)
+            textView.width = if (etWidth == -1){
+                (ScreenTool.getScreenHeight(context)*heightPercent).toInt()
+            }else{
+                etWidth
+            }
+            textView.height =  if (etWidth == -1){
+                (ScreenTool.getScreenHeight(context)*heightPercent).toInt()
+            }else{
+                etWidth
+            }
+            if (i == 0) {
+                textView.background = mEtBackgroundDrawableFocus
+            } else {
+                textView.background = mEtBackgroundDrawableNormal
+            }
+            textView.gravity = Gravity.CENTER
+
+            textView.isFocusable = false
+
+            mPwdTextViews[i] = textView
+        }
+    }
+
+    //初始化存储TextView 的容器
+    private fun initEtContainer(mTextViews: Array<PwdTextView>) {
+        for (mTextView in mTextViews) {
+            containerEt.addView(mTextView)
+        }
+    }
+
+
+    private fun setListener() {
+        // 监听输入内容
+        et.addTextChangedListener(myTextWatcher)
+
+        // 监听删除按键
+        et.setOnKeyListener(OnKeyListener { _, keyCode, event ->
+            if (keyCode == KeyEvent.KEYCODE_DEL && event.action == KeyEvent.ACTION_DOWN) {
+                onKeyDelete()
+                return@OnKeyListener true
+            }
+            false
+        })
+    }
+
+
+    // 给TextView 设置文字
+    private fun setText(inputContent: String) {
+
+        for (i in mPwdTextViews.indices) {
+            val tv = mPwdTextViews[i]
+            if (tv.text.toString().trim() == "") {
+                if (mEtPwd) {
+                    tv.drawPwd(mEtPwdRadius)
+                }
+                tv.text = inputContent
+                // 添加输入完成的监听
+                if (inputCompleteListener != null && i == mPwdTextViews.size-1) {
+                    inputCompleteListener!!.inputComplete()
+                }
+                tv.background = mEtBackgroundDrawableNormal
+                if (i < mEtNumber - 1) {
+                    mPwdTextViews[i + 1].background = mEtBackgroundDrawableFocus
+                }
+                break
+            }
+        }
+    }
+
+    // 监听删除
+    private fun onKeyDelete() {
+        for (i in mPwdTextViews.indices.reversed()) {
+            val tv = mPwdTextViews[i]
+            if (tv.text.toString().trim() != "") {
+                if (mEtPwd) {
+                    tv.clearPwd()
+                }
+                tv.text = ""
+                // 添加删除完成监听
+                if (inputCompleteListener != null) {
+                    inputCompleteListener!!.deleteContent()
+                }
+                tv.background = mEtBackgroundDrawableFocus
+                if (i < mEtNumber - 1) {
+                    mPwdTextViews[i + 1].background = mEtBackgroundDrawableNormal
+                }
+                break
+            }
+        }
+    }
+
+
+    /**
+     * 获取输入文本
+     *
+     * @return string
+     */
+    fun getInputContent(): String {
+        val buffer = StringBuffer()
+        for (tv in mPwdTextViews) {
+            buffer.append(tv.text.toString().trim())
+        }
+        return buffer.toString()
+    }
+
+    /**
+     * 删除输入内容
+     */
+    fun clearInputContent() {
+        for (i in mPwdTextViews.indices) {
+            if (i == 0) {
+                mPwdTextViews[i].background = mEtBackgroundDrawableFocus
+            } else {
+                mPwdTextViews[i].background = mEtBackgroundDrawableNormal
+            }
+            if (mEtPwd) {
+                mPwdTextViews[i].clearPwd()
+            }
+            mPwdTextViews[i].text = ""
+        }
+    }
+
+    /**
+     * 设置输入框个数
+     *
+     * @param etNumber
+     */
+    fun setEtNumber(etNumber: Int) {
+        this.mEtNumber = etNumber
+        et.removeTextChangedListener(myTextWatcher)
+        containerEt.removeAllViews()
+        initUI()
+    }
+
+
+    /**
+     * 获取输入的位数
+     *
+     * @return int
+     */
+    fun getEtNumber(): Int {
+        return mEtNumber
+    }
+
+
+    /**
+     * 设置是否是密码模式 默认不是
+     *
+     * @param isPwdMode
+     */
+    fun setPwdMode(isPwdMode: Boolean) {
+        this.mEtPwd = isPwdMode
+    }
+
+
+    /**
+     * 获取输入的EditText 用于外界设置键盘弹出
+     *
+     * @return
+     */
+    fun getEditText(): EditText? {
+        return et
+    }
+
+    // 输入完成 和 删除成功 的监听
+    private var inputCompleteListener: InputCompleteListener? = null
+
+    fun setInputCompleteListener(inputCompleteListener: InputCompleteListener) {
+        this.inputCompleteListener = inputCompleteListener
+    }
+
+
+    interface InputCompleteListener {
+        fun inputComplete()
+
+        fun deleteContent()
+    }
+
+
+    fun dp2px(dpValue: Float, context: Context): Float {
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                dpValue, context.resources.displayMetrics)
+    }
+
+    fun sp2px(spValue: Float, context: Context): Float {
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
+                spValue, context.resources.displayMetrics)
+    }
+
+
+    private inner class MyTextWatcher : TextWatcher {
+
+        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+
+        }
+
+        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+
+        }
+
+        override fun afterTextChanged(editable: Editable) {
+            val inputStr = editable.toString()
+            if (!TextUtils.isEmpty(inputStr)) {
+                setText(inputStr)
+                et!!.setText("")
+            }
+        }
+    }
+
+    private inner class PwdTextView : AppCompatTextView {
+
+        private var radius: Float = 0.toFloat()
+
+        private var hasPwd: Boolean = false
+
+        constructor(context: Context) : this(context,null)
+        constructor(context: Context, attrs: AttributeSet?) : this(context, attrs,0)
+        constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
+
+
+        override fun onDraw(canvas: Canvas) {
+            super.onDraw(canvas)
+
+            if (hasPwd) {
+                // 画一个黑色的圆
+                val paint = Paint(ANTI_ALIAS_FLAG)
+                paint.color = Color.BLACK
+                paint.style = Paint.Style.FILL
+                canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), radius, paint)
+            }
+        }
+
+
+        fun clearPwd() {
+            this.hasPwd = false
+            invalidate()
+        }
+
+
+        fun drawPwd(radius: Float) {
+            this.hasPwd = true
+            if (radius == 0f) {
+                this.radius = (width / 4).toFloat()
+            } else {
+                this.radius = radius
+            }
+            invalidate()
+        }
+
+
+    }
+}

+ 9 - 0
common/src/main/res/drawable/icon_cancle_gray.xml

@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="1024.0"
+        android:viewportHeight="1024.0">
+    <path
+        android:pathData="M579.9,512l190.1,-190.1a48,48 0,0 0,-67.9 -67.9L512,444.1 321.9,254.1a48,48 0,1 0,-67.9 67.9L444.1,512 254.1,702.1a48,48 0,1 0,67.9 67.9L512,579.9l190.1,190.1a48,48 0,0 0,67.9 -67.9L579.9,512z"
+        android:fillColor="#aaaaaa"/>
+</vector>

二進制
common/src/main/res/drawable/javashop_icon_star_nomal.png


二進制
common/src/main/res/drawable/javashop_icon_star_selected.png


二進制
common/src/main/res/drawable/sale_progress_view_bg.png


二進制
common/src/main/res/drawable/sale_progress_view_fg.png


+ 8 - 0
common/src/main/res/drawable/shape_divider_identifying.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <size
+        android:width="6dp"
+        android:height="6dp" />
+    <solid android:color="#00000000" />
+</shape>

+ 14 - 0
common/src/main/res/drawable/shape_icv_et_bg_focus.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#F2F2F2" />
+    <!-- 大小 -->
+    <size
+        android:width="25dp"
+        android:height="25dp" /><!-- 宽度和高度 -->
+    <corners android:radius="2dp" />
+
+    <stroke
+        android:width="1px"
+        android:color="#000000" />
+</shape>

+ 14 - 0
common/src/main/res/drawable/shape_icv_et_bg_normal.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#F2F2F2" />
+    <!-- 大小 -->
+    <size
+        android:width="25dp"
+        android:height="25dp" /><!-- 宽度和高度 -->
+    <corners android:radius="2dp" />
+
+    <stroke
+        android:width="1px"
+        android:color="#ccc" />
+</shape>

+ 0 - 0
common/src/main/res/layout/auto_size_tv.xml


部分文件因文件數量過多而無法顯示