Ver código fonte

添加了kfzslibrary,新的开发框架,用于后续开发

guoxin 8 anos atrás
pai
commit
6f4ac2c6ea
100 arquivos alterados com 7086 adições e 0 exclusões
  1. 64 0
      build.gradle
  2. 1 0
      kfzslibrary/.gitignore
  3. 58 0
      kfzslibrary/build.gradle
  4. 21 0
      kfzslibrary/proguard-rules.pro
  5. 26 0
      kfzslibrary/src/androidTest/java/com/kfzs/libs/ExampleInstrumentedTest.java
  6. 5 0
      kfzslibrary/src/main/AndroidManifest.xml
  7. 51 0
      kfzslibrary/src/main/java/com/kfzs/libs/DaggerActivity.java
  8. 57 0
      kfzslibrary/src/main/java/com/kfzs/libs/DaggerFragment.java
  9. 13 0
      kfzslibrary/src/main/java/com/kfzs/libs/IDaggerMvp.java
  10. 12 0
      kfzslibrary/src/main/java/com/kfzs/libs/IPresenter.java
  11. 10 0
      kfzslibrary/src/main/java/com/kfzs/libs/IView.java
  12. 13 0
      kfzslibrary/src/main/java/com/kfzs/libs/aop/Path.java
  13. 15 0
      kfzslibrary/src/main/java/com/kfzs/libs/aop/net/CheckNet.java
  14. 96 0
      kfzslibrary/src/main/java/com/kfzs/libs/aop/net/CheckNetAop.java
  15. 35 0
      kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/CheckPermission.java
  16. 116 0
      kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/CheckPermissionAop.java
  17. 48 0
      kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/core/Permission.java
  18. 26 0
      kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/core/PermissionHelper.java
  19. 270 0
      kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/core/RxPermissions.java
  20. 103 0
      kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/core/RxPermissionsFragment.java
  21. 17 0
      kfzslibrary/src/main/java/com/kfzs/libs/convert/StringConverter.java
  22. 28 0
      kfzslibrary/src/main/java/com/kfzs/libs/convert/StringConverterFactory.java
  23. 15 0
      kfzslibrary/src/main/java/com/kfzs/libs/di/http/HttpComponent.java
  24. 60 0
      kfzslibrary/src/main/java/com/kfzs/libs/di/http/HttpModule.java
  25. 14 0
      kfzslibrary/src/main/java/com/kfzs/libs/di/http/HttpScope.java
  26. 16 0
      kfzslibrary/src/main/java/com/kfzs/libs/di/http/HttpService.java
  27. 93 0
      kfzslibrary/src/main/java/com/kfzs/libs/dialog/BaseDialogFragment.java
  28. 37 0
      kfzslibrary/src/main/java/com/kfzs/libs/utils/ContextUtils.java
  29. 231 0
      kfzslibrary/src/main/java/com/kfzs/libs/utils/DeviceHelper.java
  30. 326 0
      kfzslibrary/src/main/java/com/kfzs/libs/utils/DisplayHelper.java
  31. 125 0
      kfzslibrary/src/main/java/com/kfzs/libs/utils/DrawablesHelper.java
  32. 78 0
      kfzslibrary/src/main/java/com/kfzs/libs/utils/LangHelper.java
  33. 404 0
      kfzslibrary/src/main/java/com/kfzs/libs/utils/StatusBarHelper.java
  34. 63 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaButton.java
  35. 62 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaFrameLayout.java
  36. 60 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaImageButton.java
  37. 60 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaImageView.java
  38. 63 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaLinearLayout.java
  39. 63 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaRelativeLayout.java
  40. 62 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaTextView.java
  41. 67 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaViewHelper.java
  42. 37 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/grouplist/GroupItem.java
  43. 38 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/grouplist/GroupListHeaderView.java
  44. 293 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/grouplist/GroupListItemAccessoryView.java
  45. 210 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/grouplist/GroupListView.java
  46. 211 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/Loader.java
  47. 319 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/LoadingHelper.java
  48. 238 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/LoadingLayout.java
  49. 50 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/SupportLoadingFragment.java
  50. 49 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/TargetContext.java
  51. 127 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/viewport/ShowingViewport.java
  52. 29 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/viewport/SuccessViewport.java
  53. 23 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/navigation/Navigation.java
  54. 157 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/navigation/NavigationBar.java
  55. 263 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/navigation/TabBar.java
  56. 113 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/BaseHeaderWrapper.java
  57. 155 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/BaseLoadMoreWrapper.java
  58. 28 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/BaseRecyclerViewAdapter.java
  59. 92 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/DefaultLoadMoreWrapper.java
  60. 81 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/LoadMoreScrollListener.java
  61. 33 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/ViewHolder.java
  62. 45 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/WrapperUtils.java
  63. 211 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/decoration/RecyclerViewGridDivider.java
  64. 223 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/decoration/RecyclerViewLinearDivider.java
  65. 18 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/listener/OnRecyclerViewItemClickListener.java
  66. 150 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/toast/MessageSheetToastView.java
  67. 233 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/toast/ToastView.java
  68. 301 0
      kfzslibrary/src/main/java/com/kfzs/libs/widget/toast/TopToastView.java
  69. 9 0
      kfzslibrary/src/main/res/anim/bottom_sheet_enter.xml
  70. 9 0
      kfzslibrary/src/main/res/anim/bottom_sheet_exit.xml
  71. 8 0
      kfzslibrary/src/main/res/anim/fade_in.xml
  72. 8 0
      kfzslibrary/src/main/res/anim/fade_out.xml
  73. 8 0
      kfzslibrary/src/main/res/anim/toastview_dissmiss.xml
  74. 8 0
      kfzslibrary/src/main/res/anim/toastview_show.xml
  75. 9 0
      kfzslibrary/src/main/res/anim/top_sheet_enter.xml
  76. 9 0
      kfzslibrary/src/main/res/anim/top_sheet_exit.xml
  77. 5 0
      kfzslibrary/src/main/res/drawable-v21/s_item_bg_double_border.xml
  78. 5 0
      kfzslibrary/src/main/res/drawable-v21/s_list_item_bg_bottom_border.xml
  79. 5 0
      kfzslibrary/src/main/res/drawable-v21/s_list_item_bg_none_border.xml
  80. 5 0
      kfzslibrary/src/main/res/drawable/list_item_bg_bottom_border.xml
  81. 5 0
      kfzslibrary/src/main/res/drawable/list_item_bg_bottom_border_pressed.xml
  82. 8 0
      kfzslibrary/src/main/res/drawable/list_item_bg_double_border.xml
  83. 8 0
      kfzslibrary/src/main/res/drawable/list_item_bg_double_border_pressed.xml
  84. 5 0
      kfzslibrary/src/main/res/drawable/s_item_bg_double_border.xml
  85. 5 0
      kfzslibrary/src/main/res/drawable/s_list_item_bg_bottom_border.xml
  86. 5 0
      kfzslibrary/src/main/res/drawable/s_list_item_bg_none_border.xml
  87. 18 0
      kfzslibrary/src/main/res/layout/grouplist_arrow_item.xml
  88. 71 0
      kfzslibrary/src/main/res/layout/grouplist_item_view.xml
  89. 40 0
      kfzslibrary/src/main/res/layout/navigation_bar.xml
  90. 26 0
      kfzslibrary/src/main/res/layout/recyclerview_default_load_more.xml
  91. 15 0
      kfzslibrary/src/main/res/layout/toast_single_message.xml
  92. 22 0
      kfzslibrary/src/main/res/values/grouplist_values.xml
  93. 10 0
      kfzslibrary/src/main/res/values/navigationbar_values.xml
  94. 3 0
      kfzslibrary/src/main/res/values/strings.xml
  95. 27 0
      kfzslibrary/src/main/res/values/toast_values.xml
  96. 17 0
      kfzslibrary/src/test/java/com/kfzs/libs/ExampleUnitTest.java
  97. BIN
      repo/com/aop/plugin/aop-plugin/1.0.0/aop-plugin-1.0.0.jar
  98. 1 0
      repo/com/aop/plugin/aop-plugin/1.0.0/aop-plugin-1.0.0.jar.md5
  99. 1 0
      repo/com/aop/plugin/aop-plugin/1.0.0/aop-plugin-1.0.0.jar.sha1
  100. 0 0
      repo/com/aop/plugin/aop-plugin/1.0.0/aop-plugin-1.0.0.pom

+ 64 - 0
build.gradle

@@ -30,3 +30,67 @@ allprojects {
 task clean(type: Delete) {
     delete rootProject.buildDir
 }
+
+
+ext{
+    android = [
+            compileSdkVersion:27,
+            minSdkVersion:15,
+            targetSdkVersion:27,
+            buildToolsVersion:'27.0.2',
+            /**
+             * app-module
+             */
+            versionCode_app:1,
+            versionName_app:"1.0",
+            /**
+             * kfzslibrary-module
+             */
+            versionCode_kfzslibrary:1,
+            versionName_kfzslibrary:"1.0",
+
+    ]
+
+    dependencies = [
+            support_appcompat_v7:'com.android.support:appcompat-v7:27.0.2',
+            support_constraint_layout:'com.android.support.constraint:constraint-layout:1.0.2',
+            recyclerview:'com.android.support:recyclerview-v7:27.0.2',
+            /**
+             * butterknife注解
+             */
+            butterknife:'com.jakewharton:butterknife:8.6.0',
+            butterknife_compiler:'com.jakewharton:butterknife-compiler:8.6.0',
+            /**
+             * rxjava
+             */
+            rxbinding:'com.jakewharton.rxbinding:rxbinding:1.0.0',
+            rxjava:'io.reactivex:rxjava:1.2.4',
+            /**
+             * rxandroid
+             */
+            rxandroid: 'io.reactivex:rxandroid:1.2.1',
+            /**
+             * retrofit
+             */
+            retrofit2: 'com.squareup.retrofit2:retrofit:2.4.0',
+            retrofit2_converter_gson: 'com.squareup.retrofit2:converter-gson:2.4.0',
+            okhttp3_logging_interceptor: 'com.squareup.okhttp3:logging-interceptor:3.10.0',
+            retrofit2_adapter_rxjava: 'com.squareup.retrofit2:adapter-rxjava:2.1.0',
+            /**
+             * GSON
+             */
+            gson:'com.google.code.gson:gson:2.8.2',
+            /**
+             * Dagger
+             */
+            javax_annotation:'org.glassfish:javax.annotation:10.0-b28',
+            dagger:'com.google.dagger:dagger:2.12',
+            dagger_compiler:'com.google.dagger:dagger-compiler:2.12'
+    ]
+
+
+
+
+    androidConfigs = rootProject.ext.android
+    dependenciesLibs = rootProject.ext.dependencies
+}

+ 1 - 0
kfzslibrary/.gitignore

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

+ 58 - 0
kfzslibrary/build.gradle

@@ -0,0 +1,58 @@
+apply plugin: 'com.android.library'
+//使用aop插件
+//apply plugin: 'com.aop.plugin'
+
+android {
+    compileSdkVersion androidConfigs.compileSdkVersion
+    buildToolsVersion androidConfigs.buildToolsVersion
+    defaultConfig {
+        minSdkVersion androidConfigs.minSdkVersion
+        targetSdkVersion androidConfigs.targetSdkVersion
+        versionCode androidConfigs.versionCode_kfzslibrary
+        versionName androidConfigs.versionName_kfzslibrary
+
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+
+}
+
+dependencies {
+//    compile fileTree(dir: 'libs', include: ['*.jar'])
+    /**
+     * Test
+     */
+    testCompile 'junit:junit:4.12'
+    /**
+     * surport
+     */
+    compile dependenciesLibs.recyclerview
+    dependenciesLibs.support_appcompat_v7
+    compile dependenciesLibs.recyclerview
+    /**
+     * dagger
+     */
+    provided dependenciesLibs.javax_annotation
+    compile dependenciesLibs.dagger
+    annotationProcessor dependenciesLibs.dagger_compiler
+    /**
+     * Retrofit-RxJava-Gson
+     */
+    compile dependenciesLibs.retrofit2
+    compile dependenciesLibs.retrofit2_converter_gson
+    compile dependenciesLibs.okhttp3_logging_interceptor
+    compile dependenciesLibs.rxandroid
+    compile dependenciesLibs.retrofit2_adapter_rxjava
+    compile dependenciesLibs.gson
+    /**
+     * butterknife
+     */
+    compile dependenciesLibs.butterknife
+    annotationProcessor dependenciesLibs.butterknife_compiler
+}

+ 21 - 0
kfzslibrary/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 26 - 0
kfzslibrary/src/androidTest/java/com/kfzs/libs/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
+package com.kfzs.libs;
+
+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.*;
+
+/**
+ * Instrumented 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.kfzs.libs.test", appContext.getPackageName());
+    }
+}

+ 5 - 0
kfzslibrary/src/main/AndroidManifest.xml

@@ -0,0 +1,5 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.kfzs.libs" >
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+</manifest>

+ 51 - 0
kfzslibrary/src/main/java/com/kfzs/libs/DaggerActivity.java

@@ -0,0 +1,51 @@
+package com.kfzs.libs;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+
+/**
+ * Created by guoxin on 2018/3/29.
+ */
+
+public abstract class DaggerActivity extends AppCompatActivity implements IDaggerMvp {
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setupDaggerComponent();
+        onAttachedView();
+    }
+
+    @Override
+    protected void onDestroy() {
+        onDetachedView();
+        super.onDestroy();
+    }
+
+    @Override
+    public void onAttachedView() {
+        IPresenter presenter = currentPresenter();
+        if (presenter != null) {
+            presenter.attachedView(currentIView());
+        }
+    }
+
+    @Override
+    public void onDetachedView() {
+        IPresenter presenter = currentPresenter();
+        if (presenter != null) {
+            presenter.detachedView();
+        }
+    }
+
+
+    @Override
+    public boolean isActive() {
+        return currentIView() != null;
+    }
+
+    public abstract IPresenter currentPresenter();
+    public abstract IView currentIView();
+
+}

+ 57 - 0
kfzslibrary/src/main/java/com/kfzs/libs/DaggerFragment.java

@@ -0,0 +1,57 @@
+package com.kfzs.libs;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import com.kfzs.libs.widget.loading.SupportLoadingFragment;
+
+/**
+ * Created by guoxin on 2018/3/30.
+ */
+
+public abstract class DaggerFragment extends SupportLoadingFragment implements IDaggerMvp{
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setupDaggerComponent();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        onAttachedView();
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        onDetachedView();
+    }
+
+    @Override
+    public void onAttachedView() {
+        IPresenter presenter = currentPresenter();
+        if (presenter != null) {
+            presenter.attachedView(currentIView());
+        }
+    }
+
+    @Override
+    public void onDetachedView() {
+        IPresenter presenter = currentPresenter();
+        if (presenter != null) {
+            presenter.detachedView();
+        }
+    }
+
+    @Override
+    public boolean isActive() {
+        return isAdded();
+    }
+
+
+    public abstract IPresenter currentPresenter();
+    public abstract IView currentIView();
+
+
+}

+ 13 - 0
kfzslibrary/src/main/java/com/kfzs/libs/IDaggerMvp.java

@@ -0,0 +1,13 @@
+package com.kfzs.libs;
+
+/**
+ * Created by guoxin on 2018/3/29.
+ * Dagger+MVP架构,View层需要实现的接口
+ */
+
+public interface IDaggerMvp {
+    void setupDaggerComponent();
+    void onAttachedView();
+    void onDetachedView();
+    boolean isActive();
+}

+ 12 - 0
kfzslibrary/src/main/java/com/kfzs/libs/IPresenter.java

@@ -0,0 +1,12 @@
+package com.kfzs.libs;
+
+/**
+ * Created by guoxin on 2018/3/29.
+ * MVP的Presenter层抽象控制接口
+ */
+
+public interface IPresenter {
+    void attachedView(IView view);
+    void detachedView();
+    boolean isContactViewActive();
+}

+ 10 - 0
kfzslibrary/src/main/java/com/kfzs/libs/IView.java

@@ -0,0 +1,10 @@
+package com.kfzs.libs;
+
+/**
+ * Created by guoxin on 2018/3/29.
+ * MVP的View层抽象控制接口
+ */
+
+public interface IView {
+    boolean isViewActive();
+}

+ 13 - 0
kfzslibrary/src/main/java/com/kfzs/libs/aop/Path.java

@@ -0,0 +1,13 @@
+package com.kfzs.libs.aop;
+
+/**
+ * aop的路径配置,这里将代码迁移到其他包名的项目,只需要更改AOP_PKG字段,其余两个不需要更改
+ * Created by Administrator on 2017/9/29 0029.
+ */
+
+public class Path {
+    public static final String AOP_PKG = "org.gx.notes.aop";
+    public static final String AOP_POINTCUT_PREFIX = "execution(@";
+    public static final String AOP_POINTCUT_SUFFIX = " * *(..))";
+
+}

+ 15 - 0
kfzslibrary/src/main/java/com/kfzs/libs/aop/net/CheckNet.java

@@ -0,0 +1,15 @@
+package com.kfzs.libs.aop.net;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 在某个需要网络的业务方法上添加该注解,如果当前没有网络,就不会执行该方法内部的代码,而是提示没有网络
+ * Created by Administrator on 2017/9/11 0011.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CheckNet {
+}

+ 96 - 0
kfzslibrary/src/main/java/com/kfzs/libs/aop/net/CheckNetAop.java

@@ -0,0 +1,96 @@
+package com.kfzs.libs.aop.net;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.widget.Toast;
+
+import com.kfzs.libs.aop.Path;
+import com.kfzs.libs.utils.ContextUtils;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+
+/**
+ * Created by Administrator on 2017/9/11 0011.
+ */
+@Aspect
+class CheckNetAop {
+
+    /**
+     * 切入点注解的路径
+     */
+    public static final String ANNOTATION_PATH = Path.AOP_PKG + ".net.CheckNet";
+    /**
+     * 切入点值
+     */
+    public static final String POINTCUT =
+            Path.AOP_POINTCUT_PREFIX + ANNOTATION_PATH + Path.AOP_POINTCUT_SUFFIX;
+    /**
+     * 替换的方法
+     */
+    public static final String METHOD = "checkNet()";
+
+    @Pointcut(POINTCUT)
+    public void checkNet(){}
+
+    @Around(METHOD)
+    public Object checkNetEnvironment(ProceedingJoinPoint joinPoint) throws Throwable {
+
+        //先获取是否使用了注解CheckNet
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        CheckNet checkNet = signature.getMethod().getAnnotation(CheckNet.class);
+        if(checkNet != null){
+            //使用了注解CheckNet,获取上下文,判断网络环境
+            Context context = ContextUtils.getContext(joinPoint.getThis());
+            if(context != null){
+                if(!isNetworkAvailable(context)){
+                    Toast.makeText(context,"网络进入二次元,请检查网络!",Toast.LENGTH_LONG).show();
+//                    new TopToastView.Builder(context)
+//                            .message("网络进入二次元,请检查网络!")
+//                            .bgColor("#ff0000")
+//                            .textColor("#ffffff")
+//                            .globalToastView(true)
+//                            .build()
+//                            .showToast();
+                    return null;
+                }
+            }
+        }
+
+        return joinPoint.proceed();
+    }
+
+
+
+    /**
+     * 检查当前网络是否可用
+     *
+     * @return
+     */
+    private static boolean isNetworkAvailable(Context context) {
+        // 获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)
+        ConnectivityManager connectivityManager = (ConnectivityManager)
+                context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        if (connectivityManager != null) {
+            // 获取NetworkInfo对象
+            NetworkInfo[] networkInfo = connectivityManager.getAllNetworkInfo();
+
+            if (networkInfo != null && networkInfo.length > 0) {
+                for (int i = 0; i < networkInfo.length; i++) {
+                    // 判断当前网络状态是否为连接状态
+                    if (networkInfo[i].getState() == NetworkInfo.State.CONNECTED) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+
+
+}

+ 35 - 0
kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/CheckPermission.java

@@ -0,0 +1,35 @@
+package com.kfzs.libs.aop.permission;
+
+import android.support.annotation.StringRes;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 执行某个方法时候,方法内部的代码需要某项权限,在该方法上加上该注解,就可以弹出请求权限的弹窗
+ * Created by Administrator on 2017/9/12 0012.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CheckPermission {
+    /**
+     * 需要权限的数组
+     * @return
+     */
+    String[] permissions();
+
+    /**
+     * 如果拒绝了该权限,就会弹出该提示,让用户去开启
+     * @return
+     */
+    @StringRes int message();
+
+    /**
+     * 该值用来设置用户拒绝了权限之后,是否把当前界面关闭,通常可以用在启动页面,请求一些基本的权限,如果用户拒绝,就可以直接将启动页关闭
+     * 如果这里是启动页,拒绝权限后,这里没有添加杀死当前进程的字段,如有需求,可以重写添加
+     * @return
+     */
+    boolean finish();
+}

+ 116 - 0
kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/CheckPermissionAop.java

@@ -0,0 +1,116 @@
+package com.kfzs.libs.aop.permission;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.os.Build;
+
+import com.kfzs.libs.aop.Path;
+import com.kfzs.libs.utils.ContextUtils;
+import com.kfzs.libs.aop.permission.core.PermissionHelper;
+import com.kfzs.libs.aop.permission.core.RxPermissions;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+
+
+import rx.functions.Action1;
+
+/**
+ * Created by Administrator on 2017/9/12 0012.
+ */
+@Aspect
+class CheckPermissionAop {
+
+    /**
+     * 切入点注解的路径
+     */
+    public static final String ANNOTATION_PATH = Path.AOP_PKG + ".permission.CheckPermission";
+    /**
+     * 切入点值
+     */
+    public static final String POINTCUT =
+            Path.AOP_POINTCUT_PREFIX + ANNOTATION_PATH + Path.AOP_POINTCUT_SUFFIX;
+    /**
+     * 替换的方法
+     */
+    public static final String METHOD = "check()";
+
+
+    @Pointcut(POINTCUT)
+    public void check(){}
+
+
+    @Around(METHOD)
+    public void checkPermission(final ProceedingJoinPoint joinPoint) throws Throwable {
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+            CheckPermission checkPermission = signature.getMethod().getAnnotation(CheckPermission.class);
+            String[] permissions = checkPermission.permissions();
+            final int msg = checkPermission.message();
+            final boolean finish = checkPermission.finish();
+            final Activity activity = (Activity) ContextUtils.getContext(joinPoint.getThis());
+            if(activity != null){
+                new RxPermissions(activity)
+                        .request(permissions)
+                        .subscribe(new Action1<Boolean>() {
+                            @Override
+                            public void call(Boolean granted) {
+                                if (!granted) {
+                                    // All requested permissions are granted
+                                    showDialog(activity,msg,finish);
+                                } else {
+                                    // At least one permission is denied
+                                    try {
+                                        joinPoint.proceed();
+                                    } catch (Throwable throwable) {
+                                        throwable.printStackTrace();
+                                    }
+                                }
+                            }
+                        });
+            }
+            else joinPoint.proceed();
+        }
+        else joinPoint.proceed();
+
+    }
+
+    private void showDialog(final Activity activity, int message, final boolean finish){
+
+        Resources resources = activity.getResources();
+        new AlertDialog.Builder(activity)
+                .setCancelable(false)
+                .setMessage(resources.getString(message))
+                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialogInterface, int i) {
+                        if(finish){
+                            activity.finish();
+                        }
+                    }
+                }).setPositiveButton("确定", new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialogInterface, int i) {
+                        PermissionHelper.getAppDetailSettingIntent(activity);
+                        if(finish){
+                            activity.finish();
+                        }
+                    }
+        }).create().show();
+
+
+
+
+    }
+
+
+
+
+
+}

+ 48 - 0
kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/core/Permission.java

@@ -0,0 +1,48 @@
+package com.kfzs.libs.aop.permission.core;
+
+public class Permission {
+    public final String name;
+    public final boolean granted;
+    public final boolean shouldShowRequestPermissionRationale;
+
+    Permission(String name, boolean granted) {
+        this(name, granted, false);
+    }
+
+    Permission(String name, boolean granted, boolean shouldShowRequestPermissionRationale) {
+        this.name = name;
+        this.granted = granted;
+        this.shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale;
+    }
+
+    @Override
+    @SuppressWarnings("SimplifiableIfStatement")
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        final Permission that = (Permission) o;
+
+        if (granted != that.granted) return false;
+        if (shouldShowRequestPermissionRationale != that.shouldShowRequestPermissionRationale)
+            return false;
+        return name.equals(that.name);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name.hashCode();
+        result = 31 * result + (granted ? 1 : 0);
+        result = 31 * result + (shouldShowRequestPermissionRationale ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Permission{" +
+                "name='" + name + '\'' +
+                ", granted=" + granted +
+                ", shouldShowRequestPermissionRationale=" + shouldShowRequestPermissionRationale +
+                '}';
+    }
+}

+ 26 - 0
kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/core/PermissionHelper.java

@@ -0,0 +1,26 @@
+package com.kfzs.libs.aop.permission.core;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+
+/**
+ * Created by Administrator on 2017/9/7 0007.
+ */
+
+public class PermissionHelper {
+    public static void getAppDetailSettingIntent(Context context) {
+        Intent localIntent = new Intent();
+        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (Build.VERSION.SDK_INT >= 9) {
+            localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
+            localIntent.setData(Uri.fromParts("package", context.getPackageName(), null));
+        } else if (Build.VERSION.SDK_INT <= 8) {
+            localIntent.setAction(Intent.ACTION_VIEW);
+            localIntent.setClassName("com.android.settings","com.android.settings.InstalledAppDetails");
+            localIntent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());
+        }
+        context.startActivity(localIntent);
+    }
+}

+ 270 - 0
kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/core/RxPermissions.java

