From 3708b099a7517377e287dcf2c088d91b86e72e8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=90=95=E5=8F=91=E5=BC=BA?= <903019642@qq.com>
Date: Tue, 5 Sep 2017 13:31:20 +0800
Subject: [PATCH] upload code
---
.gitignore | 9 +
.idea/compiler.xml | 22 +
.idea/copyright/profiles_settings.xml | 3 +
.idea/dictionaries/apple.xml | 3 +
.idea/gradle.xml | 19 +
.../markdown-navigator/profiles_settings.xml | 3 +
.idea/misc.xml | 95 +++
.idea/modules.xml | 9 +
.idea/runConfigurations.xml | 12 +
.idea/vcs.xml | 6 +
app/.gitignore | 1 +
app/build.gradle | 38 +
app/proguard-rules.pro | 17 +
.../ExampleInstrumentedTest.java | 26 +
app/src/main/AndroidManifest.xml | 26 +
.../main/java/com/lvfq/code/BaseActivity.java | 46 ++
.../com/lvfq/code/ImageWaterMarkActivity.java | 150 ++++
.../main/java/com/lvfq/code/MainActivity.java | 58 ++
.../main/java/com/lvfq/code/ModelBean.java | 66 ++
.../java/com/lvfq/code/MyApplication.java | 25 +
.../main/java/com/lvfq/code/NoBodyEntity.java | 14 +
.../lvfq/code/annotation/AnnotationTest1.java | 30 +
.../lvfq/code/annotation/AnnotationUtil.java | 16 +
.../java/com/lvfq/code/annotation/CusBus.java | 77 ++
.../lvfq/code/annotation/OnCusBusEvent.java | 24 +
.../java/com/lvfq/code/annotation/Type.java | 15 +
.../code/dynamic/CircleMovementMethod.java | 117 +++
.../lvfq/code/dynamic/CommentsActivity.java | 85 +++
.../main/java/com/lvfq/code/dynamic/Data.java | 121 +++
.../code/dynamic/DynamicImageActivity.java | 70 ++
.../lvfq/code/dynamic/data/CommentsBean.java | 52 ++
.../com/lvfq/code/dynamic/data/UserBean.java | 34 +
.../dynamic/view/ColorFilterImageView.java | 51 ++
.../lvfq/code/dynamic/view/CommentsView.java | 191 +++++
.../com/lvfq/code/dynamic/view/LikesView.java | 138 ++++
.../code/dynamic/view/MultiImageView.java | 213 ++++++
.../com/lvfq/code/glide/GlideActivity.java | 62 ++
.../java/com/lvfq/code/http/HttpClient.java | 56 ++
.../code/http/NobodyConverterFactory.java | 64 ++
.../com/lvfq/code/http/RequestService.java | 33 +
app/src/main/java/com/lvfq/code/mvp/Http.java | 23 +
.../main/java/com/lvfq/code/mvp/HttpUtil.java | 106 +++
.../lvfq/code/mvp/IHttpResultListener.java | 13 +
.../java/com/lvfq/code/mvp/LoginActivity.java | 77 ++
.../com/lvfq/code/mvp/RegisterActivity.java | 20 +
.../com/lvfq/code/mvp/demo1/LoginModel.java | 20 +
.../lvfq/code/mvp/demo1/LoginPresenter.java | 39 +
.../com/lvfq/code/mvp/demo1/LoginView.java | 15 +
.../com/lvfq/code/mvp/demo2/LoginModel2.java | 20 +
.../lvfq/code/mvp/demo2/LoginPresenter2.java | 46 ++
.../com/lvfq/code/mvp/demo2/LoginView2.java | 15 +
.../lvfq/code/mvp/demo3/BaseMvpPresenter.java | 28 +
.../com/lvfq/code/mvp/demo3/IBaseMvpView.java | 13 +
.../lvfq/code/mvp/demo3/IBasePresenter.java | 19 +
.../com/lvfq/code/mvp/demo3/LoginModel3.java | 27 +
.../lvfq/code/mvp/demo3/LoginPresenter3.java | 41 ++
.../com/lvfq/code/mvp/demo3/LoginView3.java | 15 +
.../code/tablayout/PagerSlidingTabStrip.java | 689 ++++++++++++++++++
.../com/lvfq/code/tablayout/TabActivity.java | 72 ++
.../com/lvfq/code/tablayout/TabFragment.java | 46 ++
.../code/tablayout/custom/TabActivity1.java | 86 +++
.../tablayout/custom/TabSelectAdapter.java | 20 +
.../lvfq/code/tablayout/custom/TabUtils.java | 174 +++++
.../tablayout/custom/UnAnimTabLayout.java | 153 ++++
.../java/com/lvfq/code/util/FileUtils.java | 381 ++++++++++
.../lvfq/code/util/Glide4_ImageLoadUtil.java | 225 ++++++
.../java/com/lvfq/code/util/ImageUtils.java | 43 ++
.../com/lvfq/code/util/MyAppGlideModule.java | 17 +
app/src/main/res/drawable/shape_tab_green.xml | 5 +
.../main/res/drawable/tab_selector_green.xml | 5 +
app/src/main/res/layout/activity_comments.xml | 20 +
.../res/layout/activity_dynamic_image.xml | 18 +
app/src/main/res/layout/activity_glide.xml | 52 ++
.../res/layout/activity_img_water_mark.xml | 22 +
app/src/main/res/layout/activity_login.xml | 14 +
app/src/main/res/layout/activity_main.xml | 40 +
app/src/main/res/layout/activity_tab.xml | 30 +
app/src/main/res/layout/activity_tab1.xml | 31 +
.../main/res/layout/item_dynamic_image.xml | 22 +
app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3418 bytes
app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2206 bytes
app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4842 bytes
app/src/main/res/mipmap-xhdpi/img_default.png | Bin 0 -> 17975 bytes
.../main/res/mipmap-xhdpi/img_like_icon.png | Bin 0 -> 1722 bytes
.../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes
.../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10486 bytes
app/src/main/res/values-w820dp/dimens.xml | 6 +
app/src/main/res/values/attrs.xml | 20 +
app/src/main/res/values/colors.xml | 8 +
app/src/main/res/values/dimens.xml | 5 +
app/src/main/res/values/strings.xml | 3 +
app/src/main/res/values/styles.xml | 15 +
.../lvfq/myworkingtest/ExampleUnitTest.java | 17 +
build.gradle | 25 +
gradle.properties | 17 +
gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53636 bytes
gradle/wrapper/gradle-wrapper.properties | 6 +
gradlew | 160 ++++
gradlew.bat | 90 +++
settings.gradle | 1 +
100 files changed, 5172 insertions(+)
create mode 100644 .gitignore
create mode 100644 .idea/compiler.xml
create mode 100644 .idea/copyright/profiles_settings.xml
create mode 100644 .idea/dictionaries/apple.xml
create mode 100644 .idea/gradle.xml
create mode 100644 .idea/markdown-navigator/profiles_settings.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/modules.xml
create mode 100644 .idea/runConfigurations.xml
create mode 100644 .idea/vcs.xml
create mode 100644 app/.gitignore
create mode 100644 app/build.gradle
create mode 100644 app/proguard-rules.pro
create mode 100644 app/src/androidTest/java/com/lvfq/myworkingtest/ExampleInstrumentedTest.java
create mode 100644 app/src/main/AndroidManifest.xml
create mode 100644 app/src/main/java/com/lvfq/code/BaseActivity.java
create mode 100644 app/src/main/java/com/lvfq/code/ImageWaterMarkActivity.java
create mode 100644 app/src/main/java/com/lvfq/code/MainActivity.java
create mode 100644 app/src/main/java/com/lvfq/code/ModelBean.java
create mode 100644 app/src/main/java/com/lvfq/code/MyApplication.java
create mode 100644 app/src/main/java/com/lvfq/code/NoBodyEntity.java
create mode 100644 app/src/main/java/com/lvfq/code/annotation/AnnotationTest1.java
create mode 100644 app/src/main/java/com/lvfq/code/annotation/AnnotationUtil.java
create mode 100644 app/src/main/java/com/lvfq/code/annotation/CusBus.java
create mode 100644 app/src/main/java/com/lvfq/code/annotation/OnCusBusEvent.java
create mode 100644 app/src/main/java/com/lvfq/code/annotation/Type.java
create mode 100755 app/src/main/java/com/lvfq/code/dynamic/CircleMovementMethod.java
create mode 100644 app/src/main/java/com/lvfq/code/dynamic/CommentsActivity.java
create mode 100644 app/src/main/java/com/lvfq/code/dynamic/Data.java
create mode 100644 app/src/main/java/com/lvfq/code/dynamic/DynamicImageActivity.java
create mode 100644 app/src/main/java/com/lvfq/code/dynamic/data/CommentsBean.java
create mode 100644 app/src/main/java/com/lvfq/code/dynamic/data/UserBean.java
create mode 100644 app/src/main/java/com/lvfq/code/dynamic/view/ColorFilterImageView.java
create mode 100644 app/src/main/java/com/lvfq/code/dynamic/view/CommentsView.java
create mode 100644 app/src/main/java/com/lvfq/code/dynamic/view/LikesView.java
create mode 100644 app/src/main/java/com/lvfq/code/dynamic/view/MultiImageView.java
create mode 100644 app/src/main/java/com/lvfq/code/glide/GlideActivity.java
create mode 100644 app/src/main/java/com/lvfq/code/http/HttpClient.java
create mode 100644 app/src/main/java/com/lvfq/code/http/NobodyConverterFactory.java
create mode 100644 app/src/main/java/com/lvfq/code/http/RequestService.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/Http.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/HttpUtil.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/IHttpResultListener.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/LoginActivity.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/RegisterActivity.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo1/LoginModel.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo1/LoginPresenter.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo1/LoginView.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo2/LoginModel2.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo2/LoginPresenter2.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo2/LoginView2.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo3/BaseMvpPresenter.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo3/IBaseMvpView.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo3/IBasePresenter.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo3/LoginModel3.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo3/LoginPresenter3.java
create mode 100644 app/src/main/java/com/lvfq/code/mvp/demo3/LoginView3.java
create mode 100755 app/src/main/java/com/lvfq/code/tablayout/PagerSlidingTabStrip.java
create mode 100644 app/src/main/java/com/lvfq/code/tablayout/TabActivity.java
create mode 100644 app/src/main/java/com/lvfq/code/tablayout/TabFragment.java
create mode 100644 app/src/main/java/com/lvfq/code/tablayout/custom/TabActivity1.java
create mode 100755 app/src/main/java/com/lvfq/code/tablayout/custom/TabSelectAdapter.java
create mode 100755 app/src/main/java/com/lvfq/code/tablayout/custom/TabUtils.java
create mode 100755 app/src/main/java/com/lvfq/code/tablayout/custom/UnAnimTabLayout.java
create mode 100644 app/src/main/java/com/lvfq/code/util/FileUtils.java
create mode 100644 app/src/main/java/com/lvfq/code/util/Glide4_ImageLoadUtil.java
create mode 100644 app/src/main/java/com/lvfq/code/util/ImageUtils.java
create mode 100644 app/src/main/java/com/lvfq/code/util/MyAppGlideModule.java
create mode 100755 app/src/main/res/drawable/shape_tab_green.xml
create mode 100755 app/src/main/res/drawable/tab_selector_green.xml
create mode 100644 app/src/main/res/layout/activity_comments.xml
create mode 100644 app/src/main/res/layout/activity_dynamic_image.xml
create mode 100644 app/src/main/res/layout/activity_glide.xml
create mode 100644 app/src/main/res/layout/activity_img_water_mark.xml
create mode 100644 app/src/main/res/layout/activity_login.xml
create mode 100644 app/src/main/res/layout/activity_main.xml
create mode 100644 app/src/main/res/layout/activity_tab.xml
create mode 100644 app/src/main/res/layout/activity_tab1.xml
create mode 100644 app/src/main/res/layout/item_dynamic_image.xml
create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-xhdpi/img_default.png
create mode 100644 app/src/main/res/mipmap-xhdpi/img_like_icon.png
create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png
create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
create mode 100644 app/src/main/res/values-w820dp/dimens.xml
create mode 100755 app/src/main/res/values/attrs.xml
create mode 100644 app/src/main/res/values/colors.xml
create mode 100644 app/src/main/res/values/dimens.xml
create mode 100644 app/src/main/res/values/strings.xml
create mode 100644 app/src/main/res/values/styles.xml
create mode 100644 app/src/test/java/com/lvfq/myworkingtest/ExampleUnitTest.java
create mode 100644 build.gradle
create mode 100644 gradle.properties
create mode 100644 gradle/wrapper/gradle-wrapper.jar
create mode 100644 gradle/wrapper/gradle-wrapper.properties
create mode 100755 gradlew
create mode 100644 gradlew.bat
create mode 100644 settings.gradle
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..39fb081
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..96cc43e
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..e7bedf3
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/dictionaries/apple.xml b/.idea/dictionaries/apple.xml
new file mode 100644
index 0000000..142834e
--- /dev/null
+++ b/.idea/dictionaries/apple.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..ae871af
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/markdown-navigator/profiles_settings.xml b/.idea/markdown-navigator/profiles_settings.xml
new file mode 100644
index 0000000..57927c5
--- /dev/null
+++ b/.idea/markdown-navigator/profiles_settings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..559ffe6
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Android
+
+
+ Android > Lint > Correctness
+
+
+ Java
+
+
+ Java language level migration aidsJava
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..66504d9
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..9a9b371
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,38 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+ defaultConfig {
+ applicationId "com.lvfq.code"
+ minSdkVersion 15
+ targetSdkVersion 22
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(include: ['*.jar'], dir: 'libs')
+ androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ compile 'com.android.support:appcompat-v7:25.1.0'
+ testCompile 'junit:junit:4.12'
+ compile 'com.squareup.retrofit2:retrofit:2.2.0'
+ compile 'com.squareup.retrofit2:converter-gson:2.2.0'
+ compile 'com.squareup.retrofit2:converter-scalars:2.3.0'
+ compile 'com.android.support:design:25.0.0'
+ compile 'com.github.lvfaqiang:AndroidUtils:1.1.2'
+ compile 'com.github.bumptech.glide:glide:4.0.0'
+ annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0'
+ compile 'com.android.support:support-v4:25.3.1'
+ compile 'com.zhy:base-rvadapter:3.0.3'
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..deab50f
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/apple/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/app/src/androidTest/java/com/lvfq/myworkingtest/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/lvfq/myworkingtest/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..3415f6e
--- /dev/null
+++ b/app/src/androidTest/java/com/lvfq/myworkingtest/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.lvfq.myworkingtest;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.lvfq.myworkingtest", appContext.getPackageName());
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6f7f118
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/lvfq/code/BaseActivity.java b/app/src/main/java/com/lvfq/code/BaseActivity.java
new file mode 100644
index 0000000..acbcae6
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/BaseActivity.java
@@ -0,0 +1,46 @@
+package com.lvfq.code;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentActivity;
+
+import com.lvfq.code.mvp.demo3.BaseMvpPresenter;
+import com.lvfq.code.mvp.demo3.IBaseMvpView;
+
+/**
+ * BaseActivity
+ *
+ * @author lvfq
+ * @date 2017/7/17 下午3:04
+ * @mainFunction :
+ */
+
+public abstract class BaseActivity> extends FragmentActivity {
+
+ private P presenter;
+
+ public abstract P bindPresenter();
+
+ public P getPresenter() {
+ return presenter;
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (presenter == null) {
+ presenter = bindPresenter();
+ if (presenter != null && this instanceof IBaseMvpView) {
+ presenter.attachView((V) this);
+ }
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (presenter != null) {
+ presenter.detachView();
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/ImageWaterMarkActivity.java b/app/src/main/java/com/lvfq/code/ImageWaterMarkActivity.java
new file mode 100644
index 0000000..da56333
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/ImageWaterMarkActivity.java
@@ -0,0 +1,150 @@
+package com.lvfq.code;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentActivity;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.lvfq.code.util.FileUtils;
+import com.lvfq.code.util.ImageUtils;
+import com.lvfq.myworkingtest.R;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * ImageWaterMarkActivity
+ *
+ * @author lvfq
+ * @date 2017/4/19 上午10:26
+ * @mainFunction :
+ */
+
+public class ImageWaterMarkActivity extends FragmentActivity {
+
+ public static String path = Environment.getExternalStorageDirectory() + File.separator + "Android" + File.separator
+ + "_test" + File.separator;
+
+
+ private ImageView iv_img;
+
+ private Uri imgPath;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_img_water_mark);
+ iv_img = (ImageView) findViewById(R.id.iv_img);
+
+
+ }
+
+ public void onClick(View view) {
+ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ imgPath = Uri.fromFile(new File(mImageFileCachePath() + "img.jpg"));
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, imgPath);
+ startActivityForResult(intent, 1);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode != RESULT_OK) {
+ return;
+ }
+
+ if (requestCode == 1) {
+ int angle = FileUtils.readPictureDegree(imgPath.getEncodedPath());
+ Log.i("lfq", "angle = " + angle);
+ try {
+ Bitmap bitmap = createBitmap(BitmapFactory.decodeStream(getContentResolver().openInputStream(imgPath)), "添加的水印文字");
+ ImageUtils.saveFile(bitmap, imgPath.getEncodedPath());
+ Bitmap bitmap1 = FileUtils.ratingImage(imgPath.getEncodedPath(), bitmap);
+
+ iv_img.setImageBitmap(bitmap);
+// iv_img.setImageBitmap(bitmap1);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+
+// bitmap.recycle();
+// bitmap1.recycle();
+ }
+ }
+
+ /**
+ * @param src 添加水印的图片
+ * @param title 水印文字
+ * @return
+ */
+ public Bitmap createBitmap(Bitmap src, String title) {
+ if (src == null) {
+ return src;
+ }
+ Bitmap bitmap = src;
+ // 获取原始图片的宽与高
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ Bitmap newBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ Canvas mCanvas = new Canvas(newBitmap);
+ // 往位图中开始画入src原始图片
+ mCanvas.drawBitmap(bitmap, 0, 0, null);
+ // 开始加入文字
+ if (null != title) {
+ Paint textPaint = new Paint();
+
+ textPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 48, getResources().getDisplayMetrics()));
+ String familyName = "宋体";
+ Typeface typeface = Typeface.create(familyName,
+ Typeface.NORMAL);
+ textPaint.setTypeface(typeface);
+ textPaint.setTextAlign(Paint.Align.CENTER);
+ float textHeight = textPaint.descent() - textPaint.ascent();
+
+ textPaint.setAntiAlias(true);
+ textPaint.setColor(Color.BLACK);
+ textPaint.setStrokeWidth(textHeight + dip2px(8));
+ textPaint.setAlpha((int) (255 * 0.8));
+ mCanvas.drawLine(0, h - (textHeight / 2 + dip2px(4)), w, h - (textHeight / 2 + dip2px(4)), textPaint); // 先画背景。
+ textPaint.setColor(Color.WHITE);
+ mCanvas.drawText(title, w / 2, h - (textHeight / 2) + dip2px(20), textPaint);
+
+ }
+ mCanvas.save(Canvas.ALL_SAVE_FLAG);
+ mCanvas.restore();
+ bitmap.recycle();
+ return newBitmap;
+ }
+
+
+ public static String mImageFileCachePath() {
+ String s = Environment.getExternalStorageDirectory() + File.separator + "Android" + File.separator
+ + "_test" + File.separator;
+ File file = new File(s);
+ if (!file.exists()) {
+ file.mkdirs();
+ }
+ return s;
+ }
+
+
+ /**
+ * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
+ */
+ public int dip2px(float dpValue) {
+ final float scale = getResources().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/MainActivity.java b/app/src/main/java/com/lvfq/code/MainActivity.java
new file mode 100644
index 0000000..8a0028f
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/MainActivity.java
@@ -0,0 +1,58 @@
+package com.lvfq.code;
+
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.lvfq.code.mvp.demo3.LoginPresenter3;
+import com.lvfq.myworkingtest.R;
+import com.lvfq.code.mvp.demo3.LoginView3;
+
+public class MainActivity extends BaseActivity implements LoginView3 {
+
+ private TextView tv_symbol;
+ private EditText et_content;
+
+ @Override
+ public LoginPresenter3 bindPresenter() {
+ return null;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ tv_symbol = (TextView) findViewById(R.id.tv_symbol);
+ et_content = (EditText) findViewById(R.id.et_content);
+ et_content.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ int width = (int) et_content.getPaint().measureText(s.toString());
+ Log.i("lfq", "width: " + width);
+ tv_symbol.setPadding(0, 0, width + 5, 0);
+ }
+ });
+
+ et_content.setText("10000");
+
+ }
+
+ @Override
+ public void onResult(String result) {
+
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/ModelBean.java b/app/src/main/java/com/lvfq/code/ModelBean.java
new file mode 100644
index 0000000..59a00df
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/ModelBean.java
@@ -0,0 +1,66 @@
+package com.lvfq.code;
+
+/**
+ * ModelBean
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/8/4 下午10:30
+ * @desc :
+ */
+
+public class ModelBean {
+
+
+ /**
+ * errorCtx : null
+ * resultData : {"isMainServer ":true,"serverNumber":1234}
+ * success : true
+ */
+
+ private ResultDataBean resultData;
+ private boolean success;
+
+ public ResultDataBean getResultData() {
+ return resultData;
+ }
+
+ public void setResultData(ResultDataBean resultData) {
+ this.resultData = resultData;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public static class ResultDataBean {
+ /**
+ * isMainServer : true
+ * serverNumber : 1234
+ */
+
+ private boolean isMainServer;
+ private int serverNumber;
+
+ public boolean isMainServer() {
+ return isMainServer;
+ }
+
+ public void setMainServer(boolean mainServer) {
+ isMainServer = mainServer;
+ }
+
+ public int getServerNumber() {
+ return serverNumber;
+ }
+
+ public void setServerNumber(int serverNumber) {
+ this.serverNumber = serverNumber;
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/MyApplication.java b/app/src/main/java/com/lvfq/code/MyApplication.java
new file mode 100644
index 0000000..2854610
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/MyApplication.java
@@ -0,0 +1,25 @@
+package com.lvfq.code;
+
+import android.app.Application;
+
+import com.lvfq.library.utils.LvUtils;
+
+/**
+ * MyApplication
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/1 下午11:15
+ * @desc :
+ */
+
+public class MyApplication extends Application {
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ LvUtils.init(this);
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/NoBodyEntity.java b/app/src/main/java/com/lvfq/code/NoBodyEntity.java
new file mode 100644
index 0000000..051e5aa
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/NoBodyEntity.java
@@ -0,0 +1,14 @@
+package com.lvfq.code;
+
+/**
+ * NoBodyEntity
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/8/4 下午11:07
+ * @desc :
+ */
+
+public class NoBodyEntity {
+}
diff --git a/app/src/main/java/com/lvfq/code/annotation/AnnotationTest1.java b/app/src/main/java/com/lvfq/code/annotation/AnnotationTest1.java
new file mode 100644
index 0000000..e5b5a5b
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/annotation/AnnotationTest1.java
@@ -0,0 +1,30 @@
+package com.lvfq.code.annotation;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentActivity;
+
+/**
+ * AnnotationTest1
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/7/26 下午1:53
+ * @desc :
+ */
+
+public class AnnotationTest1 extends FragmentActivity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+
+ }
+
+ @OnCusBusEvent(tag = "" )
+ private void mTest() {
+
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/annotation/AnnotationUtil.java b/app/src/main/java/com/lvfq/code/annotation/AnnotationUtil.java
new file mode 100644
index 0000000..bf898de
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/annotation/AnnotationUtil.java
@@ -0,0 +1,16 @@
+package com.lvfq.code.annotation;
+
+/**
+ * AnnotationUtil
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/7/26 下午2:18
+ * @desc :
+ */
+
+public class AnnotationUtil {
+
+
+}
diff --git a/app/src/main/java/com/lvfq/code/annotation/CusBus.java b/app/src/main/java/com/lvfq/code/annotation/CusBus.java
new file mode 100644
index 0000000..b9298bb
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/annotation/CusBus.java
@@ -0,0 +1,77 @@
+package com.lvfq.code.annotation;
+
+import android.app.Activity;
+import android.support.v4.app.Fragment;
+
+import java.lang.annotation.Annotation;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * CusBus
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/7/26 下午2:04
+ * @desc :
+ */
+
+public class CusBus {
+ private static CusBus instance = null;
+ private static ConcurrentMap map = new ConcurrentHashMap<>();
+ private static Map classes = new HashMap<>();
+
+ public static CusBus getInstance() {
+ if (instance == null) {
+ synchronized (CusBus.class) {
+ if (instance == null) {
+ instance = new CusBus();
+ }
+ }
+ }
+ return instance;
+ }
+
+ public void register(Fragment fragment) {
+// classes.add(fragment.getClass());
+ classes.put(fragment.hashCode(), fragment.getClass());
+
+ }
+
+ public void register(Activity activity) {
+ classes.put(activity.hashCode(), activity.getClass());
+ }
+
+ public void execute(Class extends Annotation> clazz) {
+
+// Class clazz = subscriber.getClass();
+// List methodList = new ArrayList<>();
+// Method[] methods = clazz.getMethods();
+// if (methods != null && methods.length > 0) {
+// for (Method method : methods) {
+// if (method.isAnnotationPresent(OnCusBusEvent.class)) {
+// methodList.add(method);
+// }
+// }
+// if (methodList.size() > 0) {
+// map.put(clazz, methodList);
+// }
+// }
+
+// if (methods != null && methods.length > 0) {
+// for (Method method : methods) {
+// if (method.isAnnotationPresent(clazz)) {
+// try {
+// method.invoke(subscriber, (Object[]) new Objects[]{});
+// } catch (Exception e) {
+// e.printStackTrace();
+// }
+// }
+// }
+// }
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/annotation/OnCusBusEvent.java b/app/src/main/java/com/lvfq/code/annotation/OnCusBusEvent.java
new file mode 100644
index 0000000..cf5d868
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/annotation/OnCusBusEvent.java
@@ -0,0 +1,24 @@
+package com.lvfq.code.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * OnCusBusEvent
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/7/26 下午2:10
+ * @desc :
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface OnCusBusEvent {
+ String tag();
+
+ Type type() default Type.NONE;
+}
diff --git a/app/src/main/java/com/lvfq/code/annotation/Type.java b/app/src/main/java/com/lvfq/code/annotation/Type.java
new file mode 100644
index 0000000..222e860
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/annotation/Type.java
@@ -0,0 +1,15 @@
+package com.lvfq.code.annotation;
+
+/**
+ * Type
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/7/26 下午5:27
+ * @desc :
+ */
+
+public enum Type {
+ NONE , POST, GET, MAIN
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/CircleMovementMethod.java b/app/src/main/java/com/lvfq/code/dynamic/CircleMovementMethod.java
new file mode 100755
index 0000000..a11588e
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/CircleMovementMethod.java
@@ -0,0 +1,117 @@
+package com.lvfq.code.dynamic;
+
+import android.text.Layout;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.method.BaseMovementMethod;
+import android.text.method.Touch;
+import android.text.style.BackgroundColorSpan;
+import android.text.style.ClickableSpan;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
+/**
+ * @author yiw
+ * @Description:
+ * @date 16/1/2 16:54
+ */
+public class CircleMovementMethod extends BaseMovementMethod {
+ private final static int DEFAULT_COLOR_ID = android.R.color.transparent;
+ /**
+ * 整个textView的背景色
+ */
+ private int textViewBgColor;
+ /**
+ * 点击部分文字时部分文字的背景色
+ */
+ private int clickableSpanBgClor;
+
+ private BackgroundColorSpan mBgSpan;
+ private ClickableSpan[] mClickLinks;
+
+ private boolean isParseTv = false;
+
+ public boolean isParseTv() {
+ return isParseTv;
+ }
+
+ public void setParseTv(boolean parseTv) {
+ isParseTv = parseTv;
+ }
+
+ /**
+ * @param clickableSpanBgClor 点击选中部分时的背景色
+ */
+ public CircleMovementMethod(int clickableSpanBgClor) {
+ this.clickableSpanBgClor = clickableSpanBgClor;
+ }
+
+ /**
+ * @param clickableSpanBgClor 点击选中部分时的背景色
+ * @param textViewBgColor 整个textView点击时的背景色
+ */
+ public CircleMovementMethod(int clickableSpanBgClor, int textViewBgColor) {
+ this.textViewBgColor = textViewBgColor;
+ this.clickableSpanBgClor = clickableSpanBgClor;
+ }
+
+ public boolean onTouchEvent(TextView widget, Spannable buffer,
+ MotionEvent event) {
+
+ int action = event.getAction();
+ if (action == MotionEvent.ACTION_DOWN) {
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+
+ x -= widget.getTotalPaddingLeft();
+ y -= widget.getTotalPaddingTop();
+
+ x += widget.getScrollX();
+ y += widget.getScrollY();
+
+ Layout layout = widget.getLayout();
+ int line = layout.getLineForVertical(y);
+ int off = layout.getOffsetForHorizontal(line, x);
+
+ mClickLinks = buffer.getSpans(off, off, ClickableSpan.class);
+ if (mClickLinks.length > 0) {
+ setParseTv(false);
+ // 点击的是Span区域,不要把点击事件传递
+ Selection.setSelection(buffer,
+ buffer.getSpanStart(mClickLinks[0]),
+ buffer.getSpanEnd(mClickLinks[0]));
+ //设置点击区域的背景色
+ mBgSpan = new BackgroundColorSpan(clickableSpanBgClor);
+ buffer.setSpan(mBgSpan,
+ buffer.getSpanStart(mClickLinks[0]),
+ buffer.getSpanEnd(mClickLinks[0]),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ } else {
+ setParseTv(true);
+ // textview选中效果
+// widget.setBackgroundColor(textViewBgColor);
+ widget.setBackgroundResource(DEFAULT_COLOR_ID);
+ }
+
+ } else if (action == MotionEvent.ACTION_UP) {
+ if (mClickLinks.length > 0) {
+ mClickLinks[0].onClick(widget);
+ if (mBgSpan != null) {//移除点击时设置的背景span
+ buffer.removeSpan(mBgSpan);
+ }
+ } else {
+
+ }
+ Selection.removeSelection(buffer);
+ widget.setBackgroundResource(DEFAULT_COLOR_ID);
+ } else if (action == MotionEvent.ACTION_MOVE) {
+ //这种情况不用做处理
+ } else {
+ if (mBgSpan != null) {//移除点击时设置的背景span
+ buffer.removeSpan(mBgSpan);
+ }
+ widget.setBackgroundResource(DEFAULT_COLOR_ID);
+ }
+ return Touch.onTouchEvent(widget, buffer, event);
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/CommentsActivity.java b/app/src/main/java/com/lvfq/code/dynamic/CommentsActivity.java
new file mode 100644
index 0000000..4b191ef
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/CommentsActivity.java
@@ -0,0 +1,85 @@
+package com.lvfq.code.dynamic;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import com.lvfq.code.dynamic.data.CommentsBean;
+import com.lvfq.code.dynamic.data.UserBean;
+import com.lvfq.code.dynamic.view.LikesView;
+import com.lvfq.library.utils.LvV;
+import com.lvfq.myworkingtest.R;
+import com.lvfq.code.dynamic.view.CommentsView;
+
+/**
+ * CommentsActivity
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/3 下午9:56
+ * @desc :
+ */
+
+public class CommentsActivity extends AppCompatActivity {
+
+ private CommentsView commentView;
+ private LikesView likeView;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_comments);
+
+ commentView = LvV.find(this, R.id.commentView);
+ likeView = LvV.find(this, R.id.likeView);
+
+ likeView.setList(Data.getLikes());
+ likeView.setListener(new LikesView.onItemClickListener() {
+ @Override
+ public void onItemClick(int position, UserBean bean) {
+ new MyThread().start();
+ }
+ });
+ likeView.notifyDataSetChanged();
+
+ commentView = LvV.find(this, R.id.commentView);
+ commentView.setList(Data.getComments());
+ commentView.setOnItemClickListener(new CommentsView.onItemClickListener() {
+ @Override
+ public void onItemClick(int position, CommentsBean bean) {
+ Log.i("lfq", Thread.currentThread().getName());
+ new MyThread().start();
+ }
+ });
+ commentView.notifyDataSetChanged();
+ }
+
+ private class MyThread extends Thread {
+ private Handler handler;
+
+ @Override
+ public void run() {
+// Looper.prepare();
+ handler = new Handler(getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == 1) {
+ Log.i("lfq", msg.what + " , mas.what");
+ Toast.makeText(CommentsActivity.this, Thread.currentThread().getName(), Toast.LENGTH_SHORT).show();
+ commentView.setVisibility(View.GONE);
+ }
+ }
+ };
+
+ handler.sendEmptyMessage(1);
+// Looper.loop();
+
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/Data.java b/app/src/main/java/com/lvfq/code/dynamic/Data.java
new file mode 100644
index 0000000..065c6b2
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/Data.java
@@ -0,0 +1,121 @@
+package com.lvfq.code.dynamic;
+
+import com.lvfq.code.dynamic.data.CommentsBean;
+import com.lvfq.code.dynamic.data.UserBean;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Data
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/2 上午12:14
+ * @desc :
+ */
+
+public class Data {
+
+
+// http://opgirl-tmp.adbxb.cn/images2/mi/2202/148_ce2b24f5ea4fadaf6c5591416e7990dc_75.jpg
+//
+// http://opgirl-tmp.adbxb.cn/images3/mi/20/144_dc7b83c64f60363a8212f01eef43f513_75.jpg
+// http://opgirl-tmp.adbxb.cn/images2/mi/1447/148_62de05945c28dbccaeb92f131f26f972_75.jpg
+// http://opgirl-tmp.adbxb.cn/images2/mi/1240/142_b2f099d4f8576543cb0b0c3878cae26e_75.jpg
+// http://i1.go2yd.com/corpimage.php?url=http://si1.go2yd.com/get-image/0CZZQOCHE3M&source=mb&type=_896x504
+//
+// http://i1.go2yd.com/corpimage.php?url=http://si1.go2yd.com/get-image/09yg7aATwp6&source=mb&type=_896x504
+//
+// http://opgirl-tmp.adbxb.cn/images2/mi/1307/206_773d003844d1966a7ce0cee1d245155a_75.jpg
+//
+// http://opgirl-tmp.adbxb.cn/images2/mi/2847/206_da5207eb0798f155572dca227ddf0411_75.jpg
+//
+// http://opgirl-tmp.adbxb.cn/images1/mi/2566/208_cfcb6e2cd501aadf61fc572119ad8a29_75.jpg
+//
+// http://opgirl-tmp.adbxb.cn/images2/mi/1392/206_7c9ab9991319e284c8ce781481a866a4_75.jpeg
+
+ private static String[] imgs = {
+ "http://opgirl-tmp.adbxb.cn/images2/mi/2202/148_ce2b24f5ea4fadaf6c5591416e7990dc_75.jpg",
+ "http://opgirl-tmp.adbxb.cn/images3/mi/20/144_dc7b83c64f60363a8212f01eef43f513_75.jpg",
+ "http://i1.go2yd.com/corpimage.php?url=http://si1.go2yd.com/get-image/0CZZQOCHE3M&source=mb&type=_896x504",
+ "http://opgirl-tmp.adbxb.cn/images2/mi/1447/148_62de05945c28dbccaeb92f131f26f972_75.jpg",
+ "http://opgirl-tmp.adbxb.cn/images2/mi/1240/142_b2f099d4f8576543cb0b0c3878cae26e_75.jpg",
+ "http://i1.go2yd.com/corpimage.php?url=http://si1.go2yd.com/get-image/09yg7aATwp6&source=mb&type=_896x504",
+ "http://opgirl-tmp.adbxb.cn/images2/mi/1307/206_773d003844d1966a7ce0cee1d245155a_75.jpg",
+ "http://opgirl-tmp.adbxb.cn/images2/mi/2847/206_da5207eb0798f155572dca227ddf0411_75.jpg",
+// "http://opgirl-tmp.adbxb.cn/images1/mi/2566/208_cfcb6e2cd501aadf61fc572119ad8a29_75.jpg",
+ "http://opgirl-tmp.adbxb.cn/images2/mi/1392/206_7c9ab9991319e284c8ce781481a866a4_75.jpeg"
+ };
+
+ /**
+ * 获取图片数量
+ *
+ * @param count
+ * @return
+ */
+ public static List getImgs(int count) {
+ if (count <= 0) {
+ return null;
+ }
+ List list = new ArrayList<>();
+ if (count >= 9) {
+ return Arrays.asList(imgs);
+ } else {
+ for (int i = 0; i < count; i++) {
+ list.add(imgs[i]);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * 生成评论列表
+ *
+ * @return
+ */
+ public static List getComments() {
+ List list = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ CommentsBean commentsBean = new CommentsBean();
+ commentsBean.setCommentsId(i);
+ commentsBean.setContent("zhe shi wo yong lai ce shi shu ru de wen ben nei rong " + i);
+ if (i % 2 == 0) {
+ UserBean replyUser = new UserBean();
+ replyUser.setUserId(i + 30);
+ replyUser.setUserName("用户" + replyUser.getUserId());
+ commentsBean.setReplyUser(replyUser);
+ }
+ UserBean comUser = new UserBean();
+ comUser.setUserId(i);
+ comUser.setUserName("用户" + comUser.getUserId());
+
+ commentsBean.setCommentsUser(comUser);
+
+ list.add(commentsBean);
+ }
+
+ return list;
+ }
+
+
+ /**
+ * 生成点赞列表
+ *
+ * @return
+ */
+ public static List getLikes() {
+ List list = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ UserBean userBean = new UserBean();
+ userBean.setUserName("用户" + i);
+ userBean.setUserId(i + 1);
+ list.add(userBean);
+ }
+
+ return list;
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/DynamicImageActivity.java b/app/src/main/java/com/lvfq/code/dynamic/DynamicImageActivity.java
new file mode 100644
index 0000000..2f8ba9c
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/DynamicImageActivity.java
@@ -0,0 +1,70 @@
+package com.lvfq.code.dynamic;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+import com.lvfq.code.dynamic.view.MultiImageView;
+import com.lvfq.library.utils.LvToastUtil;
+import com.lvfq.library.utils.LvV;
+import com.lvfq.myworkingtest.R;
+import com.zhy.adapter.recyclerview.CommonAdapter;
+import com.zhy.adapter.recyclerview.base.ViewHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * DynamicImageActivity
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/8/25 上午9:16
+ * @desc :
+ */
+
+public class DynamicImageActivity extends FragmentActivity {
+
+ RecyclerView recyclerView;
+ CommonAdapter mAdapter;
+ List mList = new ArrayList<>();
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_dynamic_image);
+
+ recyclerView = LvV.find(this, R.id.recyclerView);
+ mList = Data.getImgs(9);
+
+ initAdapter();
+
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+ recyclerView.setAdapter(mAdapter);
+
+ }
+
+ private void initAdapter() {
+ mAdapter = new CommonAdapter(this, R.layout.item_dynamic_image, mList) {
+ @Override
+ protected void convert(ViewHolder holder, String s, int position) {
+ MultiImageView multiImage = holder.getView(R.id.multi_image);
+ holder.setText(R.id.tv_title, (position + 1) + "张图");
+ multiImage.setList(Data.getImgs(position + 1));
+ final int pos = position;
+ multiImage.setOnItemClickListener(new MultiImageView.OnItemClickListener() {
+ @Override
+ public void onItemClick(View view, int position) {
+ LvToastUtil.showToast((Activity) mContext, "position1:" + pos + " , position2:" + position);
+ }
+ });
+ }
+ };
+
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/data/CommentsBean.java b/app/src/main/java/com/lvfq/code/dynamic/data/CommentsBean.java
new file mode 100644
index 0000000..5176b9e
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/data/CommentsBean.java
@@ -0,0 +1,52 @@
+package com.lvfq.code.dynamic.data;
+
+import java.io.Serializable;
+
+/**
+ * CommentsBean
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/3 下午10:03
+ * @desc :
+ */
+
+public class CommentsBean implements Serializable {
+ private int commentsId;
+ private String content;
+ private UserBean replyUser; // 回复人信息
+ private UserBean commentsUser; // 评论人信息
+
+ public int getCommentsId() {
+ return commentsId;
+ }
+
+ public void setCommentsId(int commentsId) {
+ this.commentsId = commentsId;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public UserBean getReplyUser() {
+ return replyUser;
+ }
+
+ public void setReplyUser(UserBean replyUser) {
+ this.replyUser = replyUser;
+ }
+
+ public UserBean getCommentsUser() {
+ return commentsUser;
+ }
+
+ public void setCommentsUser(UserBean commentsUser) {
+ this.commentsUser = commentsUser;
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/data/UserBean.java b/app/src/main/java/com/lvfq/code/dynamic/data/UserBean.java
new file mode 100644
index 0000000..3347df4
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/data/UserBean.java
@@ -0,0 +1,34 @@
+package com.lvfq.code.dynamic.data;
+
+import java.io.Serializable;
+
+/**
+ * UserBean
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/3 下午10:01
+ * @desc :
+ */
+
+public class UserBean implements Serializable {
+ private int userId;
+ private String userName;
+
+ public int getUserId() {
+ return userId;
+ }
+
+ public void setUserId(int userId) {
+ this.userId = userId;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/view/ColorFilterImageView.java b/app/src/main/java/com/lvfq/code/dynamic/view/ColorFilterImageView.java
new file mode 100644
index 0000000..ed7a6e1
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/view/ColorFilterImageView.java
@@ -0,0 +1,51 @@
+package com.lvfq.code.dynamic.view;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PorterDuff.Mode;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.widget.ImageView;
+
+/**
+ * @author hnclca
+ * @ClassName: ColorFilterImageView
+ * @Description: 实现图像根据按下抬起动作变化颜色
+ * @date 2016-02-26
+ */
+public class ColorFilterImageView extends ImageView implements OnTouchListener {
+ public ColorFilterImageView(Context context) {
+ this(context, null, 0);
+ }
+
+ public ColorFilterImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ColorFilterImageView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ private void init() {
+ setOnTouchListener(this);
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN: // 按下时图像变灰
+ setColorFilter(Color.GRAY, Mode.MULTIPLY);
+ break;
+ case MotionEvent.ACTION_UP: // 手指离开或取消操作时恢复原色
+ case MotionEvent.ACTION_CANCEL:
+ setColorFilter(Color.TRANSPARENT);
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/view/CommentsView.java b/app/src/main/java/com/lvfq/code/dynamic/view/CommentsView.java
new file mode 100644
index 0000000..6512f48
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/view/CommentsView.java
@@ -0,0 +1,191 @@
+package com.lvfq.code.dynamic.view;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.text.style.ClickableSpan;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.lvfq.code.dynamic.CircleMovementMethod;
+import com.lvfq.code.dynamic.data.CommentsBean;
+import com.lvfq.code.dynamic.data.UserBean;
+
+import java.util.List;
+
+/**
+ * CommentsView
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/3 下午9:58
+ * @desc :
+ */
+
+public class CommentsView extends LinearLayout {
+
+ private Context mContext;
+ private List mDatas;
+ private onItemClickListener listener;
+
+ public CommentsView(Context context) {
+ this(context, null);
+ }
+
+ public CommentsView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CommentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setOrientation(VERTICAL);
+ this.mContext = context;
+ }
+
+ /**
+ * 设置评论列表信息
+ *
+ * @param list
+ */
+ public void setList(List list) {
+ mDatas = list;
+ }
+
+ public void setOnItemClickListener(onItemClickListener listener) {
+ this.listener = listener;
+ }
+
+ public void notifyDataSetChanged() {
+ removeAllViews();
+ if (mDatas == null || mDatas.size() <= 0) {
+ return;
+ }
+ LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ layoutParams.setMargins(0, 10, 0, 10);
+ for (int i = 0; i < mDatas.size(); i++) {
+ View view = getView(i);
+ if (view == null) {
+ throw new NullPointerException("listview item layout is null, please check getView()...");
+ }
+ addView(view, i, layoutParams);
+ }
+ }
+
+ private View getView(final int position) {
+ final CommentsBean item = mDatas.get(position);
+ UserBean replyUser = item.getReplyUser();
+ boolean hasReply = false; // 是否有回复
+ if (replyUser != null) {
+ hasReply = true;
+ }
+ TextView textView = new TextView(mContext);
+ textView.setTextSize(15);
+ textView.setTextColor(0xff686868);
+
+ SpannableStringBuilder builder = new SpannableStringBuilder();
+ UserBean comUser = item.getCommentsUser();
+ String name = comUser.getUserName();
+ if (hasReply) {
+ builder.append(setClickableSpan(name, item.getCommentsUser()));
+ builder.append(" 回复 ");
+ builder.append(setClickableSpan(replyUser.getUserName(), item.getReplyUser()));
+
+ } else {
+ builder.append(setClickableSpan(name, item.getCommentsUser()));
+ }
+ builder.append(" : ");
+ builder.append(setClickableSpanContent(item.getContent(), position));
+ builder.append(" ");
+ textView.setText(builder);
+ // 设置点击背景色
+ textView.setHighlightColor(getResources().getColor(android.R.color.transparent));
+// textView.setHighlightColor(0xff000000);
+ final CircleMovementMethod method = new CircleMovementMethod(0xffcccccc, 0xffcccccc);
+ textView.setMovementMethod(method);
+
+ textView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (method.isParseTv()) {
+ if (listener != null) {
+ listener.onItemClick(position, item);
+ }
+ }
+ }
+ });
+
+ return textView;
+ }
+
+ /**
+ * 设置评论内容点击事件
+ *
+ * @param item
+ * @param position
+ * @return
+ */
+ public SpannableString setClickableSpanContent(final String item, final int position) {
+ final SpannableString string = new SpannableString(item);
+ ClickableSpan span = new ClickableSpan() {
+ @Override
+ public void onClick(View widget) {
+ // TODO: 2017/9/3 评论内容点击事件
+ Toast.makeText(mContext, "position: " + position + " , content: " + item, Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ super.updateDrawState(ds);
+ // 设置显示的内容文本颜色
+ ds.setColor(0xff686868);
+ ds.setUnderlineText(false);
+ }
+ };
+ string.setSpan(span, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return string;
+ }
+
+ /**
+ * 设置评论用户名字点击事件
+ *
+ * @param item
+ * @param bean
+ * @return
+ */
+ public SpannableString setClickableSpan(final String item, final UserBean bean) {
+ final SpannableString string = new SpannableString(item);
+ ClickableSpan span = new ClickableSpan() {
+ @Override
+ public void onClick(View widget) {
+ // TODO: 2017/9/3 评论用户名字点击事件
+ Toast.makeText(mContext, bean.getUserName(), Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ super.updateDrawState(ds);
+ // 设置显示的用户名文本颜色
+ ds.setColor(0xff387dcc);
+ ds.setUnderlineText(false);
+ }
+ };
+
+ string.setSpan(span, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return string;
+ }
+
+ /**
+ * 定义一个用于回调的接口
+ */
+ public interface onItemClickListener {
+ void onItemClick(int position, CommentsBean bean);
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/view/LikesView.java b/app/src/main/java/com/lvfq/code/dynamic/view/LikesView.java
new file mode 100644
index 0000000..779bcb0
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/view/LikesView.java
@@ -0,0 +1,138 @@
+package com.lvfq.code.dynamic.view;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.text.style.ClickableSpan;
+import android.text.style.DynamicDrawableSpan;
+import android.text.style.ImageSpan;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import com.lvfq.code.dynamic.CircleMovementMethod;
+import com.lvfq.code.dynamic.data.UserBean;
+import com.lvfq.myworkingtest.R;
+
+import java.util.List;
+
+/**
+ * LikesView
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/4 上午11:56
+ * @desc :
+ */
+
+public class LikesView extends TextView {
+
+ private Context mContext;
+ private List list;
+
+ public LikesView(Context context) {
+ this(context, null);
+ }
+
+ public LikesView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public LikesView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mContext = context;
+ }
+
+ /**
+ * 设置点赞数据
+ *
+ * @param list
+ */
+ public void setList(List list) {
+ this.list = list;
+ }
+
+ /**
+ * 刷新点赞列表
+ */
+ public void notifyDataSetChanged() {
+ if (list == null || list.size() <= 0) {
+ return;
+ }
+ SpannableStringBuilder builder = new SpannableStringBuilder();
+ builder.append(setImageSpan());
+ for (int i = 0; i < list.size(); i++) {
+ UserBean item = list.get(i);
+ builder.append(setClickableSpan(item.getUserName(), item));
+ if (i != list.size() - 1) {
+ builder.append(" , ");
+ } else {
+ builder.append(" ");
+ }
+ }
+
+ setText(builder);
+ setMovementMethod(new CircleMovementMethod(0xffcccccc, 0xffcccccc));
+// setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ /**
+ * 设置评论用户名字点击事件
+ *
+ * @param item
+ * @param bean
+ * @return
+ */
+ public SpannableString setClickableSpan(final String item, final UserBean bean) {
+ final SpannableString string = new SpannableString(item);
+ ClickableSpan span = new ClickableSpan() {
+ @Override
+ public void onClick(View widget) {
+ // TODO: 2017/9/3 评论用户名字点击事件
+// Toast.makeText(mContext, bean.getUserName(), Toast.LENGTH_SHORT).show();
+ if (listener != null) {
+ listener.onItemClick(0, bean);
+ }
+ }
+
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ super.updateDrawState(ds);
+ // 设置显示的文字颜色
+ ds.setColor(0xff387dcc);
+ ds.setUnderlineText(false);
+ }
+ };
+
+ string.setSpan(span, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return string;
+ }
+
+ /**
+ * 设置点赞图标
+ *
+ * @return
+ */
+ private SpannableString setImageSpan() {
+ String text = " ";
+ SpannableString imgSpanText = new SpannableString(text);
+ imgSpanText.setSpan(new ImageSpan(getContext(), R.mipmap.img_like_icon, DynamicDrawableSpan.ALIGN_BASELINE),
+ 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return imgSpanText;
+ }
+
+ private onItemClickListener listener;
+
+ public void setListener(onItemClickListener listener) {
+ this.listener = listener;
+ }
+
+ public interface onItemClickListener {
+ void onItemClick(int position, UserBean bean);
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/dynamic/view/MultiImageView.java b/app/src/main/java/com/lvfq/code/dynamic/view/MultiImageView.java
new file mode 100644
index 0000000..df00e1e
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/dynamic/view/MultiImageView.java
@@ -0,0 +1,213 @@
+package com.lvfq.code.dynamic.view;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+
+import com.bumptech.glide.Glide;
+import com.lvfq.library.utils.LvDPUtil;
+
+import java.util.List;
+
+/**
+ * @author shoyu
+ * @ClassName MultiImageView.java
+ * @Description: 显示1~N张图片的View
+ */
+
+public class MultiImageView extends LinearLayout {
+ public static int MAX_WIDTH = 0;
+
+ // 照片的Url列表
+ private List imagesList;
+
+ /**
+ * 长度 单位为Pixel *
+ */
+ private int pxOneMaxWandH; // 单张图最大允许宽高
+ private int pxMoreWandH = 0;// 多张图的宽高
+ private int pxImagePadding = LvDPUtil.dip2px(3);// 图片间的间距
+
+ private int MAX_PER_ROW_COUNT = 3;// 每行显示最大数
+
+ private LayoutParams onePicPara;
+ private LayoutParams morePara, moreParaColumnFirst;
+ private LayoutParams rowPara;
+
+ private OnItemClickListener mOnItemClickListener;
+
+ public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
+ mOnItemClickListener = onItemClickListener;
+ }
+
+ public MultiImageView(Context context) {
+ super(context);
+ }
+
+ public MultiImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setList(List lists) throws IllegalArgumentException {
+ if (lists == null) {
+ throw new IllegalArgumentException("imageList is null...");
+ }
+ imagesList = lists;
+
+ if (MAX_WIDTH > 0) {
+ // 如果需要两张和四张图横向铺满,
+// if (lists.size() == 2 || lists.size() == 4) {
+// pxMoreWandH = (MAX_WIDTH - pxImagePadding) / 2;
+// } else {
+ pxMoreWandH = (MAX_WIDTH - pxImagePadding * 2) / 3; //解决右侧图片和内容对不齐问题
+// }
+ pxOneMaxWandH = MAX_WIDTH * 2 / 3; // 一张图的时候,图片宽度
+ initImageLayoutParams();
+ }
+
+ initView();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (MAX_WIDTH == 0) {
+ int width = measureWidth(widthMeasureSpec);
+ if (width > 0) {
+ MAX_WIDTH = width - getPaddingLeft() - getPaddingRight();
+ if (imagesList != null && imagesList.size() > 0) {
+ setList(imagesList);
+ }
+ }
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ /**
+ * Determines the width of this view
+ *
+ * @param measureSpec A measureSpec packed into an int
+ * @return The width of the view, honoring constraints from measureSpec
+ */
+ private int measureWidth(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ // We were told how big to be
+ result = specSize;
+ } else {
+ // Measure the text
+ // result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
+ // + getPaddingRight();
+ if (specMode == MeasureSpec.AT_MOST) {
+ // Respect AT_MOST value if that was what is called for by
+ // measureSpec
+ result = Math.min(result, specSize);
+ }
+ }
+ return result;
+ }
+
+ private void initImageLayoutParams() {
+ int wrap = LayoutParams.WRAP_CONTENT;
+ int match = LayoutParams.MATCH_PARENT;
+
+ onePicPara = new LayoutParams(pxOneMaxWandH, wrap);
+
+ moreParaColumnFirst = new LayoutParams(pxMoreWandH, pxMoreWandH);
+ morePara = new LayoutParams(pxMoreWandH, pxMoreWandH);
+ morePara.setMargins(pxImagePadding, 0, 0, 0);
+
+ rowPara = new LayoutParams(match, wrap);
+ }
+
+ // 根据imageView的数量初始化不同的View布局,还要为每一个View作点击效果
+ private void initView() {
+ this.setOrientation(VERTICAL);
+ this.removeAllViews();
+ if (MAX_WIDTH == 0) {
+ //为了触发onMeasure()来测量MultiImageView的最大宽度,MultiImageView的宽设置为match_parent
+ addView(new View(getContext()));
+ return;
+ }
+
+ if (imagesList == null || imagesList.size() == 0) {
+ return;
+ }
+
+ if (imagesList.size() == 1) {
+ addView(createImageView(0, false));
+ } else {
+ int allCount = imagesList.size();
+ if (allCount == 4) {
+ MAX_PER_ROW_COUNT = 2;
+ } else {
+ MAX_PER_ROW_COUNT = 3;
+ }
+ int rowCount = allCount / MAX_PER_ROW_COUNT
+ + (allCount % MAX_PER_ROW_COUNT > 0 ? 1 : 0);// 行数
+ for (int rowCursor = 0; rowCursor < rowCount; rowCursor++) {
+ LinearLayout rowLayout = new LinearLayout(getContext());
+ rowLayout.setOrientation(LinearLayout.HORIZONTAL);
+
+ rowLayout.setLayoutParams(rowPara);
+ if (rowCursor != 0) {
+ rowLayout.setPadding(0, pxImagePadding, 0, 0);
+ }
+
+ int columnCount = allCount % MAX_PER_ROW_COUNT == 0 ? MAX_PER_ROW_COUNT
+ : allCount % MAX_PER_ROW_COUNT;//每行的列数
+ if (rowCursor != rowCount - 1) {
+ columnCount = MAX_PER_ROW_COUNT;
+ }
+ addView(rowLayout);
+
+ int rowOffset = rowCursor * MAX_PER_ROW_COUNT;// 行偏移
+ for (int columnCursor = 0; columnCursor < columnCount; columnCursor++) {
+ int position = columnCursor + rowOffset;
+ rowLayout.addView(createImageView(position, true));
+ }
+ }
+ }
+ }
+
+ private ImageView createImageView(final int position, final boolean isMultiImage) {
+ String url = "";
+ if (!TextUtils.isEmpty(imagesList.get(position))) {
+ url = imagesList.get(position);
+ }
+
+ ImageView imageView = new ColorFilterImageView(getContext());
+ if (isMultiImage) {
+ imageView.setScaleType(ScaleType.CENTER_CROP);
+ imageView.setLayoutParams(position % MAX_PER_ROW_COUNT == 0 ? moreParaColumnFirst : morePara);
+ } else {
+ imageView.setAdjustViewBounds(true);
+ imageView.setScaleType(ScaleType.FIT_START);
+ imageView.setMaxHeight(pxOneMaxWandH);
+ imageView.setLayoutParams(onePicPara);
+ }
+
+ imageView.setId(url.hashCode());
+ imageView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mOnItemClickListener != null) {
+ mOnItemClickListener.onItemClick(v, position);
+ }
+ }
+ });
+ // TODO: 2016/10/18 之后设置网络图片
+ Glide.with(getContext()).load(url).into(imageView);
+ return imageView;
+ }
+
+ public interface OnItemClickListener {
+ void onItemClick(View view, int position);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lvfq/code/glide/GlideActivity.java b/app/src/main/java/com/lvfq/code/glide/GlideActivity.java
new file mode 100644
index 0000000..9799e72
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/glide/GlideActivity.java
@@ -0,0 +1,62 @@
+package com.lvfq.code.glide;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentActivity;
+import android.widget.ImageView;
+
+import com.lvfq.library.utils.LvV;
+import com.lvfq.myworkingtest.R;
+import com.lvfq.code.dynamic.Data;
+import com.lvfq.myworkingtest.util.GlideApp;
+
+/**
+ * GlideActivity
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/2 下午3:17
+ * @desc :
+ */
+
+public class GlideActivity extends FragmentActivity {
+
+ ImageView iv_1;
+ ImageView iv_2;
+ ImageView iv_3;
+ ImageView iv_4;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_glide);
+
+ iv_1 = LvV.find(this, R.id.iv_1);
+ iv_2 = LvV.find(this, R.id.iv_2);
+ iv_3 = LvV.find(this, R.id.iv_3);
+ iv_4 = LvV.find(this, R.id.iv_4);
+
+// RequestOptions options = new RequestOptions();
+// options.centerCrop();
+//
+// Glide.with(this)
+// .load(Data.getImgs(1))
+// .apply(options)
+// .into(iv_1);
+
+ GlideApp.with(this)
+ .load(Data.getImgs(1))
+ .fitCenter()
+ .into(iv_1);
+
+// GlideApp.with(this).load(Data.getImgs(1)).into(iv_1);
+// Glide4_ImageLoadUtil.loadImg(this, Data.getImgs(1), R.mipmap.img_default, iv_1);
+
+// Glide4_ImageLoadUtil.loadCircleImg(this, Data.getImgs(1), R.mipmap.img_default, iv_2);
+//
+// Glide4_ImageLoadUtil.loadRoundImg(this, Data.getImgs(1), R.mipmap.img_default, iv_3);
+
+
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/http/HttpClient.java b/app/src/main/java/com/lvfq/code/http/HttpClient.java
new file mode 100644
index 0000000..d9b5780
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/http/HttpClient.java
@@ -0,0 +1,56 @@
+package com.lvfq.code.http;
+
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.OkHttpClient;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+/**
+ * HttpClient
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:00
+ * @mainFunction :
+ */
+
+public class HttpClient {
+
+ private static RequestService service;
+ private static long TIMOUT = 10000; //设置超时时间
+// http://an.zdeps.com/Invoking/user_info?keys=64b83c8381fc6d059ecd352f776124be&vci=12121212121H
+
+ /**
+ * 调用 retrofit 服务
+ *
+ * @return
+ */
+ public static RequestService getService() {
+ if (service == null) {
+ synchronized (HttpClient.class) {
+ if (service == null) {
+ service = new Retrofit.Builder()
+ .baseUrl("http://192.168.0.107:8080/")
+ .addConverterFactory(NobodyConverterFactory.create())
+ .addConverterFactory(GsonConverterFactory.create())
+// .client(new OkHttpClient().newBuilder().addInterceptor(new Interceptor() {
+// @Override
+// public Response intercept(Chain chain) throws IOException {
+// Request request = chain.request();
+// HttpUrl url = request.url().newBuilder().addQueryParameter("platformType", "ANDROID").addQueryParameter("version", V.getVersionName(MyApplication.getContext())).build();
+// return chain.proceed(request.newBuilder().url(url).build());
+// }
+// }).build())
+ .client(new OkHttpClient().newBuilder().connectTimeout(TIMOUT, TimeUnit.MILLISECONDS)
+ .writeTimeout(TIMOUT, TimeUnit.MILLISECONDS)
+ .readTimeout(TIMOUT, TimeUnit.MILLISECONDS)
+ .build())
+ .build()
+ .create(RequestService.class);
+ }
+ }
+ }
+ return service;
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lvfq/code/http/NobodyConverterFactory.java b/app/src/main/java/com/lvfq/code/http/NobodyConverterFactory.java
new file mode 100644
index 0000000..a19b45a
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/http/NobodyConverterFactory.java
@@ -0,0 +1,64 @@
+package com.lvfq.code.http;
+
+import com.lvfq.code.NoBodyEntity;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import okhttp3.RequestBody;
+import okhttp3.ResponseBody;
+import retrofit2.Converter;
+import retrofit2.Retrofit;
+
+/**
+ * NobodyConverterFactory
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/8/4 下午11:04
+ * @desc :
+ */
+
+public class NobodyConverterFactory extends Converter.Factory {
+
+ public static final NobodyConverterFactory create() {
+ return new NobodyConverterFactory();
+ }
+
+ private NobodyConverterFactory() {
+ }
+
+ //将响应对象responseBody转成目标类型对象(也就是Call里给定的类型)
+ @Override
+ public Converter responseBodyConverter(Type type, Annotation[] annotations,
+ Retrofit retrofit) {
+ //判断当前的类型是否是我们需要处理的类型
+ if (NoBodyEntity.class.equals(type)) {
+ //是则创建一个Converter返回转换数据
+ return new Converter() {
+ @Override
+ public NoBodyEntity convert(ResponseBody value) throws IOException {
+ //这里直接返回null是因为我们不需要使用到响应体,本来也没有响应体.
+ //返回的对象会存到response.body()里.
+ return null;
+ }
+ };
+ }
+ return null;
+ }
+
+ //其它两个方法我们不需要使用到.所以不需要重写.
+ @Override
+ public Converter, RequestBody> requestBodyConverter(Type type,
+ Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
+ return null;
+ }
+
+ @Override
+ public Converter, String> stringConverter(Type type, Annotation[] annotations,
+ Retrofit retrofit) {
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/http/RequestService.java b/app/src/main/java/com/lvfq/code/http/RequestService.java
new file mode 100644
index 0000000..4215f17
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/http/RequestService.java
@@ -0,0 +1,33 @@
+package com.lvfq.code.http;
+
+import com.lvfq.code.ModelBean;
+
+import retrofit2.Call;
+import retrofit2.http.Field;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.GET;
+import retrofit2.http.POST;
+import retrofit2.http.Query;
+
+/**
+ * RequestService
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:00
+ * @mainFunction :
+ */
+
+public interface RequestService {
+
+ @POST("login")
+ Call login(@Query("userName") String userName,
+ @Query("passWord") String passWord);
+
+ @FormUrlEncoded
+ @POST("Invoking/user_info")
+ Call userInfo(@Field("keys") String keys,
+ @Field("vci") String vci);
+
+ @GET("front/server")
+ Call serverInfo();
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/Http.java b/app/src/main/java/com/lvfq/code/mvp/Http.java
new file mode 100644
index 0000000..6eb3228
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/Http.java
@@ -0,0 +1,23 @@
+package com.lvfq.code.mvp;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Http
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午2:22
+ * @mainFunction :
+ */
+
+public class Http {
+
+ public static void http_login(String userName, String password, IHttpResultListener listener) {
+ Map map = new HashMap<>();
+ map.put("userName", userName);
+ map.put("passWord", password);
+ HttpUtil.post("login", map, listener);
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/HttpUtil.java b/app/src/main/java/com/lvfq/code/mvp/HttpUtil.java
new file mode 100644
index 0000000..3654dee
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/HttpUtil.java
@@ -0,0 +1,106 @@
+package com.lvfq.code.mvp;
+
+import android.os.Handler;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Map;
+
+/**
+ * HttpUtil
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午12:17
+ * @mainFunction :
+ */
+
+public class HttpUtil {
+
+ static final String HTTP = "http://192.168.2.1:8080/";
+
+ private static Handler handler = new Handler();
+
+ public static void post(final String url, final Map params, final IHttpResultListener listener) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ String result = "";
+ HttpURLConnection conn = null;
+ OutputStream out = null;
+ BufferedReader reader = null;
+ try {
+ StringBuilder paramsStr = new StringBuilder();
+ if (params != null && params.size() > 0) {
+ for (Map.Entry entry : params.entrySet()) {
+ paramsStr.append(entry.getKey()).append("=").append(entry.getValue().toString()).append("&");
+ }
+ paramsStr.deleteCharAt(paramsStr.length() - 1);
+ }
+ URL u = new URL(HTTP + url);
+ conn = (HttpURLConnection) u.openConnection();
+
+ // 设置连接参数
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ conn.setRequestMethod("POST");// 设置以POST方式
+ conn.setUseCaches(false); // Post请求不使用缓存
+ conn.setInstanceFollowRedirects(true);
+ conn.setRequestProperty("Content-Type",
+ "application/x-www-form-urlencoded");
+ conn.setRequestProperty("Charset", "UTF-8");
+
+ conn.setConnectTimeout(10000);
+ conn.setReadTimeout(10000);
+
+ // 上传的参数
+ Log.i("lfq", paramsStr.toString());
+ out = conn.getOutputStream();
+ out.write(paramsStr.toString().getBytes());
+ out.flush();
+ out.close();
+
+ reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ StringBuffer strBuf = new StringBuffer();
+ String str = null;
+ while ((str = reader.readLine()) != null) {
+ strBuf.append(str);
+ }
+ result = strBuf.toString();
+ Log.i("lfq", strBuf.toString());
+ } catch (Exception e) {
+ e.printStackTrace();
+ result = e.toString();
+ } finally {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ if (reader != null) {
+ reader.close();
+ }
+ if (conn != null) {
+ conn.disconnect();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (listener != null) {
+ final String res = result;
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ listener.onResult(res);
+ }
+ });
+ }
+ }
+ }).start();
+
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/IHttpResultListener.java b/app/src/main/java/com/lvfq/code/mvp/IHttpResultListener.java
new file mode 100644
index 0000000..df0af43
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/IHttpResultListener.java
@@ -0,0 +1,13 @@
+package com.lvfq.code.mvp;
+
+/**
+ * IHttpResultListener
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午2:20
+ * @mainFunction :
+ */
+
+public interface IHttpResultListener {
+ void onResult(String t);
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/LoginActivity.java b/app/src/main/java/com/lvfq/code/mvp/LoginActivity.java
new file mode 100644
index 0000000..86e23b7
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/LoginActivity.java
@@ -0,0 +1,77 @@
+package com.lvfq.code.mvp;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import com.lvfq.code.BaseActivity;
+import com.lvfq.code.ModelBean;
+import com.lvfq.code.mvp.demo3.LoginPresenter3;
+import com.lvfq.myworkingtest.R;
+import com.lvfq.code.http.HttpClient;
+import com.lvfq.code.mvp.demo3.LoginView3;
+
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+
+/**
+ * LoginActivity
+ *
+ * @author lvfq
+ * @date 2017/7/12 下午9:46
+ * @mainFunction :
+ */
+
+public class LoginActivity extends BaseActivity implements LoginView3 {
+
+ @Override
+ public LoginPresenter3 bindPresenter() {
+ return new LoginPresenter3();
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_login);
+ }
+
+
+ public void clickLogin(View view) {
+// getPresenter().login("发强", "123456");
+ HttpClient.getService().serverInfo().enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ ModelBean bean = response.body();
+ Log.i("lfq", bean.getResultData().isMainServer() + "");
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ Log.i("lfq", t.getMessage() + "");
+ }
+ });
+
+// Http.http_login("发强", "123456", this);
+// HttpClient.getService().login("lvfaqiang", "123456").enqueue(new Callback() {
+// @Override
+// public void onResponse(Call call, Response response) {
+// ModelBean bean = response.body();
+// Log.i("lfq", "" + bean.getStatus());
+// }
+//
+// @Override
+// public void onFailure(Call call, Throwable t) {
+// Log.i("lfq", t.toString());
+// }
+// });
+ }
+
+ @Override
+ public void onResult(final String s) {
+ Toast.makeText(LoginActivity.this, s, Toast.LENGTH_SHORT).show();
+ Log.i("lfq", "login Result: " + s);
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/RegisterActivity.java b/app/src/main/java/com/lvfq/code/mvp/RegisterActivity.java
new file mode 100644
index 0000000..c05460a
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/RegisterActivity.java
@@ -0,0 +1,20 @@
+package com.lvfq.code.mvp;
+
+import com.lvfq.code.BaseActivity;
+import com.lvfq.code.mvp.demo3.BaseMvpPresenter;
+
+/**
+ * RegisterActivity
+ *
+ * @author lvfq
+ * @date 2017/7/17 下午10:13
+ * @mainFunction :
+ */
+
+public class RegisterActivity extends BaseActivity {
+ @Override
+ public BaseMvpPresenter bindPresenter() {
+ return null;
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo1/LoginModel.java b/app/src/main/java/com/lvfq/code/mvp/demo1/LoginModel.java
new file mode 100644
index 0000000..3e732b2
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo1/LoginModel.java
@@ -0,0 +1,20 @@
+package com.lvfq.code.mvp.demo1;
+
+import com.lvfq.code.mvp.Http;
+import com.lvfq.code.mvp.IHttpResultListener;
+
+/**
+ * LoginModel
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:22
+ * @mainFunction : M 层
+ */
+
+public class LoginModel {
+
+ public void login(String userName, String passWord, IHttpResultListener listener) {
+ Http.http_login(userName, passWord, listener);
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo1/LoginPresenter.java b/app/src/main/java/com/lvfq/code/mvp/demo1/LoginPresenter.java
new file mode 100644
index 0000000..0e02ed2
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo1/LoginPresenter.java
@@ -0,0 +1,39 @@
+package com.lvfq.code.mvp.demo1;
+
+import com.lvfq.code.mvp.IHttpResultListener;
+
+/**
+ * LoginPresenter
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:21
+ * @mainFunction :
+ */
+
+public class LoginPresenter {
+
+ private LoginModel loginModel;
+ private LoginView loginView;
+
+ public LoginPresenter(LoginView loginView) {
+ this.loginView = loginView;
+ loginModel = new LoginModel();
+ }
+
+ /**
+ * 登录
+ *
+ * @param userName
+ * @param passWord
+ */
+ public void login(String userName, String passWord) {
+ loginModel.login(userName, passWord, new IHttpResultListener() {
+ @Override
+ public void onResult(String t) {
+ if (loginView != null) {
+ loginView.onResult(t);
+ }
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo1/LoginView.java b/app/src/main/java/com/lvfq/code/mvp/demo1/LoginView.java
new file mode 100644
index 0000000..cada149
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo1/LoginView.java
@@ -0,0 +1,15 @@
+package com.lvfq.code.mvp.demo1;
+
+/**
+ * LoginView
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:21
+ * @mainFunction : 解耦和
+ */
+
+public interface LoginView {
+
+ void onResult(String result);
+
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo2/LoginModel2.java b/app/src/main/java/com/lvfq/code/mvp/demo2/LoginModel2.java
new file mode 100644
index 0000000..5d5f33f
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo2/LoginModel2.java
@@ -0,0 +1,20 @@
+package com.lvfq.code.mvp.demo2;
+
+import com.lvfq.code.mvp.Http;
+import com.lvfq.code.mvp.IHttpResultListener;
+
+/**
+ * LoginModel
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:22
+ * @mainFunction : M 层
+ */
+
+public class LoginModel2 {
+
+ public void login(String userName, String passWord, IHttpResultListener listener) {
+ Http.http_login(userName, passWord, listener);
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo2/LoginPresenter2.java b/app/src/main/java/com/lvfq/code/mvp/demo2/LoginPresenter2.java
new file mode 100644
index 0000000..44b100b
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo2/LoginPresenter2.java
@@ -0,0 +1,46 @@
+package com.lvfq.code.mvp.demo2;
+
+import com.lvfq.code.mvp.IHttpResultListener;
+
+/**
+ * LoginPresenter
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:21
+ * @mainFunction :
+ */
+
+public class LoginPresenter2 {
+
+ private LoginModel2 loginModel;
+ private LoginView2 loginView;
+
+ public LoginPresenter2() {
+ loginModel = new LoginModel2();
+ }
+
+ public void attachView(LoginView2 loginView) {
+ this.loginView = loginView;
+ }
+
+ public void dettachView() {
+ this.loginView = null;
+ }
+
+ /**
+ * 登录
+ *
+ * @param userName
+ * @param passWord
+ */
+ public void login(String userName, String passWord) {
+ loginModel.login(userName, passWord, new IHttpResultListener() {
+ @Override
+ public void onResult(String t) {
+ if (loginView != null) {
+ loginView.onResult(t);
+ }
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo2/LoginView2.java b/app/src/main/java/com/lvfq/code/mvp/demo2/LoginView2.java
new file mode 100644
index 0000000..0482c3e
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo2/LoginView2.java
@@ -0,0 +1,15 @@
+package com.lvfq.code.mvp.demo2;
+
+/**
+ * LoginView
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:21
+ * @mainFunction : 解耦和
+ */
+
+public interface LoginView2 {
+
+ void onResult(String result);
+
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo3/BaseMvpPresenter.java b/app/src/main/java/com/lvfq/code/mvp/demo3/BaseMvpPresenter.java
new file mode 100644
index 0000000..cbce57a
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo3/BaseMvpPresenter.java
@@ -0,0 +1,28 @@
+package com.lvfq.code.mvp.demo3;
+
+/**
+ * BaseMvpPresenter
+ *
+ * @author lvfq
+ * @date 2017/7/17 下午3:25
+ * @mainFunction :
+ */
+
+public class BaseMvpPresenter implements IBasePresenter {
+ private V view;
+
+ @Override
+ public V getView() {
+ return view;
+ }
+
+ @Override
+ public void attachView(V view) {
+ this.view = view;
+ }
+
+ @Override
+ public void detachView() {
+ this.view = null;
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo3/IBaseMvpView.java b/app/src/main/java/com/lvfq/code/mvp/demo3/IBaseMvpView.java
new file mode 100644
index 0000000..90f39b9
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo3/IBaseMvpView.java
@@ -0,0 +1,13 @@
+package com.lvfq.code.mvp.demo3;
+
+/**
+ * IBaseMvpView
+ *
+ * @author lvfq
+ * @date 2017/7/17 下午3:15
+ * @mainFunction :
+ */
+
+public interface IBaseMvpView {
+
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo3/IBasePresenter.java b/app/src/main/java/com/lvfq/code/mvp/demo3/IBasePresenter.java
new file mode 100644
index 0000000..0ad225d
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo3/IBasePresenter.java
@@ -0,0 +1,19 @@
+package com.lvfq.code.mvp.demo3;
+
+/**
+ * IBasePresenter
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/7/26 下午12:40
+ * @desc :
+ */
+
+public interface IBasePresenter {
+ V getView();
+
+ void attachView(V view);
+
+ void detachView();
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo3/LoginModel3.java b/app/src/main/java/com/lvfq/code/mvp/demo3/LoginModel3.java
new file mode 100644
index 0000000..f91f212
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo3/LoginModel3.java
@@ -0,0 +1,27 @@
+package com.lvfq.code.mvp.demo3;
+
+import com.lvfq.code.mvp.Http;
+import com.lvfq.code.mvp.IHttpResultListener;
+
+/**
+ * LoginModel
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:22
+ * @mainFunction : M 层
+ */
+
+public class LoginModel3 {
+
+ public void login(String userName, String passWord, IHttpResultListener listener) {
+ Http.http_login(userName, passWord, listener);
+ }
+
+ /**
+ * 保存登录用户数据
+ */
+ public void saveUserData(){
+ //...
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo3/LoginPresenter3.java b/app/src/main/java/com/lvfq/code/mvp/demo3/LoginPresenter3.java
new file mode 100644
index 0000000..8be1791
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo3/LoginPresenter3.java
@@ -0,0 +1,41 @@
+package com.lvfq.code.mvp.demo3;
+
+import com.lvfq.code.mvp.IHttpResultListener;
+
+/**
+ * LoginPresenter
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:21
+ * @mainFunction :
+ */
+
+public class LoginPresenter3 extends BaseMvpPresenter {
+
+ private LoginModel3 loginModel;
+
+ public LoginPresenter3() {
+ loginModel = new LoginModel3();
+ }
+
+ /**
+ * 登录
+ *
+ * @param userName
+ * @param passWord
+ */
+ public void login(String userName, String passWord) {
+ loginModel.login(userName, passWord, new IHttpResultListener() {
+ @Override
+ public void onResult(String t) {
+ // 其他的数据操作。
+ loginModel.saveUserData();
+
+ if (getView() != null) {
+ // 最终返回界面,进行 UI 操作。
+ getView().onResult(t);
+ }
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/mvp/demo3/LoginView3.java b/app/src/main/java/com/lvfq/code/mvp/demo3/LoginView3.java
new file mode 100644
index 0000000..b12849d
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/mvp/demo3/LoginView3.java
@@ -0,0 +1,15 @@
+package com.lvfq.code.mvp.demo3;
+
+/**
+ * LoginView
+ *
+ * @author lvfq
+ * @date 2017/7/13 下午11:21
+ * @mainFunction : 解耦和
+ */
+
+public interface LoginView3 extends IBaseMvpView {
+
+ void onResult(String result);
+
+}
diff --git a/app/src/main/java/com/lvfq/code/tablayout/PagerSlidingTabStrip.java b/app/src/main/java/com/lvfq/code/tablayout/PagerSlidingTabStrip.java
new file mode 100755
index 0000000..f8727de
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/tablayout/PagerSlidingTabStrip.java
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2013 Andreas Stuetz
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.lvfq.code.tablayout;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.v4.view.ViewPager;
+import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.widget.HorizontalScrollView;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.lvfq.myworkingtest.R;
+
+import java.util.Locale;
+
+/**
+ * PagerSlidingTabStrip
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/8/29 上午10:35
+ * @desc :
+ */
+
+public class PagerSlidingTabStrip extends HorizontalScrollView {
+
+ public interface IconTabProvider {
+ public int getPageIconResId(int position);
+ }
+
+ // @formatter:off
+ private static final int[] ATTRS = new int[]{android.R.attr.textSize,
+ android.R.attr.textColor};
+ // @formatter:on
+
+ private LinearLayout.LayoutParams defaultTabLayoutParams;
+ private LinearLayout.LayoutParams expandedTabLayoutParams;
+
+ private final PageListener pageListener = new PageListener();
+ public OnPageChangeListener delegatePageListener;
+
+ private LinearLayout tabsContainer;
+ private ViewPager pager;
+
+ private int pageCount;
+
+ private int currentPosition = 0;
+ private float currentPositionOffset = 0f;
+
+ private Paint rectPaint;
+ private Paint dividerPaint;
+
+ private boolean checkedTabWidths = false;
+
+ private int indicatorColor = 0xffFF811C; // 指示器颜色
+ private int underlineColor = 0xffCECECE; // 下划线颜色
+ private int dividerColor = 0xFF811C; // 分割线颜色
+ private int indicatorPadding = 10; //指示器 左右内边距
+
+ private boolean shouldExpand = false;//FF811C
+ private boolean textAllCaps = true;
+
+ private int scrollOffset = 52;
+ private int indicatorHeight = 0; // 指示器高度
+ private int underlineHeight = 0; // 下划线高度
+ private int dividerPadding = 6; // 分割线
+ private int tabPadding = 22;
+ private int tabPaddingr = 19; // 选中的tab padding
+ private int dividerWidth = 1;
+ private int tabTextSize = 16; // 默认文字大小
+ private int tabTextColor = 0xff999999; // 默认颜色
+
+ private int tabTextSizer = 16; // 选中的文字大小
+ private int tabTextColorr = 0xffffffff; // 选中颜色
+ private Typeface tabTypeface = null;
+ private int tabTypefaceStyle = Typeface.NORMAL;
+
+ private int lastScrollX = 0;
+
+ private int tabBackgroundResId /*= R.drawable.background_tab*/;
+
+ private Locale locale;
+// PageSelectedImpl mSelected;
+
+ public PagerSlidingTabStrip(Context context) {
+ this(context, null);
+ }
+
+ public PagerSlidingTabStrip(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PagerSlidingTabStrip(Context context, AttributeSet attrs,
+ int defStyle) {
+ super(context, attrs, defStyle);
+
+ setFillViewport(true);
+ setWillNotDraw(false);
+
+ tabsContainer = new LinearLayout(context);
+ tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
+ tabsContainer.setLayoutParams(new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ addView(tabsContainer);
+
+ DisplayMetrics dm = getResources().getDisplayMetrics();
+
+ scrollOffset = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm);
+ indicatorHeight = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, indicatorHeight, dm);
+ underlineHeight = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, underlineHeight, dm);
+ dividerPadding = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, dividerPadding, dm);
+ tabPadding = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, tabPadding, dm);
+ tabPaddingr = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, tabPaddingr, dm);
+ indicatorPadding = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, indicatorPadding, dm);
+ dividerWidth = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, dividerWidth, dm);
+ tabTextSize = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm);
+ tabTextSizer = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_SP, tabTextSizer, dm);
+ // get system attrs (android:textSize and android:textColor)
+
+ TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
+
+ tabTextSize = a.getDimensionPixelSize(0, tabTextSize);
+ tabTextColor = a.getColor(1, tabTextColor);
+
+ a.recycle();
+
+ // get custom attrs
+
+ a = context.obtainStyledAttributes(attrs, R.styleable.PagerSlidingTabStrip);
+
+ indicatorColor = a.getColor(R.styleable.PagerSlidingTabStrip_indicatorColor, indicatorColor);
+ indicatorPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_indicatorPaddingLeftRight, indicatorPadding);
+ underlineColor = a.getColor(R.styleable.PagerSlidingTabStrip_underlineColor, underlineColor);
+ dividerColor = a.getColor(R.styleable.PagerSlidingTabStrip_dividerColor, dividerColor);
+ indicatorHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_indicatorHeight, indicatorHeight);
+ underlineHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_underlineHeight, underlineHeight);
+ dividerPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_dividerPadding, dividerPadding);
+ tabPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_tabPaddingLeftRight, tabPadding);
+ tabBackgroundResId = a.getResourceId(R.styleable.PagerSlidingTabStrip_tabBackground, tabBackgroundResId);
+ shouldExpand = a.getBoolean(R.styleable.PagerSlidingTabStrip_shouldExpand, shouldExpand);
+ scrollOffset = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_scrollOffset, scrollOffset);
+// textAllCaps = a.getBoolean(R.styleable.PagerSlidingTabStrip_textAllCaps, textAllCaps);
+ tabTextSize = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_tabDefTextSize, tabTextSize);
+ tabTextSizer = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_tabSelTextSize, tabTextSizer);
+ tabTextColor = a.getColor(R.styleable.PagerSlidingTabStrip_tabDefTextColor, tabTextColor);
+ tabTextColorr = a.getColor(R.styleable.PagerSlidingTabStrip_tabSelTextColor, tabTextColorr);
+
+ a.recycle();
+
+ rectPaint = new Paint();
+ rectPaint.setAntiAlias(true);
+ rectPaint.setStyle(Style.FILL);
+
+ dividerPaint = new Paint();
+ dividerPaint.setAntiAlias(true);
+ dividerPaint.setStrokeWidth(dividerWidth);
+
+ defaultTabLayoutParams = new LinearLayout.LayoutParams(0,
+ LayoutParams.MATCH_PARENT, 1.0f);
+// defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
+ expandedTabLayoutParams = new LinearLayout.LayoutParams(0,
+ LayoutParams.MATCH_PARENT, 1.0f);
+
+ if (locale == null) {
+ locale = getResources().getConfiguration().locale;
+ }
+ }
+
+ /**
+ * 设置一个回调接口
+ *
+ * @param pager
+ */
+ public void setViewPager(ViewPager pager) {
+ this.pager = pager;
+
+ if (pager.getAdapter() == null) {
+ throw new IllegalStateException(
+ "ViewPager does not have adapter instance.");
+ }
+
+ pager.setOnPageChangeListener(pageListener);
+
+ notifyDataSetChanged();
+ }
+
+ public void setOnPageChangeListener(OnPageChangeListener listener) {
+ this.delegatePageListener = listener;
+ }
+
+ public void notifyDataSetChanged() {
+
+ tabsContainer.removeAllViews();
+
+ pageCount = pager.getAdapter().getCount();
+
+ for (int i = 0; i < pageCount; i++) {
+
+ if (pager.getAdapter() instanceof IconTabProvider) {
+ addIconTab(i,
+ ((IconTabProvider) pager.getAdapter())
+ .getPageIconResId(i));
+ } else {
+ addTextTab(i, pager.getAdapter().getPageTitle(i).toString());
+ }
+
+ }
+
+ updateTabStyles();
+
+ checkedTabWidths = false;
+
+ getViewTreeObserver().addOnGlobalLayoutListener(
+ new OnGlobalLayoutListener() {
+
+ @SuppressWarnings("deprecation")
+ @SuppressLint("NewApi")
+ @Override
+ public void onGlobalLayout() {
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ getViewTreeObserver().removeGlobalOnLayoutListener(
+ this);
+ } else {
+ getViewTreeObserver().removeOnGlobalLayoutListener(
+ this);
+ }
+
+ currentPosition = pager.getCurrentItem();
+ scrollToChild(currentPosition, 0);
+ }
+ });
+
+ }
+
+ private void addTextTab(final int position, String title) {
+
+ TextView tab = new TextView(getContext());
+ tab.setText(title);
+ tab.setFocusable(true);
+ tab.setGravity(Gravity.CENTER);
+ tab.setSingleLine();
+
+ tab.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ pager.setCurrentItem(position);
+ }
+ });
+
+ tabsContainer.addView(tab);
+
+ }
+
+ private void addIconTab(final int position, int resId) {
+
+ ImageButton tab = new ImageButton(getContext());
+ tab.setFocusable(true);
+ tab.setImageResource(resId);
+
+ tab.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ pager.setCurrentItem(position);
+ }
+ });
+
+ tabsContainer.addView(tab);
+
+ }
+
+ private void updateTabStyles() {
+ int currentIndex = this.pager.getCurrentItem();
+ for (int i = 0; i < pageCount; i++) {
+
+ View v = tabsContainer.getChildAt(i);
+
+ v.setLayoutParams(defaultTabLayoutParams);
+ v.setBackgroundResource(tabBackgroundResId);
+
+ if (v instanceof TextView) {
+
+ TextView tab = (TextView) v;
+ tab.setTypeface(tabTypeface, tabTypefaceStyle);
+ v.setPadding(tabPadding, 0, tabPadding, 0);
+ if (currentIndex == i) {
+ tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSizer);
+ tab.setTextColor(tabTextColorr);
+// if (shouldExpand) {
+// v.setPadding(tabPadding, 0, tabPadding, 0);
+// } else {
+// v.setPadding(tabPadding, 0, tabPadding, 0);
+// }
+ } else {
+ tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSize);
+ tab.setTextColor(tabTextColor);
+// if (shouldExpand) {
+// v.setPadding(0, 0, 0, 0);
+// } else {
+// v.setPadding(0, 0, 0, 0);
+// }
+ }
+ // setAllCaps() is only available from API 14, so the upper case
+ // is made manually if we are on a
+ // pre-ICS-build
+ if (textAllCaps) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ tab.setAllCaps(true);
+ } else {
+ tab.setText(tab.getText().toString()
+ .toUpperCase(locale));
+ }
+ }
+ }
+ }
+
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (!shouldExpand
+ || MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
+ return;
+ }
+
+ int myWidth = getMeasuredWidth();
+ int childWidth = 0;
+ for (int i = 0; i < pageCount; i++) {
+ childWidth += tabsContainer.getChildAt(i).getMeasuredWidth();
+ }
+
+ if (!checkedTabWidths && childWidth > 0 && myWidth > 0) {
+
+ if (childWidth <= myWidth) {
+ for (int i = 0; i < pageCount; i++) {
+ tabsContainer.getChildAt(i).setLayoutParams(
+ expandedTabLayoutParams);
+ }
+ }
+
+ checkedTabWidths = true;
+ }
+ }
+
+ private void scrollToChild(int position, int offset) {
+
+ if (pageCount == 0) {
+ return;
+ }
+
+ int newScrollX = tabsContainer.getChildAt(position).getLeft() + offset;
+
+ if (position > 0 || offset > 0) {
+ newScrollX -= scrollOffset;
+ }
+
+ if (newScrollX != lastScrollX) {
+ lastScrollX = newScrollX;
+ scrollTo(newScrollX, 0);
+ }
+
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (isInEditMode() || pageCount == 0) {
+ return;
+ }
+
+ final int height = getHeight();
+
+ // draw indicator line
+
+ rectPaint.setColor(indicatorColor);
+
+ // default: line below current tab
+ View currentTab = tabsContainer.getChildAt(currentPosition);
+ float lineLeft = currentTab.getLeft();
+ float lineRight = currentTab.getRight();
+
+ // if there is an offset, start interpolating left and right coordinates
+ // between current and next tab
+ if (currentPositionOffset > 0f && currentPosition < pageCount - 1) {
+
+ View nextTab = tabsContainer.getChildAt(currentPosition + 1);
+ final float nextTabLeft = nextTab.getLeft();
+ final float nextTabRight = nextTab.getRight();
+
+ lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset)
+ * lineLeft);
+ lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset)
+ * lineRight);
+ }
+
+ canvas.drawRect(lineLeft + indicatorPadding, height - indicatorHeight, lineRight - indicatorPadding, height,
+ rectPaint);
+
+ // draw underline
+
+ rectPaint.setColor(underlineColor);
+ canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(),
+ height, rectPaint);
+
+ // draw divider
+
+ dividerPaint.setColor(dividerColor);
+ for (int i = 0; i < pageCount - 1; i++) {
+ View tab = tabsContainer.getChildAt(i);
+ canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(),
+ height - dividerPadding, dividerPaint);
+ }
+ }
+
+ private class PageListener implements OnPageChangeListener {
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset,
+ int positionOffsetPixels) {
+
+ currentPosition = position;
+ currentPositionOffset = positionOffset;
+
+ scrollToChild(position, (int) (positionOffset * tabsContainer
+ .getChildAt(position).getWidth()));
+
+ invalidate();
+
+ if (delegatePageListener != null) {
+ delegatePageListener.onPageScrolled(position, positionOffset,
+ positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (state == ViewPager.SCROLL_STATE_IDLE) {
+ scrollToChild(pager.getCurrentItem(), 0);
+ }
+
+ if (delegatePageListener != null) {
+ delegatePageListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (delegatePageListener != null) {
+ delegatePageListener.onPageSelected(position);
+ }
+// mSelected.selectedPage(position);
+ updateTabStyles();
+ }
+
+ }
+
+ public void setIndicatorColor(int indicatorColor) {
+ this.indicatorColor = indicatorColor;
+ invalidate();
+ }
+
+ public void setIndicatorColorResource(int resId) {
+ this.indicatorColor = getResources().getColor(resId);
+ invalidate();
+ }
+
+ public int getIndicatorColor() {
+ return this.indicatorColor;
+ }
+
+ public void setIndicatorHeight(int indicatorLineHeightPx) {
+ this.indicatorHeight = indicatorLineHeightPx;
+ invalidate();
+ }
+
+ public int getIndicatorHeight() {
+ return indicatorHeight;
+ }
+
+ public void setUnderlineColor(int underlineColor) {
+ this.underlineColor = underlineColor;
+ invalidate();
+ }
+
+ public void setUnderlineColorResource(int resId) {
+ this.underlineColor = getResources().getColor(resId);
+ invalidate();
+ }
+
+ public int getUnderlineColor() {
+ return underlineColor;
+ }
+
+ public void setDividerColor(int dividerColor) {
+ this.dividerColor = dividerColor;
+ invalidate();
+ }
+
+ public void setDividerColorResource(int resId) {
+ this.dividerColor = getResources().getColor(resId);
+ invalidate();
+ }
+
+ public int getDividerColor() {
+ return dividerColor;
+ }
+
+ public void setUnderlineHeight(int underlineHeightPx) {
+ this.underlineHeight = underlineHeightPx;
+ invalidate();
+ }
+
+ public int getUnderlineHeight() {
+ return underlineHeight;
+ }
+
+ public void setDividerPadding(int dividerPaddingPx) {
+ this.dividerPadding = dividerPaddingPx;
+ invalidate();
+ }
+
+ public int getDividerPadding() {
+ return dividerPadding;
+ }
+
+ public void setScrollOffset(int scrollOffsetPx) {
+ this.scrollOffset = scrollOffsetPx;
+ invalidate();
+ }
+
+ public int getScrollOffset() {
+ return scrollOffset;
+ }
+
+ public void setShouldExpand(boolean shouldExpand) {
+ this.shouldExpand = shouldExpand;
+ requestLayout();
+ }
+
+ public boolean getShouldExpand() {
+ return shouldExpand;
+ }
+
+ public boolean isTextAllCaps() {
+ return textAllCaps;
+ }
+
+ public void setAllCaps(boolean textAllCaps) {
+ this.textAllCaps = textAllCaps;
+ }
+
+ public void setTextSize(int textSizePx) {
+ this.tabTextSize = textSizePx;
+ updateTabStyles();
+ }
+
+ public int getTextSize() {
+ return tabTextSize;
+ }
+
+ public void setTextColor(int textColor) {
+ this.tabTextColor = textColor;
+ updateTabStyles();
+ }
+
+ public void setTextColorResource(int resId) {
+ this.tabTextColor = getResources().getColor(resId);
+ updateTabStyles();
+ }
+
+ public int getTextColor() {
+ return tabTextColor;
+ }
+
+ public void setTypeface(Typeface typeface, int style) {
+ this.tabTypeface = typeface;
+ this.tabTypefaceStyle = style;
+ updateTabStyles();
+ }
+
+ public void setTabBackground(int resId) {
+ this.tabBackgroundResId = resId;
+ }
+
+ public int getTabBackground() {
+ return tabBackgroundResId;
+ }
+
+ public void setTabPaddingLeftRight(int paddingPx) {
+ this.tabPadding = paddingPx;
+ updateTabStyles();
+ }
+
+ public int getTabPaddingLeftRight() {
+ return tabPadding;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ SavedState savedState = (SavedState) state;
+ super.onRestoreInstanceState(savedState.getSuperState());
+ currentPosition = savedState.currentPosition;
+ requestLayout();
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ SavedState savedState = new SavedState(superState);
+ savedState.currentPosition = currentPosition;
+ return savedState;
+ }
+
+ static class SavedState extends BaseSavedState {
+ int currentPosition;
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ private SavedState(Parcel in) {
+ super(in);
+ currentPosition = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(currentPosition);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ @Override
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/tablayout/TabActivity.java b/app/src/main/java/com/lvfq/code/tablayout/TabActivity.java
new file mode 100644
index 0000000..b217201
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/tablayout/TabActivity.java
@@ -0,0 +1,72 @@
+package com.lvfq.code.tablayout;
+
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.view.ViewPager;
+
+import com.lvfq.library.utils.LvV;
+import com.lvfq.myworkingtest.R;
+
+/**
+ * TabActivity
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/1 下午4:22
+ * @desc :
+ */
+
+public class TabActivity extends FragmentActivity {
+
+ private PagerSlidingTabStrip tabs;
+ private ViewPager viewPager;
+
+ private String[] titles = {"热点", "推荐", "标题党", "视频", "本地农业", "科技", "政治", "农业", "其他"};
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_tab);
+ tabs = LvV.find(this, R.id.tabs);
+ viewPager = LvV.find(this, R.id.viewPager);
+
+ TabAdapter adapter = new TabAdapter(getSupportFragmentManager());
+ if (adapter != null) {
+ viewPager.setAdapter(adapter);
+ tabs.setViewPager(viewPager);
+ }
+
+ }
+
+ class TabAdapter extends FragmentStatePagerAdapter {
+
+ public TabAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public int getCount() {
+ return titles.length;
+ }
+
+ @Override
+ public Fragment getItem(int pos) {
+ return TabFragment.getInstance(titles[pos]);
+ }
+
+ @Override
+ public void restoreState(Parcelable arg0, ClassLoader arg1) {
+ }
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return titles[position];
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/lvfq/code/tablayout/TabFragment.java b/app/src/main/java/com/lvfq/code/tablayout/TabFragment.java
new file mode 100644
index 0000000..ee4ac0a
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/tablayout/TabFragment.java
@@ -0,0 +1,46 @@
+package com.lvfq.code.tablayout;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * TabFragment
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/1 下午4:38
+ * @desc :
+ */
+
+public class TabFragment extends Fragment {
+
+
+ public static TabFragment getInstance(String string) {
+ TabFragment instance = new TabFragment();
+ Bundle bundle = new Bundle();
+ bundle.putString("title", string);
+ instance.setArguments(bundle);
+ return instance;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+
+ String text = getArguments().getString("title");
+ TextView textView = new TextView(getActivity());
+ textView.setText(text);
+ textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ textView.setGravity(Gravity.CENTER);
+ Log.i("lfq", "title : " + text + " , hashCode : " + hashCode());
+ return textView;
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/tablayout/custom/TabActivity1.java b/app/src/main/java/com/lvfq/code/tablayout/custom/TabActivity1.java
new file mode 100644
index 0000000..2099db7
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/tablayout/custom/TabActivity1.java
@@ -0,0 +1,86 @@
+package com.lvfq.code.tablayout.custom;
+
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.annotation.Nullable;
+import android.support.design.widget.TabLayout;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.AppCompatActivity;
+
+import com.lvfq.library.utils.LvV;
+import com.lvfq.myworkingtest.R;
+import com.lvfq.code.tablayout.TabFragment;
+
+/**
+ * TabActivity1
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/4 下午7:02
+ * @desc :
+ */
+
+public class TabActivity1 extends AppCompatActivity {
+
+ UnAnimTabLayout tabLayout;
+ private ViewPager viewPager;
+ private TabAdapter mAdapter;
+ private String[] titles = {"热点", "推荐", "标题党", "视频", "本地农业", "科技", "政治", "农业", "其他"};
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_tab1);
+ tabLayout = LvV.find(this, R.id.tab);
+ viewPager = LvV.find(this, R.id.viewPager);
+ mAdapter = new TabAdapter(getSupportFragmentManager());
+ viewPager.setAdapter(mAdapter);
+ tabLayout.setupWithViewPager(viewPager);
+ tabLayout.addOnTabSelectedListener(new TabSelectAdapter() {
+ @Override
+ public void onTabSelected(TabLayout.Tab tab) {
+// TabUtils.tabSelect(tabLayout, tab);
+ TabUtils.tabBoldCurrent(tabLayout, tab);
+// int tag = (int) tab.getTag();
+// LvToastUtil.showToast(TabActivity1.this, tag + "");
+
+ }
+ });
+ tabLayout.post(new Runnable() {
+ @Override
+ public void run() {
+ TabUtils.setIndicator(tabLayout, 10, 10);
+ }
+ });
+ }
+
+ class TabAdapter extends FragmentStatePagerAdapter {
+
+ public TabAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public int getCount() {
+ return titles.length;
+ }
+
+ @Override
+ public Fragment getItem(int pos) {
+ return TabFragment.getInstance(titles[pos]);
+ }
+
+ @Override
+ public void restoreState(Parcelable arg0, ClassLoader arg1) {
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return titles[position];
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/tablayout/custom/TabSelectAdapter.java b/app/src/main/java/com/lvfq/code/tablayout/custom/TabSelectAdapter.java
new file mode 100755
index 0000000..76bc4e6
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/tablayout/custom/TabSelectAdapter.java
@@ -0,0 +1,20 @@
+package com.lvfq.code.tablayout.custom;
+
+import android.support.design.widget.TabLayout;
+
+public class TabSelectAdapter implements TabLayout.OnTabSelectedListener {
+ @Override
+ public void onTabSelected(TabLayout.Tab tab) {
+
+ }
+
+ @Override
+ public void onTabUnselected(TabLayout.Tab tab) {
+
+ }
+
+ @Override
+ public void onTabReselected(TabLayout.Tab tab) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lvfq/code/tablayout/custom/TabUtils.java b/app/src/main/java/com/lvfq/code/tablayout/custom/TabUtils.java
new file mode 100755
index 0000000..081ba9e
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/tablayout/custom/TabUtils.java
@@ -0,0 +1,174 @@
+package com.lvfq.code.tablayout.custom;
+
+import android.content.res.Resources;
+import android.graphics.Typeface;
+import android.support.design.widget.TabLayout;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.lang.reflect.Field;
+
+/**
+ * 修改Tablayout tab的字体和shadow
+ * created by qibin
+ */
+public class TabUtils {
+
+ public static void boldTab(TabLayout.Tab tab) {
+ setTabStyle(tab, Typeface.DEFAULT_BOLD, 0, 0, 0, 0);
+ }
+
+ /**
+ * 选中某条, 改变样式
+ *
+ * @param tabLayout
+ * @param currentTab
+ */
+ public static void tabSelect(TabLayout tabLayout, TabLayout.Tab currentTab) {
+ int tabCount = tabLayout.getTabCount();
+ TabLayout.Tab tab;
+ for (int i = 0; i < tabCount; i++) {
+ tab = tabLayout.getTabAt(i);
+ setTabStyle(tab, Typeface.DEFAULT, 0, 0, 0, 0x00000000);
+ }
+
+ setTabStyle(currentTab, Typeface.DEFAULT_BOLD, 1, 2, 2, 0x55000000);
+ }
+
+ public static void tabSelectAt(TabLayout tabLayout, TabLayout.Tab currentTab, int position) {
+ int tabCount = tabLayout.getTabCount();
+ TabLayout.Tab tab;
+ for (int i = 0; i < tabCount; i++) {
+ tab = tabLayout.getTabAt(i);
+ if (i != position) {
+ setTabStyle(tab, Typeface.DEFAULT, 0, 0, 0, 0x00000000);
+ } else {
+ setTabStyle(currentTab, Typeface.DEFAULT_BOLD, 1, 2, 2, 0x55000000);
+ }
+ }
+ }
+
+ /**
+ * 通过反射去设置样式
+ *
+ * @param tab
+ * @param tf
+ * @param radius
+ * @param dx
+ * @param dy
+ * @param color
+ */
+ public static void setTabStyle(TabLayout.Tab tab, Typeface tf, int radius, float dx, float dy, int color) {
+ TextView tv = getTextView(tab);
+ if (tv == null) {
+ return;
+ }
+ //TODO 暂时不做阴影效果
+// tv.setTextSize(18);
+ tv.setTypeface(tf);
+ tv.setShadowLayer(radius, dx, dy, color);
+ }
+
+ private static TextView getTextView(TabLayout.Tab tab) {
+ try {
+ Field mView = tab.getClass().getDeclaredField("mView");
+ mView.setAccessible(true);
+ Object mViewObj = mView.get(tab);
+ Field mTextView = mViewObj.getClass().getDeclaredField("mTextView");
+ mTextView.setAccessible(true);
+ return (TextView) mTextView.get(mViewObj);
+ } catch (Exception e) {
+
+ }
+
+ return null;
+ }
+
+ /**
+ * 通过反射去设置下划线样式bufen
+ *
+ * @param tab
+ * @param leftDip
+ * @param rightDip
+ */
+ public static void setIndicator(TabLayout tab, int leftDip, int rightDip) {
+ try {
+ Field tabStrip = TabLayout.class.getDeclaredField("mTabStrip");
+ tabStrip.setAccessible(true);
+ LinearLayout llTab = (LinearLayout) tabStrip.get(tab);
+ int left = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, leftDip, Resources.getSystem().getDisplayMetrics());
+ int right = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rightDip, Resources.getSystem().getDisplayMetrics());
+
+ for (int i = 0; i < llTab.getChildCount(); i++) {
+ View child = llTab.getChildAt(i);
+ child.setPadding(0, 0, 0, 0);
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
+ params.leftMargin = left;
+ params.rightMargin = right;
+ child.setLayoutParams(params);
+ child.invalidate();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 加粗current
+ *
+ * @param tabLayout
+ * @param currentTab
+ */
+ public static void tabBoldCurrent(TabLayout tabLayout, TabLayout.Tab currentTab) {
+ int tabCount = tabLayout.getTabCount();
+ TabLayout.Tab tab;
+ for (int i = 0; i < tabCount; i++) {
+ tab = tabLayout.getTabAt(i);
+ TextView tv = getTextView(tab);
+ if (tv == null) {
+ continue;
+ }
+ tv.setTypeface(Typeface.DEFAULT);
+ }
+
+ TextView tv = getTextView(currentTab);
+ if (tv == null) {
+ return;
+ }
+ tv.setTypeface(Typeface.DEFAULT_BOLD);
+ }
+
+
+ public static void enableTabs(TabLayout tabLayout, Boolean enable) {
+ ViewGroup viewGroup = getTabViewGroup(tabLayout);
+ if (viewGroup != null)
+ for (int childIndex = 0; childIndex < viewGroup.getChildCount(); childIndex++) {
+ View tabView = viewGroup.getChildAt(childIndex);
+ if (tabView != null)
+ tabView.setEnabled(enable);
+ }
+ }
+
+ public static View getTabView(TabLayout tabLayout, int position) {
+ View tabView = null;
+ ViewGroup viewGroup = getTabViewGroup(tabLayout);
+ if (viewGroup != null && viewGroup.getChildCount() > position)
+ tabView = viewGroup.getChildAt(position);
+
+ return tabView;
+ }
+
+ private static ViewGroup getTabViewGroup(TabLayout tabLayout) {
+ ViewGroup viewGroup = null;
+
+ if (tabLayout != null && tabLayout.getChildCount() > 0) {
+ View view = tabLayout.getChildAt(0);
+ if (view != null && view instanceof ViewGroup)
+ viewGroup = (ViewGroup) view;
+ }
+ return viewGroup;
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/tablayout/custom/UnAnimTabLayout.java b/app/src/main/java/com/lvfq/code/tablayout/custom/UnAnimTabLayout.java
new file mode 100755
index 0000000..bdbcb6a
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/tablayout/custom/UnAnimTabLayout.java
@@ -0,0 +1,153 @@
+package com.lvfq.code.tablayout.custom;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.design.widget.TabLayout;
+import android.util.AttributeSet;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * 重写TabLayout关于mSelectedTab的方法,解决动画卡断问题
+ * 利用反射将mSelectedTab设置为null, 这样可以做到禁用动画
+ * 利用静态代理重写tabSelect事件,解决mSelectedTab置为null后重复点击某一item会多次回调的问题
+ */
+public class UnAnimTabLayout extends TabLayout {
+
+ private Tab mCurrentSelectedTab;
+
+ public UnAnimTabLayout(Context context) {
+ super(context);
+ }
+
+ public UnAnimTabLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public UnAnimTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public void removeAllTabs() {
+ mCurrentSelectedTab = null;
+ super.removeAllTabs();
+ }
+
+ public int getSelectedTabPosition() {
+ return mCurrentSelectedTab != null ? mCurrentSelectedTab.getPosition() : -1;
+ }
+
+ /**
+ * 重写父类的remove逻辑
+ * 具体实现方式: 1. 在调用真正remove之前将mSelectedTab设置为自己保存的mCurrentSelectedTab
+ * 2. 调用父类的removeTabAt()方法
+ * 3. 将父类的mSelectedTab置为null
+ * @param position
+ */
+ public void removeTabAt(int position) {
+ Field mSelectedTab = null;
+ try {
+ mSelectedTab = getClass().getSuperclass().getDeclaredField("mSelectedTab");
+ mSelectedTab.setAccessible(true);
+ mSelectedTab.set(this, mCurrentSelectedTab);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ super.removeTabAt(position);
+
+ if (mSelectedTab != null && mSelectedTab.isAccessible()) {
+ try {
+ mSelectedTab.set(this, null);
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void addOnTabSelectedListener(@NonNull OnTabSelectedListener listener) {
+ super.addOnTabSelectedListener(new TabSelectedListenerProxy(listener));
+ }
+
+ // proxy for tab event listener
+ class TabSelectedListenerProxy implements OnTabSelectedListener {
+
+ private OnTabSelectedListener mListener;
+ TabSelectedListenerProxy(OnTabSelectedListener li) {
+ mListener = li;
+ }
+
+ @Override
+ public void onTabSelected(Tab tab) {
+ final Tab currentTab = mCurrentSelectedTab;
+
+ try {
+ Field mSelectedTab = UnAnimTabLayout.class.getSuperclass().getDeclaredField("mSelectedTab");
+ mSelectedTab.setAccessible(true);
+ mSelectedTab.set(UnAnimTabLayout.this, null);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ if (currentTab == tab) {
+ if (currentTab != null) {
+ try {
+ Method dispatchTabUnselected = UnAnimTabLayout.class.getSuperclass()
+ .getDeclaredMethod("dispatchTabReselected", Tab.class);
+ dispatchTabUnselected.setAccessible(true);
+ dispatchTabUnselected.invoke(UnAnimTabLayout.this, tab);
+
+ final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
+ Method setScrollPosition = UnAnimTabLayout.class.getSuperclass()
+ .getDeclaredMethod("setScrollPosition", int.class, float.class, boolean.class);
+ setScrollPosition.setAccessible(true);
+ setScrollPosition.invoke(UnAnimTabLayout.this, newPosition, 0f, true);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ if (currentTab != null && currentTab == tab) { return;}
+
+ if (currentTab != null) {
+ try {
+ Method dispatchTabUnselected = UnAnimTabLayout.class.getSuperclass()
+ .getDeclaredMethod("dispatchTabUnselected", Tab.class);
+ dispatchTabUnselected.setAccessible(true);
+ dispatchTabUnselected.invoke(UnAnimTabLayout.this, currentTab);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ mCurrentSelectedTab = tab;
+ mListener.onTabSelected(tab);
+ }
+
+ @Override
+ public void onTabUnselected(Tab tab) {
+ // 永远不会执行到~
+ }
+
+ @Override
+ public void onTabReselected(Tab tab) {
+ // 永远不会执行到~
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/util/FileUtils.java b/app/src/main/java/com/lvfq/code/util/FileUtils.java
new file mode 100644
index 0000000..4ba8e28
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/util/FileUtils.java
@@ -0,0 +1,381 @@
+package com.lvfq.code.util;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.media.ExifInterface;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.util.Date;
+
+public class FileUtils {
+
+ public static String mImageFileCachePath() {
+ String s = Environment.getExternalStorageDirectory() + File.separator + "Android" + File.separator
+ + "_test" + File.separator;
+ File file = new File(s);
+ if (!file.exists()) {
+ file.mkdirs();
+ }
+ return s;
+ }
+
+ /**
+ * 把图片压缩到200K
+ *
+ * @param oldpath
+ * 压缩前的图片路径
+ * @param newPath
+ * 压缩后的图片路径
+ * @return
+ */
+ /**
+ * 把图片压缩到200K
+ *
+ * @param oldpath 压缩前的图片路径
+ * @param newPath 压缩后的图片路径
+ * @return
+ */
+ public static File compressFile(String oldpath, String newPath) {
+ Bitmap compressBitmap = FileUtils.decodeFile(oldpath);
+ Bitmap newBitmap = ratingImage(oldpath, compressBitmap);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ newBitmap.compress(CompressFormat.PNG, 100, os);
+ byte[] bytes = os.toByteArray();
+
+ File file = null;
+ try {
+ file = FileUtils.getFileFromBytes(bytes, newPath);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (newBitmap != null) {
+ if (!newBitmap.isRecycled()) {
+ newBitmap.recycle();
+ }
+ newBitmap = null;
+ }
+ if (compressBitmap != null) {
+ if (!compressBitmap.isRecycled()) {
+ compressBitmap.recycle();
+ }
+ compressBitmap = null;
+ }
+ }
+ return file;
+ }
+
+ public static Bitmap ratingImage(String filePath, Bitmap bitmap) {
+ int degree = readPictureDegree(filePath);
+ return rotaingImageView(degree, bitmap);
+ }
+
+ /**
+ * 旋转图片
+ *
+ * @param angle
+ * @param bitmap
+ * @return Bitmap
+ */
+ public static Bitmap rotaingImageView(int angle, Bitmap bitmap) {
+ // 旋转图片 动作
+ Matrix matrix = new Matrix();
+ matrix.postRotate(angle);
+ System.out.println("angle2=" + angle);
+ // 创建新的图片
+ Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
+ bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+ return resizedBitmap;
+ }
+
+ /**
+ * 读取图片属性:旋转的角度
+ *
+ * @param path 图片绝对路径
+ * @return degree旋转的角度
+ */
+ public static int readPictureDegree(String path) {
+ int degree = 0;
+ try {
+ ExifInterface exifInterface = new ExifInterface(path);
+ int orientation = exifInterface.getAttributeInt(
+ ExifInterface.TAG_ORIENTATION,
+ ExifInterface.ORIENTATION_NORMAL);
+ switch (orientation) {
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ degree = 90;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ degree = 180;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ degree = 270;
+ break;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return degree;
+ }
+
+ /**
+ * 把字节数组保存为一个文件
+ *
+ * @param b
+ * @param outputFile
+ * @return
+ */
+ public static File getFileFromBytes(byte[] b, String outputFile) {
+ File ret = null;
+ BufferedOutputStream stream = null;
+ try {
+ ret = new File(outputFile);
+ FileOutputStream fstream = new FileOutputStream(ret);
+ stream = new BufferedOutputStream(fstream);
+ stream.write(b);
+ } catch (Exception e) {
+ // log.error("helper:get file from byte process error!");
+ e.printStackTrace();
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // log.error("helper:get file from byte process error!");
+ e.printStackTrace();
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * 图片压缩
+ *
+ * @param fPath
+ * @return
+ */
+ public static Bitmap decodeFile(String fPath) {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inJustDecodeBounds = true;
+ opts.inDither = false; // Disable Dithering mode
+ opts.inPurgeable = true; // Tell to gc that whether it needs free
+ opts.inInputShareable = true; // Which kind of reference will be used to
+ BitmapFactory.decodeFile(fPath, opts);
+ final int REQUIRED_SIZE = 800;
+ int scale = 1;
+ if (opts.outHeight > REQUIRED_SIZE || opts.outWidth > REQUIRED_SIZE) {
+ final int heightRatio = Math.round((float) opts.outHeight
+ / (float) REQUIRED_SIZE);
+ final int widthRatio = Math.round((float) opts.outWidth
+ / (float) REQUIRED_SIZE);
+ scale = heightRatio < widthRatio ? heightRatio : widthRatio;//
+ }
+ opts.inJustDecodeBounds = false;
+ opts.inSampleSize = scale;
+ Bitmap bm = BitmapFactory.decodeFile(fPath, opts).copy(
+ Config.ARGB_8888, false);
+ return bm;
+ }
+
+ /**
+ * 创建目录
+ *
+ * @param path
+ */
+ public static void setMkdir(String path) {
+ File file = new File(path);
+ if (!file.exists()) {
+ file.mkdirs();
+ Log.e("file", "目录不存在 创建目录 ");
+ } else {
+ Log.e("file", "目录存在");
+ }
+ }
+
+ /**
+ * 获取目录名称
+ *
+ * @param url
+ * @return FileName
+ */
+ public static String getFileName(String url) {
+ int lastIndexStart = url.lastIndexOf("/");
+ if (lastIndexStart != -1) {
+ return url.substring(lastIndexStart + 1, url.length());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * 删除该目录下的文件
+ *
+ * @param path
+ */
+ public static void delFile(String path) {
+ if (!TextUtils.isEmpty(path)) {
+ File file = new File(path);
+ if (file.exists()) {
+
+ if (file.isDirectory()) {
+ if (file.listFiles() == null || file.listFiles().length <= 0) {
+ file.delete();
+ return;
+ }
+ for (File f : file.listFiles()) {
+ delFile(f.getAbsolutePath());
+ }
+ }
+ file.delete();
+ }
+ }
+ }
+
+
+ /**
+ * 图像压缩(质量,大小),
+ *
+ * @param fileUri
+ * @return
+ */
+ public static File scal(Uri fileUri) {
+ String path = fileUri.getPath();
+ File outputFile = new File(path);
+ long fileSize = outputFile.length();
+ final long fileMaxSize = 200 * 1024;
+ if (fileSize >= fileMaxSize) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeFile(path, options);
+ int height = options.outHeight;
+ int width = options.outWidth;
+
+ double scale = Math.sqrt((float) fileSize / fileMaxSize);
+ options.outHeight = (int) (height / scale);
+ options.outWidth = (int) (width / scale);
+ options.inSampleSize = (int) (scale + 0.8);
+ options.inJustDecodeBounds = false;
+
+ Bitmap bitmap = BitmapFactory.decodeFile(path, options);
+ String myPahth = createImageFile().getPath();
+ outputFile = new File(myPahth);
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(outputFile);
+ bitmap.compress(CompressFormat.JPEG, 100, fos);
+ fos.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ if (!bitmap.isRecycled()) {
+ bitmap.recycle();
+ } else {
+ File tempFile = outputFile;
+ outputFile = new File(createImageFile().getPath());
+ copyFileUsingFileChannels(tempFile, outputFile);
+ }
+
+ }
+ return outputFile;
+
+ }
+
+ private static String getOutputImageUri() {
+ return new Date().getTime() + ".png";
+ }
+
+ public static Uri createImageFile() {
+ return Uri.parse(mImageFileCachePath() + getOutputImageUri());
+ // Create an image file name
+// String imageFileName = System.currentTimeMillis() + "";
+// File storageDir = Environment.getExternalStoragePublicDirectory(
+// Environment.DIRECTORY_PICTURES);
+// File image = null;
+// try {
+// image = File.createTempFile(imageFileName, ".jpg", storageDir);
+//// image = File.createTempFile(
+//// imageFileName, /* prefix */
+//// .jpg, /* suffix */
+//// storageDir /* directory */
+//// );
+// } catch (IOException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+// }
+//
+// // Save a file: path for use with ACTION_VIEW intents
+// return Uri.fromFile(image);
+ }
+
+ public static void copyFileUsingFileChannels(File source, File dest) {
+ FileChannel inputChannel = null;
+ FileChannel outputChannel = null;
+ try {
+ try {
+ inputChannel = new FileInputStream(source).getChannel();
+ outputChannel = new FileOutputStream(dest).getChannel();
+ outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ } finally {
+ try {
+ inputChannel.close();
+ outputChannel.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * 绝对路径转成相对路径
+ *
+ * @param context
+ * @param uri
+ * @return
+ */
+
+ public static String getRealFilePath(final Context context, final Uri uri) {
+ if (null == uri) return null;
+ final String scheme = uri.getScheme();
+ String data = null;
+ if (scheme == null)
+ data = uri.getPath();
+ else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
+ data = uri.getPath();
+ } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
+ Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
+ if (null != cursor) {
+ if (cursor.moveToFirst()) {
+ int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
+ if (index > -1) {
+ data = cursor.getString(index);
+ }
+ }
+ cursor.close();
+ }
+ }
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lvfq/code/util/Glide4_ImageLoadUtil.java b/app/src/main/java/com/lvfq/code/util/Glide4_ImageLoadUtil.java
new file mode 100644
index 0000000..0619f9f
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/util/Glide4_ImageLoadUtil.java
@@ -0,0 +1,225 @@
+package com.lvfq.code.util;
+
+import android.content.Context;
+import android.widget.ImageView;
+
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
+import com.bumptech.glide.request.RequestOptions;
+
+/**
+ * ImageLoadUtil
+ *
+ * @author lvfq
+ * @date 2017/7/19 下午9:30
+ * @mainFunction :
+ */
+
+public class Glide4_ImageLoadUtil {
+
+ private static final int RADIUS = 4;
+
+ /**
+ * 初始化 Options 参数
+ *
+ * @param resourceId
+ * @param errorResourceId
+ * @return
+ */
+ private static RequestOptions initOptions(int resourceId, int errorResourceId) {
+ RequestOptions options = new RequestOptions()
+ .centerCrop()
+ .placeholder(resourceId)
+ .error(errorResourceId == 0 ? resourceId : errorResourceId)
+ .diskCacheStrategy(DiskCacheStrategy.ALL);
+ return options;
+ }
+
+ /**
+ * 调用 Glide 加载
+ *
+ * @param context
+ * @param options
+ * @param url
+ * @param imageView
+ */
+ private static void glideApply(Context context, RequestOptions options, Object url, ImageView imageView) {
+ GlideApp.with(context)
+ .applyDefaultRequestOptions(options)
+ .load(url)
+ .into(imageView);
+ }
+
+ /************* 默认加载方式 ****************/
+ /**
+ * 默认加载图片
+ *
+ * @param context
+ * @param url
+ * @param resourceId
+ * @param imageView
+ */
+ public static void loadImg(Context context, Object url, int resourceId, ImageView imageView) {
+ loadImg(context, url, resourceId, 0, imageView);
+ }
+
+ /**
+ * 默认加载图片
+ *
+ * @param context
+ * @param url
+ * @param resourceId
+ * @param imageView
+ */
+ public static void loadImg(Context context, Object url, int resourceId, int errorResourceId, ImageView imageView) {
+ RequestOptions options = initOptions(resourceId, errorResourceId);
+ glideApply(context, options, url, imageView);
+ }
+
+ /************* 加载圆形图 ****************/
+ /**
+ * 加载圆形图片
+ *
+ * @param context
+ * @param url
+ * @param resourceId
+ * @param imageView
+ */
+ public static void loadCircleImg(Context context, Object url, int resourceId, ImageView imageView) {
+ loadCircleImg(context, url, resourceId, 0, imageView);
+ }
+
+ /**
+ * 加载圆形图片
+ *
+ * @param context
+ * @param url
+ * @param resourceId
+ * @param errorResourceId 给 0 默认显示 resouceId
+ * @param imageView
+ */
+ public static void loadCircleImg(Context context, Object url, int resourceId, int errorResourceId, ImageView imageView) {
+ RequestOptions options = initOptions(resourceId, errorResourceId)
+ .circleCrop();
+
+ glideApply(context, options, url, imageView);
+ }
+
+ /************* 加载圆角图片 方式 1 ****************/
+
+
+ /**
+ * 加载圆角
+ *
+ * @param context
+ * @param url
+ * @param resourceId 占位图
+ * @param errorResourceId 加载失败图
+ * @param imageView
+ * @param dp
+ */
+ public static void loadRoundImg(Context context, Object url, int resourceId, int errorResourceId, ImageView imageView, int dp) {
+ RequestOptions options = initOptions(resourceId, errorResourceId)
+ .transform(new RoundedCorners(dp));
+
+ glideApply(context, options, url, imageView);
+ }
+
+ /**
+ * 加载圆角
+ *
+ * @param context
+ * @param url
+ * @param resourceId 占位图(也是加载失败图)
+ * @param imageView
+ * @param dp
+ */
+ public static void loadRoundImg(Context context, Object url, int resourceId, ImageView imageView, int dp) {
+ RequestOptions options = initOptions(resourceId, 0)
+ .transform(new RoundedCorners(dp));
+
+ glideApply(context, options, url, imageView);
+ }
+
+ /**
+ * 加载圆角,默认圆角值为 4
+ *
+ * @param context
+ * @param url
+ * @param resourceId 占位图(也是加载失败图)
+ * @param imageView
+ */
+ public static void loadRoundImg(Context context, Object url, int resourceId, ImageView imageView) {
+ RequestOptions options = initOptions(resourceId, 0);
+// .transform(new RoundedCorners(RADIUS)).transform(new CenterCrop());
+
+// Glide.with(context)
+// .applyDefaultRequestOptions(options)
+// .load(url)
+// .into(imageView);
+ glideApply(context, options, url, imageView);
+ }
+
+
+ /************* 加载圆角图片 方式 2 ****************/
+
+ /**
+ * 加载圆角图片
+ *
+ * @param context
+ * @param url
+ * @param resourceId 占位图
+ * @param errorResourceId 加载失败图
+ * @param imageView
+ * @param dp
+ * @param type
+ */
+// public static void loadRoundImgCorner(Context context, Object url, int resourceId, int errorResourceId, ImageView imageView, int dp, RoundedCornersTransformation.CornerType type) {
+// RequestOptions options = initOptions(resourceId, errorResourceId)
+// .transform(new RoundedCornersTransformation(context, dp, 0, type));
+//
+// glideApply(context, options, url, imageView);
+// }
+
+ /**
+ * 加载圆角图片 默认圆角值为 4
+ *
+ * @param context
+ * @param url
+ * @param resourceId 占位图
+ * @param errorResourceId 加载失败图
+ * @param imageView
+ */
+// public static void loadRoundImgCorner(Context context, Object url, int resourceId, int errorResourceId, ImageView imageView) {
+// loadRoundImgCorner(context, url, resourceId, errorResourceId, imageView, RADIUS, RoundedCornersTransformation.CornerType.ALL);
+// }
+
+ /**
+ * 加载圆角图片
+ *
+ * @param context
+ * @param url
+ * @param resourceId 占位图(也是加载失败图)
+ * @param imageView
+ * @param dp
+ */
+// public static void loadRoundImgCorner(Context context, Object url, int resourceId, ImageView imageView, int dp) {
+// loadRoundImgCorner(context, url, resourceId, 0, imageView, dp, RoundedCornersTransformation.CornerType.ALL);
+// }
+
+ /**
+ * 加载圆角图片
+ *
+ * @param context
+ * @param url
+ * @param resourceId 占位图
+ * @param errorResourceId 加载失败图
+ * @param imageView
+ * @param dp
+ */
+// public static void loadRoundImgCorner(Context context, Object url, int resourceId, int errorResourceId, ImageView imageView, int dp) {
+// loadRoundImgCorner(context, url, resourceId, errorResourceId, imageView, dp, RoundedCornersTransformation.CornerType.ALL);
+// }
+
+
+}
diff --git a/app/src/main/java/com/lvfq/code/util/ImageUtils.java b/app/src/main/java/com/lvfq/code/util/ImageUtils.java
new file mode 100644
index 0000000..f66e1d1
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/util/ImageUtils.java
@@ -0,0 +1,43 @@
+package com.lvfq.code.util;
+
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * ImageUtils
+ *
+ * @author lvfq
+ * @date 2017/4/19 下午2:35
+ * @mainFunction :
+ */
+
+public class ImageUtils {
+ /**
+ * 把图片村保存在相应的文件当中
+ *
+ * @param pBitmap
+ * @param fileName
+ */
+ public static void saveFile(Bitmap pBitmap, String fileName) {
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(fileName);
+ pBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
+ fos.flush();
+ Log.i("jiangqq", "保存图片到sdcard卡成功.");
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/lvfq/code/util/MyAppGlideModule.java b/app/src/main/java/com/lvfq/code/util/MyAppGlideModule.java
new file mode 100644
index 0000000..ca63b55
--- /dev/null
+++ b/app/src/main/java/com/lvfq/code/util/MyAppGlideModule.java
@@ -0,0 +1,17 @@
+package com.lvfq.code.util;
+
+import com.bumptech.glide.annotation.GlideModule;
+import com.bumptech.glide.module.AppGlideModule;
+
+/**
+ * MyAppGlideModule
+ *
+ * @author lvfq
+ * @Github: https://github.com/lvfaqiang
+ * @Blog: http://blog.csdn.net/lv_fq
+ * @date 2017/9/3 下午1:26
+ * @desc :
+ */
+
+@GlideModule
+public final class MyAppGlideModule extends AppGlideModule {}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/shape_tab_green.xml b/app/src/main/res/drawable/shape_tab_green.xml
new file mode 100755
index 0000000..79e38ee
--- /dev/null
+++ b/app/src/main/res/drawable/shape_tab_green.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/tab_selector_green.xml b/app/src/main/res/drawable/tab_selector_green.xml
new file mode 100755
index 0000000..4c19a28
--- /dev/null
+++ b/app/src/main/res/drawable/tab_selector_green.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_comments.xml b/app/src/main/res/layout/activity_comments.xml
new file mode 100644
index 0000000..b535665
--- /dev/null
+++ b/app/src/main/res/layout/activity_comments.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_dynamic_image.xml b/app/src/main/res/layout/activity_dynamic_image.xml
new file mode 100644
index 0000000..9a82664
--- /dev/null
+++ b/app/src/main/res/layout/activity_dynamic_image.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_glide.xml b/app/src/main/res/layout/activity_glide.xml
new file mode 100644
index 0000000..f5b596d
--- /dev/null
+++ b/app/src/main/res/layout/activity_glide.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_img_water_mark.xml b/app/src/main/res/layout/activity_img_water_mark.xml
new file mode 100644
index 0000000..f622e34
--- /dev/null
+++ b/app/src/main/res/layout/activity_img_water_mark.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 0000000..c35f843
--- /dev/null
+++ b/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..417cc22
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_tab.xml b/app/src/main/res/layout/activity_tab.xml
new file mode 100644
index 0000000..a3ae1d5
--- /dev/null
+++ b/app/src/main/res/layout/activity_tab.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_tab1.xml b/app/src/main/res/layout/activity_tab1.xml
new file mode 100644
index 0000000..85ec184
--- /dev/null
+++ b/app/src/main/res/layout/activity_tab1.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_dynamic_image.xml b/app/src/main/res/layout/item_dynamic_image.xml
new file mode 100644
index 0000000..3def17c
--- /dev/null
+++ b/app/src/main/res/layout/item_dynamic_image.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..cde69bcccec65160d92116f20ffce4fce0b5245c
GIT binary patch
literal 3418
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
literal 0
HcmV?d00001
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..bfa42f0e7b91d006d22352c9ff2f134e504e3c1d
GIT binary patch
literal 4842
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
literal 0
HcmV?d00001
diff --git a/app/src/main/res/mipmap-xhdpi/img_default.png b/app/src/main/res/mipmap-xhdpi/img_default.png
new file mode 100644
index 0000000000000000000000000000000000000000..d045b3feedc79846cfd8dab03507a43c93836c9c
GIT binary patch
literal 17975
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
literal 0
HcmV?d00001
diff --git a/app/src/main/res/mipmap-xhdpi/img_like_icon.png b/app/src/main/res/mipmap-xhdpi/img_like_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..90ec85d44fe0cfd3a4ec19ed8c1f9d3cea401b4b
GIT binary patch
literal 1722
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
literal 0
HcmV?d00001
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..aee44e138434630332d88b1680f33c4b24c70ab3
GIT binary patch
literal 10486
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
+
+ 64dp
+
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
new file mode 100755
index 0000000..da187e2
--- /dev/null
+++ b/app/src/main/res/values/attrs.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..d52f7d5
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,8 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+ #fff
+ #00ce9b
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..47c8224
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,5 @@
+
+
+ 16dp
+ 16dp
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..6095883
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ MyWorkingTest
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..81d4153
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/test/java/com/lvfq/myworkingtest/ExampleUnitTest.java b/app/src/test/java/com/lvfq/myworkingtest/ExampleUnitTest.java
new file mode 100644
index 0000000..97348ea
--- /dev/null
+++ b/app/src/test/java/com/lvfq/myworkingtest/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.lvfq.myworkingtest;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..6fc6672
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.3'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ mavenCentral()
+ maven { url 'https://jitpack.io' }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..13372aef5e24af05341d49695ee84e5f9b594659
GIT binary patch
literal 53636
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