@@ -0,0 +1,270 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.kfzs.libs.aop.permission.core;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.FragmentManager;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx.Observable;
+import rx.functions.Func1;
+import rx.subjects.PublishSubject;
+
+public class RxPermissions {
+
+    static final String TAG = "RxPermissions";
+
+    RxPermissionsFragment mRxPermissionsFragment;
+
+    public RxPermissions(@NonNull Activity activity) {
+        mRxPermissionsFragment = getRxPermissionsFragment(activity);
+    }
+
+    private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {
+        RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(activity);
+        boolean isNewInstance = rxPermissionsFragment == null;
+        if (isNewInstance) {
+            rxPermissionsFragment = new RxPermissionsFragment();
+            FragmentManager fragmentManager = activity.getFragmentManager();
+            fragmentManager
+                    .beginTransaction()
+                    .add(rxPermissionsFragment, TAG)
+                    .commitAllowingStateLoss();
+            fragmentManager.executePendingTransactions();
+        }
+
+        return rxPermissionsFragment;
+    }
+
+    private RxPermissionsFragment findRxPermissionsFragment(Activity activity) {
+        return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG);
+    }
+
+    public void setLogging(boolean logging) {
+        mRxPermissionsFragment.setLogging(logging);
+    }
+
+    /**
+     * Map emitted items from the source observable into {@code true} if permissions in parameters
+     * are granted, or {@code false} if not.
+     * <p>
+     * If one or several permissions have never been requested, invoke the related framework method
+     * to ask the user if he allows the permissions.
+     */
+    @SuppressWarnings("WeakerAccess")
+    public Observable.Transformer<Object, Boolean> ensure(final String... permissions) {
+        return new Observable.Transformer<Object, Boolean>() {
+            @Override
+            public Observable<Boolean> call(Observable<Object> o) {
+                return request(o, permissions)
+                        // Transform Observable<Permission> to Observable<Boolean>
+                        .buffer(permissions.length)
+                        .flatMap(new Func1<List<Permission>, Observable<Boolean>>() {
+                            @Override
+                            public Observable<Boolean> call(List<Permission> permissions) {
+                                if (permissions.isEmpty()) {
+                                    // Occurs during orientation change, when the subject receives onComplete.
+                                    // In that case we don't want to propagate that empty list to the
+                                    // subscriber, only the onComplete.
+                                    return Observable.empty();
+                                }
+                                // Return true if all permissions are granted.
+                                for (Permission p : permissions) {
+                                    if (!p.granted) {
+                                        return Observable.just(false);
+                                    }
+                                }
+                                return Observable.just(true);
+                            }
+                        });
+            }
+        };
+    }
+
+    /**
+     * Map emitted items from the source observable into {@link Permission} objects for each
+     * permission in parameters.
+     * <p>
+     * If one or several permissions have never been requested, invoke the related framework method
+     * to ask the user if he allows the permissions.
+     */
+    @SuppressWarnings("WeakerAccess")
+    public Observable.Transformer<Object, Permission> ensureEach(final String... permissions) {
+        return new Observable.Transformer<Object, Permission>() {
+            @Override
+            public Observable<Permission> call(Observable<Object> o) {
+                return request(o, permissions);
+            }
+        };
+    }
+
+    /**
+     * Request permissions immediately, <b>must be invoked during initialization phase
+     * of your application</b>.
+     */
+    @SuppressWarnings({"WeakerAccess", "unused"})
+    public Observable<Boolean> request(final String... permissions) {
+        return Observable.just(null).compose(ensure(permissions));
+    }
+
+    /**
+     * Request permissions immediately, <b>must be invoked during initialization phase
+     * of your application</b>.
+     */
+    @SuppressWarnings({"WeakerAccess", "unused"})
+    public Observable<Permission> requestEach(final String... permissions) {
+        return Observable.just(null).compose(ensureEach(permissions));
+    }
+
+    private Observable<Permission> request(final Observable<?> trigger, final String... permissions) {
+        if (permissions == null || permissions.length == 0) {
+            throw new IllegalArgumentException("RxPermissions.request/requestEach requires at least one input permission");
+        }
+        return oneOf(trigger, pending(permissions))
+                .flatMap(new Func1<Object, Observable<Permission>>() {
+                    @Override
+                    public Observable<Permission> call(Object o) {
+                        return requestImplementation(permissions);
+                    }
+                });
+    }
+
+    private Observable<?> pending(final String... permissions) {
+        for (String p : permissions) {
+            if (!mRxPermissionsFragment.containsByPermission(p)) {
+                return Observable.empty();
+            }
+        }
+        return Observable.just(null);
+    }
+
+    private Observable<?> oneOf(Observable<?> trigger, Observable<?> pending) {
+        if (trigger == null) {
+            return Observable.just(null);
+        }
+        return Observable.merge(trigger, pending);
+    }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    private Observable<Permission> requestImplementation(final String... permissions) {
+        List<Observable<Permission>> list = new ArrayList<>(permissions.length);
+        List<String> unrequestedPermissions = new ArrayList<>();
+
+        // In case of multiple permissions, we create an Observable for each of them.
+        // At the end, the observables are combined to have a unique response.
+        for (String permission : permissions) {
+            mRxPermissionsFragment.log("Requesting permission " + permission);
+            if (isGranted(permission)) {
+                // Already granted, or not Android M
+                // Return a granted Permission object.
+                list.add(Observable.just(new Permission(permission, true, false)));
+                continue;
+            }
+
+            if (isRevoked(permission)) {
+                // Revoked by a policy, return a denied Permission object.
+                list.add(Observable.just(new Permission(permission, false, false)));
+                continue;
+            }
+
+            PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission);
+            // Create a new subject if not exists
+            if (subject == null) {
+                unrequestedPermissions.add(permission);
+                subject = PublishSubject.create();
+                mRxPermissionsFragment.setSubjectForPermission(permission, subject);
+            }
+
+            list.add(subject);
+        }
+
+        if (!unrequestedPermissions.isEmpty()) {
+            String[] unrequestedPermissionsArray = unrequestedPermissions.toArray(new String[unrequestedPermissions.size()]);
+            requestPermissionsFromFragment(unrequestedPermissionsArray);
+        }
+        return Observable.concat(Observable.from(list));
+    }
+
+    /**
+     * Invokes Activity.shouldShowRequestPermissionRationale and wraps
+     * the returned value in an observable.
+     * <p>
+     * In case of multiple permissions, only emits true if
+     * Activity.shouldShowRequestPermissionRationale returned true for
+     * all revoked permissions.
+     * <p>
+     * You shouldn't call this method if all permissions have been granted.
+     * <p>
+     * For SDK &lt; 23, the observable will always emit false.
+     */
+    @SuppressWarnings("WeakerAccess")
+    public Observable<Boolean> shouldShowRequestPermissionRationale(final Activity activity, final String... permissions) {
+        if (!isMarshmallow()) {
+            return Observable.just(false);
+        }
+        return Observable.just(shouldShowRequestPermissionRationaleImplementation(activity, permissions));
+    }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    private boolean shouldShowRequestPermissionRationaleImplementation(final Activity activity, final String... permissions) {
+        for (String p : permissions) {
+            if (!isGranted(p) && !activity.shouldShowRequestPermissionRationale(p)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    void requestPermissionsFromFragment(String[] permissions) {
+        mRxPermissionsFragment.log("requestPermissionsFromFragment " + TextUtils.join(", ", permissions));
+        mRxPermissionsFragment.requestPermissions(permissions);
+    }
+
+    /**
+     * Returns true if the permission is already granted.
+     * <p>
+     * Always true if SDK &lt; 23.
+     */
+    @SuppressWarnings("WeakerAccess")
+    public boolean isGranted(String permission) {
+        return !isMarshmallow() || mRxPermissionsFragment.isGranted(permission);
+    }
+
+    /**
+     * Returns true if the permission has been revoked by a policy.
+     * <p>
+     * Always false if SDK &lt; 23.
+     */
+    @SuppressWarnings("WeakerAccess")
+    public boolean isRevoked(String permission) {
+        return isMarshmallow() && mRxPermissionsFragment.isRevoked(permission);
+    }
+
+    boolean isMarshmallow() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
+    }
+
+    void onRequestPermissionsResult(String permissions[], int[] grantResults) {
+        mRxPermissionsFragment.onRequestPermissionsResult(permissions, grantResults, new boolean[permissions.length]);
+    }
+
+}

+ 103 - 0
kfzslibrary/src/main/java/com/kfzs/libs/aop/permission/core/RxPermissionsFragment.java

@@ -0,0 +1,103 @@
+package com.kfzs.libs.aop.permission.core;
+
+import android.annotation.TargetApi;
+import android.app.Fragment;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import rx.subjects.PublishSubject;
+
+public class RxPermissionsFragment extends Fragment {
+
+    private static final int PERMISSIONS_REQUEST_CODE = 42;
+
+    // Contains all the current permission requests.
+    // Once granted or denied, they are removed from it.
+    private Map<String, PublishSubject<Permission>> mSubjects = new HashMap<>();
+    private boolean mLogging;
+
+    public RxPermissionsFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setRetainInstance(true);
+    }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    void requestPermissions(@NonNull String[] permissions) {
+        requestPermissions(permissions, PERMISSIONS_REQUEST_CODE);
+    }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+
+        if (requestCode != PERMISSIONS_REQUEST_CODE) return;
+
+        boolean[] shouldShowRequestPermissionRationale = new boolean[permissions.length];
+
+        for (int i = 0; i < permissions.length; i++) {
+            shouldShowRequestPermissionRationale[i] = shouldShowRequestPermissionRationale(permissions[i]);
+        }
+
+        onRequestPermissionsResult(permissions, grantResults, shouldShowRequestPermissionRationale);
+    }
+
+    void onRequestPermissionsResult(String permissions[], int[] grantResults, boolean[] shouldShowRequestPermissionRationale) {
+        for (int i = 0, size = permissions.length; i < size; i++) {
+            log("onRequestPermissionsResult  " + permissions[i]);
+            // Find the corresponding subject
+            PublishSubject<Permission> subject = mSubjects.get(permissions[i]);
+            if (subject == null) {
+                // No subject found
+                Log.e(RxPermissions.TAG, "RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.");
+                return;
+            }
+            mSubjects.remove(permissions[i]);
+            boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
+            subject.onNext(new Permission(permissions[i], granted, shouldShowRequestPermissionRationale[i]));
+            subject.onCompleted();
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    boolean isGranted(String permission) {
+        return getActivity().checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    boolean isRevoked(String permission) {
+        return getActivity().getPackageManager().isPermissionRevokedByPolicy(permission, getActivity().getPackageName());
+    }
+
+    public void setLogging(boolean logging) {
+        mLogging = logging;
+    }
+
+    public PublishSubject<Permission> getSubjectByPermission(@NonNull String permission) {
+        return mSubjects.get(permission);
+    }
+
+    public boolean containsByPermission(@NonNull String permission) {
+        return mSubjects.containsKey(permission);
+    }
+
+    public PublishSubject<Permission> setSubjectForPermission(@NonNull String permission, @NonNull PublishSubject<Permission> subject) {
+        return mSubjects.put(permission, subject);
+    }
+
+    void log(String message) {
+        if (mLogging) {
+            Log.d(RxPermissions.TAG, message);
+        }
+    }
+
+}

+ 17 - 0
kfzslibrary/src/main/java/com/kfzs/libs/convert/StringConverter.java

@@ -0,0 +1,17 @@
+package com.kfzs.libs.convert;
+
+import java.io.IOException;
+
+import okhttp3.ResponseBody;
+import retrofit2.Converter;
+
+/**
+ * Created by ljy on 2018/3/8.
+ */
+public class StringConverter implements Converter<ResponseBody, String> {
+
+    @Override
+    public String convert(ResponseBody value) throws IOException {
+        return value.string();
+    }
+}

+ 28 - 0
kfzslibrary/src/main/java/com/kfzs/libs/convert/StringConverterFactory.java

@@ -0,0 +1,28 @@
+package com.kfzs.libs.convert;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import okhttp3.ResponseBody;
+import retrofit2.Converter;
+import retrofit2.Retrofit;
+
+/**
+ * Created by guoxin on 2018/3/29.
+ */
+
+public class StringConverterFactory extends Converter.Factory {
+
+    public static StringConverterFactory create(){
+        return new StringConverterFactory();
+    }
+
+    @Override
+    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
+        if (type == String.class) {
+            return new StringConverter();
+        }
+        //其它类型我们不处理,返回null就行
+        return null;
+    }
+}

+ 15 - 0
kfzslibrary/src/main/java/com/kfzs/libs/di/http/HttpComponent.java

@@ -0,0 +1,15 @@
+package com.kfzs.libs.di.http;
+
+import javax.inject.Singleton;
+
+import dagger.Component;
+
+/**
+ * Created by guoxin on 2018/3/29.
+ * Dagger实现的网络访问依赖注入中间件Component
+ */
+@Component(modules = HttpModule.class)
+@Singleton
+public interface HttpComponent {
+    HttpService getHttpService();
+}

+ 60 - 0
kfzslibrary/src/main/java/com/kfzs/libs/di/http/HttpModule.java

@@ -0,0 +1,60 @@
+package com.kfzs.libs.di.http;
+
+
+import com.kfzs.libs.convert.StringConverterFactory;
+
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Singleton;
+
+import dagger.Module;
+import dagger.Provides;
+import okhttp3.OkHttpClient;
+import retrofit2.Retrofit;
+import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+/**
+ * Created by guoxin on 2018/3/29.
+ */
+@Module
+public class HttpModule {
+
+    public static final String BASE_URL = "https://www.baidu.com";
+    public static final int CONNECT_TIMEOUT = 15;
+    public static final int READ_TIMEOUT = 15;
+
+    @Provides
+    @Singleton
+    public OkHttpClient provideOkHttpClient(){
+//        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
+//        loggingInterceptor.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE);
+        OkHttpClient okhttpClient = new OkHttpClient.Builder()
+                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
+                .readTimeout(READ_TIMEOUT,TimeUnit.SECONDS)
+//                .addInterceptor(new AddPuplicParameIntercept())
+//                .addInterceptor(loggingInterceptor)
+                .build();
+        return okhttpClient;
+    }
+
+    @Provides
+    @Singleton
+    public Retrofit provideRetrofit(OkHttpClient okHttpClient){
+        Retrofit retrofit = new Retrofit.Builder()
+                .client(okHttpClient)
+                .baseUrl(BASE_URL)
+                .addConverterFactory(StringConverterFactory.create())
+                .addConverterFactory(GsonConverterFactory.create())
+                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+                .build();
+        return retrofit;
+    }
+
+    @Provides
+    @Singleton
+    public HttpService provideHttpService(Retrofit retrofit){
+        return retrofit.create(HttpService.class);
+    }
+
+}

+ 14 - 0
kfzslibrary/src/main/java/com/kfzs/libs/di/http/HttpScope.java

@@ -0,0 +1,14 @@
+package com.kfzs.libs.di.http;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Scope;
+
+/**
+ * Created by guoxin on 2018/3/29.
+ */
+@Scope
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HttpScope {
+}

+ 16 - 0
kfzslibrary/src/main/java/com/kfzs/libs/di/http/HttpService.java

@@ -0,0 +1,16 @@
+package com.kfzs.libs.di.http;
+
+
+import retrofit2.http.GET;
+import rx.Observable;
+
+/**
+ * Created by guoxin on 2018/3/29.
+ */
+
+public interface HttpService {
+
+    @GET("/")
+    Observable<String> sufferBaidu();
+
+}

+ 93 - 0
kfzslibrary/src/main/java/com/kfzs/libs/dialog/BaseDialogFragment.java

@@ -0,0 +1,93 @@
+package com.kfzs.libs.dialog;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.annotation.LayoutRes;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.app.AlertDialog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+
+import butterknife.ButterKnife;
+
+/**
+ * 使用DialogFragment创建Dialog的快捷基础类
+ * Created by Administrator on 2018/2/11 0011.
+ */
+
+public abstract class BaseDialogFragment extends DialogFragment {
+
+    /**
+     * 没有设置dialog的弹出动画,这个是默认值
+     */
+    private static final int NO_SET_ANIMATION = -1;
+
+    protected Activity activity;
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        activity = (Activity) context;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        View contentView = LayoutInflater.from(activity).inflate(dialogContentViewLayoutId(), null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        AlertDialog dialog = builder.show();
+        Window window = dialog.getWindow();
+        if (window != null) {
+            window.setContentView(contentView);
+            window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+            window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+            if(windowAnimationStyle() != NO_SET_ANIMATION){
+                window.setWindowAnimations(windowAnimationStyle());
+            }
+            windowOtherSettings(window);
+        }
+        ButterKnife.bind(this, contentView);
+        setupContentView();
+        return dialog;
+    }
+
+    /**
+     * 关于Window的其他配置
+     * @param window
+     */
+    public void windowOtherSettings(Window window){
+
+    }
+
+    /**
+     * @return dialog的布局文件id
+     */
+    public abstract @LayoutRes
+    int dialogContentViewLayoutId();
+
+    /**
+     * 初始化dialog的控件,这里绑定了ButterKnife,直接使用@BindView
+     */
+    public abstract void setupContentView();
+
+    /**
+     * 重写该方法,可以修改dialog的弹出动画
+     * 比如 :
+     * <style name="BottomSheetDialogStyle">
+     *     <item name="android:windowEnterAnimation">@anim/bottom_sheet_enter</item>
+     *     <item name="android:windowExitAnimation">@anim/bottom_sheet_exit</item>
+     * </style>
+     * @return 返回dialog弹出动画的style
+     */
+    protected int windowAnimationStyle(){
+        return NO_SET_ANIMATION;
+    }
+
+
+}

+ 37 - 0
kfzslibrary/src/main/java/com/kfzs/libs/utils/ContextUtils.java

@@ -0,0 +1,37 @@
+package com.kfzs.libs.utils;
+
+import android.app.Activity;
+import android.content.Context;
+import android.support.v4.app.Fragment;
+import android.view.View;
+
+/**
+ * Created by Administrator on 2017/9/28 0028.
+ */
+
+public class ContextUtils {
+
+    /**
+     * 通过对象获取上下文
+     *
+     * @param object
+     * @return
+     */
+    public static Context getContext(Object object) {
+        if (object instanceof Activity) {
+            return (Activity) object;
+        } else if (object instanceof Fragment) {
+            Fragment fragment = (Fragment) object;
+            return fragment.getActivity();
+        } else if (object instanceof android.app.Fragment) {
+            android.app.Fragment fragment = (android.app.Fragment) object;
+            return fragment.getActivity();
+        }
+        else if (object instanceof View) {
+            View view = (View) object;
+            return view.getContext();
+        }
+        return null;
+    }
+
+}

+ 231 - 0
kfzslibrary/src/main/java/com/kfzs/libs/utils/DeviceHelper.java

@@ -0,0 +1,231 @@
+package com.kfzs.libs.utils;
+
+/**
+ * Created by guoxin on 2018/3/30.
+ */
+
+import android.annotation.TargetApi;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Environment;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import java.io.File;
+import java.io.FileInputStream;
+import java.lang.reflect.Method;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class DeviceHelper {
+    private final static String TAG = "DeviceHelper";
+    private final static String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
+    private static final String KEY_FLYME_VERSION_NAME = "ro.build.display.id";
+    private final static String FLYME = "flyme";
+    private final static String ZTEC2016 = "zte c2016";
+    private final static String ZUKZ1 = "zuk z1";
+    private final static String MEIZUBOARD[] = {"m9", "M9", "mx", "MX"};
+    private static String sMiuiVersionName;
+    private static String sFlymeVersionName;
+    private static boolean sIsTabletChecked = false;
+    private static boolean sIsTabletValue = false;
+
+    static {
+        FileInputStream fileInputStream = null;
+        try {
+            fileInputStream = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop"));
+            Properties properties = new Properties();
+            properties.load(fileInputStream);
+            Class<?> clzSystemProperties = Class.forName("android.os.SystemProperties");
+            Method getMethod = clzSystemProperties.getDeclaredMethod("get", String.class);
+            // miui
+            sMiuiVersionName =getLowerCaseName(properties, getMethod, KEY_MIUI_VERSION_NAME);
+            //flyme
+            sFlymeVersionName = getLowerCaseName(properties, getMethod, KEY_FLYME_VERSION_NAME);
+
+        } catch (Exception e) {
+//            QMUILog.printErrStackTrace(TAG, e, "getProperty error");
+        } finally {
+            LangHelper.close(fileInputStream);
+        }
+    }
+
+    private static boolean _isTablet(Context context) {
+        return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >=
+                Configuration.SCREENLAYOUT_SIZE_LARGE;
+    }
+
+    /**
+     * 判断是否为平板设备
+     */
+    public static boolean isTablet(Context context) {
+        if (sIsTabletChecked) {
+            return sIsTabletValue;
+        }
+        sIsTabletValue = _isTablet(context);
+        sIsTabletChecked = true;
+        return sIsTabletValue;
+    }
+
+    /**
+     * 判断是否是flyme系统
+     */
+    public static boolean isFlyme() {
+        return !TextUtils.isEmpty(sFlymeVersionName) && sFlymeVersionName.contains(FLYME);
+    }
+
+    /**
+     * 判断是否是MIUI系统
+     */
+    public static boolean isMIUI() {
+        return !TextUtils.isEmpty(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV5() {
+        return "v5".equals(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV6() {
+        return "v6".equals(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV7() {
+        return "v7".equals(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV8() {
+        return "v8".equals(sMiuiVersionName);
+    }
+
+    public static boolean isMIUIV9() {
+        return "v9".equals(sMiuiVersionName);
+    }
+
+    public static boolean isFlymeVersionHigher5_2_4() {
+        //查不到默认高于5.2.4
+        boolean isHigher = true;
+        if(sFlymeVersionName != null && !sFlymeVersionName.equals("")){
+            Pattern pattern = Pattern.compile("(\\d+\\.){2}\\d");
+            Matcher matcher = pattern.matcher(sFlymeVersionName);
+            if (matcher.find()) {
+                String versionString = matcher.group();
+                if (versionString != null && !versionString.equals("")) {
+                    String[] version = versionString.split("\\.");
+                    if (version.length == 3) {
+                        if (Integer.valueOf(version[0]) < 5) {
+                            isHigher = false;
+                        } else if (Integer.valueOf(version[0]) > 5) {
+                            isHigher = true;
+                        } else {
+                            if (Integer.valueOf(version[1]) < 2) {
+                                isHigher = false;
+                            } else if (Integer.valueOf(version[1]) > 2) {
+                                isHigher = true;
+                            } else {
+                                if (Integer.valueOf(version[2]) < 4) {
+                                    isHigher = false;
+                                } else if (Integer.valueOf(version[2]) >= 5) {
+                                    isHigher = true;
+                                }
+                            }
+                        }
+                    }
+
+                }
+            }
+        }
+        return isMeizu() && isHigher;
+    }
+
+    /**
+     * 判断是否为魅族
+     */
+    public static boolean isMeizu() {
+        return isPhone(MEIZUBOARD) || isFlyme();
+    }
+
+    /**
+     * 判断是否为小米
+     */
+    public static boolean isXiaomi() {
+        return Build.BRAND.toLowerCase().contains("xiaomi");
+    }
+
+
+    /**
+     * 判断是否为 ZUK Z1 和 ZTK C2016。
+     * 两台设备的系统虽然为 android 6.0,但不支持状态栏icon颜色改变,因此经常需要对它们进行额外判断。
+     */
+    public static boolean isZUKZ1() {
+        final String board = Build.MODEL;
+        return board != null && board.toLowerCase().contains(ZUKZ1);
+    }
+
+    public static boolean isZTKC2016() {
+        final String board = Build.MODEL;
+        return board != null && board.toLowerCase().contains(ZTEC2016);
+    }
+
+    private static boolean isPhone(String[] boards) {
+        final String board = Build.BOARD;
+        if (board == null) {
+            return false;
+        }
+        for (String board1 : boards) {
+            if (board.equals(board1)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断悬浮窗权限(目前主要用户魅族与小米的检测)。
+     */
+    public static boolean isFloatWindowOpAllowed(Context context) {
+        final int version = Build.VERSION.SDK_INT;
+        if (version >= 19) {
+            return checkOp(context, 24);  // 24 是AppOpsManager.OP_SYSTEM_ALERT_WINDOW 的值,该值无法直接访问
+        } else {
+            try {
+                return (context.getApplicationInfo().flags & 1 << 27) == 1 << 27;
+            } catch (Exception e) {
+                e.printStackTrace();
+                return false;
+            }
+        }
+    }
+
+    @TargetApi(19)
+    private static boolean checkOp(Context context, int op) {
+        final int version = Build.VERSION.SDK_INT;
+        if (version >= Build.VERSION_CODES.KITKAT) {
+            AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+            try {
+                Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class);
+                int property = (Integer) method.invoke(manager, op,
+                        Binder.getCallingUid(), context.getPackageName());
+                return AppOpsManager.MODE_ALLOWED == property;
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return false;
+    }
+
+    @Nullable
+    private static String getLowerCaseName(Properties p, Method get, String key) {
+        String name = p.getProperty(key);
+        if (name == null) {
+            try {
+                name = (String) get.invoke(null, key);
+            } catch (Exception ignored) {}
+        }
+        if (name != null) name = name.toLowerCase();
+        return name;
+    }
+}

+ 326 - 0
kfzslibrary/src/main/java/com/kfzs/libs/utils/DisplayHelper.java

@@ -0,0 +1,326 @@
+package com.kfzs.libs.utils;
+
+/**
+ * Created by guoxin on 2018/3/30.
+ */
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.net.ConnectivityManager;
+import android.os.Build;
+import android.os.Environment;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+
+import java.lang.reflect.Field;
+import java.util.Locale;
+
+
+public class DisplayHelper {
+
+    /**
+     * 屏幕密度,系统源码注释不推荐使用
+     */
+    public static final float DENSITY = Resources.getSystem()
+            .getDisplayMetrics().density;
+    private static final String TAG = "Devices";
+    /**
+     * 屏幕密度
+     */
+    public static float sDensity = 0f;
+    /**
+     * 是否有摄像头
+     */
+    private static Boolean sHasCamera = null;
+
+    /**
+     * 获取 DisplayMetrics
+     */
+    public static DisplayMetrics getDisplayMetrics(Context context) {
+        DisplayMetrics displayMetrics = new DisplayMetrics();
+        ((WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE))
+                .getDefaultDisplay().getMetrics(displayMetrics);
+        return displayMetrics;
+    }
+
+    /**
+     * 把以 dp 为单位的值,转化为以 px 为单位的值
+     *
+     * @param dpValue 以 dp 为单位的值
+     * @return px value
+     */
+    public static int dpToPx(int dpValue) {
+        return (int) (dpValue * DENSITY + 0.5f);
+    }
+
+    /**
+     * 把以 px 为单位的值,转化为以 dp 为单位的值
+     *
+     * @param pxValue 以 px 为单位的值
+     * @return dp值
+     */
+    public static int pxToDp(float pxValue) {
+        return (int) (pxValue / DENSITY + 0.5f);
+    }
+
+    public static float getDensity(Context context) {
+        if (sDensity == 0f) {
+            sDensity = getDisplayMetrics(context).density;
+        }
+        return sDensity;
+    }
+
+    /**
+     * 获取屏幕宽度
+     */
+    public static int getScreenWidth(Context context) {
+        return getDisplayMetrics(context).widthPixels;
+    }
+
+    /**
+     * 获取屏幕高度
+     */
+    public static int getScreenHeight(Context context) {
+        return getDisplayMetrics(context).heightPixels;
+    }
+
+    /**
+     * 获取屏幕的真实宽高
+     */
+    public static int[] getRealScreenSize(Context context) {
+        int[] size = new int[2];
+        int widthPixels, heightPixels;
+        WindowManager w = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        Display d = w.getDefaultDisplay();
+        DisplayMetrics metrics = new DisplayMetrics();
+        d.getMetrics(metrics);
+        // since SDK_INT = 1;
+        widthPixels = metrics.widthPixels;
+        heightPixels = metrics.heightPixels;
+        try {
+            // used when 17 > SDK_INT >= 14; includes window decorations (statusbar bar/menu bar)
+            widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
+            heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
+        } catch (Exception ignored) {
+        }
+        try {
+            // used when SDK_INT >= 17; includes window decorations (statusbar bar/menu bar)
+            Point realSize = new Point();
+            Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
+            widthPixels = realSize.x;
+            heightPixels = realSize.y;
+        } catch (Exception ignored) {
+        }
+
+        size[0] = widthPixels;
+        size[1] = heightPixels;
+        return size;
+
+    }
+
+    /**
+     * 单位转换: dp -> px
+     */
+    public static int dp2px(Context context, int dp) {
+        return (int) (getDensity(context) * dp + 0.5);
+    }
+
+    /**
+     * 单位转换:px -> dp
+     */
+    public static int px2dp(Context context, int px) {
+        return (int) (px / getDensity(context) + 0.5);
+    }
+
+    /**
+     * 判断是否有状态栏
+     */
+    public static boolean hasStatusBar(Context context) {
+        if (context instanceof Activity) {
+            Activity activity = (Activity) context;
+            WindowManager.LayoutParams attrs = activity.getWindow().getAttributes();
+            return (attrs.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != WindowManager.LayoutParams.FLAG_FULLSCREEN;
+        }
+        return true;
+    }
+
+    /**
+     * 获取ActionBar高度
+     */
+    public static int getActionBarHeight(Context context) {
+        int actionBarHeight = 0;
+        TypedValue tv = new TypedValue();
+        if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
+            actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,
+                    context.getResources().getDisplayMetrics());
+        }
+        return actionBarHeight;
+    }
+
+    /**
+     * 获取状态栏高度
+     */
+    public static int getStatusBarHeight(Context context) {
+        Class<?> c;
+        Object obj;
+        Field field;
+        int x;
+        try {
+            c = Class.forName("com.android.internal.R$dimen");
+            obj = c.newInstance();
+            field = c.getField("status_bar_height");
+            x = Integer.parseInt(field.get(obj).toString());
+            return context.getResources()
+                    .getDimensionPixelSize(x);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return 0;
+    }
+
+    /**
+     * 获取虚拟菜单的高度,若无则返回0
+     */
+    public static int getNavMenuHeight(Context context) {
+        return getRealScreenSize(context)[1] - getScreenHeight(context);
+    }
+
+    public static boolean hasCamera(Context context) {
+        if (sHasCamera == null) {
+            PackageManager pckMgr = context.getPackageManager();
+            boolean flag = pckMgr
+                    .hasSystemFeature("android.hardware.camera.front");
+            boolean flag1 = pckMgr.hasSystemFeature("android.hardware.camera");
+            boolean flag2;
+            flag2 = flag || flag1;
+            sHasCamera = flag2;
+        }
+        return sHasCamera;
+    }
+
+    /**
+     * 是否有硬件menu
+     */
+    @SuppressWarnings("SimplifiableIfStatement")
+    public static boolean hasHardwareMenuKey(Context context) {
+        boolean flag;
+        if (Build.VERSION.SDK_INT < 11)
+            flag = true;
+        else if (Build.VERSION.SDK_INT >= 14) {
+            flag = ViewConfiguration.get(context).hasPermanentMenuKey();
+        } else
+            flag = false;
+        return flag;
+    }
+
+    /**
+     * 是否有网络功能
+     */
+    public static boolean hasInternet(Context context) {
+        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        return cm.getActiveNetworkInfo() != null;
+    }
+
+    /**
+     * 判断是否存在pckName包
+     */
+    public static boolean isPackageExist(Context context, String pckName) {
+        try {
+            PackageInfo pckInfo = context.getPackageManager()
+                    .getPackageInfo(pckName, 0);
+            if (pckInfo != null)
+                return true;
+        } catch (PackageManager.NameNotFoundException ignored) {
+        }
+        return false;
+    }
+
+    /**
+     * 判断 SD Card 是否 ready
+     */
+    public static boolean isSdcardReady() {
+        return Environment.MEDIA_MOUNTED.equals(Environment
+                .getExternalStorageState());
+    }
+
+    /**
+     * 获取当前国家的语言
+     */
+    public static String getCurCountryLan(Context context) {
+        Configuration config = context.getResources().getConfiguration();
+        Locale sysLocale;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            sysLocale = config.getLocales().get(0);
+        } else {
+            //noinspection deprecation
+            sysLocale = config.locale;
+        }
+        return sysLocale.getLanguage()
+                + "-"
+                + sysLocale.getCountry();
+    }
+
+    /**
+     * 判断是否为中文环境
+     */
+    public static boolean isZhCN(Context context) {
+        Configuration config = context.getResources().getConfiguration();
+        Locale sysLocale;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            sysLocale = config.getLocales().get(0);
+        } else {
+            //noinspection deprecation
+            sysLocale = config.locale;
+        }
+        String lang = sysLocale.getCountry();
+        return lang.equalsIgnoreCase("CN");
+    }
+
+    /**
+     * 设置全屏
+     */
+    public static void setFullScreen(Context context) {
+        if (context instanceof Activity) {
+            Activity activity = (Activity) context;
+            WindowManager.LayoutParams params = activity.getWindow().getAttributes();
+            params.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
+            activity.getWindow().setAttributes(params);
+            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+        }
+
+    }
+
+    /**
+     * 取消全屏
+     */
+    public static void cancelFullScreen(Context context) {
+        if (context instanceof Activity) {
+            Activity activity = (Activity) context;
+            WindowManager.LayoutParams params = activity.getWindow().getAttributes();
+            params.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
+            activity.getWindow().setAttributes(params);
+            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+        }
+    }
+
+    /**
+     * 判断是否全屏
+     */
+    public static boolean isFullScreen(Activity activity) {
+        WindowManager.LayoutParams params = activity.getWindow().getAttributes();
+        return (params.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN;
+    }
+
+
+    public static boolean isElevationSupported() {
+        return Build.VERSION.SDK_INT >= 21;
+    }
+}

+ 125 - 0
kfzslibrary/src/main/java/com/kfzs/libs/utils/DrawablesHelper.java

@@ -0,0 +1,125 @@
+package com.kfzs.libs.utils;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.v4.content.ContextCompat;
+import android.widget.TextView;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by Administrator on 2017/2/22 0022.
+ */
+
+/**
+ * TextView及其子类设置CompoundDrawables助手
+ */
+public class DrawablesHelper {
+
+    public static final int LEFT = 0;
+    public static final int RIGHT = 1;
+    public static final int TOP = 2;
+    public static final int BOTTOM = 3;
+
+
+    private int mDirection = LEFT;
+    private WeakReference<TextView> mViewWeakReference;
+    private int mWidth;
+    private int mHeight;
+    private @DrawableRes
+    int mDrawable;
+
+    public DrawablesHelper(TextView view){
+        mViewWeakReference = new WeakReference<>(view);
+    }
+
+    public DrawablesHelper direction(int direction){
+        mDirection = direction;
+        return this;
+    }
+
+    public DrawablesHelper drawableWidthPx(int width){
+        mWidth = width;
+        return this;
+    }
+
+    public DrawablesHelper drawableHeightPx(int height){
+        mHeight = height;
+        return this;
+    }
+
+    public DrawablesHelper drawable(@DrawableRes int drawable){
+        mDrawable = drawable;
+        return this;
+    }
+
+    public void commit(){
+        TextView textView = mViewWeakReference.get();
+        if(textView != null){
+            Drawable drawable;
+            if(mWidth != 0 && mHeight != 0){
+                drawable = getDrawable(textView.getContext(), mDrawable, mWidth, mHeight);
+            }
+            else drawable = getDrawable(textView.getContext(), mDrawable);
+
+            Drawable[] compoundDrawables = textView.getCompoundDrawables();
+            switch (mDirection){
+                case LEFT:
+                    leftDrawable(textView,drawable,compoundDrawables);
+                    break;
+                case RIGHT:
+                    rightDrawable(textView,drawable,compoundDrawables);
+                    break;
+                case TOP:
+                    topDrawable(textView,drawable,compoundDrawables);
+                    break;
+                case BOTTOM:
+                    bottomDrawable(textView,drawable,compoundDrawables);
+                    break;
+            }
+        }
+    }
+
+    private DrawablesHelper leftDrawable(TextView textView, Drawable drawable, Drawable[] compoundDrawables){
+        textView.setCompoundDrawables(drawable,compoundDrawables[1],compoundDrawables[2],compoundDrawables[3]);
+        return this;
+    }
+    private DrawablesHelper rightDrawable(TextView textView, Drawable drawable, Drawable[] compoundDrawables){
+        textView.setCompoundDrawables(compoundDrawables[0],compoundDrawables[1],drawable,compoundDrawables[3]);
+        return this;
+    }
+
+    private DrawablesHelper topDrawable(TextView textView, Drawable drawable, Drawable[] compoundDrawables){
+        textView.setCompoundDrawables(compoundDrawables[0],drawable,compoundDrawables[2],compoundDrawables[3]);
+        return this;
+    }
+
+    private DrawablesHelper bottomDrawable(TextView textView, Drawable drawable, Drawable[] compoundDrawables){
+        textView.setCompoundDrawables(compoundDrawables[0],compoundDrawables[1],compoundDrawables[2],drawable);
+        return this;
+    }
+
+    /**
+     * 获取drawable
+     *
+     * @param context
+     * @param drawableResId
+     * @param drawablePxWidth
+     * @param drawablePxHeight
+     * @return
+     */
+    private static Drawable getDrawable(Context context, int drawableResId, int drawablePxWidth, int drawablePxHeight) {
+        Drawable drawable = ContextCompat.getDrawable(context,drawableResId);
+        drawable.setBounds(0, 0, drawablePxWidth, drawablePxHeight);
+        return drawable;
+    }
+
+    private static Drawable getDrawable(Context context, int drawableResId) {
+        Drawable drawable = ContextCompat.getDrawable(context,drawableResId);
+        drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
+        return drawable;
+    }
+
+
+}

+ 78 - 0
kfzslibrary/src/main/java/com/kfzs/libs/utils/LangHelper.java

@@ -0,0 +1,78 @@
+package com.kfzs.libs.utils;
+
+/**
+ * Created by guoxin on 2018/3/30.
+ */
+
+import android.support.annotation.Nullable;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Locale;
+
+public class LangHelper {
+
+    /**
+     * 获取数值的位数,例如9返回1,99返回2,999返回3
+     *
+     * @param number 要计算位数的数值,必须>0
+     * @return 数值的位数,若传的参数小于等于0,则返回0
+     */
+    public static int getNumberDigits(int number) {
+        if (number <= 0) return 0;
+        return (int) (Math.log10(number) + 1);
+    }
+
+
+    public static int getNumberDigits(long number) {
+        if (number <= 0) return 0;
+        return (int) (Math.log10(number) + 1);
+    }
+
+    /**
+     * 规范化价格字符串显示的工具类
+     *
+     * @param price 价格
+     * @return 保留两位小数的价格字符串
+     */
+    public static String regularizePrice(float price) {
+        return String.format(Locale.CHINESE, "%.2f", price);
+    }
+
+    /**
+     * 规范化价格字符串显示的工具类
+     *
+     * @param price 价格
+     * @return 保留两位小数的价格字符串
+     */
+    public static String regularizePrice(double price) {
+        return String.format(Locale.CHINESE, "%.2f", price);
+    }
+
+
+    public static boolean isNullOrEmpty(@Nullable CharSequence string) {
+        return string == null || string.length() == 0;
+    }
+
+    public static void close(Closeable c) {
+        if (c != null) {
+            try {
+                c.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static boolean objectEquals(Object a, Object b) {
+        return (a == b) || (a != null && a.equals(b));
+    }
+
+    public static int constrain(int amount, int low, int high) {
+        return amount < low ? low : (amount > high ? high : amount);
+    }
+
+    public static float constrain(float amount, float low, float high) {
+        return amount < low ? low : (amount > high ? high : amount);
+    }
+}

+ 404 - 0
kfzslibrary/src/main/java/com/kfzs/libs/utils/StatusBarHelper.java

@@ -0,0 +1,404 @@
+package com.kfzs.libs.utils;
+
+/**
+ * Created by guoxin on 2018/3/30.
+ */
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.support.annotation.ColorInt;
+import android.support.annotation.IntDef;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+
+public class StatusBarHelper {
+
+    private final static int STATUSBAR_TYPE_DEFAULT = 0;
+    private final static int STATUSBAR_TYPE_MIUI = 1;
+    private final static int STATUSBAR_TYPE_FLYME = 2;
+    private final static int STATUSBAR_TYPE_ANDROID6 = 3; // Android 6.0
+    private final static int STATUS_BAR_DEFAULT_HEIGHT_DP = 25; // 大部分状态栏都是25dp
+    // 在某些机子上存在不同的density值,所以增加两个虚拟值
+    public static float sVirtualDensity = -1;
+    public static float sVirtualDensityDpi = -1;
+    private static int sStatusbarHeight = -1;
+    private static @StatusBarType int mStatuBarType = STATUSBAR_TYPE_DEFAULT;
+    private static Integer sTransparentValue;
+
+    public static void translucent(Activity activity) {
+        translucent(activity, 0x40000000);
+    }
+
+    /**
+     * 沉浸式状态栏。
+     * 支持 4.4 以上版本的 MIUI 和 Flyme,以及 5.0 以上版本的其他 Android。
+     *
+     * @param activity 需要被设置沉浸式状态栏的 Activity。
+     */
+    @TargetApi(19)
+    public static void translucent(Activity activity, @ColorInt int colorOn5x) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+            // 版本小于4.4,绝对不考虑沉浸式
+            return;
+        }
+        // 小米和魅族4.4 以上版本支持沉浸式
+        if (DeviceHelper.isMeizu() || DeviceHelper.isMIUI()) {
+            Window window = activity.getWindow();
+            window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
+                    WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            return;
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            Window window = activity.getWindow();
+            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && supportTransclentStatusBar6()) {
+                // android 6以后可以改状态栏字体颜色,因此可以自行设置为透明
+                // ZUK Z1是个另类,自家应用可以实现字体颜色变色,但没开放接口
+                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+                window.setStatusBarColor(Color.TRANSPARENT);
+            } else {
+                // android 5不能修改状态栏字体颜色,因此直接用FLAG_TRANSLUCENT_STATUS,nexus表现为半透明
+                // 魅族和小米的表现如何?
+                // update: 部分手机运用FLAG_TRANSLUCENT_STATUS时背景不是半透明而是没有背景了。。。。。
+//                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+                // 采取setStatusBarColor的方式,部分机型不支持,那就纯黑了,保证状态栏图标可见
+                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+                window.setStatusBarColor(colorOn5x);
+            }
+//        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+//            // android4.4的默认是从上到下黑到透明,我们的背景是白色,很难看,因此只做魅族和小米的
+//        } else if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1){
+//            // 如果app 为白色,需要更改状态栏颜色,因此不能让19一下支持透明状态栏
+//            Window window = activity.getWindow();
+//            Integer transparentValue = getStatusBarAPITransparentValue(activity);
+//            if(transparentValue != null) {
+//                window.getDecorView().setSystemUiVisibility(transparentValue);
+//            }
+        }
+    }
+
+    /**
+     * 设置状态栏黑色字体图标,
+     * 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android
+     *
+     * @param activity 需要被处理的 Activity
+     */
+    public static boolean setStatusBarLightMode(Activity activity) {
+        // 无语系列:ZTK C2016只能时间和电池图标变色。。。。
+        if (DeviceHelper.isZTKC2016()) {
+            return false;
+        }
+
+        if (mStatuBarType != STATUSBAR_TYPE_DEFAULT) {
+            return setStatusBarLightMode(activity, mStatuBarType);
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            if (isMIUICustomStatusBarLightModeImpl() && MIUISetStatusBarLightMode(activity.getWindow(), true)) {
+                mStatuBarType = STATUSBAR_TYPE_MIUI;
+                return true;
+            } else if (FlymeSetStatusBarLightMode(activity.getWindow(), true)) {
+                mStatuBarType = STATUSBAR_TYPE_FLYME;
+                return true;
+            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                Android6SetStatusBarLightMode(activity.getWindow(), true);
+                mStatuBarType = STATUSBAR_TYPE_ANDROID6;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 已知系统类型时,设置状态栏黑色字体图标。
+     * 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android
+     *
+     * @param activity 需要被处理的 Activity
+     * @param type     StatusBar 类型,对应不同的系统
+     */
+    private static boolean setStatusBarLightMode(Activity activity, @StatusBarType int type) {
+        if (type == STATUSBAR_TYPE_MIUI) {
+            return MIUISetStatusBarLightMode(activity.getWindow(), true);
+        } else if (type == STATUSBAR_TYPE_FLYME) {
+            return FlymeSetStatusBarLightMode(activity.getWindow(), true);
+        } else if (type == STATUSBAR_TYPE_ANDROID6) {
+            return Android6SetStatusBarLightMode(activity.getWindow(), true);
+        }
+        return false;
+    }
+
+
+    /**
+     * 设置状态栏白色字体图标
+     * 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android
+     */
+    public static boolean setStatusBarDarkMode(Activity activity) {
+        if (mStatuBarType == STATUSBAR_TYPE_DEFAULT) {
+            // 默认状态,不需要处理
+            return true;
+        }
+
+        if (mStatuBarType == STATUSBAR_TYPE_MIUI) {
+            return MIUISetStatusBarLightMode(activity.getWindow(), false);
+        } else if (mStatuBarType == STATUSBAR_TYPE_FLYME) {
+            return FlymeSetStatusBarLightMode(activity.getWindow(), false);
+        } else if (mStatuBarType == STATUSBAR_TYPE_ANDROID6) {
+            return Android6SetStatusBarLightMode(activity.getWindow(), false);
+        }
+        return true;
+    }
+
+    @TargetApi(23)
+    private static int changeStatusBarModeRetainFlag(Window window, int out) {
+        out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+        out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_FULLSCREEN);
+        out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+        out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+        out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+        out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+        return out;
+    }
+
+    public static int retainSystemUiFlag(Window window, int out, int type) {
+        int now = window.getDecorView().getSystemUiVisibility();
+        if ((now & type) == type) {
+            out |= type;
+        }
+        return out;
+    }
+
+
+    /**
+     * 设置状态栏字体图标为深色,Android 6
+     *
+     * @param window 需要设置的窗口
+     * @param light  是否把状态栏字体及图标颜色设置为深色
+     * @return boolean 成功执行返回true
+     */
+    @TargetApi(23)
+    private static boolean Android6SetStatusBarLightMode(Window window, boolean light) {
+        View decorView = window.getDecorView();
+        int systemUi = light ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
+        systemUi = changeStatusBarModeRetainFlag(window, systemUi);
+        decorView.setSystemUiVisibility(systemUi);
+        return true;
+    }
+
+    /**
+     * 设置状态栏字体图标为深色,需要 MIUIV6 以上
+     *
+     * @param window 需要设置的窗口
+     * @param dark   是否把状态栏字体及图标颜色设置为深色
+     * @return boolean 成功执行返回 true
+     */
+    @SuppressWarnings("unchecked")
+    public static boolean MIUISetStatusBarLightMode(Window window, boolean dark) {
+        boolean result = false;
+        if (window != null) {
+            Class clazz = window.getClass();
+            try {
+                int darkModeFlag;
+                Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
+                Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
+                darkModeFlag = field.getInt(layoutParams);
+                Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
+                if (dark) {
+                    extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
+                } else {
+                    extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
+                }
+                result = true;
+            } catch (Exception ignored) {
+
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 更改状态栏图标、文字颜色的方案是否是MIUI自家的, MIUI9之后用回Android原生实现
+     * 见小米开发文档说明:https://dev.mi.com/console/doc/detail?pId=1159
+     */
+    private static boolean isMIUICustomStatusBarLightModeImpl() {
+        return DeviceHelper.isMIUIV5() || DeviceHelper.isMIUIV6() ||
+                DeviceHelper.isMIUIV7() || DeviceHelper.isMIUIV8();
+    }
+
+    /**
+     * 设置状态栏图标为深色和魅族特定的文字风格
+     * 可以用来判断是否为 Flyme 用户
+     *
+     * @param window 需要设置的窗口
+     * @param dark   是否把状态栏字体及图标颜色设置为深色
+     * @return boolean 成功执行返回true
+     */
+    public static boolean FlymeSetStatusBarLightMode(Window window, boolean dark) {
+
+        // flyme 在 6.2.0.0A 支持了 Android 官方的实现方案,旧的方案失效
+        Android6SetStatusBarLightMode(window, dark);
+
+        boolean result = false;
+        if (window != null) {
+            try {
+                WindowManager.LayoutParams lp = window.getAttributes();
+                Field darkFlag = WindowManager.LayoutParams.class
+                        .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
+                Field meizuFlags = WindowManager.LayoutParams.class
+                        .getDeclaredField("meizuFlags");
+                darkFlag.setAccessible(true);
+                meizuFlags.setAccessible(true);
+                int bit = darkFlag.getInt(null);
+                int value = meizuFlags.getInt(lp);
+                if (dark) {
+                    value |= bit;
+                } else {
+                    value &= ~bit;
+                }
+                meizuFlags.setInt(lp, value);
+                window.setAttributes(lp);
+                result = true;
+            } catch (Exception ignored) {
+
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 获取是否全屏
+     *
+     * @return 是否全屏
+     */
+    public static boolean isFullScreen(Activity activity) {
+        boolean ret = false;
+        try {
+            WindowManager.LayoutParams attrs = activity.getWindow().getAttributes();
+            ret = (attrs.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return ret;
+    }
+
+    /**
+     * API19之前透明状态栏:获取设置透明状态栏的system ui visibility的值,这是部分有提供接口的rom使用的
+     * http://stackoverflow.com/questions/21865621/transparent-status-bar-before-4-4-kitkat
+     */
+    public static Integer getStatusBarAPITransparentValue(Context context) {
+        if (sTransparentValue != null) {
+            return sTransparentValue;
+        }
+        String[] systemSharedLibraryNames = context.getPackageManager()
+                .getSystemSharedLibraryNames();
+        String fieldName = null;
+        for (String lib : systemSharedLibraryNames) {
+            if ("touchwiz".equals(lib)) {
+                fieldName = "SYSTEM_UI_FLAG_TRANSPARENT_BACKGROUND";
+            } else if (lib.startsWith("com.sonyericsson.navigationbar")) {
+                fieldName = "SYSTEM_UI_FLAG_TRANSPARENT";
+            }
+        }
+
+        if (fieldName != null) {
+            try {
+                Field field = View.class.getField(fieldName);
+                if (field != null) {
+                    Class<?> type = field.getType();
+                    if (type == int.class) {
+                        sTransparentValue = field.getInt(null);
+                    }
+                }
+            } catch (Exception ignored) {
+            }
+        }
+        return sTransparentValue;
+    }
+
+    /**
+     * 检测 Android 6.0 是否可以启用 window.setStatusBarColor(Color.TRANSPARENT)。
+     */
+    public static boolean supportTransclentStatusBar6() {
+        return !(DeviceHelper.isZUKZ1() || DeviceHelper.isZTKC2016());
+    }
+
+    /**
+     * 获取状态栏的高度。
+     */
+    public static int getStatusbarHeight(Context context) {
+        if (sStatusbarHeight == -1) {
+            initStatusBarHeight(context);
+        }
+        return sStatusbarHeight;
+    }
+
+    private static void initStatusBarHeight(Context context) {
+        Class<?> clazz;
+        Object obj = null;
+        Field field = null;
+        try {
+            clazz = Class.forName("com.android.internal.R$dimen");
+            obj = clazz.newInstance();
+            if (DeviceHelper.isMeizu()) {
+                try {
+                    field = clazz.getField("status_bar_height_large");
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                }
+            }
+            if (field == null) {
+                field = clazz.getField("status_bar_height");
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+        if (field != null && obj != null) {
+            try {
+                int id = Integer.parseInt(field.get(obj).toString());
+                sStatusbarHeight = context.getResources().getDimensionPixelSize(id);
+            } catch (Throwable t) {
+                t.printStackTrace();
+            }
+        }
+        if (DeviceHelper.isTablet(context)
+                && sStatusbarHeight > DisplayHelper.dp2px(context, STATUS_BAR_DEFAULT_HEIGHT_DP)) {
+            //状态栏高度大于25dp的平板,状态栏通常在下方
+            sStatusbarHeight = 0;
+        } else {
+            if (sStatusbarHeight <= 0
+                    || sStatusbarHeight > DisplayHelper.dp2px(context, STATUS_BAR_DEFAULT_HEIGHT_DP * 2)) {
+                //安卓默认状态栏高度为25dp,如果获取的状态高度大于2倍25dp的话,这个数值可能有问题,用回桌面定义的值从新获取。出现这种可能性较低,只有小部分手机出现
+                if (sVirtualDensity == -1) {
+                    sStatusbarHeight = DisplayHelper.dp2px(context, STATUS_BAR_DEFAULT_HEIGHT_DP);
+                } else {
+                    sStatusbarHeight = (int) (STATUS_BAR_DEFAULT_HEIGHT_DP * sVirtualDensity + 0.5f);
+                }
+            }
+        }
+    }
+
+    public static void setVirtualDensity(float density) {
+        sVirtualDensity = density;
+    }
+
+    public static void setVirtualDensityDpi(float densityDpi) {
+        sVirtualDensityDpi = densityDpi;
+    }
+
+    @IntDef({STATUSBAR_TYPE_DEFAULT, STATUSBAR_TYPE_MIUI, STATUSBAR_TYPE_FLYME, STATUSBAR_TYPE_ANDROID6})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface StatusBarType {
+    }
+
+}

+ 63 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaButton.java

@@ -0,0 +1,63 @@
+package com.kfzs.libs.widget.alpha;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatButton;
+import android.util.AttributeSet;
+
+/**
+ * 在 pressed 和 disabled 时改变 View 的透明度
+ */
+public class AlphaButton extends AppCompatButton {
+
+    private AlphaViewHelper mAlphaViewHelper;
+
+    public AlphaButton(Context context) {
+        super(context);
+    }
+
+    public AlphaButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlphaButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    private AlphaViewHelper getAlphaViewHelper() {
+        if (mAlphaViewHelper == null) {
+            mAlphaViewHelper = new AlphaViewHelper(this);
+        }
+        return mAlphaViewHelper;
+    }
+
+    @Override
+    public void setPressed(boolean pressed) {
+        super.setPressed(pressed);
+        getAlphaViewHelper().onPressedChanged(this, pressed);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        getAlphaViewHelper().onEnabledChanged(this, enabled);
+    }
+
+    /**
+     * 设置是否要在 press 时改变透明度
+     *
+     * @param changeAlphaWhenPress 是否要在 press 时改变透明度
+     */
+    public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
+        getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
+    }
+
+    /**
+     * 设置是否要在 disabled 时改变透明度
+     *
+     * @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
+     */
+    public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
+        getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
+    }
+
+}

+ 62 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaFrameLayout.java

@@ -0,0 +1,62 @@
+package com.kfzs.libs.widget.alpha;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * 在 pressed 和 disabled 时改变 View 的透明度
+ */
+public class AlphaFrameLayout extends FrameLayout {
+
+    private AlphaViewHelper mAlphaViewHelper;
+
+    public AlphaFrameLayout(Context context) {
+        super(context);
+    }
+
+    public AlphaFrameLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlphaFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    private AlphaViewHelper getAlphaViewHelper() {
+        if (mAlphaViewHelper == null) {
+            mAlphaViewHelper = new AlphaViewHelper(this);
+        }
+        return mAlphaViewHelper;
+    }
+
+    @Override
+    public void setPressed(boolean pressed) {
+        super.setPressed(pressed);
+        getAlphaViewHelper().onPressedChanged(this, pressed);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        getAlphaViewHelper().onEnabledChanged(this, enabled);
+    }
+
+    /**
+     * 设置是否要在 press 时改变透明度
+     *
+     * @param changeAlphaWhenPress 是否要在 press 时改变透明度
+     */
+    public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
+        getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
+    }
+
+    /**
+     * 设置是否要在 disabled 时改变透明度
+     *
+     * @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
+     */
+    public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
+        getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
+    }
+}

+ 60 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaImageButton.java

@@ -0,0 +1,60 @@
+package com.kfzs.libs.widget.alpha;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatImageButton;
+import android.util.AttributeSet;
+
+public class AlphaImageButton extends AppCompatImageButton {
+
+    private AlphaViewHelper mAlphaViewHelper;
+
+    public AlphaImageButton(Context context) {
+        super(context);
+    }
+
+    public AlphaImageButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlphaImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    private AlphaViewHelper getAlphaViewHelper() {
+        if (mAlphaViewHelper == null) {
+            mAlphaViewHelper = new AlphaViewHelper(this);
+        }
+        return mAlphaViewHelper;
+    }
+
+    @Override
+    public void setPressed(boolean pressed) {
+        super.setPressed(pressed);
+        getAlphaViewHelper().onPressedChanged(this, pressed);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        getAlphaViewHelper().onEnabledChanged(this, enabled);
+    }
+
+    /**
+     * 设置是否要在 press 时改变透明度
+     *
+     * @param changeAlphaWhenPress 是否要在 press 时改变透明度
+     */
+    public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
+        getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
+    }
+
+    /**
+     * 设置是否要在 disabled 时改变透明度
+     *
+     * @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
+     */
+    public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
+        getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
+    }
+
+}

+ 60 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaImageView.java

@@ -0,0 +1,60 @@
+package com.kfzs.libs.widget.alpha;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatImageView;
+import android.util.AttributeSet;
+
+public class AlphaImageView extends AppCompatImageView {
+
+    private AlphaViewHelper mAlphaViewHelper;
+
+    public AlphaImageView(Context context) {
+        super(context);
+    }
+
+    public AlphaImageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlphaImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    private AlphaViewHelper getAlphaViewHelper() {
+        if (mAlphaViewHelper == null) {
+            mAlphaViewHelper = new AlphaViewHelper(this);
+        }
+        return mAlphaViewHelper;
+    }
+
+    @Override
+    public void setPressed(boolean pressed) {
+        super.setPressed(pressed);
+        getAlphaViewHelper().onPressedChanged(this, pressed);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        getAlphaViewHelper().onEnabledChanged(this, enabled);
+    }
+
+    /**
+     * 设置是否要在 press 时改变透明度
+     *
+     * @param changeAlphaWhenPress 是否要在 press 时改变透明度
+     */
+    public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
+        getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
+    }
+
+    /**
+     * 设置是否要在 disabled 时改变透明度
+     *
+     * @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
+     */
+    public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
+        getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
+    }
+
+}

+ 63 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaLinearLayout.java

@@ -0,0 +1,63 @@
+package com.kfzs.libs.widget.alpha;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+/**
+ * 在 pressed 和 disabled 时改变 View 的透明度
+ */
+public class AlphaLinearLayout extends LinearLayout {
+
+    private AlphaViewHelper mAlphaViewHelper;
+
+    public AlphaLinearLayout(Context context) {
+        super(context);
+    }
+
+    public AlphaLinearLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlphaLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    private AlphaViewHelper getAlphaViewHelper() {
+        if (mAlphaViewHelper == null) {
+            mAlphaViewHelper = new AlphaViewHelper(this);
+        }
+        return mAlphaViewHelper;
+    }
+
+    @Override
+    public void setPressed(boolean pressed) {
+        super.setPressed(pressed);
+        getAlphaViewHelper().onPressedChanged(this, pressed);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        getAlphaViewHelper().onEnabledChanged(this, enabled);
+    }
+
+    /**
+     * 设置是否要在 press 时改变透明度
+     *
+     * @param changeAlphaWhenPress 是否要在 press 时改变透明度
+     */
+    public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
+        getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
+    }
+
+    /**
+     * 设置是否要在 disabled 时改变透明度
+     *
+     * @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
+     */
+    public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
+        getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
+    }
+
+}

+ 63 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaRelativeLayout.java

@@ -0,0 +1,63 @@
+package com.kfzs.libs.widget.alpha;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+
+/**
+ * 在 pressed 和 disabled 时改变 View 的透明度
+ */
+public class AlphaRelativeLayout extends RelativeLayout {
+
+    private AlphaViewHelper mAlphaViewHelper;
+
+    public AlphaRelativeLayout(Context context) {
+        super(context);
+    }
+
+    public AlphaRelativeLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlphaRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    private AlphaViewHelper getAlphaViewHelper() {
+        if (mAlphaViewHelper == null) {
+            mAlphaViewHelper = new AlphaViewHelper(this);
+        }
+        return mAlphaViewHelper;
+    }
+
+    @Override
+    public void setPressed(boolean pressed) {
+        super.setPressed(pressed);
+        getAlphaViewHelper().onPressedChanged(this, pressed);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        getAlphaViewHelper().onEnabledChanged(this, enabled);
+    }
+
+    /**
+     * 设置是否要在 press 时改变透明度
+     *
+     * @param changeAlphaWhenPress 是否要在 press 时改变透明度
+     */
+    public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
+        getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
+    }
+
+    /**
+     * 设置是否要在 disabled 时改变透明度
+     *
+     * @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
+     */
+    public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
+        getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
+    }
+
+}

+ 62 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaTextView.java

@@ -0,0 +1,62 @@
+package com.kfzs.libs.widget.alpha;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatTextView;
+import android.util.AttributeSet;
+
+/**
+ * 在 pressed 和 disabled 时改变 View 的透明度
+ */
+public class AlphaTextView extends AppCompatTextView {
+
+    private AlphaViewHelper mAlphaViewHelper;
+
+    public AlphaTextView(Context context) {
+        super(context);
+    }
+
+    public AlphaTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlphaTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    private AlphaViewHelper getAlphaViewHelper() {
+        if (mAlphaViewHelper == null) {
+            mAlphaViewHelper = new AlphaViewHelper(this);
+        }
+        return mAlphaViewHelper;
+    }
+
+    @Override
+    public void setPressed(boolean pressed) {
+        super.setPressed(pressed);
+        getAlphaViewHelper().onPressedChanged(this, pressed);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        getAlphaViewHelper().onEnabledChanged(this, enabled);
+    }
+
+    /**
+     * 设置是否要在 press 时改变透明度
+     *
+     * @param changeAlphaWhenPress 是否要在 press 时改变透明度
+     */
+    public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
+        getAlphaViewHelper().setChangeAlphaWhenPress(changeAlphaWhenPress);
+    }
+
+    /**
+     * 设置是否要在 disabled 时改变透明度
+     *
+     * @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
+     */
+    public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
+        getAlphaViewHelper().setChangeAlphaWhenDisable(changeAlphaWhenDisable);
+    }
+}

+ 67 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/alpha/AlphaViewHelper.java

@@ -0,0 +1,67 @@
+package com.kfzs.libs.widget.alpha;
+
+import android.support.annotation.NonNull;
+import android.view.View;
+
+public class AlphaViewHelper {
+
+    private View mTarget;
+
+    /**
+     * 设置是否要在 press 时改变透明度
+     */
+    private boolean mChangeAlphaWhenPress = true;
+
+    /**
+     * 设置是否要在 disabled 时改变透明度
+     */
+    private boolean mChangeAlphaWhenDisable = true;
+
+    private float mNormalAlpha = 1f;
+    private float mPressedAlpha = 0.5f;
+    private float mDisabledAlpha = 0.5f;
+
+    public AlphaViewHelper(@NonNull View target) {
+        mTarget = target;
+    }
+
+    public void onPressedChanged(View target, boolean pressed) {
+        if (mTarget.isEnabled()) {
+            mTarget.setAlpha(mChangeAlphaWhenPress && pressed && target.isClickable()? mPressedAlpha : mNormalAlpha);
+        } else {
+            if (mChangeAlphaWhenDisable) {
+                target.setAlpha(mDisabledAlpha);
+            }
+        }
+    }
+
+    public void onEnabledChanged(View target, boolean enabled) {
+        float alphaForIsEnable;
+        if (mChangeAlphaWhenDisable) {
+            alphaForIsEnable = enabled ? mNormalAlpha : mDisabledAlpha;
+        } else {
+            alphaForIsEnable = mNormalAlpha;
+        }
+        target.setAlpha(alphaForIsEnable);
+    }
+
+    /**
+     * 设置是否要在 press 时改变透明度
+     *
+     * @param changeAlphaWhenPress 是否要在 press 时改变透明度
+     */
+    public void setChangeAlphaWhenPress(boolean changeAlphaWhenPress) {
+        mChangeAlphaWhenPress = changeAlphaWhenPress;
+    }
+
+    /**
+     * 设置是否要在 disabled 时改变透明度
+     *
+     * @param changeAlphaWhenDisable 是否要在 disabled 时改变透明度
+     */
+    public void setChangeAlphaWhenDisable(boolean changeAlphaWhenDisable) {
+        mChangeAlphaWhenDisable = changeAlphaWhenDisable;
+        onEnabledChanged(mTarget, mTarget.isEnabled());
+    }
+
+}

+ 37 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/grouplist/GroupItem.java

@@ -0,0 +1,37 @@
+package com.kfzs.libs.widget.grouplist;
+
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.StringRes;
+
+/**
+ * Created by Administrator on 2017/11/23 0023.
+ */
+interface GroupItem {
+
+    GroupItem itemBackground(@DrawableRes int drawable);
+    GroupItem imageView(Drawable drawable);
+    GroupItem imageView(@DrawableRes int drawable);
+
+    GroupItem titleText(String text);
+    GroupItem subTitleText(String text);
+    GroupItem detailText(String text);
+
+    GroupItem titleText(@StringRes int text);
+    GroupItem subTitleText(@StringRes int text);
+    GroupItem detailText(@StringRes int text);
+
+    GroupItem titleTextSize(int unit, float size);
+    GroupItem subTitleTextSize(int unit, float size);
+    GroupItem detailTextSize(int unit, float size);
+
+    GroupItem titleTextSize(float size);
+    GroupItem subTitleTextSize(float size);
+    GroupItem detailTextSize(float size);
+
+    GroupItem titleTextColor(@ColorRes int color);
+    GroupItem subTitleTextColor(@ColorRes int color);
+    GroupItem detailTextColor(@ColorRes int color);
+
+}

+ 38 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/grouplist/GroupListHeaderView.java

@@ -0,0 +1,38 @@
+package com.kfzs.libs.widget.grouplist;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatTextView;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+
+/**
+ * Created by Administrator on 2017/10/9 0009.
+ */
+class GroupListHeaderView extends AppCompatTextView {
+    public GroupListHeaderView(Context context) {
+        this(context,null);
+    }
+
+    public GroupListHeaderView(Context context, AttributeSet attrs) {
+        this(context,attrs,0);
+    }
+
+    public GroupListHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context,attrs,defStyleAttr);
+    }
+
+
+    private void init(Context context, AttributeSet attrs, int defStyleAttr){
+        setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
+        setSingleLine(true);
+        setEllipsize(TextUtils.TruncateAt.END);
+    }
+
+
+
+
+
+
+}

+ 293 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/grouplist/GroupListItemAccessoryView.java

@@ -0,0 +1,293 @@
+package com.kfzs.libs.widget.grouplist;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.ViewCompat;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.kfzs.libs.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Created by Administrator on 2017/11/22 0022.
+ */
+
+public class GroupListItemAccessoryView extends LinearLayout implements GroupItem{
+
+    private ImageView mImageView;
+    private TextView mTitleView;
+    private TextView mSubTitleView;
+    private TextView mDetailView;
+    private ViewGroup mAccessoryView;
+    protected CheckBox mSwitchView;
+    protected ImageView mArrowView;
+
+
+    public GroupListItemAccessoryView(Context context) {
+        this(context,null);
+    }
+
+    public GroupListItemAccessoryView(Context context, AttributeSet attrs) {
+        this(context,attrs, 0);
+    }
+
+    public GroupListItemAccessoryView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context,attrs,defStyleAttr);
+    }
+
+    private void init(Context context, AttributeSet attrs, int defStyleAttr){
+        LayoutInflater.from(context).inflate(R.layout.grouplist_item_view, this, true);
+        initWidget();
+
+        setMinimumHeight(getResources().getDimensionPixelSize(R.dimen.gx_groupList_item_minHeight));
+        setGravity(Gravity.CENTER_VERTICAL);
+
+        Drawable drawable  = ContextCompat.getDrawable(context,R.drawable.s_item_bg_double_border);
+        if(Build.VERSION.SDK_INT >= 16){
+            setBackground(drawable);
+        }
+        else setBackgroundDrawable(drawable);
+    }
+
+    private void initWidget(){
+        mImageView = (ImageView) findViewById(R.id.gx_groupList_item_imageView);
+        mTitleView = (TextView) findViewById(R.id.gx_groupList_item_titleTextView);
+        mSubTitleView = (TextView) findViewById(R.id.gx_groupList_item_subTitleTextView);
+        mDetailView = (TextView) findViewById(R.id.gx_groupList_item_detailTextView);
+        mAccessoryView = (ViewGroup) findViewById(R.id.gx_groupList_item_accessoryView);
+    }
+
+
+    public GroupListItemAccessoryView accessoryArrow(){
+        setAccessoryType(ACCESSORY_TYPE_ARROW);
+        return this;
+    }
+
+    public GroupListItemAccessoryView accessoryArrow(Drawable drawable){
+        setAccessoryType(ACCESSORY_TYPE_ARROW);
+        arrowDrawable(drawable);
+        return this;
+    }
+
+    public GroupListItemAccessoryView accessoryArrow(@DrawableRes int drawable){
+        setAccessoryType(ACCESSORY_TYPE_ARROW);
+        arrowDrawable(drawable);
+        return this;
+    }
+
+    public GroupListItemAccessoryView accessorySwitch(){
+        setAccessoryType(ACCESSORY_TYPE_SWITCH);
+        return this;
+    }
+
+    public GroupListItemAccessoryView accessorySwitch(@DrawableRes int drawable){
+        setAccessoryType(ACCESSORY_TYPE_SWITCH);
+        switchDrawable(drawable);
+        return this;
+    }
+
+    private void arrowDrawable(Drawable drawable) {
+        mArrowView.setImageDrawable(drawable);
+    }
+
+    private void arrowDrawable(@DrawableRes int drawable) {
+        mArrowView.setImageResource(drawable);
+    }
+
+    private void switchDrawable(@DrawableRes int drawable) {
+        mSwitchView.setButtonDrawable(drawable);
+    }
+
+
+    @Override
+    public GroupListItemAccessoryView itemBackground(@DrawableRes int drawable) {
+        ViewCompat.setBackground(this, ContextCompat.getDrawable(getContext(), drawable));
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView imageView(@NonNull Drawable drawable) {
+        mImageView.setImageDrawable(drawable);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView imageView(@DrawableRes int drawable) {
+        mImageView.setImageResource(drawable);
+        return this;
+    }
+
+
+    @Override
+    public GroupListItemAccessoryView titleText(String text) {
+        mTitleView.setText(text);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView subTitleText(String text) {
+        if(!TextUtils.isEmpty(text)){
+            mSubTitleView.setText(text);
+            mSubTitleView.setVisibility(VISIBLE);
+        }
+        else mSubTitleView.setVisibility(GONE);
+
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView detailText(String text) {
+        mDetailView.setText(text);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView titleText(@StringRes int text) {
+        mTitleView.setText(text);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView subTitleText(@StringRes int text) {
+        String str = getResources().getString(text);
+       return subTitleText(str);
+    }
+
+    @Override
+    public GroupListItemAccessoryView detailText(@StringRes int text) {
+        mDetailView.setText(text);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView titleTextSize(int unit, float size) {
+        mTitleView.setTextSize(unit,size);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView subTitleTextSize(int unit, float size) {
+        mSubTitleView.setTextSize(unit,size);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView detailTextSize(int unit, float size) {
+        mDetailView.setTextSize(unit,size);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView titleTextSize(float size) {
+        mTitleView.setTextSize(size);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView subTitleTextSize(float size) {
+        mSubTitleView.setTextSize(size);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView detailTextSize(float size) {
+        mDetailView.setTextSize(size);
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView titleTextColor(@ColorRes int color) {
+        mTitleView.setTextColor(ContextCompat.getColor(getContext(), color));
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView subTitleTextColor(@ColorRes int color) {
+        mSubTitleView.setTextColor(ContextCompat.getColor(getContext(), color));
+        return this;
+    }
+
+    @Override
+    public GroupListItemAccessoryView detailTextColor(@ColorRes int color) {
+        mDetailView.setTextColor(ContextCompat.getColor(getContext(), color));
+        return this;
+    }
+
+
+    private ViewGroup.LayoutParams getAccessoryLayoutParams() {
+        return new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+    }
+
+
+    private void setAccessoryType(@AccessoryViewType int type){
+        mAccessoryView.removeAllViews();
+        switch (type){
+            case ACCESSORY_TYPE_ARROW:
+                if(mArrowView == null){
+                    mArrowView = new ImageView(getContext());
+                    mArrowView.setLayoutParams(getAccessoryLayoutParams());
+                }
+                mAccessoryView.addView(mArrowView);
+                break;
+            case ACCESSORY_TYPE_SWITCH:
+                if(mSwitchView == null){
+                    mSwitchView = new CheckBox(getContext());
+                    mSwitchView.setLayoutParams(getAccessoryLayoutParams());
+                    // disable掉且不可点击,然后通过整个item的点击事件来toggle开关的状态
+                    mSwitchView.setClickable(false);
+                }
+                mAccessoryView.addView(mSwitchView);
+                break;
+        }
+
+    }
+
+    public void toggleSwitch(){
+        if(mSwitchView != null){
+            mSwitchView.toggle();
+        }
+    }
+
+
+//    /**
+//     * 右侧不显示任何东西
+//     */
+//    public final static int ACCESSORY_TYPE_NONE = 0;
+    /**
+     * 右侧显示一个箭头
+     */
+    public final static int ACCESSORY_TYPE_ARROW = 1;
+    /**
+     * 右侧显示一个开关
+     */
+    public final static int ACCESSORY_TYPE_SWITCH = 2;
+//    /**
+//     * 自定义右侧显示的 View
+//     */
+//    public final static int ACCESSORY_TYPE_CUSTOM = 3;
+
+//    @IntDef({ACCESSORY_TYPE_NONE, ACCESSORY_TYPE_ARROW, ACCESSORY_TYPE_SWITCH, ACCESSORY_TYPE_CUSTOM})
+    @IntDef({ACCESSORY_TYPE_ARROW, ACCESSORY_TYPE_SWITCH})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AccessoryViewType{}
+
+
+}

+ 210 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/grouplist/GroupListView.java

@@ -0,0 +1,210 @@
+package com.kfzs.libs.widget.grouplist;
+
+import android.content.Context;
+import android.support.annotation.ColorRes;
+import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.ViewCompat;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.kfzs.libs.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Created by Administrator on 2017/10/9 0009.
+ */
+
+public class GroupListView extends LinearLayout {
+
+    public static final String TAG = "GroupListView";
+
+
+    public static final int SEPARATOR_STYLE_NORMAL = 0;
+    public static final int SEPARATOR_STYLE_NONE = 1;
+    private int mSeparatorStyle = SEPARATOR_STYLE_NORMAL;
+    private SparseArray<Section> mSections;
+
+    public GroupListView(Context context) {
+        this(context,null);
+    }
+
+    public GroupListView(Context context, @Nullable AttributeSet attrs) {
+        this(context,attrs, 0);
+    }
+
+    public GroupListView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context,attrs,defStyleAttr);
+    }
+
+
+    protected void init(Context context, AttributeSet attrs, int defStyleAttr){
+        mSections = new SparseArray<Section>();
+        setOrientation(VERTICAL);
+    }
+
+    public void setSeparatorStyle(@SeparatorStyle int separatorStyle) {
+        mSeparatorStyle = separatorStyle;
+    }
+
+    private void addSection(Section section){
+        mSections.append(mSections.size(),section);
+    }
+
+    private void removeSection(Section section) {
+        for (int i = 0; i < mSections.size(); i++) {
+            Section each = mSections.valueAt(i);
+            if (each == section) {
+                mSections.remove(i);
+            }
+        }
+    }
+    public Section getSection(int index) {
+        return mSections.get(index);
+    }
+
+    public @SeparatorStyle int getSeparatorStyle() {
+        return mSeparatorStyle;
+    }
+
+    public static class Section{
+
+        private SparseArray<View> mItemViews;
+        private Context mContext;
+        private String mTitle = "";
+        private int mHeaderHeight;
+        private int mHeaderTextSize;
+        private int mUnit = TypedValue.COMPLEX_UNIT_PX;
+        private int mHeaderTextColor;
+        private int mPadding;
+
+        private int mSeparatorDrawableForSingle = 0;
+        private int mSeparatorDrawableForTop = 0;
+        private int mSeparatorDrawableForBottom = 0;
+        private int mSeparatorDrawableForMiddle = 0;
+
+        public Section(Context context){
+            mContext = context;
+            mItemViews = new SparseArray<View>();
+            mPadding = context.getResources().getDimensionPixelOffset(R.dimen.gx_groupList_item_horizontalPadding);
+            mHeaderHeight = context.getResources().getDimensionPixelOffset(R.dimen.gx_groupList_item_headerHeight);
+            mHeaderTextSize = (int) context.getResources().getDimension(R.dimen.gx_groupList_item_header_textSize);
+            mHeaderTextColor = ContextCompat.getColor(mContext,R.color.gx_groupList_item_header_textColor);
+        }
+
+        public Section headerTitle(String title){
+            mTitle = title;
+            return this;
+        }
+
+        public Section headerTextSize(int size){
+            mHeaderTextSize = size;
+            return this;
+        }
+
+        public Section headerTextSize(int unit,int size){
+            mUnit = unit;
+            mHeaderTextSize = size;
+            return this;
+        }
+
+        public Section headerTextColor(@ColorRes int color){
+            mHeaderTextColor = ContextCompat.getColor(mContext, color);
+            return this;
+        }
+
+        public Section headerHeight(int height){
+            mHeaderHeight = height;
+            return this;
+        }
+
+        public Section itemPadding(int padding){
+            mPadding = padding;
+            return this;
+        }
+
+        public Section addItemView(GroupItem itemView){
+            mItemViews.append(mItemViews.size(), (View) itemView);
+            return this;
+        }
+
+        public void attachToGroupListView(GroupListView groupListView){
+
+            attachHeaderView(groupListView);
+
+            if (groupListView.getSeparatorStyle() == SEPARATOR_STYLE_NORMAL) {
+                if (mSeparatorDrawableForSingle == 0) {
+                    mSeparatorDrawableForSingle = R.drawable.s_item_bg_double_border;
+                }
+                if (mSeparatorDrawableForTop == 0) {
+                    mSeparatorDrawableForTop = R.drawable.s_item_bg_double_border;
+                }
+
+                if (mSeparatorDrawableForBottom == 0) {
+                    mSeparatorDrawableForBottom = R.drawable.s_list_item_bg_bottom_border;
+                }
+
+                if (mSeparatorDrawableForMiddle == 0) {
+                    mSeparatorDrawableForMiddle = R.drawable.s_list_item_bg_bottom_border;
+                }
+            }
+
+            int itemCount = mItemViews.size();
+            for(int i=0;i<itemCount;i++){
+                View itemView = mItemViews.get(i);
+                int resDrawableId;
+                if (groupListView.getSeparatorStyle() == SEPARATOR_STYLE_NORMAL) {
+                    if (itemCount == 1) {
+                        resDrawableId = mSeparatorDrawableForSingle;
+                    } else if (i == 0) {
+                        resDrawableId = mSeparatorDrawableForTop;
+                    } else if (i == itemCount - 1) {
+                        resDrawableId = mSeparatorDrawableForBottom;
+                    } else {
+                        resDrawableId = mSeparatorDrawableForMiddle;
+                    }
+                } else {
+                    resDrawableId = R.drawable.s_list_item_bg_none_border;
+                }
+
+                ViewCompat.setBackground(itemView, ContextCompat.getDrawable(mContext,resDrawableId));
+                int[] padding = new int[]{mPadding, itemView.getPaddingTop(), mPadding, itemView.getPaddingBottom()};
+                itemView.setPadding(padding[0], padding[1], padding[2], padding[3]);
+                groupListView.addView(itemView);
+            }
+
+            groupListView.addSection(this);
+
+        }
+
+        private void attachHeaderView(GroupListView groupListView){
+            GroupListHeaderView headerView = new GroupListHeaderView(mContext);
+            headerView.setTextSize(mUnit,mHeaderTextSize);
+            headerView.setTextColor(mHeaderTextColor);
+            headerView.setPadding(mPadding, headerView.getPaddingTop(), mPadding, headerView.getPaddingBottom());
+            LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,mHeaderHeight);
+            headerView.setLayoutParams(params);
+            if(!TextUtils.isEmpty(mTitle)){
+                headerView.setText(mTitle);
+            }
+            groupListView.addView(headerView);
+        }
+
+
+    }
+
+
+
+    @IntDef({SEPARATOR_STYLE_NORMAL, SEPARATOR_STYLE_NONE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SeparatorStyle {
+    }
+}

+ 211 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/Loader.java

@@ -0,0 +1,211 @@
+package com.kfzs.libs.widget.loading;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import com.kfzs.libs.widget.loading.viewport.ShowingViewport;
+import com.kfzs.libs.widget.loading.viewport.SuccessViewport;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * loading事件构造类
+ * Created by Administrator on 2017/9/26 0026.
+ */
+
+public final class Loader {
+
+    private Builder mBuilder;
+
+    private Loader(Builder builder){
+        mBuilder = builder;
+    }
+
+    public int getKey(){
+        return mBuilder.getTarget().hashCode();
+    }
+
+    public void showViewport(Class<? extends ShowingViewport> cls){
+        mBuilder.showViewport(cls);
+    }
+
+    public LoadingLayout getLoadLayout(){
+        return mBuilder.getLoadingLayout();
+    }
+
+    public void clear(){
+        mBuilder.clearReference();
+    }
+
+    /**
+     * 数据构建类
+     */
+    public static class Builder{
+
+        private WeakReference<Object> mObjectWeakReference;
+        private LoadingLayout mLoadingLayout;
+        private TargetContext mTargetContext;
+        private Class<? extends ShowingViewport> mDefaultViewportClass;
+
+        public Builder(View view){
+            mObjectWeakReference = new WeakReference<>((Object)view);
+            mTargetContext = getTargetContext(view);
+            mLoadingLayout = new LoadingLayout(mTargetContext);
+            mLoadingLayout.setObjectWeakReference(mObjectWeakReference);
+        }
+
+        public Builder(Activity activity){
+            mObjectWeakReference = new WeakReference<>((Object) activity);
+            mTargetContext = getTargetContext(activity);
+            mLoadingLayout = new LoadingLayout(mTargetContext);
+            mLoadingLayout.setObjectWeakReference(mObjectWeakReference);
+        }
+
+        public Builder(SupportLoadingFragment fragment){
+            mObjectWeakReference = new WeakReference<>((Object)fragment);
+            mTargetContext = getTargetContext(fragment);
+            mLoadingLayout = new LoadingLayout(mTargetContext);
+            mLoadingLayout.setObjectWeakReference(mObjectWeakReference);
+        }
+
+        public void clearReference(){
+            mLoadingLayout = null;
+            mObjectWeakReference.clear();
+        }
+
+        public Builder addViewport(ShowingViewport viewport){
+            if(viewport != null){
+                mLoadingLayout.addShowingViewport(viewport);
+            }
+            return this;
+        }
+
+
+        public Builder setDefaultViewport(Class<? extends ShowingViewport> defaultViewportClass){
+            mDefaultViewportClass = defaultViewportClass;
+            return this;
+        }
+
+//        public Builder setOnReloadListener(ShowingViewport.OnReloadListener onReloadListener){
+//            mLoadingLayout.setOnReloadListener(onReloadListener);
+//            return this;
+//        }
+
+        public Object getTarget() {
+            return mObjectWeakReference.get();
+        }
+
+        public Loader build(){
+            mLoadingLayout.setSuccessViewport(
+                    new SuccessViewport(
+                            mTargetContext.getContext(),
+                            mTargetContext.getOldContent(),
+                            null
+                    )
+            );
+            if (mTargetContext.getParentView() != null) {//不为空时,替换的target为Activity和xml中的View
+
+                if(mObjectWeakReference.get() != null && mObjectWeakReference.get() instanceof Activity){
+                    mTargetContext.getParentView()
+                            .addView(
+                                    mLoadingLayout,
+                                    mTargetContext.getChildIndex(),
+                                    mTargetContext.getOldContent().getLayoutParams()
+                            );
+                    mTargetContext.getParentView()
+                            .addView(
+                                    mTargetContext.getOldContent(),
+                                    mTargetContext.getChildIndex() + 1,
+                                    mTargetContext.getOldContent().getLayoutParams()
+                            );
+                    mTargetContext.getOldContent().setVisibility(View.GONE);
+                }
+                else {
+                    //为xml中的View时,考虑到RelativeLayout和ConstraintLayout这种,
+                    // xml中的View需要依靠某些View的Id来确定相对位置,因此必须将替换的View的Id设置为当前替换目标的Id,
+                    // 不然依赖的View,找不到该Id就会使得界面上的布局显示错乱
+                    mLoadingLayout.setId(mTargetContext.getOldContentId());
+                    mTargetContext.getParentView()
+                            .addView(
+                                    mLoadingLayout,
+                                    mTargetContext.getChildIndex(),
+                                    mTargetContext.getOldContent().getLayoutParams()
+                            );
+                }
+
+            }
+
+
+            if(mDefaultViewportClass != null){
+                mLoadingLayout.replaceWithViewport(mDefaultViewportClass);
+            }
+            else mLoadingLayout.replaceWithViewport(SuccessViewport.class);
+
+            return new Loader(this);
+        }
+
+
+        public void showViewport(Class<? extends ShowingViewport> cls){
+            mLoadingLayout.replaceWithViewport(cls);
+        }
+
+        public LoadingLayout getLoadingLayout() {
+            return mLoadingLayout;
+        }
+    }
+
+
+    private static TargetContext getTargetContext(Object target) {
+        ViewGroup contentParent;
+        Context context;
+        if (target instanceof Activity) {
+            Activity activity = (Activity) target;
+            context = activity;
+            contentParent = (ViewGroup) activity.findViewById(android.R.id.content);
+        } else if (target instanceof View) {
+            View view = (View) target;
+            contentParent = (ViewGroup) (view.getParent());
+            context = view.getContext();
+        }
+        else if(target instanceof SupportLoadingFragment){
+            SupportLoadingFragment fragment = (SupportLoadingFragment) target;
+            View view = fragment.getView();
+            contentParent = (ViewGroup) view;
+            context = fragment.getContext();
+        }
+        else {
+            throw new IllegalArgumentException("The target must be within Activity, SupportLoadingFragment, View.");
+        }
+        int childIndex = 0;
+        int childCount = contentParent == null ? 0 : contentParent.getChildCount();
+        View oldContent;
+        if (target instanceof View) {
+            oldContent = (View) target;
+            for (int i = 0; i < childCount; i++) {
+                if (contentParent.getChildAt(i) == oldContent) {
+                    childIndex = i;
+                    break;
+                }
+            }
+        } else {
+            oldContent = contentParent != null ? contentParent.getChildAt(0) : null;
+        }
+        if (oldContent == null) {
+            throw new IllegalArgumentException(String.format("unexpected error when register LoadHelper in %s", target
+                    .getClass().getSimpleName()));
+        }
+
+        int oldContentId = oldContent.getId();
+
+        if (contentParent != null) {
+            contentParent.removeView(oldContent);
+        }
+
+        return new TargetContext(context, contentParent, oldContent, oldContentId, childIndex);
+    }
+
+
+
+}

+ 319 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/LoadingHelper.java

@@ -0,0 +1,319 @@
+package com.kfzs.libs.widget.loading;
+
+import android.app.Activity;
+import android.support.annotation.NonNull;
+import android.util.SparseArray;
+import android.view.View;
+
+import com.kfzs.libs.widget.loading.viewport.ShowingViewport;
+import com.kfzs.libs.widget.loading.viewport.SuccessViewport;
+
+/**
+ * 界面或者View,任何一处都可以使用的加载辅助类,
+ * 该类使用方便,无侵入,可以全局设置(已经去掉相关代码,暂时不支持),也可以在具体的界面或某个具体View上设置。
+ * Created by Administrator on 2017/9/26 0026.
+ */
+
+/**
+ * 基本用法举例如下:
+ * 第一步:创建需要显示的ShowingViewport类。
+ * LoadingViewport loadingViewport = new LoadingViewport();
+ * ErrorViewport errorViewport = new ErrorViewport();
+ * errorViewport.setOnReloadListener(
+ *          new ShowingViewport.OnReloadListener() {
+ *              @Override
+ *              public void onReload(View v) {
+ *
+ *              }
+ *          }
+ * );
+ * 注:LoadingViewport为继承自ShowingViewport的类,表示正在加载状态的视图,ErrorViewport为继承自ShowingViewport的类,表示加载错误的视图状态,
+ * setOnReloadListener表示设置重新加载时候的回调,ErrorViewport中具体哪个控件能够响应该回调,需要在对象的initRetry中配置。
+ * 第二步:构建一个Loader对象,用来添加loading事件的各种视图状态,还有loading的目标对象。
+ * 注:Builder构造方法中传入的就是loading的目标对象,例子中传入的是Activity,也可以是某个Fragment或者View。addViewport是添加一种会用到的视图状态,setDefaultViewport是设置默认显示的视图状态。
+ * Loader loader =new Loader.Builder(MainActivity.this).addViewport(loadingViewport).addViewport(errorViewport).setDefaultViewport(LoadingViewport.class).build();
+ *第三步:注册loading事件,并且绑定Loader对象。
+ *LoadingHelper.getHelper().register(MainActivity.this, loader);
+ * 第四步:通过LoadingHelper对象,根据业务逻辑,可以随意切换视图状态,例如:
+ * 显示成功状态: LoadingHelper.getHelper().showSuccess(MainActivity.this);
+ * 显示当前自定义好的错误状态:LoadingHelper.getHelper().showViewport(MainActivity.this,ErrorViewport.class);
+ * 如果有其他状态,需要先自定义,然后根据显示错误状态的类似代码进行显示,如果要显示某种状态,必须在Loader中先添加该状态的实例对象,否则无法找到。
+ * 第五步:注销loading事件,并将目标绑定的Loader对象从LoadingHelper单例中移除。
+ *  LoadingHelper.getHelper().unRegister(MainActivity.this);
+ *  注释:(1)如果是在Activity中注册Activity和View的loading事件,前四步可以在onCreate中调用,
+ *  但如果是在Fragment中注册Fragment和View的loading事件,需要在onCreateView完成之后才能调用,因为只有onCreateView方法完成后,
+ *  Fragment才会有根视图,可在Fragment的onViewCreated中完成前四步。第五步需要在Activity和Fragment的onDestroy方法和onDestroyView方法中调用。
+ * (2)使用loading事件的目标对象,即Activity,Fragment,View三种,不能够修改hashcode的默认方法,因为注册loading事件对应绑定的loader对象,就是通过hash值来确定唯一性的。
+ */
+
+public final class LoadingHelper {
+
+    private static volatile LoadingHelper sHelper;
+
+    private SparseArray<Loader> mLoaders;
+//    private Settings mDefaultSettings;
+
+
+    private LoadingHelper(){
+        mLoaders = new SparseArray<Loader>();
+
+    }
+    public static LoadingHelper getHelper(){
+
+        if(sHelper == null){
+            synchronized (LoadingHelper.class){
+                if(sHelper == null){
+                    sHelper = new LoadingHelper();
+                }
+            }
+        }
+        return sHelper;
+    }
+
+//    public Settings defaultSettings(){
+//        return new Settings();
+//    }
+//
+//    void setDefaultSettings(Settings settings){
+//        mDefaultSettings = settings;
+//    }
+
+
+    /**
+     * 通过全局配置好的统一Loader,进行Loading事件,该方法使用的前提,必须全局配置过Settings类
+     * @param target
+     * @param onReloadListener
+     * @return
+     */
+//    public LoadingHelper registerWithDefault(@NonNull Object target, ShowingViewport.OnReloadListener onReloadListener){
+//        Loader loader =
+//                getDefaultBuilder(target,mDefaultSettings)
+////                        .setOnReloadListener(onReloadListener)
+//                        .build();
+//        registerLoader(target,loader);
+//        return getHelper();
+//    }
+
+    /**
+     * 注册Loading事件
+     * @param target 只能是Activity,SupportLoadingFragment,View的子类
+     * @param loader 封装loading数据的对象
+     * @return LoadingHelper加载单例助手
+     */
+    private LoadingHelper registerLoader(@NonNull Object target, Loader loader){
+        targetLegal(target);
+        mLoaders.put(loader.getKey(),loader);
+        return getHelper();
+    }
+    /**
+     *注销Loading事件,这里传入的ta
+     * @param target 只能是Activity,SupportLoadingFragment,View的子类,并且这里的target必须与调用register注册的target是同一个对象
+     */
+    private void unRegisterLoader(@NonNull Object target){
+        if(target != null){
+            targetLegal(target);
+            int hashCode = target.hashCode();
+            mLoaders.get(hashCode).clear();
+            mLoaders.delete(hashCode);
+        }
+    }
+
+    public LoadingHelper register(@NonNull View view, Loader loader){
+        return registerLoader(view,loader);
+    }
+
+    public LoadingHelper register(@NonNull Activity activity,Loader loader){
+        return registerLoader(activity,loader);
+    }
+
+    public LoadingHelper register(@NonNull SupportLoadingFragment fragment, Loader loader){
+        return registerLoader(fragment,loader);
+    }
+
+    public void unRegister(@NonNull Activity activity){
+        unRegisterLoader(activity);
+    }
+
+    public void unRegister(@NonNull SupportLoadingFragment fragment){
+        unRegisterLoader(fragment);
+    }
+
+    public void unRegister(@NonNull View view){
+        unRegisterLoader(view);
+    }
+
+    /**
+     *获取loading时候的LoadingLayout
+     * @param target  该target必须传入与注册时候的target是同一个对象
+     * @return
+     */
+    public LoadingLayout getLoadLayout(@NonNull Object target){
+        return getLoader(target).getLoadLayout();
+    }
+
+    /**
+     * 获取当前拥有的Loader数量
+     * @return
+     */
+    public int getLoaderSize(){
+        return mLoaders.size();
+    }
+
+
+    /**
+     * 显示某个ShowingViewport视图
+     * @param target  注册时候对应的target
+     * @param viewport ShowingViewport视图class类型
+     */
+    private void showViewportUI(@NonNull Object target, Class<? extends ShowingViewport> viewport){
+        targetLegal(target);
+        Loader loader = getLoader(target);
+        if(loader != null){
+            loader.showViewport(viewport);
+        }
+    }
+
+    public void showViewport(@NonNull Activity activity, Class<? extends ShowingViewport> viewport){
+        showViewportUI(activity,viewport);
+    }
+
+    public void showViewport(@NonNull View view, Class<? extends ShowingViewport> viewport){
+        showViewportUI(view,viewport);
+    }
+
+    public void showViewport(@NonNull SupportLoadingFragment fragment, Class<? extends ShowingViewport> viewport){
+        showViewportUI(fragment,viewport);
+    }
+
+
+
+    /**
+     * 显示加载成功,或者完成时候的状态,也就是正常要显示的界面
+     * @param target
+     */
+    private void showSuccessUI(@NonNull Object target){
+        targetLegal(target);
+        Loader loader = getLoader(target);
+        if(loader != null){
+            loader.showViewport(SuccessViewport.class);
+        }
+    }
+
+    public void showSuccess(@NonNull Activity activity){
+        showSuccessUI(activity);
+    }
+
+    public void showSuccess(@NonNull View view){
+        showSuccessUI(view);
+    }
+
+    public void showSuccess(@NonNull SupportLoadingFragment fragment){
+        showSuccessUI(fragment);
+    }
+
+
+    /**
+     * 获取默认的Loader.Builder,该方法用于全局配置统一的加载视图,
+     * 从配置好的Settings中获取设置的Loader.Builder对象
+     * @param target
+     * @param defaultSettings
+     * @return
+     */
+//    private Loader.Builder getDefaultBuilder(Object target, Settings defaultSettings){
+//        Loader.Builder builder = new Loader.Builder(target);
+//        if(defaultSettings == null){
+//            throw new IllegalStateException("before use registerWithDefault(Object target),you must first init a defaultSettings");
+//        }
+//        ArrayMap<Class<? extends ShowingViewport>,ShowingViewport> viewports = defaultSettings.getViewports();
+//        if(viewports != null && viewports.size() > 0){
+//            Set<Class<? extends ShowingViewport>> set = viewports.keySet();
+//            for(Iterator<Class<? extends ShowingViewport>> it = set.iterator(); it.hasNext();){
+//                builder.addViewport(viewports.get(it.next()));
+//            }
+//        }
+//
+//        Class<? extends ShowingViewport> defaultViewport = defaultSettings.getDefaultViewportClass();
+//        if(defaultViewport != null){
+//            builder.setDefaultViewport(defaultViewport);
+//        }
+//        return builder;
+//    }
+
+    /**
+     * @param target
+     * @return 根据传入的target获取对于target注册的loader事件,这里是通过target的hash值作为唯一定位值,因此target不能够重写hash,否则将会无效
+     */
+    private Loader getLoader(@NonNull Object target){
+        return mLoaders.get(target.hashCode());
+    }
+
+
+    /**
+     * 判断传入的target是否合法
+     * @param target 只能是Activity,Fragment,View对象
+     */
+    private void targetLegal(@NonNull Object target){
+        if(target == null){
+            throw new IllegalStateException("target must not be null");
+        }
+        if(!(target instanceof Activity) && !(target instanceof View) && !(target instanceof SupportLoadingFragment)){
+            throw new IllegalStateException("target must be extends Activity,Fragment or View");
+        }
+
+    }
+
+
+    /**
+     * 用来全局统一配置的配置选项类
+     */
+//    public static class Settings{
+//
+//        private ArrayMap<Class<? extends ShowingViewport>,ShowingViewport> mViewports;
+//        private Class<? extends ShowingViewport> mDefaultViewportClass;
+//
+//        public Settings(){
+//            mViewports = new ArrayMap<>();
+//        }
+//
+//        public Class<? extends ShowingViewport> getDefaultViewportClass() {
+//            return mDefaultViewportClass;
+//        }
+//
+//        public ArrayMap<Class<? extends ShowingViewport>, ShowingViewport> getViewports() {
+//            return mViewports;
+//        }
+//
+//
+//        /**
+//         * 设置默认显示的ShowingViewport视图
+//         * @param defaultViewportClass
+//         * @return
+//         */
+//        public Settings setDefaultShowingViewportClass(Class<? extends ShowingViewport> defaultViewportClass) {
+//            mDefaultViewportClass = defaultViewportClass;
+//            return this;
+//        }
+//
+//        /**
+//         * 添加一项需要显示的ShowingViewport视图
+//         * @param viewport
+//         * @return
+//         */
+//        public Settings addShowingViewport(ShowingViewport viewport){
+//            if(viewport != null){
+//                Class<? extends ShowingViewport> cls = viewport.getClass();
+//                if(!mViewports.containsKey(cls)){
+//                    mViewports.put(cls,viewport);
+//                }
+//            }
+//            return this;
+//        }
+//
+//        public void save(){
+//            getHelper().setDefaultSettings(this);
+//        }
+//
+//
+//    }
+
+}

+ 238 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/LoadingLayout.java

@@ -0,0 +1,238 @@
+package com.kfzs.libs.widget.loading;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.v4.util.ArrayMap;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.kfzs.libs.widget.loading.viewport.ShowingViewport;
+import com.kfzs.libs.widget.loading.viewport.SuccessViewport;
+
+import java.lang.ref.WeakReference;
+
+
+/**
+ * ShowingViewport的状态容器视图
+ * Created by Administrator on 2017/9/26 0026.
+ */
+
+public final class LoadingLayout extends FrameLayout {
+
+//    private ShowingViewport.OnReloadListener mOnReloadListener;
+    private Context mContext;
+    ArrayMap<Class<? extends ShowingViewport>,ShowingViewport> mViewports;
+    /**
+     * 通过TargetContext封装好的目标对象数据集合
+     */
+    private TargetContext mTargetContext;
+    /**
+     * 传入的目标对象,代表当前loading的目标是谁,这里只允许Activity,Fragment,View三种
+     */
+    private WeakReference<Object> mObjectWeakReference;
+
+
+    public LoadingLayout(@NonNull TargetContext targetContext) {
+        super(targetContext.getContext());
+        mTargetContext = targetContext;
+        this.mContext = targetContext.getContext();
+        mViewports = new ArrayMap<>();
+    }
+
+
+    public void setObjectWeakReference(WeakReference<Object> objectWeakReference) {
+        mObjectWeakReference = objectWeakReference;
+    }
+
+//    public void setOnReloadListener(ShowingViewport.OnReloadListener onReloadListener) {
+//        mOnReloadListener = onReloadListener;
+//        if(mViewports != null && mViewports.size() > 0){
+//            Set<Class<? extends ShowingViewport>> set = mViewports.keySet();
+//            for(Iterator<Class<? extends ShowingViewport>> it = set.iterator(); it.hasNext();){
+//                ShowingViewport showingViewport = mViewports.get(it.next());
+//                showingViewport.setOnReloadListener(onReloadListener);
+//            }
+//        }
+//    }
+
+    /**
+     * 添加一个状态ShowingViewport视图
+     * @param viewport
+     */
+    public void addShowingViewport(@NonNull ShowingViewport viewport){
+//        ShowingViewport cloneViewport = viewport.copy();
+        ShowingViewport cloneViewport = viewport;
+        cloneViewport.init( mContext,null, cloneViewport.getOnReloadListener());
+        Class<? extends ShowingViewport> cls = cloneViewport.getClass();
+        if(!mViewports.containsKey(cls)){
+            mViewports.put(cls,cloneViewport);
+        }
+    }
+
+    /**
+     * 保存ShowingViewport在mViewports中
+     * @param successViewport
+     */
+    public void setSuccessViewport(ShowingViewport successViewport){
+        Class<? extends ShowingViewport> cls = successViewport.getClass();
+        if(!mViewports.containsKey(cls)){
+            mViewports.put(cls,successViewport);
+        }
+    }
+
+
+    /**
+     * 用viewport替换当前的视图
+     * @param viewport 要替换的视图
+     */
+    public void replaceWithViewport(Class<? extends ShowingViewport> viewport){
+        if(!mViewports.containsKey(viewport)){
+            throw new IllegalArgumentException(
+                    String.format("The ShowingViewport (%s) is non-existent.", viewport.getSimpleName())
+            );
+        }
+        if (isMainThread()) {
+            showViewport(viewport);
+        } else {
+            postToMainThread(viewport);
+        }
+    }
+
+    private void postToMainThread(final Class<? extends ShowingViewport> viewport) {
+        post(new Runnable() {
+            @Override
+            public void run() {
+                showViewport(viewport);
+            }
+        });
+    }
+
+    private boolean isMainThread() {
+        return Looper.myLooper() == Looper.getMainLooper();
+    }
+
+    /**
+     * 显示cls对应的视图
+     * @param cls
+     */
+    private void showViewport(Class<? extends ShowingViewport> cls) {
+        if(cls == SuccessViewport.class){
+            ViewGroup parentView = mTargetContext.getParentView();
+            if(mObjectWeakReference.get() != null && mObjectWeakReference.get() instanceof Activity) {
+                setVisibility(View.GONE);
+                mTargetContext.getOldContent().setVisibility(View.VISIBLE);
+            }
+            else {
+                ShowingViewport successViewport = mViewports.get(SuccessViewport.class);
+                if(parentView != null){
+                    //将要显示加载成功的视图,也就是当前加载完成后正常显示的视图,因此需要将LoadingLayout从跟视图移除
+                    parentView.removeView(this);
+                    //先remove,防止多次重复调用SuccessViewport,addView时候抛出异常
+                    ViewGroup viewGroup = (ViewGroup) successViewport.getRootView().getParent();
+                    if(viewGroup != null){
+                        viewGroup.removeView(successViewport.getRootView());
+                    }
+                    //remove以后,添加就不会出问题,这里添加,显示加载完成后要显示的视图
+                    parentView.addView(successViewport.getRootView(),mTargetContext.getChildIndex(),mTargetContext.getOldContent().getLayoutParams());
+                }
+                else {
+                    addView(successViewport.getRootView());
+                }
+            }
+
+        }
+        else {
+
+            if (getChildCount() > 0) {
+                removeAllViews();
+            }
+
+            for (Class key : mViewports.keySet()) {
+                if (key == cls) {
+                    if(mObjectWeakReference.get() != null && mObjectWeakReference.get() instanceof Activity){
+                        setVisibility(View.VISIBLE);
+                        mTargetContext.getOldContent().setVisibility(View.GONE);
+                        addView(mViewports.get(key).getRootView());
+                    }
+                    else {
+
+                        //将oldContent先从父View移除,防止当前oldContent已经添加在某个视图上,再次调用addView会抛出异常
+                        ViewGroup viewGroup = (ViewGroup) mTargetContext.getOldContent().getParent();
+                        if(viewGroup != null){
+                            viewGroup.removeView(mTargetContext.getOldContent());
+                        }
+                        //将当前对象从parent移除,与上面oldContent同理
+                        ViewGroup thisParent = (ViewGroup) getParent();
+                        if (thisParent != null) {
+                            thisParent.removeView(this);
+                        }
+                        //添加当前要显示的showViewport视图到LoadingLayout
+                        addView(mViewports.get(key).getRootView());
+                        //在跟视图上替换成当前要设置的LoadingLayout
+                        ViewGroup parentView = mTargetContext.getParentView();
+                        parentView.addView(this,mTargetContext.getOldContent().getLayoutParams());
+
+                    }
+
+                }
+            }
+        }
+
+
+//        if(mObjectWeakReference.get() != null && mObjectWeakReference.get() instanceof Activity){
+//
+//            ViewGroup parentView = mTargetContext.getParentView();
+//            if(cls == SuccessViewport.class){
+//                parentView.removeView(this);
+//                mTargetContext.getOldContent().setVisibility(View.VISIBLE);
+//            }
+//            else {
+//                if (getChildCount() > 0) {
+//                    removeAllViews();
+//                }
+//
+//                for (Class key : mViewports.keySet()) {
+//                    if (key == cls) {
+//                        addView(mViewports.get(key).getRootView());
+//                    }
+//                }
+//            }
+//        }
+//        else {
+//
+//            if(cls == SuccessViewport.class){
+//                ViewGroup parentView = mTargetContext.getParentView();
+//                ShowingViewport successViewport = mViewports.get(SuccessViewport.class);
+//                if(parentView != null){
+//                    parentView.removeView(this);
+//                    parentView.addView(successViewport.getRootView(),mTargetContext.getChildIndex(),mTargetContext.getOldContent().getLayoutParams());
+//                }
+//                else addView(successViewport.getRootView());
+//
+//            }
+//            else {
+//                if (getChildCount() > 0) {
+//                    removeAllViews();
+//                }
+//
+//                for (Class key : mViewports.keySet()) {
+//                    if (key == cls) {
+//                        addView(mViewports.get(key).getRootView());
+//                    }
+//                }
+//            }
+//
+//        }
+
+
+
+
+    }
+
+
+
+
+}

+ 50 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/SupportLoadingFragment.java

@@ -0,0 +1,50 @@
+package com.kfzs.libs.widget.loading;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import butterknife.ButterKnife;
+
+
+/**
+ * Fragment需要loading事件时候需要继承的基类
+ * Created by Administrator on 2018/2/12 0012.
+ */
+
+public abstract class SupportLoadingFragment extends Fragment {
+
+    protected Activity activity;
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        activity = (Activity) context;
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        //为了支持Loader,这里必须要添加一层底层容器,否则点击返回键第一次只会将原来的布局返回,不能起到原本的作用,需要点击两次返回键才会生效
+        FrameLayout loaderContainer = new FrameLayout(activity);
+        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
+        loaderContainer.setLayoutParams(layoutParams);
+        //添加Fragment的布局
+        View rootView = inflater.inflate(layoutResId(),loaderContainer,false);
+        loaderContainer.addView(rootView);
+        ButterKnife.bind(this, rootView);
+        setupViews(savedInstanceState);
+        return loaderContainer;
+    }
+
+    public abstract @LayoutRes int layoutResId();
+    public abstract void setupViews(@Nullable Bundle savedInstanceState);
+
+}

+ 49 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/TargetContext.java

@@ -0,0 +1,49 @@
+package com.kfzs.libs.widget.loading;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * 封装loading事件的目标对象的各种数据集合
+ * Created by Administrator on 2017/9/26 0026.
+ */
+
+final class TargetContext {
+
+    private Context mContext;
+    private ViewGroup mParentView;
+    private View mOldContent;
+    private int mChildIndex;
+    private int mOldContentId;
+
+    public TargetContext(Context context, ViewGroup parentView, View oldContent, int oldContentId, int childIndex) {
+        this.mContext = context;
+        this.mParentView = parentView;
+        this.mOldContent = oldContent;
+        this.mOldContentId = oldContentId;
+        this.mChildIndex = childIndex;
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public View getOldContent() {
+        return mOldContent;
+    }
+
+    public int getChildIndex() {
+        return mChildIndex;
+    }
+
+    public int getOldContentId() {
+        return mOldContentId;
+    }
+
+
+
+    public ViewGroup getParentView() {
+        return mParentView;
+    }
+}

+ 127 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/viewport/ShowingViewport.java

@@ -0,0 +1,127 @@
+package com.kfzs.libs.widget.loading.viewport;
+
+import android.content.Context;
+import android.view.View;
+
+import java.io.Serializable;
+
+
+/**
+ * 使用该类必须要继承,加载过程中不同的状态,比如错误提示页面,加载中,数据为空,都应该继承该类,
+ * 并将具体显示的UI视图,通过构造方法传入,该类支持点击重试,可以是当前整个界面点击重试刷新,
+ * 也可以是具体某个按钮点击刷新,具体的逻辑重写抽象方法initRetry。
+ * 重写抽象方法onCreateView,里面返回是一个layout资源id,用来表示当前定义的状态ShowingViewport视图的界面
+ * Created by Administrator on 2017/9/26 0026.
+ */
+
+public abstract class ShowingViewport implements Serializable {
+    private static final long serialVersionUID = 4415260470501529556L;
+    private View mRootView;
+    /**
+     * Context不能参与序列化,否则ShowingViewport整个对象无法序列化,
+     * ShowingViewport对象需要序列化,他内部的对象也需要序列化,不能够让Context参加序列化。
+     * 通过序列化深克隆已经弃用,目前不支持全局配置,因此Context不再需要加上transient修饰。
+     */
+    private Context mContext;
+    private OnReloadListener mOnReloadListener;
+
+    public ShowingViewport() {
+    }
+
+    ShowingViewport(Context context,View view, OnReloadListener onReloadListener) {
+        this.mRootView = view;
+        this.mContext = context;
+        this.mOnReloadListener = onReloadListener;
+    }
+
+    /**
+     * @param context
+     * @param view
+     * @param onReloadListener
+     */
+    public void init(Context context, View view, OnReloadListener onReloadListener) {
+        this.mRootView = view;
+        this.mContext = context;
+        this.mOnReloadListener = onReloadListener;
+    }
+
+
+    /**
+     * 深克隆(深拷贝),也可以实现Cloneable接口,然后重写clone方法,
+     * 这里用的序列化方式实现。
+     * 该序列化,只是拷贝对象本身
+     * @return
+     */
+//    public ShowingViewport copy() {
+//        ByteArrayOutputStream bao = new ByteArrayOutputStream();
+//        ObjectOutputStream oos;
+//        try {
+//            oos = new ObjectOutputStream(bao);
+//            oos.writeObject(this);
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//        }
+//        ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
+//        ObjectInputStream ois;
+//        Object obj = null;
+//        try {
+//            ois = new ObjectInputStream(bis);
+//            obj = ois.readObject();
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//        return (ShowingViewport) obj;
+//    }
+
+
+    public void setOnReloadListener(OnReloadListener onReloadListener) {
+        this.mOnReloadListener = onReloadListener;
+    }
+
+    public OnReloadListener getOnReloadListener() {
+        return mOnReloadListener;
+    }
+
+    /**
+     * 获取当前ShowingViewport的视图View,如果没有就通过onCreateView传入的layout资源id加载
+     * @return
+     */
+    public View getRootView() {
+        int resId = onCreateView();
+        if (resId == 0 && mRootView != null) {
+            return mRootView;
+        }
+        mRootView = View.inflate(mContext, onCreateView(), null);
+        initRetry(mContext,mRootView);
+        return mRootView;
+    }
+
+    /**
+     * 监听重新加载的方法,直接调用即可
+     * @param view
+     */
+    public void onReload(View view){
+        if(mOnReloadListener != null){
+            mOnReloadListener.onReload(view);
+        }
+    }
+
+
+    public interface OnReloadListener {
+        void onReload(View v);
+    }
+
+    /**
+     *
+     * @return 返回当前ShowingViewport的视图layout资源id
+     */
+    protected abstract int onCreateView();
+
+    /**
+     * ShowingViewport视图中一些具体的控件初始化可在该方法中设置,
+     * 并且可以在该方法中设置重新加载得到点击事件
+     * @param context
+     * @param view
+     */
+    protected abstract void initRetry(Context context, View view);
+}

+ 29 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/loading/viewport/SuccessViewport.java

@@ -0,0 +1,29 @@
+package com.kfzs.libs.widget.loading.viewport;
+
+import android.content.Context;
+import android.view.View;
+
+/**
+ * 该类不能被继承,加载成功或者完成时候显示的界面
+ * Created by Administrator on 2017/9/26 0026.
+ */
+public final class SuccessViewport extends ShowingViewport {
+
+    public SuccessViewport(Context context, View view, OnReloadListener onReloadListener) {
+        super(context, view, onReloadListener);
+    }
+
+    /**
+     * 这里传0,因为在初始化SuccessViewport时候,会将界面的View传递进来,作为当前的rootView
+     * @return
+     */
+    @Override
+    protected int onCreateView() {
+        return 0;
+    }
+
+    @Override
+    protected void initRetry(Context context, View view) {
+
+    }
+}

+ 23 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/navigation/Navigation.java

@@ -0,0 +1,23 @@
+package com.kfzs.libs.widget.navigation;
+
+import android.support.annotation.ColorRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+import android.view.View;
+
+/**
+ * Created by Administrator on 2017/11/24 0024.
+ */
+
+public interface Navigation {
+
+    Navigation contentInset(int contentInset);
+    Navigation titleText(String text);
+    Navigation titleText(@StringRes int text);
+    Navigation titleTextSize(int unit, int size);
+    Navigation titleTextSize(int size);
+    Navigation titleTextColor(@ColorRes int color);
+    NavigationBar addItemInLeft(@NonNull View item);
+    Navigation addItemInRight(@NonNull View item);
+
+}

+ 157 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/navigation/NavigationBar.java

@@ -0,0 +1,157 @@
+package com.kfzs.libs.widget.navigation;
+
+import android.content.Context;
+import android.support.annotation.ColorRes;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+import android.support.v4.content.ContextCompat;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.kfzs.libs.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * 能够切换Android,IOS风格的简单导航栏
+ * Created by Administrator on 2017/11/23 0023.
+ */
+
+public class NavigationBar extends RelativeLayout implements Navigation{
+
+    public static final int ANDROID = 0;
+    public static final int IOS = 1;
+    private int mNavigationType = ANDROID;
+    private LinearLayout mLeftContainerView;
+    private TextView mTitleView;
+    private LinearLayout mRightContainerView;
+    private int mItemMargin;
+
+    public NavigationBar(Context context) {
+        this(context,null);
+    }
+
+    public NavigationBar(Context context, AttributeSet attrs) {
+        this(context, attrs,0);
+    }
+
+    public NavigationBar(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context);
+    }
+
+
+    private void init(Context context){
+        LayoutInflater.from(context).inflate(R.layout.navigation_bar,this,true);
+        mLeftContainerView = (LinearLayout)findViewById(R.id.navigationBar_left_container);
+        mTitleView = (TextView) findViewById(R.id.navigationBar_titleTextView);
+        mRightContainerView = (LinearLayout)findViewById(R.id.navigationBar_right_container);
+        int contentInset = getResources().getDimensionPixelSize(R.dimen.navigationBar_contentInset);
+        setPadding(contentInset,getPaddingTop(),contentInset,getPaddingBottom());
+        mItemMargin = getResources().getDimensionPixelSize(R.dimen.navigationBar_itemMargin);
+        changeToAndroidStyle();
+    }
+
+    @Override
+    public NavigationBar contentInset(int contentInset){
+        setPadding(contentInset,getPaddingTop(),contentInset,getPaddingBottom());
+        return this;
+    }
+
+    @Override
+    public NavigationBar titleText(String text){
+        mTitleView.setText(text);
+        return this;
+    }
+
+    @Override
+    public NavigationBar titleText(@StringRes int text){
+        mTitleView.setText(text);
+        return this;
+    }
+
+    @Override
+    public NavigationBar titleTextSize(int unit,int size){
+        mTitleView.setTextSize(unit,size);
+        return this;
+    }
+
+    @Override
+    public NavigationBar titleTextSize(int size){
+        mTitleView.setTextSize(size);
+        return this;
+    }
+
+    @Override
+    public NavigationBar titleTextColor(@ColorRes int color){
+        mTitleView.setTextColor(ContextCompat.getColor(getContext(),color));
+        return this;
+    }
+
+    @Override
+    public NavigationBar addItemInLeft(@NonNull View item){
+        LinearLayout.LayoutParams params = getItemLayoutParams();
+        item.setLayoutParams(params);
+        mLeftContainerView.addView(item);
+        return this;
+    }
+
+    @Override
+    public NavigationBar addItemInRight(@NonNull View item){
+        LinearLayout.LayoutParams params = getItemLayoutParams();
+        params.leftMargin = mItemMargin;
+        item.setLayoutParams(params);
+        mRightContainerView.addView(item);
+        return this;
+    }
+
+    private LinearLayout.LayoutParams getItemLayoutParams(){
+        return new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+    }
+
+    private void changeToAndroidStyle(){
+        LayoutParams titleParams = (LayoutParams) mTitleView.getLayoutParams();
+        titleParams.addRule(RelativeLayout.RIGHT_OF,mLeftContainerView.getId());
+        titleParams.addRule(RelativeLayout.CENTER_IN_PARENT,0);
+        mTitleView.setLayoutParams(titleParams);
+    }
+
+    private void changeToIosStyle(){
+        LayoutParams titleParams = (LayoutParams) mTitleView.getLayoutParams();
+        titleParams.addRule(RelativeLayout.RIGHT_OF,0);
+        titleParams.addRule(RelativeLayout.CENTER_IN_PARENT);
+        mTitleView.setLayoutParams(titleParams);
+    }
+
+    private void setAllViewVisibility(int visibility){
+        mLeftContainerView.setVisibility(visibility);
+        mTitleView.setVisibility(visibility);
+        mRightContainerView.setVisibility(visibility);
+    }
+
+
+    public void changeNavigationType(@NavigationType int type){
+        if (mNavigationType == type)return;
+        mNavigationType = type;
+        switch (mNavigationType){
+            case ANDROID:
+                changeToAndroidStyle();
+                break;
+            case IOS:
+                changeToIosStyle();
+                break;
+        }
+    }
+
+    @IntDef({ANDROID,IOS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NavigationType{
+
+    }
+}

+ 263 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/navigation/TabBar.java

@@ -0,0 +1,263 @@
+package com.kfzs.libs.widget.navigation;
+
+import android.content.Context;
+import android.support.annotation.ColorRes;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.IntDef;
+import android.support.annotation.StringRes;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.kfzs.libs.utils.DrawablesHelper;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Tab导航
+ * Created by Administrator on 2017/11/24 0024.
+ */
+
+public class TabBar extends LinearLayout implements View.OnClickListener{
+
+    public static final int TOP = 0;
+    public static final int BOTTOM = 1;
+    public static final int LEFT = 2;
+    public static final int RIGHT = 3;
+
+    private SparseArray<Tab> mTabSparseArray = new SparseArray<>();
+    private @DrawableDirection int mDirection = TOP;
+    private View mCheckedButton;
+
+    private OnTabSelectListener mOnTabSelectListener;
+    private OnTabRepeatClickListener mOnTabRepeatClickListener;
+
+    public TabBar(Context context) {
+        super(context);
+    }
+
+    public TabBar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+
+    public static Tab newTab(Context context){
+        return new Tab(context);
+    }
+
+    public void clearAllTabs(){
+        mTabSparseArray.clear();
+        removeAllViews();
+    }
+
+
+    public TabBar addTab(Tab tab,int index){
+        mTabSparseArray.put(index,tab);
+        return this;
+    }
+    public TabBar direction(@DrawableDirection int direction){
+        mDirection = direction;
+        return this;
+    }
+
+    public TabBar setOnTabSelectListener(OnTabSelectListener onTabSelectListener) {
+        if(onTabSelectListener != null){
+            mOnTabSelectListener = onTabSelectListener;
+        }
+        return this;
+    }
+
+    public TabBar setOnTabRepeatClickListener(OnTabRepeatClickListener onTabRepeatClickListener) {
+        mOnTabRepeatClickListener = onTabRepeatClickListener;
+        return this;
+    }
+
+    /**
+     * 添加tab之后必须调用此方法,否则check方法不会起作用
+     */
+    public void commit(){
+        removeAllViews();
+        setOrientation(LinearLayout.HORIZONTAL);
+        for(int i=0;i<mTabSparseArray.size();i++){
+            TextView button = createTabButton(mTabSparseArray.get(i));
+            button.setId(i);
+            button.setOnClickListener(this);
+            addView(button,i,getButtonLayoutParams());
+        }
+
+    }
+
+
+    private TextView createTabButton(Tab tab){
+        TextView button = new TextView(getContext());
+        button.setGravity(Gravity.CENTER);
+        button.setPadding(0,tab.mTabPadding,0,tab.mTabPadding);
+        button.setCompoundDrawablePadding(0);
+        if(tab.mShowTitle){
+            button.setText(tab.mTitle);
+        }
+        button.setTextSize(tab.mUnit,tab.mTitleTextSize);
+        button.setTextColor(ContextCompat.getColorStateList(button.getContext(),tab.mSColor));
+        if(tab.mBgDrawable == -1){
+            ViewCompat.setBackground(button,null);
+        }
+        else ViewCompat.setBackground(button, ContextCompat.getDrawable(getContext(),tab.mBgDrawable));
+        switch (mDirection){
+            case TOP:
+                new DrawablesHelper(button)
+                        .direction(DrawablesHelper.TOP)
+                        .drawable(tab.mIconDrawable)
+                        .commit();
+                break;
+            case BOTTOM:
+                new DrawablesHelper(button)
+                        .direction(DrawablesHelper.BOTTOM)
+                        .drawable(tab.mIconDrawable)
+                        .commit();
+                break;
+            case LEFT:
+                new DrawablesHelper(button)
+                        .direction(DrawablesHelper.LEFT)
+                        .drawable(tab.mIconDrawable)
+                        .commit();
+                break;
+            case RIGHT:
+                new DrawablesHelper(button)
+                        .direction(DrawablesHelper.RIGHT)
+                        .drawable(tab.mIconDrawable)
+                        .commit();
+                break;
+            default:
+                new DrawablesHelper(button)
+                        .direction(DrawablesHelper.TOP)
+                        .drawable(tab.mIconDrawable)
+                        .commit();
+        }
+
+        return button;
+    }
+
+    private LayoutParams getButtonLayoutParams(){
+        LayoutParams params = new LayoutParams(0, LayoutParams.MATCH_PARENT);
+        params.weight = 1;
+        params.gravity = Gravity.CENTER_VERTICAL;
+        return params;
+    }
+
+    @Override
+    public void onClick(View view) {
+
+        if(view == mCheckedButton){
+            //重复点击已经选择的Tab,回调重复点击
+            if(mOnTabRepeatClickListener != null){
+                mOnTabRepeatClickListener.onTabRepeatClick((TextView) view,view.getId());
+            }
+            return;
+        }
+        if(mCheckedButton != null){
+            mCheckedButton.setSelected(false);
+        }
+        view.setSelected(true);
+        mCheckedButton = view;
+        if(mOnTabSelectListener != null){
+            mOnTabSelectListener.onTabSelected((TextView) view,view.getId());
+        }
+    }
+
+    public void checked(int index){
+        View child = getChildAt(index);
+        if(child != null){
+            child.performClick();
+        }
+    }
+
+
+    public static class Tab{
+
+        private Context mContext;
+        private boolean mShowTitle = true;
+        private String mTitle;
+        private @ColorRes
+        int mSColor = android.R.color.black;
+        private @DrawableRes
+        int mIconDrawable;
+        private @DrawableRes
+        int mBgDrawable = -1;
+        private int mTabPadding;
+        private int mTitleTextSize;
+        private int mUnit = TypedValue.COMPLEX_UNIT_SP;
+
+        public Tab(Context context){
+            mContext = context;
+        }
+
+        public Tab showTitle(boolean showTitle){
+            mShowTitle = showTitle;
+            return this;
+        }
+
+        public Tab title(String text){
+            mTitle = text;
+            return this;
+        }
+
+        public Tab title(@StringRes int text){
+            mTitle = mContext.getResources().getString(text);
+            return this;
+        }
+
+        public Tab titleTextSize(int size){
+            mTitleTextSize = size;
+            return this;
+        }
+
+        public Tab titleTextSize(int unit,int size){
+            mUnit = unit;
+            mTitleTextSize = size;
+            return this;
+        }
+
+        public Tab tabPadding(int padding){
+            mTabPadding = padding;
+            return this;
+        }
+
+        public Tab titleColor(@ColorRes int sColor){
+            mSColor = sColor;
+            return this;
+        }
+
+        public Tab icon(@DrawableRes int sDrawable){
+            mIconDrawable = sDrawable;
+            return this;
+        }
+
+        public Tab background(@DrawableRes int sDrawable){
+            mBgDrawable = sDrawable;
+            return this;
+        }
+
+    }
+
+
+    @IntDef({TOP,BOTTOM,LEFT, RIGHT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DrawableDirection{
+
+    }
+
+    public interface OnTabSelectListener{
+        void onTabSelected(TextView tab, int index);
+    }
+
+    public interface OnTabRepeatClickListener{
+        void onTabRepeatClick(TextView tab, int index);
+    }
+}

+ 113 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/BaseHeaderWrapper.java

@@ -0,0 +1,113 @@
+package com.kfzs.libs.widget.rv;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.view.ViewGroup;
+
+/**
+ * Created by Administrator on 2017/12/15 0015.
+ */
+
+public abstract class BaseHeaderWrapper extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
+
+    public static final int ITEM_TYPE_HEADER = Integer.MAX_VALUE - 2;
+
+    private Context mContext;
+    private RecyclerView.Adapter<RecyclerView.ViewHolder> mInnerAdapter;
+    private boolean isHaveStatesView = true;
+
+    /**
+     * 采用装饰者模式的构造方法
+     * @param context 上下文对象
+     * @param adapter 当前包装的普通Adapter对象
+     */
+    public BaseHeaderWrapper(Context context, @NonNull RecyclerView.Adapter<RecyclerView.ViewHolder> adapter){
+        mContext = context;
+        mInnerAdapter = adapter;
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+
+
+    public abstract RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent);
+    public abstract void onBindViewHolderOfHeader(RecyclerView.ViewHolder holder, int position);
+
+    @Override
+    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if(isHeaderType(viewType)){
+            return onCreateHeaderViewHolder(parent);
+        }
+
+        return mInnerAdapter.onCreateViewHolder(parent,viewType);
+    }
+
+    @Override
+    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+        if(!isHeaderType(holder.getItemViewType())){
+            mInnerAdapter.onBindViewHolder(holder,position);
+        }
+        else {
+            onBindViewHolderOfHeader(holder,position);
+        }
+    }
+
+
+    @Override
+    public int getItemCount() {
+        return mInnerAdapter.getItemCount() + (isHaveStatesView ? 1 : 0);
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (position == 0 && isHaveStatesView) {
+            return ITEM_TYPE_HEADER;
+        }
+        return mInnerAdapter.getItemViewType(position);
+    }
+
+    @Override
+    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+        WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback() {
+            @Override
+            public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position) {
+                if (position == getItemCount() - 1 && isHaveStatesView) {
+                    return layoutManager.getSpanCount();
+                }
+                if (oldLookup != null && isHaveStatesView) {
+                    return oldLookup.getSpanSize(position);
+                }
+                return 1;
+            }
+        });
+    }
+
+    @Override
+    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
+        mInnerAdapter.onViewAttachedToWindow(holder);
+
+        if (holder.getLayoutPosition() == getItemCount() - 1 && isHaveStatesView) {
+            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+            if (lp != null
+                    && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
+                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
+
+                p.setFullSpan(true);
+            }
+        }
+    }
+
+    public boolean isHeaderType(int type) {
+        return type == ITEM_TYPE_HEADER;
+    }
+
+
+
+
+
+}

+ 155 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/BaseLoadMoreWrapper.java

@@ -0,0 +1,155 @@
+package com.kfzs.libs.widget.rv;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.view.ViewGroup;
+
+/**
+ * Created by Administrator on 2017/12/15 0015.
+ */
+
+public abstract class BaseLoadMoreWrapper extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
+
+    public static final int ITEM_TYPE_LOAD_MORE = Integer.MAX_VALUE - 1;
+
+    protected static final int STATE_READY = 0;
+    protected static final int STATE_LOADING = 1;
+    protected static final int STATE_NO_MORE = 2;
+
+    private int mCurState = STATE_READY;
+    private Context mContext;
+    private RecyclerView.Adapter<RecyclerView.ViewHolder> mInnerAdapter;
+    private boolean isHaveStatesView = true;
+
+    private LoadMoreScrollListener mLoadMoreScrollListener;
+    private OnLoadMoreListener mOnLoadMoreListener;
+
+    public BaseLoadMoreWrapper(Context context, @NonNull RecyclerView.Adapter<RecyclerView.ViewHolder> adapter){
+        mContext = context;
+        mInnerAdapter = adapter;
+        mLoadMoreScrollListener = new LoadMoreScrollListener() {
+            @Override
+            public void loadMore() {
+                if(mCurState != STATE_NO_MORE) {
+                    if (mOnLoadMoreListener != null && isHaveStatesView) {
+                        showLoading();
+                        mOnLoadMoreListener.onLoadMore();
+                    }
+                }
+
+            }
+        };
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public abstract void showComplete();
+    public abstract void showLoading();
+    public abstract void showNoMore();
+
+    public void setCurState(int curState) {
+        mCurState = curState;
+    }
+
+    public int getCurState() {
+        return mCurState;
+    }
+
+
+    public abstract RecyclerView.ViewHolder onCreateLoadMoreViewHolder(ViewGroup parent);
+    public abstract void onBindViewHolderOfLoadMoreState(RecyclerView.ViewHolder holder, int position);
+
+    @Override
+    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if(isLoadMoreType(viewType)){
+            return onCreateLoadMoreViewHolder(parent);
+        }
+
+        return mInnerAdapter.onCreateViewHolder(parent,viewType);
+    }
+
+    @Override
+    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+        if(!isLoadMoreType(holder.getItemViewType())){
+            mInnerAdapter.onBindViewHolder(holder,position);
+        }
+        else {
+            onBindViewHolderOfLoadMoreState(holder,position);
+        }
+    }
+
+
+    @Override
+    public int getItemCount() {
+        return mInnerAdapter.getItemCount() + (isHaveStatesView ? 1 : 0);
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (position == getItemCount() - 1 && isHaveStatesView) {
+            return ITEM_TYPE_LOAD_MORE;
+        }
+        return mInnerAdapter.getItemViewType(position);
+    }
+
+    @Override
+    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+        WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback() {
+            @Override
+            public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position) {
+                if (position == getItemCount() - 1 && isHaveStatesView) {
+                    return layoutManager.getSpanCount();
+                }
+                if (oldLookup != null && isHaveStatesView) {
+                    return oldLookup.getSpanSize(position);
+                }
+                return 1;
+            }
+        });
+        recyclerView.addOnScrollListener(mLoadMoreScrollListener);
+    }
+
+
+    @Override
+    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
+        mInnerAdapter.onViewAttachedToWindow(holder);
+
+        if (holder.getLayoutPosition() == getItemCount() - 1 && isHaveStatesView) {
+            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+
+            if (lp != null
+                    && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
+                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
+
+                p.setFullSpan(true);
+            }
+        }
+    }
+
+    public boolean isLoadMoreType(int type) {
+        return type == ITEM_TYPE_LOAD_MORE;
+    }
+
+
+
+
+    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
+        mOnLoadMoreListener = onLoadMoreListener;
+    }
+
+    public OnLoadMoreListener getOnLoadMoreListener() {
+        return mOnLoadMoreListener;
+    }
+
+    public interface OnLoadMoreListener {
+        void onLoadMore();
+    }
+
+
+
+}

+ 28 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/BaseRecyclerViewAdapter.java

@@ -0,0 +1,28 @@
+package com.kfzs.libs.widget.rv;
+
+import android.support.v7.widget.RecyclerView;
+
+/**
+ * Created by Administrator on 2018/2/5 0005.
+ */
+
+public abstract class BaseRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
+
+    private boolean mHasHeader = false;
+
+    @Override
+    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+        int pos = mHasHeader ? position -1 : position;
+        onBindViewHolderWithHeader(holder,pos);
+    }
+
+    public void setHasHeader(boolean hasHeader) {
+        mHasHeader = hasHeader;
+    }
+
+    public boolean isHasHeader() {
+        return mHasHeader;
+    }
+
+    public abstract void onBindViewHolderWithHeader(RecyclerView.ViewHolder holder, int position);
+}

+ 92 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/DefaultLoadMoreWrapper.java

@@ -0,0 +1,92 @@
+package com.kfzs.libs.widget.rv;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.kfzs.libs.R;
+
+
+/**
+ * Created by Administrator on 2017/12/15 0015.
+ */
+
+public class DefaultLoadMoreWrapper extends BaseLoadMoreWrapper {
+
+    private View mViewLoadMore;
+    private TextView mTextView;
+    private ProgressBar mProgressBar;
+
+    public DefaultLoadMoreWrapper(Context context, @NonNull RecyclerView.Adapter adapter) {
+        super(context, adapter);
+    }
+
+    @Override
+    public void showComplete() {
+        setCurState(STATE_READY);
+        mProgressBar.setVisibility(View.GONE);
+        mTextView.setText("查看更多");
+    }
+
+    @Override
+    public void showLoading() {
+        setCurState(STATE_LOADING);
+        mProgressBar.setVisibility(View.VISIBLE);
+        mTextView.setText("加载中……");
+    }
+
+
+    @Override
+    public void showNoMore() {
+        setCurState(STATE_NO_MORE);
+        mProgressBar.setVisibility(View.GONE);
+        mTextView.setText("没有更多");
+    }
+
+    @Override
+    public RecyclerView.ViewHolder onCreateLoadMoreViewHolder(ViewGroup parent) {
+        if(mViewLoadMore == null){
+            mViewLoadMore = LayoutInflater.from(getContext()).inflate(R.layout.recyclerview_default_load_more,parent,false);
+            mTextView = mViewLoadMore.findViewById(R.id.tv_state);
+            mProgressBar = mViewLoadMore.findViewById(R.id.pb_loading);
+        }
+        return new ViewHolder(getContext(), mViewLoadMore);
+    }
+
+
+    @Override
+    public void onBindViewHolderOfLoadMoreState(final RecyclerView.ViewHolder holder, int position) {
+
+        holder.itemView.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                if(!NoDoubleClick.isDoubleClick()){//防止双击
+                    if(getCurState() == STATE_READY){
+                        if(getOnLoadMoreListener() != null){
+                            showLoading();
+                            getOnLoadMoreListener().onLoadMore();
+                        }
+                    }
+                }
+            }
+        });
+
+    }
+
+    private static class NoDoubleClick{
+        private static long mLastClickTime;
+        private final static int SPACE_TIME = 500;
+
+        public synchronized static boolean isDoubleClick() {
+            long currentTime = System.currentTimeMillis();
+            boolean isClick2 = currentTime - mLastClickTime <= SPACE_TIME;
+            mLastClickTime = currentTime;
+            return isClick2;
+        }
+    }
+}

+ 81 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/LoadMoreScrollListener.java

@@ -0,0 +1,81 @@
+package com.kfzs.libs.widget.rv;
+
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+
+/**
+ * Desc:用于RecyclerView加载更多的监听,实现滑动到底部自动加载更多
+ */
+abstract class LoadMoreScrollListener extends RecyclerView.OnScrollListener {
+
+    private int mPreviousTotal;
+    private boolean mIsLoading = true;
+    private LinearLayoutManager mLinearLayoutManager;
+    private StaggeredGridLayoutManager mStaggeredGridLayoutManager;
+    private int[] mLastPositions;
+    private int mTotalItemCount;
+    private int mLastVisibleItemPosition;
+    /**
+     * 是否向下滚动
+     *
+     */
+    private boolean mIsSlidingToLast;
+
+    @Override
+    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+        super.onScrollStateChanged(recyclerView, newState);
+        if (recyclerView.getLayoutManager() instanceof LinearLayoutManager)
+            mLinearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
+        else if (recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
+            mStaggeredGridLayoutManager = (StaggeredGridLayoutManager) recyclerView.getLayoutManager();
+            mLastPositions = mStaggeredGridLayoutManager.findLastVisibleItemPositions(null);
+        }
+
+        int visibleItemCount = recyclerView.getChildCount();
+        if (mLinearLayoutManager != null) {
+            mTotalItemCount = mLinearLayoutManager.getItemCount();
+            mLastVisibleItemPosition = mLinearLayoutManager.findLastVisibleItemPosition();
+        } else if (mStaggeredGridLayoutManager != null) {
+            mTotalItemCount = mStaggeredGridLayoutManager.getItemCount();
+            mLastVisibleItemPosition = mLastPositions[0];
+        }
+
+        if (mIsLoading) {
+            if (mTotalItemCount > mPreviousTotal) {//加载更多结束
+                mIsLoading = false;
+                mPreviousTotal = mTotalItemCount;
+            } else if (mTotalItemCount < mPreviousTotal) {//用户刷新结束
+                mPreviousTotal = mTotalItemCount;
+                mIsLoading = false;
+            } else {//有可能是在第一页刷新也可能是加载完毕
+
+            }
+        }
+
+        if (!mIsLoading
+                && mIsSlidingToLast
+                && visibleItemCount > 0
+                && mTotalItemCount - 1 == mLastVisibleItemPosition
+                && recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
+            mIsSlidingToLast = false;
+            loadMore();
+        }
+
+    }
+
+    @Override
+    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+        super.onScrolled(recyclerView, dx, dy);
+//        if(dy > 0){//向下滑动
+//            mIsSlidingToLast = true;
+//        }
+//        else {//向上滑动
+//            mIsSlidingToLast = false;
+//        }
+        mIsSlidingToLast = dy > 0;
+    }
+
+
+    public abstract void loadMore();
+}

+ 33 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/ViewHolder.java

@@ -0,0 +1,33 @@
+package com.kfzs.libs.widget.rv;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.util.SparseArray;
+import android.view.View;
+
+/**
+ * Created by Administrator on 2017/12/15 0015.
+ */
+
+public class ViewHolder extends RecyclerView.ViewHolder{
+
+    private SparseArray<View> views;
+    protected View itemView;
+    private Context mContext;
+
+    public ViewHolder(Context context, View itemView) {
+        super(itemView);
+        mContext = context;
+        views = new SparseArray<>();
+        this.itemView = itemView;
+    }
+
+    public View getView(int resId){
+        View view = views.get(resId);
+        if(view == null){
+            view = itemView.findViewById(resId);
+            views.put(resId,view);
+        }
+        return view;
+    }
+}

+ 45 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/WrapperUtils.java

@@ -0,0 +1,45 @@
+package com.kfzs.libs.widget.rv;
+
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.view.ViewGroup;
+
+/**
+ * Created by zhy on 16/6/28.
+ */
+class WrapperUtils {
+    public interface SpanSizeCallback {
+        int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position);
+    }
+
+    public static void onAttachedToRecyclerView(RecyclerView.Adapter innerAdapter, RecyclerView recyclerView, final SpanSizeCallback callback) {
+        innerAdapter.onAttachedToRecyclerView(recyclerView);
+
+        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+        if (layoutManager instanceof GridLayoutManager) {
+            final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
+            final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup();
+
+            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
+                @Override
+                public int getSpanSize(int position) {
+                    return callback.getSpanSize(gridLayoutManager, spanSizeLookup, position);
+                }
+            });
+            gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount());
+        }
+    }
+
+    public static void setFullSpan(RecyclerView.ViewHolder holder) {
+        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+
+        if (lp != null
+                && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
+
+            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
+
+            p.setFullSpan(true);
+        }
+    }
+}

+ 211 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/decoration/RecyclerViewGridDivider.java

@@ -0,0 +1,211 @@
+package com.kfzs.libs.widget.rv.decoration;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.support.annotation.ColorRes;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.view.View;
+
+/**
+ *
+ */
+public class RecyclerViewGridDivider extends RecyclerView.ItemDecoration {
+    /**
+     * 绘制分割线的画笔
+     */
+    private Paint mPaint;
+    private Builder mBuilder;
+
+    public RecyclerViewGridDivider(Context context, Builder builder) {
+        mBuilder = builder;
+        initPaint(context,builder.mDividerColor);
+    }
+
+    private void initPaint(Context context, @ColorRes int dividerColor){
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setColor(ContextCompat.getColor(context,dividerColor));
+    }
+
+    @Override
+    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+
+        drawHorizontal(c, parent);
+        drawVertical(c, parent);
+    }
+
+    private int getSpanCount(RecyclerView parent) {
+        // 列数
+        int spanCount = -1;
+        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
+        if (layoutManager instanceof GridLayoutManager) {
+
+            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
+        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
+            spanCount = ((StaggeredGridLayoutManager) layoutManager)
+                    .getSpanCount();
+        }
+        return spanCount;
+    }
+
+    public void drawHorizontal(Canvas c, RecyclerView parent) {
+        int childCount = parent.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            boolean s = isLastColumn(parent,i,getSpanCount(parent),parent.getAdapter().getItemCount());
+            if(!s){
+                View child = parent.getChildAt(i);
+                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
+                        .getLayoutParams();
+                int left = child.getRight() + params.rightMargin;
+                int right = left + mBuilder.mDividerSize;
+                int top = child.getTop() - params.topMargin;
+                int bottom = child.getBottom() + params.bottomMargin + mBuilder.mDividerSize;
+                c.drawRect(left,top,right,bottom,mPaint);
+            }
+        }
+
+    }
+
+    public void drawVertical(Canvas c, RecyclerView parent) {
+        int childCount = parent.getChildCount();
+        int spanCount = getSpanCount(parent);
+        for (int i = 0; i < childCount; i++) {
+
+            View child = parent.getChildAt(i);
+            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
+                    .getLayoutParams();
+            int left = child.getLeft() - params.leftMargin;
+            int right = child.getRight() + params.rightMargin;
+            int top = child.getBottom() + params.bottomMargin;
+            int bottom = top + mBuilder.mDividerSize;
+            c.drawRect(left,top,right,bottom,mPaint);
+
+
+        }
+    }
+
+    private boolean isLastColumn(RecyclerView parent, int pos, int spanCount,
+                                 int childCount) {
+        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
+        if (layoutManager instanceof GridLayoutManager) {
+            if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
+            {
+                return true;
+            }
+        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
+            int orientation = ((StaggeredGridLayoutManager) layoutManager)
+                    .getOrientation();
+            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
+                if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
+                {
+                    return true;
+                }
+            } else {
+                childCount = childCount - childCount % spanCount;
+                if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
+                    return true;
+            }
+        }
+        return false;
+    }
+
+//    private boolean isLastRow(RecyclerView parent, int pos, int spanCount,
+//                                 int childCount) {
+//        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
+//        if (layoutManager instanceof GridLayoutManager) {
+//            if (pos / spanCount == totalRow(childCount,spanCount) - 1)// 如果是最后一列,则不需要绘制右边
+//            {
+//                return true;
+//            }
+//        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
+//            int orientation = ((StaggeredGridLayoutManager) layoutManager)
+//                    .getOrientation();
+//            if (orientation == StaggeredGridLayoutManager.VERTICAL) {
+//                if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
+//                {
+//                    return true;
+//                }
+//            } else {
+//                childCount = childCount - childCount % spanCount;
+//                if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
+//                    return true;
+//            }
+//        }
+//        return false;
+//    }
+
+    private int totalRow(int childCount,int spanCount){
+        if(childCount % spanCount == 0){
+            return childCount / spanCount;
+        }
+        else return childCount / spanCount + 1;
+    }
+
+    private int getColumn(int position,int spanCount){
+        return position % spanCount;
+    }
+
+    private int getRow(int position,int spanCount){
+        return position / spanCount;
+    }
+
+
+
+    @Override
+    public void getItemOffsets(Rect outRect, View view,
+                               RecyclerView parent, RecyclerView.State state) {
+        int position = parent.getChildAdapterPosition(view);
+        int spanCount = getSpanCount(parent);
+        int childCount = parent.getAdapter().getItemCount();
+
+
+        if(isLastColumn(parent,position,spanCount,childCount)){//最后一列
+            outRect.set(0,0,0,mBuilder.mDividerSize);
+        }
+        else {
+            outRect.set(0,0,mBuilder.mDividerSize,mBuilder.mDividerSize);
+        }
+
+    }
+
+    public static class Builder{
+        /**
+         * 分割线的尺寸,如果当前是垂直,该值就是分割线的宽度,
+         * 如果分割线是水平,该值就是分割线的高度,默认值10px
+         */
+        private int mDividerSize = 10;
+        /**
+         * 分割线颜色,默认是系统的
+         */
+        private @ColorRes
+        int mDividerColor = android.R.color.background_dark;
+
+        private Context mContext;
+
+        public Builder(Context context){
+            mContext = context;
+        }
+
+
+        public Builder dividerColor(int dividerColor) {
+            mDividerColor = dividerColor;
+            return this;
+        }
+
+        public Builder dividerSize(int dividerSize) {
+            mDividerSize = dividerSize;
+            return this;
+        }
+
+        public RecyclerViewGridDivider build(){
+            return new RecyclerViewGridDivider(mContext,this);
+        }
+
+    }
+
+}

+ 223 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/decoration/RecyclerViewLinearDivider.java

@@ -0,0 +1,223 @@
+package com.kfzs.libs.widget.rv.decoration;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.support.annotation.ColorRes;
+import android.support.annotation.IntDef;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Created by Administrator on 2017/2/27 0027.
+ */
+
+public class RecyclerViewLinearDivider extends RecyclerView.ItemDecoration {
+
+    /**
+     * 绘制分割线的画笔
+     */
+    private Paint mPaint;
+    private Builder mBuilder;
+
+    public RecyclerViewLinearDivider(Context context, Builder builder) {
+        mBuilder = builder;
+        initPaint(context,builder.mDividerColor);
+    }
+
+
+    private void initPaint(Context context, @ColorRes int dividerColor){
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setColor(ContextCompat.getColor(context,dividerColor));
+    }
+
+
+
+    /**
+     *
+     * @param outRect 该参数里面的是个方向值,表示绘制时,每个ItemView的各个方向的padding值
+     * @param view
+     * @param parent
+     * @param state
+     */
+    @Override
+    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+        int position = parent.getChildAdapterPosition(view);
+        int lastItemPosition = parent.getAdapter().getItemCount() - 1;
+        if(LinearLayoutManager.VERTICAL == mBuilder.mOrientation){
+            if(position == 0){
+                //第一个Item上面需要绘制分割线,让top方向留下可绘制的宽度
+                if(mBuilder.mHasStartDivider){
+                    outRect.top = mBuilder.mDividerSize;
+                }
+                outRect.bottom = mBuilder.mDividerSize;
+            }
+            else if(position == lastItemPosition){//最后一个item,如果这里不判断,最后会留有一段padding
+                if(mBuilder.mHasEndDivider){
+                    outRect.bottom = mBuilder.mDividerSize;
+                }
+            }
+            else outRect.bottom = mBuilder.mDividerSize;
+        }
+        else if(LinearLayoutManager.HORIZONTAL == mBuilder.mOrientation){
+            if(position == 0){
+                //第一个Item上面需要绘制分割线,让top方向留下可绘制的宽度
+                if(mBuilder.mHasStartDivider){
+                    outRect.left = mBuilder.mDividerSize;
+                }
+                outRect.right = mBuilder.mDividerSize;
+            }
+            else if(position == lastItemPosition){//最后一个item,如果这里不判断,最后会留有一段padding
+                if(mBuilder.mHasEndDivider){
+                    outRect.right = mBuilder.mDividerSize;
+                }
+            }
+            else outRect.right = mBuilder.mDividerSize;
+
+        }
+    }
+
+    @Override
+    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+        super.onDraw(c, parent, state);
+        int childCount = parent.getChildCount();
+        if(LinearLayoutManager.VERTICAL == mBuilder.mOrientation){
+            drawVertical(c,parent,childCount);
+        }
+        else if(LinearLayoutManager.HORIZONTAL == mBuilder.mOrientation){
+            drawHorizontal(c,parent,childCount);
+        }
+    }
+
+    private void drawVertical(Canvas c, RecyclerView parent, int childCount){
+        int left = parent.getPaddingLeft() + mBuilder.mMarginLeft;
+        int right = parent.getWidth() - parent.getPaddingRight() - mBuilder.mMarginRight;
+
+        //绘制第一个Item上面的分割线
+        if(mBuilder.mHasStartDivider && childCount > 0){
+            View child = parent.getChildAt(0);
+            c.drawRect(left, child.getTop() - mBuilder.mDividerSize, right, child.getTop(), mPaint);
+        }
+
+        int forCount = !mBuilder.mHasEndDivider ? childCount - 1 : childCount;
+        for (int i = 0; i < forCount; i++) {
+            View child = parent.getChildAt(i);
+            c.drawRect(left, child.getBottom(), right, child.getBottom() + mBuilder.mDividerSize, mPaint);
+        }
+
+    }
+
+    private void drawHorizontal(Canvas c, RecyclerView parent, int childCount){
+        int top = parent.getPaddingTop();
+        int bottom = parent.getHeight() - parent.getPaddingBottom();
+
+
+        //绘制第一个Item左边的分割线
+        if(mBuilder.mHasStartDivider && childCount > 0){
+            View child = parent.getChildAt(0);
+            c.drawRect(child.getLeft() - mBuilder.mDividerSize, top, child.getLeft(), bottom, mPaint);
+        }
+
+        int forCount = !mBuilder.mHasEndDivider ? childCount - 1 : childCount;
+        for (int i = 0; i < forCount; i++) {
+            View child = parent.getChildAt(i);
+            c.drawRect(child.getRight(), top, child.getRight()+  mBuilder.mDividerSize, bottom, mPaint);
+        }
+    }
+
+
+
+    @IntDef({LinearLayoutManager.HORIZONTAL, LinearLayoutManager.VERTICAL})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface LayoutManagerOrientation{
+
+    }
+
+    public static class Builder{
+        /**
+         * 分割线的尺寸,如果当前RecyclerView是垂直滚动,该值就是分割线的高度,
+         * 如果RecycleView是水平滚动,该值就是分割线的宽度,默认值10px
+         */
+        private int mDividerSize = 10;
+        /**
+         * 分割线距离RecyclerView左边的距离,默认为0,也就是在最左边开始绘制,
+         * 该值只有RecycleView垂直滚动才有效
+         */
+        private int mMarginLeft = 0;
+        /**
+         * 分割线距离RecyclerView右边边的距离,默认为0,也就是在最右边开始绘制,
+         * 该值只有RecycleView垂直滚动才有效
+         */
+        private int mMarginRight = 0;
+        /**
+         * RecyclerView最后一个Item下面是否绘制分割线,默认不绘制
+         */
+        private boolean mHasEndDivider = false;
+        /**
+         * RecyclerView第一个Item上面是否绘制分割线,默认不绘制
+         */
+        private boolean mHasStartDivider = false;
+
+        /**
+         * 分割线颜色,默认是系统的
+         */
+        private @ColorRes
+        int mDividerColor = android.R.color.background_dark;
+
+        /**
+         * 当前RecycleView的滚动方向
+         */
+        private @LayoutManagerOrientation int mOrientation = LinearLayoutManager.VERTICAL;
+
+        private Context mContext;
+
+        public Builder(Context context){
+            mContext = context;
+        }
+
+        public Builder dividerColor(int dividerColor) {
+            mDividerColor = dividerColor;
+            return this;
+        }
+
+        public Builder dividerSize(int dividerSize) {
+            mDividerSize = dividerSize;
+            return this;
+        }
+
+        public Builder marginRight(int marginRight) {
+            mMarginRight = marginRight;
+            return this;
+        }
+
+        public Builder marginLeft(int marginLeft) {
+            mMarginLeft = marginLeft;
+            return this;
+        }
+
+        public Builder hasEndDivider(boolean hasEndDivider) {
+            mHasEndDivider = hasEndDivider;
+            return this;
+        }
+
+        public Builder hasStartDivider(boolean hasStartDivider) {
+            mHasStartDivider = hasStartDivider;
+            return this;
+        }
+
+        public Builder orientation(int orientation) {
+            mOrientation = orientation;
+            return this;
+        }
+
+        public RecyclerViewLinearDivider build(){
+            return new RecyclerViewLinearDivider(mContext,this);
+        }
+    }
+}

+ 18 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/rv/listener/OnRecyclerViewItemClickListener.java

@@ -0,0 +1,18 @@
+package com.kfzs.libs.widget.rv.listener;
+
+import android.view.View;
+
+/**
+ * RecyclerView的通用Item点击监听器
+ * Created by Administrator on 2018/2/11 0011.
+ */
+
+public interface OnRecyclerViewItemClickListener<T> {
+    /**
+     *RecyclerView的item单击事件,需要设置在Adapter上
+     * @param itemView 就是ViewHolder中的itemView
+     * @param data  每个item对应的javaBean对象
+     * @param position 点击的item的序号
+     */
+    void onRecyclerViewItemClick(View itemView, T data, int position);
+}

+ 150 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/toast/MessageSheetToastView.java

@@ -0,0 +1,150 @@
+package com.kfzs.libs.widget.toast;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.annotation.ColorRes;
+import android.support.annotation.IntDef;
+import android.support.v4.content.ContextCompat;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.widget.TextView;
+import com.kfzs.libs.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import butterknife.BindView;
+
+/**
+ * 单独显示文字提示的ToastView,如果需要自定义其他的ToastView,可以参考这个
+ * Created by Administrator on 2018/2/13 0013.
+ */
+
+public class MessageSheetToastView extends ToastView{
+
+    public static final int TOP = 0;
+    public static final int BOTTOM = 1;
+    TextView tvMessage;
+
+    /**
+     * 默认TOP
+     */
+    private @SheetDirection int sheetDirection = TOP;
+    private Builder builder;
+
+    public void setBuilder(Builder builder) {
+        this.builder = builder;
+        if (builder != null) {
+            sheetDirection = builder.sheetDirection;
+        }
+    }
+
+    @Override
+    protected int windowAnimationStyle() {
+        if(TOP == sheetDirection){
+            return R.style.TopSheetAnimStyle;
+        }
+        else if(BOTTOM == sheetDirection){
+            return R.style.BottomSheetAnimStyle;
+        }
+
+        else throw new IllegalArgumentException("MessageSheetToastView's sheetDirection must be MessageSheetToastView.TOP or MessageSheetToastView.BOTTOM");
+    }
+
+    @Override
+    public int windowGravity() {
+        if(TOP == sheetDirection){
+            return Gravity.TOP;
+        }
+        else if(BOTTOM == sheetDirection){
+            return Gravity.BOTTOM;
+        }
+
+        else throw new IllegalArgumentException("MessageSheetToastView's sheetDirection must be MessageSheetToastView.TOP or MessageSheetToastView.BOTTOM");
+    }
+
+    @Override
+    public int toastViewLayout() {
+        return R.layout.toast_single_message;
+    }
+
+    @Override
+    public void setupContentView() {
+        tvMessage = getView().findViewById(R.id.tv_message);
+        if (builder != null) {
+            tvMessage.setText(builder.msg);
+            tvMessage.setTextColor(builder.textColor);
+            tvMessage.setBackgroundColor(builder.bgColor);
+            tvMessage.setTextSize(TypedValue.COMPLEX_UNIT_SP,builder.textSize);
+            setStatusBarMarginColor(builder.statusBarColor);
+            setDismissTime(builder.autoDismissTime);
+        }
+    }
+
+    public static class Builder{
+        private Context context;
+        private int sheetDirection;
+        private String msg;
+        private int textColor = Color.WHITE;
+        private int bgColor = Color.RED;
+        private int statusBarColor = Color.TRANSPARENT;
+        private int textSize = 17;
+        private long autoDismissTime = 1000;
+
+        public Builder(Context context){
+            this.context = context;
+        }
+
+        public Builder message(String msg) {
+            this.msg = msg;
+            return this;
+        }
+
+        public Builder sheetDirection(@SheetDirection int sheetDirection) {
+            this.sheetDirection = sheetDirection;
+            return this;
+        }
+
+        public Builder textColor(@ColorRes int color) {
+            this.textColor = ContextCompat.getColor(context, color);
+            return this;
+        }
+
+        public Builder textSize(int textSize) {
+            this.textSize = textSize;
+            return this;
+        }
+
+        public Builder bgColor(@ColorRes int color) {
+            this.bgColor = ContextCompat.getColor(context, color);
+            return this;
+        }
+
+        public Builder statusBarColor(@ColorRes int color) {
+            this.statusBarColor = ContextCompat.getColor(context, color);
+            return this;
+        }
+
+        public Builder autoDismissTime(long time) {
+            this.autoDismissTime = time;
+            return this;
+        }
+
+        public MessageSheetToastView build(){
+            MessageSheetToastView messageSheetToastView = new MessageSheetToastView();
+            messageSheetToastView.setBuilder(this);
+            return messageSheetToastView;
+        }
+    }
+
+
+    /**
+     * 方向,这里只有上下两种种
+     */
+    @IntDef({TOP,BOTTOM})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface SheetDirection{
+
+    }
+
+
+
+}

+ 233 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/toast/ToastView.java

@@ -0,0 +1,233 @@
+package com.kfzs.libs.widget.toast;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import butterknife.ButterKnife;
+
+
+/**
+ * 自定义toast的基类
+ * Created by Administrator on 2018/2/13 0013.
+ */
+
+public abstract class ToastView extends DialogFragment {
+
+    /**
+     * 没有设置dialog的弹出动画,这个是默认值
+     */
+    private static final int NO_SET_ANIMATION = -1;
+    private Activity activity;
+    private FrameLayout containerView;
+    /**
+     * 显示后,是否自动关闭,默认关闭
+     */
+    private boolean autoDismiss = true;
+    /**
+     * 延迟关闭的时间,默认1秒
+     */
+    private long dismissTime = 1000;
+    private Handler dismissHandler;
+    private Runnable delayDismissRunnable = new Runnable() {
+        @Override
+        public void run() {
+            dismiss();
+        }
+    };
+
+    public void setDismissTime(long dismissTime) {
+        this.dismissTime = dismissTime;
+    }
+
+    public void setAutoDismiss(boolean autoDismiss) {
+        this.autoDismiss = autoDismiss;
+    }
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        activity = (Activity) context;
+
+    }
+
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        /**
+         *  如果采用onCreateView方式初始化Dialog,并未有使用自己创建的Dialog实例,
+         *  因此这种方式产生的Dialog是DialogFragment内部自己创建的,创建时机是在DialogFragment源码中的onStart()中,
+         *  而要设置Dialog的宽高,必须要Dialog初始化之后才能够生效,因此需要在super.onStart();调用之后设置。
+         */
+        Window window = getDialog().getWindow();
+        if(window != null){
+            window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
+        }
+
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        //注意:这里传入的ViewGroup container为null
+        windowConfigs();
+        dismissHandler = new Handler();
+        //Gravity.TOP这种情况在视图上方添加一个statusBar高度的margin,让状态栏露出来
+        //这里就不再进行区分Gravity.BOTTOM情况下,手机上是否有虚拟导航键显示,如果要做处理,与Gravity.TOP类似
+        if(Gravity.TOP == windowGravity()){
+            //为了确保露出来的状态栏高度能够配置颜色,因此在最外加一层FrameLayout,通过设置FrameLayout的背景颜色就可以模拟状态栏改变颜色
+            containerView = new FrameLayout(activity);
+            containerView.setPadding(0,getStatusHeight(activity),0,0);
+            inflater.inflate(toastViewLayout(), containerView,true);
+            //
+            ButterKnife.bind(this, containerView);
+            //
+            setupContentView();
+            return containerView;
+        }
+        else {
+            View toastView = inflater.inflate(toastViewLayout(),null);
+            //
+            ButterKnife.bind(this,toastView);
+            //
+            setupContentView();
+            return toastView;
+        }
+
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        delayDismissDialog();
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        dismissHandler.removeCallbacks(delayDismissRunnable);
+        dismissHandler = null;
+    }
+
+    /**
+     * 设置状态栏的颜色
+     * @param color
+     */
+    void setStatusBarMarginColor(int color){
+        if(windowGravity() == Gravity.TOP){
+            if (containerView != null) {
+                containerView.setBackgroundColor(color);
+            }
+        }
+    }
+
+
+    /**
+     * window的属性配置,这里在onCreateView中设置,不通过类似BaseDialogFragment方式在onCreateDialog配置,
+     * 是想让整个ToastView的视图界面将状态栏填充,防止从屏幕顶部显示动画效果在移动到状态栏处就突然闪动消失
+     */
+    private void windowConfigs() {
+        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
+        Window window = getDialog().getWindow();
+        if(window != null){
+            if(Build.VERSION.SDK_INT >= 19){
+                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            }
+            //清理蒙板
+            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+            window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+            if(windowAnimationStyle() != NO_SET_ANIMATION){
+                window.setWindowAnimations(windowAnimationStyle());
+            }
+            window.setGravity(windowGravity());
+            windowOtherSettings(window);
+        }
+    }
+
+    /**
+     * window显示内容的Gravity
+     * @return
+     */
+    public int windowGravity(){
+        return Gravity.CENTER;
+    }
+
+    /**
+     * 关于Window的其他配置,可以重写该方法
+     * @param window
+     */
+    public void windowOtherSettings(Window window){
+
+    }
+
+    /**
+     * 延迟相应时间关闭ToastView
+     */
+    private void delayDismissDialog(){
+        if(autoDismiss){
+            dismissHandler.postDelayed(delayDismissRunnable,dismissTime);
+        }
+    }
+
+    /**
+     * @return dialog的布局文件id
+     */
+    public abstract @LayoutRes int toastViewLayout();
+
+    /**
+     * 初始化dialog的控件,这里绑定了ButterKnife,直接使用@BindView
+     */
+    public abstract void setupContentView();
+
+    /**
+     * 重写该方法,可以修改dialog的弹出动画
+     * 比如 :
+     * <style name="BottomSheetDialogStyle">
+     *     <item name="android:windowEnterAnimation">@anim/bottom_sheet_enter</item>
+     *     <item name="android:windowExitAnimation">@anim/bottom_sheet_exit</item>
+     * </style>
+     * @return 返回dialog弹出动画的style
+     */
+    protected int windowAnimationStyle(){
+        return NO_SET_ANIMATION;
+    }
+
+    /**
+     * 获得状态栏的高度
+     *
+     * @param context
+     * @return
+     */
+    private int getStatusHeight(Context context) {
+
+        int statusHeight = -1;
+        try {
+            Class<?> clazz = Class.forName("com.android.internal.R$dimen");
+            Object object = clazz.newInstance();
+            int height = Integer.parseInt(clazz.getField("status_bar_height")
+                    .get(object).toString());
+            statusHeight = context.getResources().getDimensionPixelSize(height);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return statusHeight;
+    }
+
+
+
+}

+ 301 - 0
kfzslibrary/src/main/java/com/kfzs/libs/widget/toast/TopToastView.java

@@ -0,0 +1,301 @@
+package com.kfzs.libs.widget.toast;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.support.annotation.ColorRes;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v7.widget.AppCompatTextView;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+import android.widget.TextView;
+
+import com.kfzs.libs.R;
+
+import java.lang.ref.WeakReference;
+
+
+/**
+ * Created by Administrator on 2017/9/28 0028.
+ */
+@Deprecated
+public class TopToastView extends DialogFragment {
+
+    public static final int DISMISS_DURATION = 4000;
+    //显示toast的间隔时间,如果有按钮点击,不能让toast一直不停显示
+    //下次可显示toast的间隔时间
+    public static final long INTERVAL_TIME = 10000;
+    public static final String INTERVAL_KEY = "top_toast_time_interval";
+
+    protected Builder mBuilder;
+    private int mActionBarHeight;
+    private int mScreenWidth;
+    private int mStatusBarHeight;
+    private Handler mHandler;
+
+    private Runnable mDelayDismiss = new Runnable() {
+        @Override
+        public void run() {
+            dismiss();
+        }
+    };
+
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        Window window = getDialog().getWindow();
+        if(window != null){
+            window.setLayout(mScreenWidth,mActionBarHeight+mStatusBarHeight);
+        }
+
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+        Window window = getDialog().getWindow();
+        if(window != null){
+            if(Build.VERSION.SDK_INT >= 19){
+                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            }
+//            window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+            //清理背景变暗
+            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+            window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+            window.getAttributes().windowAnimations = R.style.ToastView;
+            window.getAttributes().gravity = Gravity.TOP;
+        }
+
+
+        mHandler = new Handler();
+
+        mActionBarHeight = getActionBarHeight(mBuilder.mContext.get());
+        mScreenWidth = getScreenWidth(mBuilder.mContext.get());
+        mStatusBarHeight = getStatusHeight(mBuilder.mContext.get());
+
+        TextView toastTextView = new AppCompatTextView(mBuilder.mContext.get());
+        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,getActionBarHeight(mBuilder.mContext.get()));
+        layoutParams.topMargin = mStatusBarHeight;
+        toastTextView.setLayoutParams(layoutParams);
+        toastTextView.setGravity(Gravity.CENTER_VERTICAL);
+        int paddingHorizontal = dip2px(mBuilder.mContext.get(),20);
+        toastTextView.setPadding(paddingHorizontal,0,paddingHorizontal,0);
+        toastTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP,18);
+        toastTextView.setLines(1);
+        toastTextView.setEllipsize(TextUtils.TruncateAt.END);
+        toastTextView.setText(mBuilder.mMessage);
+        toastTextView.setBackgroundColor(mBuilder.mBgColor);
+        toastTextView.setTextColor(mBuilder.mTextColor);
+
+        FrameLayout rootView = new FrameLayout(mBuilder.mContext.get());
+        rootView.setBackgroundColor(mBuilder.mStatusBarColor);
+        rootView.addView(toastTextView);
+
+        return rootView;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        delayDismiss();
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        mHandler.removeCallbacks(mDelayDismiss);
+        mHandler = null;
+    }
+
+    private void delayDismiss(){
+        if(mBuilder.mAutoDismiss){
+            mHandler.postDelayed(mDelayDismiss,DISMISS_DURATION);
+        }
+    }
+
+
+    public void showToast(){
+        if(mBuilder.mIsGlobalToastView){
+            if(!canShowToast(mBuilder.getContext().get()))return;
+        }
+        show(((FragmentActivity)mBuilder.mContext.get()).getSupportFragmentManager(),TopToastView.class.getSimpleName());
+    }
+
+    /**
+     * 防止同时显示多个ToastView
+     * @param context
+     * @return
+     */
+    private boolean canShowToast(Context context){
+        synchronized (this) {
+
+            SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+            long lastTime = sharedPreferences.getLong(INTERVAL_KEY,0);
+            long currentTime = System.currentTimeMillis();
+            if(currentTime - lastTime >= INTERVAL_TIME){
+                sharedPreferences.edit().putLong(INTERVAL_KEY,currentTime).apply();
+                return true;
+            }
+            return false;
+        }
+    }
+
+    private int getActionBarHeight(Context context){
+        TypedArray actionbarSizeTypedArray = context.obtainStyledAttributes(new int[]{android.R.attr.actionBarSize});
+        //actionbar高度
+        int height = (int) actionbarSizeTypedArray.getDimension(0,0);
+        actionbarSizeTypedArray.recycle();
+        return height;
+    }
+
+    /**
+     * 获得屏幕高度
+     *
+     * @param context
+     * @return
+     */
+    public static int getScreenWidth(Context context) {
+        WindowManager wm = (WindowManager) context
+                .getSystemService(Context.WINDOW_SERVICE);
+        DisplayMetrics outMetrics = new DisplayMetrics();
+        wm.getDefaultDisplay().getMetrics(outMetrics);
+        return outMetrics.widthPixels;
+    }
+
+
+    /**
+     * 获得状态栏的高度
+     *
+     * @param context
+     * @return
+     */
+    public int getStatusHeight(Context context) {
+
+        int statusHeight = -1;
+        try {
+            Class<?> clazz = Class.forName("com.android.internal.R$dimen");
+            Object object = clazz.newInstance();
+            int height = Integer.parseInt(clazz.getField("status_bar_height")
+                    .get(object).toString());
+            statusHeight = context.getResources().getDimensionPixelSize(height);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return statusHeight;
+    }
+
+    /**
+     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
+     */
+    private int dip2px(Context context, float dpValue) {
+        final float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+
+
+    public static class Builder{
+
+        private WeakReference<Context> mContext;
+        private int mBgColor = Color.RED;
+        private int mStatusBarColor = Color.LTGRAY;
+        private int mTextColor = Color.WHITE;
+        private String mMessage;
+        private boolean mAutoDismiss = true;
+        private boolean mIsGlobalToastView = false;
+
+        public Builder(Context context){
+            mContext = new WeakReference<>(context);
+        }
+
+        public WeakReference<Context> getContext() {
+            return mContext;
+        }
+
+        public Builder bgColor(@ColorRes int color){
+            mBgColor = getResources().getColor(color);
+            return this;
+        }
+
+        public Builder bgColor(String color){
+            mBgColor = Color.parseColor(color);
+            return this;
+        }
+
+        public Builder statusBarColor(@ColorRes int color){
+            mStatusBarColor = getResources().getColor(color);
+            return this;
+        }
+
+        public Builder statusBarColor(String color){
+            mStatusBarColor = Color.parseColor(color);
+            return this;
+        }
+
+        public Builder textColor(@ColorRes int color){
+            mTextColor = getResources().getColor(color);
+            return this;
+        }
+
+        public Builder textColor(String color){
+            mTextColor = Color.parseColor(color);
+            return this;
+        }
+
+
+        public Builder message(@StringRes int msg){
+            mMessage = getResources().getString(msg);
+            return this;
+        }
+
+        public Builder message(String msg){
+            mMessage = msg;
+            return this;
+        }
+
+        public Builder autoDismiss(boolean autoDismiss){
+            mAutoDismiss = autoDismiss;
+            return this;
+        }
+
+        public Builder globalToastView(boolean global) {
+            mIsGlobalToastView = global;
+            return this;
+        }
+
+        public TopToastView build(){
+            TopToastView topToastView = new TopToastView();
+            topToastView.mBuilder = this;
+            return topToastView;
+        }
+
+        private Resources getResources(){
+            return mContext.get().getResources();
+        }
+
+    }
+
+
+}

+ 9 - 0
kfzslibrary/src/main/res/anim/bottom_sheet_enter.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate
+        android:duration="300"
+        android:fromYDelta="100%"
+        android:toYDelta="0"
+        />
+
+</set>

+ 9 - 0
kfzslibrary/src/main/res/anim/bottom_sheet_exit.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate
+        android:duration="300"
+        android:fromYDelta="0"
+        android:toYDelta="100%"
+        />
+
+</set>

+ 8 - 0
kfzslibrary/src/main/res/anim/fade_in.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha
+        android:fromAlpha="0"
+        android:toAlpha="1"
+        android:duration="300"
+        />
+</set>

+ 8 - 0
kfzslibrary/src/main/res/anim/fade_out.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <alpha
+        android:fromAlpha="1"
+        android:toAlpha="0"
+        android:duration="300"
+        />
+</set>

+ 8 - 0
kfzslibrary/src/main/res/anim/toastview_dissmiss.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate
+        android:duration="300"
+        android:fromYDelta="0"
+        android:toYDelta="-100%"
+        />
+</set>

+ 8 - 0
kfzslibrary/src/main/res/anim/toastview_show.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate
+        android:duration="300"
+        android:fromYDelta="-100%"
+        android:toYDelta="0"
+        />
+</set>

+ 9 - 0
kfzslibrary/src/main/res/anim/top_sheet_enter.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate
+        android:duration="300"
+        android:fromYDelta="-100%"
+        android:toYDelta="0"
+        />
+
+</set>

+ 9 - 0
kfzslibrary/src/main/res/anim/top_sheet_exit.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate
+        android:duration="300"
+        android:fromYDelta="0"
+        android:toYDelta="-100%"
+        />
+
+</set>

+ 5 - 0
kfzslibrary/src/main/res/drawable-v21/s_item_bg_double_border.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/mui_drawable_color_list_item_pressed">
+    <item android:drawable="@drawable/list_item_bg_double_border"/>
+</ripple>

+ 5 - 0
kfzslibrary/src/main/res/drawable-v21/s_list_item_bg_bottom_border.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/mui_drawable_color_list_item_pressed">
+    <item android:drawable="@drawable/list_item_bg_bottom_border"/>
+</ripple>

+ 5 - 0
kfzslibrary/src/main/res/drawable-v21/s_list_item_bg_none_border.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/mui_drawable_color_list_item_pressed">
+    <item android:drawable="@android:color/white"/>
+</ripple>

+ 5 - 0
kfzslibrary/src/main/res/drawable/list_item_bg_bottom_border.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:drawable="@color/mui_drawable_color_list_item_pressed"/>
+    <item android:drawable="@android:color/white" android:bottom="@dimen/mui_list_divider_height"/>
+</layer-list>

+ 5 - 0
kfzslibrary/src/main/res/drawable/list_item_bg_bottom_border_pressed.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:drawable="@color/mui_drawable_color_list_item_pressed"/>
+    <item android:drawable="@color/mui_drawable_color_list_item_pressed" android:bottom="@dimen/mui_list_divider_height"/>
+</layer-list>

+ 8 - 0
kfzslibrary/src/main/res/drawable/list_item_bg_double_border.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@color/mui_drawable_color_list_item_pressed"/>
+    <item
+        android:bottom="@dimen/mui_list_divider_height"
+        android:drawable="@android:color/white"
+        android:top="@dimen/mui_list_divider_height"/>
+</layer-list>

+ 8 - 0
kfzslibrary/src/main/res/drawable/list_item_bg_double_border_pressed.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@color/mui_drawable_color_list_item_pressed"/>
+    <item
+        android:bottom="@dimen/mui_list_divider_height"
+        android:drawable="@color/mui_drawable_color_list_item_pressed"
+        android:top="@dimen/mui_list_divider_height"/>
+</layer-list>

+ 5 - 0
kfzslibrary/src/main/res/drawable/s_item_bg_double_border.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/list_item_bg_double_border_pressed" android:state_pressed="true"/>
+    <item android:drawable="@drawable/list_item_bg_double_border"/>
+</selector>

+ 5 - 0
kfzslibrary/src/main/res/drawable/s_list_item_bg_bottom_border.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/list_item_bg_bottom_border_pressed" android:state_pressed="true"/>
+    <item android:drawable="@drawable/list_item_bg_bottom_border"/>
+</selector>

+ 5 - 0
kfzslibrary/src/main/res/drawable/s_list_item_bg_none_border.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@color/mui_drawable_color_list_item_pressed" android:state_pressed="true"/>
+    <item android:drawable="@android:color/white"/>
+</selector>

+ 18 - 0
kfzslibrary/src/main/res/layout/grouplist_arrow_item.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+
+    <include
+        layout="@layout/grouplist_item_view"
+        />
+
+
+    <ImageView
+        android:id="@+id/gx_groupList_item_arrow"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        />
+
+
+</merge>

+ 71 - 0
kfzslibrary/src/main/res/layout/grouplist_item_view.xml

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+
+    <ImageView
+        android:id="@+id/gx_groupList_item_imageView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginRight="@dimen/gx_groupList_item_innerMargin"
+        android:contentDescription="@null"
+        android:scaleType="centerCrop"
+        />
+
+
+        <RelativeLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:layout_marginRight="@dimen/gx_groupList_item_innerMargin"
+            >
+            <TextView
+                android:id="@+id/gx_groupList_item_titleTextView"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:includeFontPadding="false"
+                android:maxLines="1"
+                android:textColor="@color/gx_groupList_item_title_textColor"
+                android:textSize="@dimen/gx_groupList_item_title_textSize"
+                />
+
+            <TextView
+                android:id="@+id/gx_groupList_item_subTitleTextView"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:includeFontPadding="false"
+                android:maxLines="1"
+                android:textColor="@color/gx_groupList_item_subTitle_textColor"
+                android:textSize="@dimen/gx_groupList_item_subTitle_textSize"
+                android:visibility="gone"
+                android:layout_below="@id/gx_groupList_item_titleTextView"
+                />
+
+        </RelativeLayout>
+
+
+        <TextView
+            android:id="@+id/gx_groupList_item_detailTextView"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:includeFontPadding="false"
+            android:layout_gravity="center_vertical"
+            android:layout_marginRight="@dimen/gx_groupList_item_innerMargin"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:gravity="right"
+            android:textColor="@color/gx_groupList_item_detail_textColor"
+            android:textSize="@dimen/gx_groupList_item_detail_textSize"
+            />
+
+
+    <FrameLayout
+        android:id="@+id/gx_groupList_item_accessoryView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        />
+
+
+</merge>

+ 40 - 0
kfzslibrary/src/main/res/layout/navigation_bar.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+
+    <LinearLayout
+        android:id="@+id/navigationBar_left_container"
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_centerVertical="true"
+        android:gravity="center_vertical"
+        android:layout_marginRight="@dimen/navigationBar_innerMargin"
+        />
+
+
+    <TextView
+        android:id="@+id/navigationBar_titleTextView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:textSize="@dimen/navigationBar_titleTextSize"
+        android:textColor="@color/navigationBar_titleTextColor"
+        />
+
+    <LinearLayout
+        android:id="@+id/navigationBar_right_container"
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_centerVertical="true"
+        android:gravity="center_vertical|right"
+        android:layout_toRightOf="@id/navigationBar_titleTextView"
+        android:layout_marginLeft="@dimen/navigationBar_innerMargin"
+        />
+
+
+
+</merge>

+ 26 - 0
kfzslibrary/src/main/res/layout/recyclerview_default_load_more.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:gravity="center"
+        android:background="#eeeeee"
+        >
+
+    <ProgressBar
+        android:id="@+id/pb_loading"
+        android:layout_width="20dp"
+        android:layout_height="20dp"
+        android:indeterminate="true"
+        android:layout_marginRight="5dp"
+        style="?android:attr/progressBarStyleSmall"
+        android:visibility="gone"
+        />
+    <TextView
+        android:id="@+id/tv_state"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="15sp"
+        android:textColor="#282828"
+        android:text="查看更多"
+        />
+</LinearLayout>

+ 15 - 0
kfzslibrary/src/main/res/layout/toast_single_message.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tv_message"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/actionBarSize"
+    android:ellipsize="end"
+    android:gravity="center_vertical"
+    android:paddingLeft="16dp"
+    android:paddingRight="16dp"
+    android:paddingTop="5dp"
+    android:paddingBottom="5dp"
+    />
+
+

+ 22 - 0
kfzslibrary/src/main/res/values/grouplist_values.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+<!--##################################grouplist的公共配置########################################-->
+    <!--dimen-->
+    <dimen name="mui_list_divider_height">1px</dimen>
+    <dimen name="gx_groupList_item_minHeight">45dp</dimen>
+    <dimen name="gx_groupList_item_horizontalPadding">16dp</dimen>
+    <dimen name="gx_groupList_item_innerMargin">10dp</dimen>
+    <dimen name="gx_groupList_item_headerHeight">10dp</dimen>
+    <!--字体大小-->
+    <dimen name="gx_groupList_item_title_textSize">15sp</dimen>
+    <dimen name="gx_groupList_item_subTitle_textSize">12sp</dimen>
+    <dimen name="gx_groupList_item_detail_textSize">13sp</dimen>
+    <dimen name="gx_groupList_item_header_textSize">16sp</dimen>
+    <!--color-->
+    <color name="gx_groupList_item_title_textColor">#000000</color>
+    <color name="gx_groupList_item_subTitle_textColor">#282828</color>
+    <color name="gx_groupList_item_detail_textColor">#888888</color>
+    <color name="gx_groupList_item_header_textColor">#000000</color>
+    <color name="mui_drawable_color_list_item_pressed">#DEE0E2</color>
+</resources>

+ 10 - 0
kfzslibrary/src/main/res/values/navigationbar_values.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <dimen name="navigationBar_contentInset">12dp</dimen>
+    <dimen name="navigationBar_innerMargin">10dp</dimen>
+    <dimen name="navigationBar_itemMargin">8dp</dimen>
+    <dimen name="navigationBar_titleTextSize">20sp</dimen>
+    <color name="navigationBar_titleTextColor">#ffffff</color>
+
+</resources>

+ 3 - 0
kfzslibrary/src/main/res/values/strings.xml

@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">KFZSLibrary</string>
+</resources>

+ 27 - 0
kfzslibrary/src/main/res/values/toast_values.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <style name="ToastView" parent="@android:style/Theme.Dialog">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:backgroundDimEnabled">true</item><!--activity不变暗-->
+        <item name="android:background">@android:color/transparent</item>
+        <item name="android:windowEnterAnimation">@anim/toastview_show</item>
+        <item name="android:windowExitAnimation">@anim/toastview_dissmiss</item>
+    </style>
+
+
+    <style name="TopSheetAnimStyle" >
+        <item name="android:windowEnterAnimation">@anim/top_sheet_enter</item>
+        <item name="android:windowExitAnimation">@anim/top_sheet_exit</item>
+    </style>
+
+    <style name="BottomSheetAnimStyle" >
+        <item name="android:windowEnterAnimation">@anim/bottom_sheet_enter</item>
+        <item name="android:windowExitAnimation">@anim/bottom_sheet_exit</item>
+    </style>
+    <style name="FadeAnimStyle" >
+        <item name="android:windowEnterAnimation">@anim/fade_in</item>
+        <item name="android:windowExitAnimation">@anim/fade_out</item>
+    </style>
+
+</resources>

+ 17 - 0
kfzslibrary/src/test/java/com/kfzs/libs/ExampleUnitTest.java

@@ -0,0 +1,17 @@
+package com.kfzs.libs;
+
+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);
+    }
+}

BIN
repo/com/aop/plugin/aop-plugin/1.0.0/aop-plugin-1.0.0.jar


+ 1 - 0
repo/com/aop/plugin/aop-plugin/1.0.0/aop-plugin-1.0.0.jar.md5

@@ -0,0 +1 @@
+a225ba91589dfcf43e57200897a71566

+ 1 - 0
repo/com/aop/plugin/aop-plugin/1.0.0/aop-plugin-1.0.0.jar.sha1

@@ -0,0 +1 @@
+b6ad5141f4a3fd48ea23f62cd9bb0ac08f687f49

+ 0 - 0
repo/com/aop/plugin/aop-plugin/1.0.0/aop-plugin-1.0.0.pom


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff