diff --git a/android_common/.gitignore b/android_common/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/android_common/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/android_common/build.gradle b/android_common/build.gradle
new file mode 100644
index 0000000..df9bc04
--- /dev/null
+++ b/android_common/build.gradle
@@ -0,0 +1,31 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+
+ defaultConfig {
+ minSdkVersion 21
+ targetSdkVersion 25
+ 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(dir: 'libs', include: ['*.jar'])
+ 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.3.1'
+ testCompile 'junit:junit:4.12'
+}
diff --git a/android_common/proguard-rules.pro b/android_common/proguard-rules.pro
new file mode 100644
index 0000000..9fe7e2e
--- /dev/null
+++ b/android_common/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in D:\Develop\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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/android_common/src/androidTest/java/com/pinger/common/ExampleInstrumentedTest.java b/android_common/src/androidTest/java/com/pinger/common/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..0cbc788
--- /dev/null
+++ b/android_common/src/androidTest/java/com/pinger/common/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.pinger.common;
+
+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.pinger.common.test", appContext.getPackageName());
+ }
+}
diff --git a/android_common/src/main/AndroidManifest.xml b/android_common/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..3df1894
--- /dev/null
+++ b/android_common/src/main/AndroidManifest.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/android_common/src/main/java/com/pinger/common/app/BaseApplication.java b/android_common/src/main/java/com/pinger/common/app/BaseApplication.java
new file mode 100644
index 0000000..b9594e1
--- /dev/null
+++ b/android_common/src/main/java/com/pinger/common/app/BaseApplication.java
@@ -0,0 +1,18 @@
+package com.pinger.common.app;
+
+import android.app.Application;
+
+import com.pinger.common.utils.UiUtil;
+
+/**
+ * @author Pinger
+ * @since 2017年5月5日 0005 下午 5:37
+ */
+public class BaseApplication extends Application {
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ UiUtil.init(getApplicationContext());
+ }
+}
diff --git a/android_common/src/main/java/com/pinger/common/utils/UiUtil.java b/android_common/src/main/java/com/pinger/common/utils/UiUtil.java
new file mode 100644
index 0000000..17f6782
--- /dev/null
+++ b/android_common/src/main/java/com/pinger/common/utils/UiUtil.java
@@ -0,0 +1,24 @@
+package com.pinger.common.utils;
+
+import android.content.Context;
+
+/**
+ * @author Pinger
+ * @since 2017年4月7日 0007 下午 2:15
+ * 与Ui相关的操作都放在这里,并且封装全局唯一的Context
+ */
+public class UiUtil {
+
+ private static Context mContext;
+
+ public static void init(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * 返回一个全局唯一的Context
+ */
+ public synchronized static Context getContext() {
+ return mContext;
+ }
+}
diff --git a/android_common/src/main/res/values/strings.xml b/android_common/src/main/res/values/strings.xml
new file mode 100644
index 0000000..973f4ee
--- /dev/null
+++ b/android_common/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ android_common
+
diff --git a/android_common/src/test/java/com/pinger/common/ExampleUnitTest.java b/android_common/src/test/java/com/pinger/common/ExampleUnitTest.java
new file mode 100644
index 0000000..8b4c42a
--- /dev/null
+++ b/android_common/src/test/java/com/pinger/common/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.pinger.common;
+
+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/android_transition/build.gradle b/android_transition/build.gradle
index 026a78d..c21e82c 100644
--- a/android_transition/build.gradle
+++ b/android_transition/build.gradle
@@ -20,6 +20,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+
+ dataBinding {
+ enabled = true
+ }
}
dependencies {
@@ -30,4 +34,5 @@ dependencies {
compile 'com.android.support:appcompat-v7:25.1.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7'
testCompile 'junit:junit:4.12'
+ compile 'com.android.support:recyclerview-v7:25.1.1'
}
diff --git a/android_transition/src/main/AndroidManifest.xml b/android_transition/src/main/AndroidManifest.xml
index 4584499..549ab5d 100644
--- a/android_transition/src/main/AndroidManifest.xml
+++ b/android_transition/src/main/AndroidManifest.xml
@@ -8,7 +8,7 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:theme="@style/AppTheme">
+ android:theme="@style/MaterialAnimations">
@@ -16,8 +16,31 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/java/com/pinger/transition/AnimationsActivity1.java b/android_transition/src/main/java/com/pinger/transition/AnimationsActivity1.java
new file mode 100644
index 0000000..f62fdf9
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/AnimationsActivity1.java
@@ -0,0 +1,99 @@
+package com.pinger.transition;
+
+import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.transition.Fade;
+import android.transition.TransitionManager;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+import com.pinger.transition.databinding.ActivityAnimations1Binding;
+
+
+public class AnimationsActivity1 extends BaseDetailActivity {
+ private ImageView square;
+ private ViewGroup viewRoot;
+ private boolean sizeChanged;
+ private int savedWidth;
+ private boolean positionChanged;
+ private Sample sample;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ bindData();
+ setupWindowAnimations();
+ setupLayout();
+ setupToolbar();
+ }
+
+ private void setupWindowAnimations() {
+ getWindow().setReenterTransition(new Fade());
+ }
+
+ private void bindData() {
+ ActivityAnimations1Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_animations1);
+ sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE);
+ binding.setAnimationsSample(sample);
+ }
+
+ private void setupLayout() {
+ square = (ImageView) findViewById(R.id.square_green);
+ viewRoot = (ViewGroup) findViewById(R.id.sample3_root);
+ findViewById(R.id.sample3_button1).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ changeLayout();
+ }
+ });
+ findViewById(R.id.sample3_button2).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ changePosition();
+ }
+ });
+
+ findViewById(R.id.sample3_button3).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent i = new Intent(AnimationsActivity1.this, AnimationsActivity2.class);
+ i.putExtra(EXTRA_SAMPLE, sample);
+ transitionTo(i);
+ }
+ });
+ }
+
+ private void changeLayout() {
+ TransitionManager.beginDelayedTransition(viewRoot);
+
+ ViewGroup.LayoutParams params = square.getLayoutParams();
+ if (sizeChanged) {
+ params.width = savedWidth;
+ } else {
+ savedWidth = params.width;
+ params.width = 200;
+ }
+ sizeChanged = !sizeChanged;
+ square.setLayoutParams(params);
+ }
+
+ private void changePosition() {
+ TransitionManager.beginDelayedTransition(viewRoot);
+
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) square.getLayoutParams();
+ if (positionChanged) {
+ lp.gravity = Gravity.CENTER;
+ } else {
+ lp.gravity = Gravity.LEFT;
+ }
+ positionChanged = !positionChanged;
+ square.setLayoutParams(lp);
+ }
+
+
+
+}
diff --git a/android_transition/src/main/java/com/pinger/transition/AnimationsActivity2.java b/android_transition/src/main/java/com/pinger/transition/AnimationsActivity2.java
new file mode 100644
index 0000000..07edd09
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/AnimationsActivity2.java
@@ -0,0 +1,146 @@
+package com.pinger.transition;
+
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.view.View;
+import android.view.ViewGroup;
+
+
+import com.pinger.transition.databinding.ActivityAnimations2Binding;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AnimationsActivity2 extends BaseDetailActivity {
+
+ private static final int DELAY = 100;
+ private Scene scene0;
+ private Scene scene1;
+ private Scene scene2;
+ private Scene scene3;
+ private Scene scene4;
+ private final List viewsToAnimate = new ArrayList();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ bindData();
+ setupLayout();
+ setupToolbar();
+ setupWindowAnimations();
+ }
+
+ private void bindData() {
+ ActivityAnimations2Binding binding = DataBindingUtil.setContentView(
+ this, R.layout.activity_animations2);
+ Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE);
+ binding.setAnimationsSample(sample);
+ }
+
+ private void setupWindowAnimations() {
+ getWindow().setEnterTransition(TransitionInflater.from(this).inflateTransition(
+ R.transition.slide_from_bottom));
+ getWindow().getEnterTransition().addListener(new Transition.TransitionListener() {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ getWindow().getEnterTransition().removeListener(this);
+ TransitionManager.go(scene0);
+ }
+ });
+ }
+
+ private void setupLayout() {
+ final ViewGroup activityRoot = (ViewGroup) findViewById(R.id.buttons_group);
+ ViewGroup sceneRoot = (ViewGroup) findViewById(R.id.scene_root);
+
+ scene0 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene0, this);
+ scene0.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ for (int i = 0; i < viewsToAnimate.size(); i++) { + View child = viewsToAnimate.get(i); + child.animate() + .setStartDelay(i * DELAY) + .scaleX(1) + .scaleY(1); + + } + } + }); + scene0.setExitAction(new Runnable() { + @Override + public void run() { + TransitionManager.beginDelayedTransition(activityRoot); + View title = scene0.getSceneRoot().findViewById(R.id.scene0_title); + title.setScaleX(0); + title.setScaleY(0); + } + }); + + + scene1 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene1, this); + scene2 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene2, this); + scene3 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene3, this); + scene4 = Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene4, this); + + View button1 = findViewById(R.id.sample3_button1); + button1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + TransitionManager.go(scene1, new ChangeBounds()); + } + }); + View button2 = findViewById(R.id.sample3_button2); + button2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + TransitionManager.go(scene2, TransitionInflater.from(AnimationsActivity2.this). + inflateTransition(R.transition.slide_and_changebounds)); + } + }); + + View button3 = findViewById(R.id.sample3_button3); + button3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + TransitionManager.go(scene3, TransitionInflater.from(AnimationsActivity2.this). + inflateTransition(R.transition.slide_and_changebounds_sequential)); + } + }); + + View button4 = findViewById(R.id.sample3_button4); + button4.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + TransitionManager.go(scene4, TransitionInflater.from(AnimationsActivity2.this). + inflateTransition(R.transition.slide_and_changebounds_sequential_with_interpolators)); + } + }); + + viewsToAnimate.add(button1); + viewsToAnimate.add(button2); + viewsToAnimate.add(button3); + viewsToAnimate.add(button4); + } +} diff --git a/android_transition/src/main/java/com/pinger/transition/BaseDetailActivity.java b/android_transition/src/main/java/com/pinger/transition/BaseDetailActivity.java new file mode 100644 index 0000000..db45d4b --- /dev/null +++ b/android_transition/src/main/java/com/pinger/transition/BaseDetailActivity.java @@ -0,0 +1,37 @@ +package com.pinger.transition; + +import android.content.Intent; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.util.Pair; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.View; + +/** + * Created by lgvalle on 12/09/15. + */ +public class BaseDetailActivity extends AppCompatActivity { + static final String EXTRA_SAMPLE = "sample"; + static final String EXTRA_TYPE = "type"; + static final int TYPE_PROGRAMMATICALLY = 0; + static final int TYPE_XML = 1; + + void setupToolbar() { + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowTitleEnabled(false); + } + + @Override + public boolean onSupportNavigateUp() { + onBackPressed(); + return true; + } + + @SuppressWarnings("unchecked") void transitionTo(Intent i) { + final Pair[] pairs = TransitionHelper.createSafeTransitionParticipants(this, true);
+ ActivityOptionsCompat transitionActivityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(this, pairs);
+ startActivity(i, transitionActivityOptions.toBundle());
+ }
+}
diff --git a/android_transition/src/main/java/com/pinger/transition/MainActivity.java b/android_transition/src/main/java/com/pinger/transition/MainActivity.java
index 1bd27d8..d6d357d 100644
--- a/android_transition/src/main/java/com/pinger/transition/MainActivity.java
+++ b/android_transition/src/main/java/com/pinger/transition/MainActivity.java
@@ -1,36 +1,59 @@
package com.pinger.transition;
-import android.content.Intent;
import android.os.Bundle;
-import android.support.v4.app.ActivityOptionsCompat;
-import android.support.v4.util.Pair;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.widget.ImageView;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.Toolbar;
+import android.transition.Slide;
+import android.view.Gravity;
-public class MainActivity extends AppCompatActivity {
+import java.util.Arrays;
+import java.util.List;
- private ImageView mImageView1;
- private ImageView mImageView2;
+public class MainActivity extends AppCompatActivity {
+ private List samples;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- mImageView1 = (ImageView) findViewById(R.id.image1);
- mImageView2 = (ImageView) findViewById(R.id.image2);
+ setupWindowAnimations();
+ setupSamples();
+ setupToolbar();
+ setupLayout();
}
- public void start(View view) {
- // 单个动画跳转
- //startActivity(new Intent(this,SecondActivity.class), ActivityOptionsCompat.makeSceneTransitionAnimation(this,mImageView1,"shareImage1").toBundle());
+ private void setupWindowAnimations() {
+ // Re-enter transition is executed when returning to this activity
+ Slide slideTransition = new Slide();
+ slideTransition.setSlideEdge(Gravity.LEFT);
+ slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
+ getWindow().setReenterTransition(slideTransition);
+ getWindow().setExitTransition(slideTransition);
+ }
+ private void setupSamples() {
+ samples = Arrays.asList(
+ new Sample(ContextCompat.getColor(this, R.color.sample_red), "Transitions"),
+ new Sample(ContextCompat.getColor(this, R.color.sample_blue), "Shared Elements"),
+ new Sample(ContextCompat.getColor(this, R.color.sample_green), "View animations"),
+ new Sample(ContextCompat.getColor(this, R.color.sample_yellow), "Circular Reveal Animation")
+ );
+ }
- // 多个动画跳转
- startActivity(new Intent(MainActivity.this, SecondActivity.class),
- ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this,
- Pair.create((View) mImageView1, "shareImage1"),
- Pair.create((View) mImageView2, "shareImage2")).toBundle());
+ private void setupToolbar() {
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayShowTitleEnabled(false);
+ }
+ private void setupLayout() {
+ RecyclerView recyclerView = (RecyclerView) findViewById(R.id.sample_list);
+ recyclerView.setHasFixedSize(true);
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+ SamplesRecyclerAdapter samplesRecyclerAdapter = new SamplesRecyclerAdapter(this, samples);
+ recyclerView.setAdapter(samplesRecyclerAdapter);
}
}
diff --git a/android_transition/src/main/java/com/pinger/transition/RevealActivity.java b/android_transition/src/main/java/com/pinger/transition/RevealActivity.java
new file mode 100644
index 0000000..a6c46de
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/RevealActivity.java
@@ -0,0 +1,291 @@
+package com.pinger.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.support.annotation.ColorRes;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.Toolbar;
+import android.transition.Fade;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.pinger.transition.databinding.ActivityRevealBinding;
+
+
+public class RevealActivity extends BaseDetailActivity implements View.OnTouchListener {
+ private static final int DELAY = 100;
+ private RelativeLayout bgViewGroup;
+ private Toolbar toolbar;
+ private Interpolator interpolator;
+ private TextView body;
+ private View btnRed;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ bindData();
+ setupWindowAnimations();
+ setupLayout();
+ setupToolbar();
+ }
+
+ private void bindData() {
+ ActivityRevealBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_reveal);
+ Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE);
+ binding.setReveal1Sample(sample);
+ }
+
+ private void setupWindowAnimations() {
+ interpolator = AnimationUtils.loadInterpolator(this, android.R.interpolator.linear_out_slow_in);
+ setupEnterAnimations();
+ setupExitAnimations();
+ }
+
+ private void setupEnterAnimations() {
+ Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
+ getWindow().setSharedElementEnterTransition(transition);
+ transition.addListener(new Transition.TransitionListener() {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ // Removing listener here is very important because shared element transition is executed again backwards on exit. If we don't remove the listener this code will be triggered again.
+ transition.removeListener(this);
+ hideTarget();
+ animateRevealShow(toolbar);
+ animateButtonsIn();
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ }
+ });
+ }
+
+ private void setupExitAnimations() {
+ Fade returnTransition = new Fade();
+ getWindow().setReturnTransition(returnTransition);
+ returnTransition.setDuration(getResources().getInteger(R.integer.anim_duration_medium));
+ returnTransition.setStartDelay(getResources().getInteger(R.integer.anim_duration_medium));
+ returnTransition.addListener(new Transition.TransitionListener() {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ transition.removeListener(this);
+ animateButtonsOut();
+ animateRevealHide(bgViewGroup);
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ }
+ });
+ }
+
+ private void setupLayout() {
+ bgViewGroup = (RelativeLayout) findViewById(R.id.reveal_root);
+ toolbar = (Toolbar) findViewById(R.id.toolbar);
+ body = ((TextView) findViewById(R.id.sample_body));
+ View btnGreen = findViewById(R.id.square_green);
+ btnGreen.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ revealGreen();
+ }
+ });
+ btnRed = findViewById(R.id.square_red);
+ btnRed.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ revealRed();
+ }
+ });
+ View btnBlue = findViewById(R.id.square_blue);
+ btnBlue.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ revealBlue();
+ }
+ });
+ findViewById(R.id.square_yellow).setOnTouchListener(this);
+ }
+
+ private void revealBlue() {
+ animateButtonsOut();
+ Animator anim = animateRevealColorFromCoordinates(bgViewGroup, R.color.sample_blue, bgViewGroup.getWidth() / 2, 0);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ animateButtonsIn();
+ }
+ });
+ body.setText(R.string.reveal_body4);
+ body.setTextColor(ContextCompat.getColor(this, R.color.theme_blue_background));
+ }
+
+ private void revealRed() {
+ final ViewGroup.LayoutParams originalParams = btnRed.getLayoutParams();
+ Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
+ transition.addListener(new Transition.TransitionListener() {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ animateRevealColor(bgViewGroup, R.color.sample_red);
+ body.setText(R.string.reveal_body3);
+ body.setTextColor(ContextCompat.getColor(RevealActivity.this, R.color.theme_red_background));
+ btnRed.setLayoutParams(originalParams);
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+
+ }
+ });
+ TransitionManager.beginDelayedTransition(bgViewGroup, transition);
+ RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
+ layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
+ btnRed.setLayoutParams(layoutParams);
+ }
+
+ private void revealYellow(float x, float y) {
+ animateRevealColorFromCoordinates(bgViewGroup, R.color.sample_yellow, (int) x, (int) y);
+ body.setText(R.string.reveal_body1);
+ body.setTextColor(ContextCompat.getColor(this, R.color.theme_yellow_background));
+ }
+
+ private void revealGreen() {
+ animateRevealColor(bgViewGroup, R.color.sample_green);
+ body.setText(R.string.reveal_body2);
+ body.setTextColor(ContextCompat.getColor(this, R.color.theme_green_background));
+ }
+
+ private void hideTarget() {
+ findViewById(R.id.shared_target).setVisibility(View.GONE);
+ }
+
+ private void animateButtonsIn() {
+ for (int i = 0; i < bgViewGroup.getChildCount(); i++) { + View child = bgViewGroup.getChildAt(i); + child.animate() + .setStartDelay(100 + i * DELAY) + .setInterpolator(interpolator) + .alpha(1) + .scaleX(1) + .scaleY(1); + } + } + + private void animateButtonsOut() { + for (int i = 0; i < bgViewGroup.getChildCount(); i++) { + View child = bgViewGroup.getChildAt(i); + child.animate() + .setStartDelay(i) + .setInterpolator(interpolator) + .alpha(0) + .scaleX(0f) + .scaleY(0f); + } + } + + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { + if (view.getId() == R.id.square_yellow) { + revealYellow(motionEvent.getRawX(), motionEvent.getRawY()); + } + } + return false; + } + + private void animateRevealShow(View viewRoot) { + int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; + int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; + int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight()); + + Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius); + viewRoot.setVisibility(View.VISIBLE); + anim.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + anim.setInterpolator(new AccelerateInterpolator()); + anim.start(); + } + + private void animateRevealColor(ViewGroup viewRoot, @ColorRes int color) { + int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; + int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; + animateRevealColorFromCoordinates(viewRoot, color, cx, cy); + } + + private Animator animateRevealColorFromCoordinates(ViewGroup viewRoot, @ColorRes int color, int x, int y) { + float finalRadius = (float) Math.hypot(viewRoot.getWidth(), viewRoot.getHeight()); + + Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, x, y, 0, finalRadius); + viewRoot.setBackgroundColor(ContextCompat.getColor(this, color)); + anim.setDuration(getResources().getInteger(R.integer.anim_duration_long)); + anim.setInterpolator(new AccelerateDecelerateInterpolator()); + anim.start(); + return anim; + } + + private void animateRevealHide(final View viewRoot) { + int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; + int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; + int initialRadius = viewRoot.getWidth(); + + Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, initialRadius, 0); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + viewRoot.setVisibility(View.INVISIBLE); + } + }); + anim.setDuration(getResources().getInteger(R.integer.anim_duration_medium)); + anim.start(); + } +} diff --git a/android_transition/src/main/java/com/pinger/transition/Sample.java b/android_transition/src/main/java/com/pinger/transition/Sample.java new file mode 100644 index 0000000..18dcf78 --- /dev/null +++ b/android_transition/src/main/java/com/pinger/transition/Sample.java @@ -0,0 +1,38 @@ +package com.pinger.transition; + +import android.databinding.BindingAdapter; +import android.support.annotation.ColorRes; +import android.support.v4.graphics.drawable.DrawableCompat; +import android.widget.ImageView; + +import java.io.Serializable; + +/** + * Created by lgvalle on 04/09/15. + */ +public class Sample implements Serializable { + + final int color; + private final String name; + + public Sample(@ColorRes int color, String name) { + this.color = color; + this.name = name; + } + + @BindingAdapter("bind:colorTint") + public static void setColorTint(ImageView view, @ColorRes int color) { + DrawableCompat.setTint(view.getDrawable(), color); + //view.setColorFilter(color, PorterDuff.Mode.SRC_IN); + } + + public String getName() { + return name; + } + + public int getColor() { + return color; + } + + +} diff --git a/android_transition/src/main/java/com/pinger/transition/SamplesRecyclerAdapter.java b/android_transition/src/main/java/com/pinger/transition/SamplesRecyclerAdapter.java new file mode 100644 index 0000000..88e0126 --- /dev/null +++ b/android_transition/src/main/java/com/pinger/transition/SamplesRecyclerAdapter.java @@ -0,0 +1,99 @@ +package com.pinger.transition; + +import android.app.Activity; +import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.util.Pair; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + + +import com.pinger.transition.databinding.RowSampleBinding; + +import java.util.List; + +public class SamplesRecyclerAdapter extends RecyclerView.Adapter {
+ private final Activity activity;
+ private final List samples;
+
+ public SamplesRecyclerAdapter(Activity activity, List samples) {
+ this.activity = activity;
+ this.samples = samples;
+ }
+
+ @Override
+ public SamplesViewHolder onCreateViewHolder(ViewGroup parent, int position) {
+ RowSampleBinding binding = RowSampleBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
+ return new SamplesViewHolder(binding.getRoot());
+ }
+
+ @Override
+ public void onBindViewHolder(final SamplesViewHolder viewHolder, final int position) {
+ final Sample sample = samples.get(viewHolder.getAdapterPosition());
+ viewHolder.binding.setSample(sample);
+ viewHolder.binding.sampleLayout.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ switch (viewHolder.getAdapterPosition()) {
+ case 0:
+ transitionToActivity(TransitionActivity1.class, sample);
+ break;
+ case 1:
+ transitionToActivity(SharedElementActivity.class, viewHolder, sample);
+ break;
+ case 2:
+ transitionToActivity(AnimationsActivity1.class, sample);
+ break;
+ case 3:
+ transitionToActivity(RevealActivity.class, viewHolder, sample, R.string.transition_reveal1);
+ break;
+ }
+ }
+ });
+ }
+
+ private void transitionToActivity(Class target, Sample sample) {
+ final Pair[] pairs = TransitionHelper.createSafeTransitionParticipants(activity, true);
+ startActivity(target, pairs, sample);
+ }
+
+
+ private void transitionToActivity(Class target, SamplesViewHolder viewHolder, Sample sample, int transitionName) {
+ final Pair[] pairs = TransitionHelper.createSafeTransitionParticipants(activity, false,
+ new Pair(viewHolder.binding.sampleIcon, activity.getString(transitionName)));
+ startActivity(target, pairs, sample);
+ }
+
+ private void transitionToActivity(Class target, SamplesViewHolder viewHolder, Sample sample) {
+ final Pair[] pairs = TransitionHelper.createSafeTransitionParticipants(activity, false,
+ new Pair(viewHolder.binding.sampleIcon, activity.getString(R.string.square_blue_name)),
+ new Pair(viewHolder.binding.sampleName, activity.getString(R.string.sample_blue_title)));
+ startActivity(target, pairs, sample);
+ }
+
+ private void startActivity(Class target, Pair[] pairs, Sample sample) {
+ Intent i = new Intent(activity, target);
+ ActivityOptionsCompat transitionActivityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, pairs);
+ i.putExtra("sample", sample);
+ activity.startActivity(i, transitionActivityOptions.toBundle());
+ }
+
+ @Override
+ public int getItemCount() {
+ return samples.size();
+ }
+
+
+ public class SamplesViewHolder extends RecyclerView.ViewHolder {
+ final RowSampleBinding binding;
+
+ public SamplesViewHolder(View rootView) {
+ super(rootView);
+ binding = DataBindingUtil.bind(rootView);
+
+ }
+ }
+}
diff --git a/android_transition/src/main/java/com/pinger/transition/SecondActivity.java b/android_transition/src/main/java/com/pinger/transition/SecondActivity.java
deleted file mode 100644
index efc70dd..0000000
--- a/android_transition/src/main/java/com/pinger/transition/SecondActivity.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.pinger.transition;
-
-import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
-
-public class SecondActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_second);
- }
-}
diff --git a/android_transition/src/main/java/com/pinger/transition/SharedElementActivity.java b/android_transition/src/main/java/com/pinger/transition/SharedElementActivity.java
new file mode 100644
index 0000000..cc4caf5
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/SharedElementActivity.java
@@ -0,0 +1,49 @@
+package com.pinger.transition;
+
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.transition.ChangeBounds;
+import android.transition.Slide;
+import android.view.Gravity;
+
+import com.pinger.transition.databinding.ActivitySharedelementBinding;
+
+
+public class SharedElementActivity extends BaseDetailActivity {
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE);
+ bindData(sample);
+ setupWindowAnimations();
+ setupLayout(sample);
+ setupToolbar();
+ }
+
+ private void bindData(Sample sample) {
+ ActivitySharedelementBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_sharedelement);
+ binding.setSharedSample(sample);
+ }
+
+ private void setupWindowAnimations() {
+ // We are not interested in defining a new Enter Transition. Instead we change default transition duration
+ getWindow().getEnterTransition().setDuration(getResources().getInteger(R.integer.anim_duration_long));
+ }
+
+ private void setupLayout(Sample sample) {
+ // Transition for fragment1
+ Slide slideTransition = new Slide(Gravity.LEFT);
+ slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
+ // Create fragment and define some of it transitions
+ SharedElementFragment1 sharedElementFragment1 = SharedElementFragment1.newInstance(sample);
+ sharedElementFragment1.setReenterTransition(slideTransition);
+ sharedElementFragment1.setExitTransition(slideTransition);
+ sharedElementFragment1.setSharedElementEnterTransition(new ChangeBounds());
+
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.sample2_content, sharedElementFragment1)
+ .commit();
+ }
+}
diff --git a/android_transition/src/main/java/com/pinger/transition/SharedElementFragment1.java b/android_transition/src/main/java/com/pinger/transition/SharedElementFragment1.java
new file mode 100644
index 0000000..38af818
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/SharedElementFragment1.java
@@ -0,0 +1,77 @@
+package com.pinger.transition;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.transition.ChangeBounds;
+import android.transition.Slide;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+/**
+ * Created by lgvalle on 05/09/15.
+ */
+public class SharedElementFragment1 extends Fragment {
+
+ private static final String EXTRA_SAMPLE = "sample";
+
+ public static SharedElementFragment1 newInstance(Sample sample) {
+
+ Bundle args = new Bundle();
+
+ args.putSerializable(EXTRA_SAMPLE, sample);
+ SharedElementFragment1 fragment = new SharedElementFragment1();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.activity_sharedelement_fragment1, container, false);
+ final Sample sample = (Sample) getArguments().getSerializable(EXTRA_SAMPLE);
+
+ final ImageView squareBlue = (ImageView) view.findViewById(R.id.square_blue);
+ DrawableCompat.setTint(squareBlue.getDrawable(), sample.color);
+
+ view.findViewById(R.id.sample2_button1).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ addNextFragment(sample, squareBlue, false);
+ }
+ });
+
+ view.findViewById(R.id.sample2_button2).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ addNextFragment(sample, squareBlue, true);
+ }
+ });
+
+ return view;
+ }
+
+ private void addNextFragment(Sample sample, ImageView squareBlue, boolean overlap) {
+ SharedElementFragment2 sharedElementFragment2 = SharedElementFragment2.newInstance(sample);
+
+ Slide slideTransition = new Slide(Gravity.RIGHT);
+ slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_medium));
+
+ ChangeBounds changeBoundsTransition = new ChangeBounds();
+ changeBoundsTransition.setDuration(getResources().getInteger(R.integer.anim_duration_medium));
+
+ sharedElementFragment2.setEnterTransition(slideTransition);
+ sharedElementFragment2.setAllowEnterTransitionOverlap(overlap);
+ sharedElementFragment2.setAllowReturnTransitionOverlap(overlap);
+ sharedElementFragment2.setSharedElementEnterTransition(changeBoundsTransition);
+
+ getFragmentManager().beginTransaction()
+ .replace(R.id.sample2_content, sharedElementFragment2)
+ .addToBackStack(null)
+ .addSharedElement(squareBlue, getString(R.string.square_blue_name))
+ .commit();
+ }
+
+}
diff --git a/android_transition/src/main/java/com/pinger/transition/SharedElementFragment2.java b/android_transition/src/main/java/com/pinger/transition/SharedElementFragment2.java
new file mode 100644
index 0000000..9c0c1c9
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/SharedElementFragment2.java
@@ -0,0 +1,33 @@
+package com.pinger.transition;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+public class SharedElementFragment2 extends Fragment {
+ private static final String EXTRA_SAMPLE = "sample";
+
+ public static SharedElementFragment2 newInstance(Sample sample) {
+ Bundle args = new Bundle();
+ args.putSerializable(EXTRA_SAMPLE, sample);
+ SharedElementFragment2 fragment = new SharedElementFragment2();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.activity_sharedelement_fragment2, container, false);
+ Sample sample = (Sample) getArguments().getSerializable(EXTRA_SAMPLE);
+
+ ImageView squareBlue = (ImageView) view.findViewById(R.id.square_blue);
+ DrawableCompat.setTint(squareBlue.getDrawable(), sample.color);
+
+ return view;
+ }
+
+}
diff --git a/android_transition/src/main/java/com/pinger/transition/TransitionActivity1.java b/android_transition/src/main/java/com/pinger/transition/TransitionActivity1.java
new file mode 100644
index 0000000..1925645
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/TransitionActivity1.java
@@ -0,0 +1,113 @@
+package com.pinger.transition;
+
+import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.transition.Fade;
+import android.transition.Slide;
+import android.transition.Visibility;
+import android.view.View;
+
+import com.pinger.transition.databinding.ActivityTransition1Binding;
+
+
+public class TransitionActivity1 extends BaseDetailActivity {
+ private Sample sample;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ bindData();
+ setupWindowAnimations();
+ setupLayout();
+ setupToolbar();
+ }
+
+ private void bindData() {
+ ActivityTransition1Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_transition1);
+ sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE);
+ binding.setTransition1Sample(sample);
+ }
+
+ private void setupWindowAnimations() {
+ Visibility enterTransition = buildEnterTransition();
+ getWindow().setEnterTransition(enterTransition);
+ }
+
+
+ private void setupLayout() {
+ findViewById(R.id.sample1_button1).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent i = new Intent(TransitionActivity1.this, TransitionActivity2.class);
+ i.putExtra(EXTRA_SAMPLE, sample);
+ i.putExtra(EXTRA_TYPE, TYPE_PROGRAMMATICALLY);
+ transitionTo(i);
+ }
+ });
+
+ findViewById(R.id.sample1_button2).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent i = new Intent(TransitionActivity1.this, TransitionActivity2.class);
+ i.putExtra(EXTRA_SAMPLE, sample);
+ i.putExtra(EXTRA_TYPE, TYPE_XML);
+ transitionTo(i);
+ }
+ });
+
+ findViewById(R.id.sample1_button3).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent i = new Intent(TransitionActivity1.this, TransitionActivity3.class);
+ i.putExtra(EXTRA_SAMPLE, sample);
+ i.putExtra(EXTRA_TYPE, TYPE_PROGRAMMATICALLY);
+ transitionTo(i);
+ }
+ });
+
+ findViewById(R.id.sample1_button4).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent i = new Intent(TransitionActivity1.this, TransitionActivity3.class);
+ i.putExtra(EXTRA_SAMPLE, sample);
+ i.putExtra(EXTRA_TYPE, TYPE_XML);
+ transitionTo(i);
+ }
+ });
+
+ findViewById(R.id.sample1_button5).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Visibility returnTransition = buildReturnTransition();
+ getWindow().setReturnTransition(returnTransition);
+
+ finishAfterTransition();
+ }
+ });
+ findViewById(R.id.sample1_button6).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ /**
+ * If no return transition is defined Android will use reversed enter transition
+ * In this case, return transition will be a reversed Slide (defined in buildEnterTransition)
+ */
+ finishAfterTransition();
+ }
+ });
+ }
+
+ private Visibility buildEnterTransition() {
+ Fade enterTransition = new Fade();
+ enterTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
+ // This view will not be affected by enter transition animation
+ enterTransition.excludeTarget(R.id.square_red, true);
+ return enterTransition;
+ }
+
+ private Visibility buildReturnTransition() {
+ Visibility enterTransition = new Slide();
+ enterTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
+ return enterTransition;
+ }
+}
diff --git a/android_transition/src/main/java/com/pinger/transition/TransitionActivity2.java b/android_transition/src/main/java/com/pinger/transition/TransitionActivity2.java
new file mode 100644
index 0000000..6ab852b
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/TransitionActivity2.java
@@ -0,0 +1,59 @@
+package com.pinger.transition;
+
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.transition.Explode;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.view.View;
+
+import com.pinger.transition.databinding.ActivityTransition2Binding;
+
+
+public class TransitionActivity2 extends BaseDetailActivity {
+
+ private int type;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ bindData();
+ setupWindowAnimations();
+ setupLayout();
+ setupToolbar();
+ }
+
+ private void bindData() {
+ ActivityTransition2Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_transition2);
+ Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE);
+ type = getIntent().getExtras().getInt(EXTRA_TYPE);
+ binding.setTransition2Sample(sample);
+ }
+
+ private void setupWindowAnimations() {
+ Transition transition;
+
+ if (type == TYPE_PROGRAMMATICALLY) {
+ transition = buildEnterTransition();
+ } else {
+ transition = TransitionInflater.from(this).inflateTransition(R.transition.explode);
+ }
+ getWindow().setEnterTransition(transition);
+ }
+
+ private void setupLayout() {
+ findViewById(R.id.exit_button).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ finishAfterTransition();
+ }
+ });
+ }
+
+ private Transition buildEnterTransition() {
+ Explode enterTransition = new Explode();
+ enterTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
+ return enterTransition;
+ }
+
+}
diff --git a/android_transition/src/main/java/com/pinger/transition/TransitionActivity3.java b/android_transition/src/main/java/com/pinger/transition/TransitionActivity3.java
new file mode 100644
index 0000000..f2e56f2
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/TransitionActivity3.java
@@ -0,0 +1,62 @@
+package com.pinger.transition;
+
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.transition.Slide;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.Visibility;
+import android.view.Gravity;
+import android.view.View;
+
+import com.pinger.transition.databinding.ActivityTransition3Binding;
+
+
+public class TransitionActivity3 extends BaseDetailActivity {
+
+ private int type;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ bindData();
+ setupWindowAnimations();
+ setupLayout();
+ setupToolbar();
+ }
+
+ private void bindData() {
+ ActivityTransition3Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_transition3);
+ Sample sample = (Sample) getIntent().getExtras().getSerializable(EXTRA_SAMPLE);
+ type = getIntent().getExtras().getInt(EXTRA_TYPE);
+ binding.setTransition3Sample(sample);
+ }
+
+ private void setupWindowAnimations() {
+ Transition transition;
+
+ if (type == TYPE_PROGRAMMATICALLY) {
+ transition = buildEnterTransition();
+ } else {
+ transition = TransitionInflater.from(this).inflateTransition(R.transition.slide_from_bottom);
+ }
+ getWindow().setEnterTransition(transition);
+ }
+
+ private void setupLayout() {
+ findViewById(R.id.exit_button).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ finishAfterTransition();
+ }
+ });
+ }
+
+ private Visibility buildEnterTransition() {
+ Slide enterTransition = new Slide();
+ enterTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
+ enterTransition.setSlideEdge(Gravity.RIGHT);
+ return enterTransition;
+ }
+
+}
diff --git a/android_transition/src/main/java/com/pinger/transition/TransitionHelper.java b/android_transition/src/main/java/com/pinger/transition/TransitionHelper.java
new file mode 100644
index 0000000..ca4d97a
--- /dev/null
+++ b/android_transition/src/main/java/com/pinger/transition/TransitionHelper.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * 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.pinger.transition;
+
+import android.app.Activity;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.Pair;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Helper class for creating content transitions used with {@link android.app.ActivityOptions}.
+ */
+class TransitionHelper {
+
+ /**
+ * Create the transition participants required during a activity transition while
+ * avoiding glitches with the system UI.
+ *
+ * @param activity The activity used as start for the transition.
+ * @param includeStatusBar If false, the status bar will not be added as the transition
+ * participant.
+ * @return All transition participants.
+ */
+ public static Pair[] createSafeTransitionParticipants(@NonNull Activity activity,
+ boolean includeStatusBar, @Nullable Pair... otherParticipants) {
+ // Avoid system UI glitches as described here:
+ // https://plus.google.com/+AlexLockwood/posts/RPtwZ5nNebb
+ View decor = activity.getWindow().getDecorView();
+ View statusBar = null;
+ if (includeStatusBar) {
+ statusBar = decor.findViewById(android.R.id.statusBarBackground);
+ }
+ View navBar = decor.findViewById(android.R.id.navigationBarBackground);
+
+ // Create pair of transition participants.
+ List participants = new ArrayList(3);
+ addNonNullViewToTransitionParticipants(statusBar, participants);
+ addNonNullViewToTransitionParticipants(navBar, participants);
+ // only add transition participants if there's at least one none-null element
+ if (otherParticipants != null && !(otherParticipants.length == 1
+ && otherParticipants[0] == null)) {
+ participants.addAll(Arrays.asList(otherParticipants));
+ }
+ return participants.toArray(new Pair[participants.size()]);
+ }
+
+ private static void addNonNullViewToTransitionParticipants(View view, List participants) {
+ if (view == null) {
+ return;
+ }
+ participants.add(new Pair(view, view.getTransitionName()));
+ }
+
+}
diff --git a/android_transition/src/main/res/drawable/circle_24dp.xml b/android_transition/src/main/res/drawable/circle_24dp.xml
new file mode 100644
index 0000000..d92150a
--- /dev/null
+++ b/android_transition/src/main/res/drawable/circle_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android_transition/src/main/res/drawable/square.xml b/android_transition/src/main/res/drawable/square.xml
new file mode 100644
index 0000000..ec66c24
--- /dev/null
+++ b/android_transition/src/main/res/drawable/square.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_animations1.xml b/android_transition/src/main/res/layout/activity_animations1.xml
new file mode 100644
index 0000000..7078c87
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_animations1.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_animations2.xml b/android_transition/src/main/res/layout/activity_animations2.xml
new file mode 100644
index 0000000..c3f43b9
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_animations2.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_animations_scene0.xml b/android_transition/src/main/res/layout/activity_animations_scene0.xml
new file mode 100644
index 0000000..2183aaf
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_animations_scene0.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_animations_scene1.xml b/android_transition/src/main/res/layout/activity_animations_scene1.xml
new file mode 100644
index 0000000..fedb536
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_animations_scene1.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_animations_scene2.xml b/android_transition/src/main/res/layout/activity_animations_scene2.xml
new file mode 100644
index 0000000..2de48a3
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_animations_scene2.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_animations_scene3.xml b/android_transition/src/main/res/layout/activity_animations_scene3.xml
new file mode 100644
index 0000000..20abe59
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_animations_scene3.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_animations_scene4.xml b/android_transition/src/main/res/layout/activity_animations_scene4.xml
new file mode 100644
index 0000000..4ee0dad
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_animations_scene4.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_main.xml b/android_transition/src/main/res/layout/activity_main.xml
index 2c626f9..1926d27 100644
--- a/android_transition/src/main/res/layout/activity_main.xml
+++ b/android_transition/src/main/res/layout/activity_main.xml
@@ -1,36 +1,32 @@
-
+
-
+
+
-
+
+
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_reveal.xml b/android_transition/src/main/res/layout/activity_reveal.xml
new file mode 100644
index 0000000..36782d5
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_reveal.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_second.xml b/android_transition/src/main/res/layout/activity_second.xml
deleted file mode 100644
index e73aa69..0000000
--- a/android_transition/src/main/res/layout/activity_second.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_sharedelement.xml b/android_transition/src/main/res/layout/activity_sharedelement.xml
new file mode 100644
index 0000000..589f57e
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_sharedelement.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_sharedelement_fragment1.xml b/android_transition/src/main/res/layout/activity_sharedelement_fragment1.xml
new file mode 100644
index 0000000..46e1d5c
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_sharedelement_fragment1.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_sharedelement_fragment2.xml b/android_transition/src/main/res/layout/activity_sharedelement_fragment2.xml
new file mode 100644
index 0000000..d6c6fa0
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_sharedelement_fragment2.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_transition1.xml b/android_transition/src/main/res/layout/activity_transition1.xml
new file mode 100644
index 0000000..af60bd6
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_transition1.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_transition2.xml b/android_transition/src/main/res/layout/activity_transition2.xml
new file mode 100644
index 0000000..b6bb0cd
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_transition2.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/activity_transition3.xml b/android_transition/src/main/res/layout/activity_transition3.xml
new file mode 100644
index 0000000..e46decf
--- /dev/null
+++ b/android_transition/src/main/res/layout/activity_transition3.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/row_sample.xml b/android_transition/src/main/res/layout/row_sample.xml
new file mode 100644
index 0000000..66b5edd
--- /dev/null
+++ b/android_transition/src/main/res/layout/row_sample.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/layout/square.xml b/android_transition/src/main/res/layout/square.xml
new file mode 100644
index 0000000..bbd8ea1
--- /dev/null
+++ b/android_transition/src/main/res/layout/square.xml
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/android_transition/src/main/res/menu/menu_main.xml b/android_transition/src/main/res/menu/menu_main.xml
new file mode 100644
index 0000000..b1cb908
--- /dev/null
+++ b/android_transition/src/main/res/menu/menu_main.xml
@@ -0,0 +1,6 @@
+
diff --git a/android_transition/src/main/res/transition/changebounds_with_arcmotion.xml b/android_transition/src/main/res/transition/changebounds_with_arcmotion.xml
new file mode 100644
index 0000000..4ab1e59
--- /dev/null
+++ b/android_transition/src/main/res/transition/changebounds_with_arcmotion.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/transition/explode.xml b/android_transition/src/main/res/transition/explode.xml
new file mode 100644
index 0000000..9eff59c
--- /dev/null
+++ b/android_transition/src/main/res/transition/explode.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/transition/slide_and_changebounds.xml b/android_transition/src/main/res/transition/slide_and_changebounds.xml
new file mode 100644
index 0000000..be7492b
--- /dev/null
+++ b/android_transition/src/main/res/transition/slide_and_changebounds.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/transition/slide_and_changebounds_sequential.xml b/android_transition/src/main/res/transition/slide_and_changebounds_sequential.xml
new file mode 100644
index 0000000..f5bf7b8
--- /dev/null
+++ b/android_transition/src/main/res/transition/slide_and_changebounds_sequential.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/transition/slide_and_changebounds_sequential_with_interpolators.xml b/android_transition/src/main/res/transition/slide_and_changebounds_sequential_with_interpolators.xml
new file mode 100644
index 0000000..17e3c9b
--- /dev/null
+++ b/android_transition/src/main/res/transition/slide_and_changebounds_sequential_with_interpolators.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/transition/slide_from_bottom.xml b/android_transition/src/main/res/transition/slide_from_bottom.xml
new file mode 100644
index 0000000..cf3f12d
--- /dev/null
+++ b/android_transition/src/main/res/transition/slide_from_bottom.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/android_transition/src/main/res/values-w820dp/dimens.xml b/android_transition/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/android_transition/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 64dp
+
diff --git a/android_transition/src/main/res/values/colors.xml b/android_transition/src/main/res/values/colors.xml
index 3ab3e9c..b27ab06 100644
--- a/android_transition/src/main/res/values/colors.xml
+++ b/android_transition/src/main/res/values/colors.xml
@@ -1,6 +1,72 @@
+
- #3F51B5
- #303F9F
- #FF4081
+ #9ccc
+
+ #039BE5
+ #0277BD
+ #424242
+ #3F51B5
+
+ @android:color/white
+ #616161
+
+ #ff4444
+ #33b5e5
+ #669900
+ #ff8800
+
+
+
+ #84ffff
+ #4FC3F7
+ #ff193a
+ @color/text_dark
+ @android:color/black
+ #039BE5
+
+ #b9f6ca
+ #669900
+ #e919ff
+ @color/text_dark
+ #558B2F
+
+ #b388ff
+ #7e57c2
+ #ff9419
+ @color/text_light
+ #6c4aa6
+
+ #ff8a80
+ #ff5252
+ #fffc19
+ @color/text_light
+ #e64a4a
+
+ #ffff8d
+ #ff8800
+ #19dcff
+ @color/text_dark
+ #EF6C00
+
+ #00e676
+ #ff5252
+ #E0E0E0
+
+
+
diff --git a/android_transition/src/main/res/values/dimens.xml b/android_transition/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..0a220f1
--- /dev/null
+++ b/android_transition/src/main/res/values/dimens.xml
@@ -0,0 +1,17 @@
+
+
+ 4dp
+ 8dp
+ 16dp
+ 72dp
+
+
+ 4dp
+ 8dp
+
+ 40dp
+
+ 1500
+ 500
+ 300
+
diff --git a/android_transition/src/main/res/values/strings.xml b/android_transition/src/main/res/values/strings.xml
index 13fba55..b8094da 100644
--- a/android_transition/src/main/res/values/strings.xml
+++ b/android_transition/src/main/res/values/strings.xml
@@ -1,3 +1,19 @@
- android_transition
+ Transition
+
+ Hello world!
+ Settings
+
+ square_red
+ square_blue
+ square_green
+ transition_reveal1
+
+ sample_blue_title
+ Bacon ipsum dolor amet cupidatat bresaola minim, aliquip beef aute ea porchetta. Meatball brisket do, rump in beef ea ham hock spare ribs mollit qui dolore ipsum voluptate cow. Drumstick prosciutto salami duis jerky jowl. Mollit ball tip short ribs doner fugiat frankfurter leberkas andouille kevin pork loin nostrud ham culpa. Rump pariatur ham hock excepteur picanha pork. Corned beef flank proident shankle rump.
+ Porchetta landjaeger tail meatball t-bone spare ribs. Sirloin pork chop bacon pork belly strip steak. Porchetta ham meatball pig salami short ribs jowl spare ribs sirloin tongue jerky cupim chuck.
+ Circular Reveal Animation starting from the center of target view
+ Circular Reveal Animation starting from touch coordinates
+ View layout change animation with Circular Reveal Animation on finish
+ Circular Reveal Animation from top with nested animations on end
diff --git a/android_transition/src/main/res/values/styles.xml b/android_transition/src/main/res/values/styles.xml
index 5885930..57c6455 100644
--- a/android_transition/src/main/res/values/styles.xml
+++ b/android_transition/src/main/res/values/styles.xml
@@ -1,11 +1,114 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android_utils/.gitignore b/android_utils/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/android_utils/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/android_utils/build.gradle b/android_utils/build.gradle
new file mode 100644
index 0000000..89c491a
--- /dev/null
+++ b/android_utils/build.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+
+ defaultConfig {
+ applicationId "com.pinger.android.utils"
+ minSdkVersion 21
+ targetSdkVersion 25
+ 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(dir: 'libs', include: ['*.jar'])
+ 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.3.1'
+ compile 'com.android.support:palette-v7:25.3.1'
+ compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7'
+ testCompile 'junit:junit:4.12'
+}
diff --git a/android_utils/proguard-rules.pro b/android_utils/proguard-rules.pro
new file mode 100644
index 0000000..a10f7cc
--- /dev/null
+++ b/android_utils/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in F:\Work\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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/android_utils/src/androidTest/java/com/pinger/android/utils/ExampleInstrumentedTest.java b/android_utils/src/androidTest/java/com/pinger/android/utils/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..2e10922
--- /dev/null
+++ b/android_utils/src/androidTest/java/com/pinger/android/utils/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.pinger.android.utils;
+
+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.pinger.android.utils", appContext.getPackageName());
+ }
+}
diff --git a/android_utils/src/main/AndroidManifest.xml b/android_utils/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7958449
--- /dev/null
+++ b/android_utils/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_utils/src/main/java/com/pinger/android/utils/inject/InjectUtils.java b/android_utils/src/main/java/com/pinger/android/utils/inject/InjectUtils.java
new file mode 100644
index 0000000..6d46a64
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/inject/InjectUtils.java
@@ -0,0 +1,190 @@
+package com.pinger.android.utils.inject;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.Log;
+import android.view.View;
+
+import com.pinger.android.utils.inject.annotation.BindView;
+import com.pinger.android.utils.inject.annotation.ClickEvent;
+import com.pinger.android.utils.inject.annotation.ContentView;
+import com.pinger.android.utils.inject.annotation.ListenerInvocationHandler;
+import com.pinger.android.utils.inject.annotation.ViewFinder;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Pinger
+ * @since 2017年6月18日 21:28
+ * 注解工具类,支持注入布局,控件和事件,事件支持点击,长按。
+ */
+
+public class InjectUtils {
+
+
+ private static final String TAG = InjectUtils.class.getSimpleName();
+
+ /**
+ * 注入到Activity里
+ */
+ public static void inject(Activity activity) {
+ injectLayout(activity);
+ inject(new ViewFinder(activity), activity);
+ }
+
+ /**
+ * 注入到Fragment等使用View填充的对象里
+ */
+ public static void inject(View view, Object object) {
+ inject(new ViewFinder(view), object);
+ }
+
+
+ /**
+ * 注入到View里
+ */
+ public static void inject(View view) {
+ inject(new ViewFinder(view), view);
+ }
+
+
+ /**
+ * 注入
+ */
+ private static void inject(ViewFinder finder, Object object) {
+ injectView(finder, object);
+ injectClick(finder, object);
+ }
+
+
+ /**
+ * 事件注入
+ */
+ private static void injectClick(ViewFinder finder, Object object) {
+ Class> clazz = object.getClass();
+ Method[] methods = clazz.getDeclaredMethods();
+ for (Method method : methods) {
+ Annotation[] annotations = method.getAnnotations();
+ for (Annotation annotation : annotations) {
+ Class> annotationType = annotation.annotationType();
+ performClickEvent(finder, object, method, annotation, annotationType);
+ }
+ }
+ }
+
+ /**
+ * 执行事件点击
+ */
+ private static void performClickEvent(ViewFinder finder, Object object, Method method, Annotation annotation, Class> annotationType) {
+ ClickEvent clickEvent = annotationType.getAnnotation(ClickEvent.class);
+ if (clickEvent != null) {
+
+ // 获取点击事件的各个属性
+ String setter = clickEvent.setter();
+ Class> type = clickEvent.type();
+ String callBackMethod = clickEvent.callBackMethod();
+
+ // 使用动态代理调用设置监听的方法
+ Map methodMap = new HashMap();
+ // 将点击回调的方法作为键,注解的方法作为值,存入代理的方法,
+ // 就是使用注解的方法来代理点击回调的方法
+ methodMap.put(callBackMethod, method);
+
+
+ try {
+ // 获取注解内部的方法
+ Method valueMethod = annotationType.getDeclaredMethod("value");
+ // 存入的ids
+ int[] viewIds = (int[]) valueMethod.invoke(annotation);
+
+ for (int id : viewIds) {
+ if (id != View.NO_ID) {
+ View view = finder.findViewById(id);
+
+ // 使用反射进行方法的调用
+ Method setListener = view.getClass().getMethod(setter, type);
+
+ ListenerInvocationHandler handler = new ListenerInvocationHandler(object, methodMap);
+ // 生成代理对象
+ Object proxy = Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, handler);
+
+ // 激活方法
+ setListener.invoke(view, proxy);
+ }
+
+ }
+
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "注入事件失败,激活方法失败");
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "注入事件失败,方法调用失败");
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "注入事件失败,非法访问");
+ }
+ }
+
+ }
+
+ /**
+ * 控件注入
+ */
+ private static void injectView(ViewFinder finder, Object object) {
+ Class> clazz = object.getClass();
+ // 获取所有的字段
+ Field[] fields = clazz.getDeclaredFields();
+ for (Field field : fields) {
+ // 获取每个字段的注解
+ BindView bindView = field.getAnnotation(BindView.class);
+ // 如果字段上没有注解则跳过
+ if (bindView != null) {
+
+ // 获取控件的Id
+ int viewId = bindView.value();
+ if (viewId != View.NO_ID) {
+ try {
+ field.setAccessible(true);
+ field.set(object, finder.findViewById(viewId));
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ Log.e(TAG, "注入控件失败,非法访问异常");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 布局注入
+ */
+ private static void injectLayout(Context context) {
+ Class> clazz = context.getClass();
+ // 获取类上的布局注解对象
+ ContentView contentView = clazz.getAnnotation(ContentView.class);
+
+ // 如果类上没有注解,则直接返回(有的类可能并不需要页面)
+ if (contentView == null) return;
+
+ // 获取注入的布局控件Id
+ int layoutId = contentView.value();
+
+ // 反射调用setContentView方法
+ try {
+ Method method = clazz.getMethod("setContentView", int.class);
+ method.invoke(context, layoutId);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "注入布局失败,没有setContentView这个方法");
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "注入布局失败,setContentView方法调用失败");
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "注入布局失败,setContentView非法访问");
+ }
+ }
+
+
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/BindView.java b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/BindView.java
new file mode 100644
index 0000000..339a433
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/BindView.java
@@ -0,0 +1,17 @@
+package com.pinger.android.utils.inject.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author Pinger
+ * @since 2017年6月18日 21:35
+ * 控件绑定注解,使用在字段上,生命周期为运行期
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface BindView {
+ int value();
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/CheckNet.java b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/CheckNet.java
new file mode 100644
index 0000000..6aff9ca
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/CheckNet.java
@@ -0,0 +1,18 @@
+package com.pinger.android.utils.inject.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author Pinger
+ * @since 2017年6月22日 0:57
+ */
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CheckNet {
+ // 网络错误时间的提示
+ String value() default "网络异常,请检查您的网络";
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ClickEvent.java b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ClickEvent.java
new file mode 100644
index 0000000..d5cabd8
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ClickEvent.java
@@ -0,0 +1,30 @@
+package com.pinger.android.utils.inject.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * @author Pinger
+ * @since 2017年6月18日 22:48
+ */
+@Target(ANNOTATION_TYPE)
+@Retention(RUNTIME)
+public @interface ClickEvent {
+
+ /**
+ * 事件设置方法的字符串
+ */
+ String setter();
+
+ /**
+ * 事件设置方法参数的对象
+ */
+ Class> type();
+
+ /** 事件设置成功的回调方法字符串 */
+ String callBackMethod();
+
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ContentView.java b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ContentView.java
new file mode 100644
index 0000000..b5ca0a6
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ContentView.java
@@ -0,0 +1,19 @@
+package com.pinger.android.utils.inject.annotation;
+
+import android.view.View;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author Pinger
+ * @since 2017年6月18日 21:32
+ * 注入布局注解,使用在类上,生命周期层次为运行期
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ContentView {
+ int value() default View.NO_ID;
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ListenerInvocationHandler.java b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ListenerInvocationHandler.java
new file mode 100644
index 0000000..84f3cb0
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ListenerInvocationHandler.java
@@ -0,0 +1,71 @@
+package com.pinger.android.utils.inject.annotation;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+
+/**
+ * @author Pinger
+ * @since 2017年6月18日 23:30
+ * 事件点击方法的代理对象
+ */
+
+public class ListenerInvocationHandler implements InvocationHandler {
+
+
+ private final Object mObject;
+ private final Map methodMap;
+
+ public ListenerInvocationHandler(Object object, Map methodMap) {
+ this.mObject = object;
+ this.methodMap = methodMap;
+ }
+
+
+ /**
+ * Processes a method invocation on a proxy instance and returns
+ * the result. This method will be invoked on an invocation handler
+ * when a method is invoked on a proxy instance that it is
+ * associated with.
+ *
+ * @param proxy the proxy instance that the method was invoked on
+ * @param method the {@code Method} instance corresponding to
+ * the interface method invoked on the proxy instance. The declaring
+ * class of the {@code Method} object will be the interface that
+ * the method was declared in, which may be a superinterface of the
+ * proxy interface that the proxy class inherits the method through.
+ * @param args an array of objects containing the values of the
+ * arguments passed in the method invocation on the proxy instance,
+ * or {@code null} if interface method takes no arguments.
+ * Arguments of primitive types are wrapped in instances of the
+ * appropriate primitive wrapper class, such as
+ * {@code java.lang.Integer} or {@code java.lang.Boolean}.
+ * @return the value to return from the method invocation on the
+ * proxy instance. If the declared return type of the interface
+ * method is a primitive type, then the value returned by
+ * this method must be an instance of the corresponding primitive
+ * wrapper class; otherwise, it must be a type assignable to the
+ * declared return type. If the value returned by this method is
+ * {@code null} and the interface method's return type is
+ * primitive, then a {@code NullPointerException} will be
+ * thrown by the method invocation on the proxy instance. If the
+ * value returned by this method is otherwise not compatible with
+ * the interface method's declared return type as described above,
+ * a {@code ClassCastException} will be thrown by the method
+ * invocation on the proxy instance.
+ */
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+
+ String name = method.getName();
+ Method invocationMethod = methodMap.get(name);
+
+ if (invocationMethod == null) {
+ // 不需要代理
+ return method.invoke(proxy, args);
+ } else {
+ return invocationMethod.invoke(mObject, args);
+ }
+ }
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/OnClick.java b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/OnClick.java
new file mode 100644
index 0000000..08f638a
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/OnClick.java
@@ -0,0 +1,26 @@
+package com.pinger.android.utils.inject.annotation;
+
+import android.view.View;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * @author Pinger
+ * @since 2017年6月18日 22:48
+ * 事件注入,注入的监听需要再次注入
+ */
+
+@Target(METHOD)
+@Retention(RUNTIME)
+@ClickEvent(
+ setter = "setOnClickListener",
+ type = View.OnClickListener.class,
+ callBackMethod = "onClick"
+)
+public @interface OnClick {
+ int[] value();
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/OnLongClick.java b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/OnLongClick.java
new file mode 100644
index 0000000..6b6a8d9
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/OnLongClick.java
@@ -0,0 +1,26 @@
+package com.pinger.android.utils.inject.annotation;
+
+import android.view.View;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * @author Pinger
+ * @since 2017年6月19日 23:49
+ * 长按事件注解
+ */
+
+@Target(METHOD)
+@Retention(RUNTIME)
+@ClickEvent(
+ setter = "setOnLongClickListener",
+ type = View.OnLongClickListener.class,
+ callBackMethod = "onLongClick"
+)
+public @interface OnLongClick {
+ int[] value();
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ViewFinder.java b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ViewFinder.java
new file mode 100644
index 0000000..56e27b5
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/inject/annotation/ViewFinder.java
@@ -0,0 +1,31 @@
+package com.pinger.android.utils.inject.annotation;
+
+import android.app.Activity;
+import android.view.View;
+
+/**
+ * @author Pinger
+ * @since 2017年6月22日 1:01
+ * View的辅助类,负责根据id查找对应的控件对象
+ */
+
+public class ViewFinder {
+
+ private Activity mActivity;
+ private View mView;
+
+ public ViewFinder(Activity activity) {
+ this.mActivity = activity;
+ }
+
+ public ViewFinder(View view) {
+ this.mView = view;
+ }
+
+ /**
+ * 查找View
+ */
+ public View findViewById(int viewId) {
+ return mActivity != null ? mActivity.findViewById(viewId) : mView.findViewById(viewId);
+ }
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/test/BaseActivity.java b/android_utils/src/main/java/com/pinger/android/utils/test/BaseActivity.java
new file mode 100644
index 0000000..89e9961
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/test/BaseActivity.java
@@ -0,0 +1,23 @@
+package com.pinger.android.utils.test;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+
+import com.pinger.android.utils.inject.InjectUtils;
+
+
+/**
+ * @author Pinger
+ * @since 2017年6月18日 21:28
+ */
+
+public class BaseActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ InjectUtils.inject(this);
+ }
+
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/test/MainActivity.java b/android_utils/src/main/java/com/pinger/android/utils/test/MainActivity.java
new file mode 100644
index 0000000..fc8f706
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/test/MainActivity.java
@@ -0,0 +1,43 @@
+package com.pinger.android.utils.test;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.pinger.android.utils.R;
+import com.pinger.android.utils.inject.annotation.BindView;
+import com.pinger.android.utils.inject.annotation.ContentView;
+import com.pinger.android.utils.inject.annotation.OnClick;
+import com.pinger.android.utils.inject.annotation.OnLongClick;
+
+@ContentView(R.layout.activity_main)
+public class MainActivity extends BaseActivity {
+
+ @BindView(R.id.text1)
+ TextView mTextView1;
+
+ @BindView(R.id.text2)
+ TextView mTextView2;
+
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mTextView2.setText("注解成功");
+ }
+
+ @OnClick({R.id.text1,R.id.text2})
+ public void onClick(View view) {
+ Toast.makeText(this, "文本点击", Toast.LENGTH_SHORT).show();
+ }
+
+ @OnLongClick({R.id.text1,R.id.text2})
+ public boolean onLongClick(View view) {
+ Toast.makeText(this, "文本2长按", Toast.LENGTH_SHORT).show();
+ return false;
+ }
+
+}
diff --git a/android_utils/src/main/java/com/pinger/android/utils/view/PaletteUtil.java b/android_utils/src/main/java/com/pinger/android/utils/view/PaletteUtil.java
new file mode 100644
index 0000000..39e33fe
--- /dev/null
+++ b/android_utils/src/main/java/com/pinger/android/utils/view/PaletteUtil.java
@@ -0,0 +1,120 @@
+package com.pinger.android.utils.view;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.support.v7.graphics.Palette;
+
+/**
+ * 获取图片背景色,实现渐变和圆角处理
+ */
+public class PaletteUtil implements Palette.PaletteAsyncListener {
+
+ private static PaletteUtil instance;
+
+ private PatternCallBack patternCallBack;
+
+ public static PaletteUtil getInstance() {
+ if (instance == null) {
+ instance = new PaletteUtil();
+ }
+ return instance;
+ }
+
+ public synchronized void init(Bitmap bitmap, PatternCallBack patternCallBack) {
+ Palette.from(bitmap).generate(this);
+ this.patternCallBack = patternCallBack;
+ }
+
+ public synchronized void init(Resources resources, int resourceId, PatternCallBack patternCallBack) {
+ Bitmap bitmap = BitmapFactory.decodeResource(resources, resourceId);
+ Palette.from(bitmap).generate(this);
+ this.patternCallBack = patternCallBack;
+ }
+
+ @Override
+ public synchronized void onGenerated(Palette palette) {
+ Palette.Swatch a = palette.getVibrantSwatch();
+ Palette.Swatch b = palette.getLightVibrantSwatch();
+ int colorEasy = 0;
+ if (b != null) {
+ colorEasy = b.getRgb();
+ }
+ patternCallBack.onCallBack(changedImageViewShape(a.getRgb(), colorEasy)
+ , a.getTitleTextColor());
+ }
+
+ /**
+ * 创建Drawable对象
+ *
+ * @param RGBValues
+ * @param two
+ * @return
+ */
+ private Drawable changedImageViewShape(int RGBValues, int two) {
+ if (two == 0) {
+ two = colorEasy(RGBValues);
+ } else {
+ two = colorBurn(two);
+ }
+ GradientDrawable shape = new GradientDrawable(GradientDrawable.Orientation.TL_BR
+ , new int[]{RGBValues, two});
+ shape.setShape(GradientDrawable.RECTANGLE);
+ //设置渐变方式
+ shape.setGradientType(GradientDrawable.LINEAR_GRADIENT);
+ //圆角
+ shape.setCornerRadius(8);
+ return shape;
+ }
+
+
+ /**
+ * 颜色变浅处理
+ *
+ * @param RGBValues
+ * @return
+ */
+ private int colorEasy(int RGBValues) {
+ int red = RGBValues>> 16 & 0xff;
+ int green = RGBValues>> 8 & 0xff;
+ int blue = RGBValues & 0xff;
+ if (red == 0) {
+ red = 10;
+ }
+ if (green == 0) {
+ green = 10;
+ }
+ if (blue == 0) {
+ blue = 10;
+ }
+ red = (int) Math.floor(red * (1 + 0.1));
+ green = (int) Math.floor(green * (1 + 0.1));
+ blue = (int) Math.floor(blue * (1 + 0.1));
+ return Color.rgb(red, green, blue);
+ }
+
+ /**
+ * 颜色加深处理
+ *
+ * @param RGBValues
+ * @return
+ */
+ private int colorBurn(int RGBValues) {
+ int red = RGBValues>> 16 & 0xff;
+ int green = RGBValues>> 8 & 0xff;
+ int blue = RGBValues & 0xff;
+ red = (int) Math.floor(red * (1 - 0.1));
+ green = (int) Math.floor(green * (1 - 0.1));
+ blue = (int) Math.floor(blue * (1 - 0.1));
+ return Color.rgb(red, green, blue);
+ }
+
+
+ public interface PatternCallBack {
+ void onCallBack(Drawable drawable, int titleColor);
+ }
+
+}
diff --git a/android_utils/src/main/res/layout/activity_main.xml b/android_utils/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..ba7d288
--- /dev/null
+++ b/android_utils/src/main/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/android_utils/src/main/res/mipmap-hdpi/ic_launcher.png b/android_utils/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
Binary files /dev/null and b/android_utils/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android_utils/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android_utils/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
Binary files /dev/null and b/android_utils/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/android_utils/src/main/res/mipmap-mdpi/ic_launcher.png b/android_utils/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
Binary files /dev/null and b/android_utils/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android_utils/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android_utils/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
Binary files /dev/null and b/android_utils/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/android_utils/src/main/res/mipmap-xhdpi/ic_launcher.png b/android_utils/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
Binary files /dev/null and b/android_utils/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android_utils/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android_utils/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
Binary files /dev/null and b/android_utils/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/android_utils/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android_utils/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
Binary files /dev/null and b/android_utils/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android_utils/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android_utils/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
Binary files /dev/null and b/android_utils/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android_utils/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android_utils/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
Binary files /dev/null and b/android_utils/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android_utils/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android_utils/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
Binary files /dev/null and b/android_utils/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/android_utils/src/main/res/values/colors.xml b/android_utils/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/android_utils/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/android_utils/src/main/res/values/strings.xml b/android_utils/src/main/res/values/strings.xml
new file mode 100644
index 0000000..3cac886
--- /dev/null
+++ b/android_utils/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ android_utils
+
diff --git a/android_utils/src/main/res/values/styles.xml b/android_utils/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/android_utils/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/android_utils/src/test/java/com/pinger/android/utils/ExampleUnitTest.java b/android_utils/src/test/java/com/pinger/android/utils/ExampleUnitTest.java
new file mode 100644
index 0000000..e1dd9bb
--- /dev/null
+++ b/android_utils/src/test/java/com/pinger/android/utils/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.pinger.android.utils;
+
+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/android_widget/src/main/java/com/pinger/test/activity/GifIconTransformation.java b/android_widget/src/main/java/com/pinger/test/activity/GifIconTransformation.java
new file mode 100644
index 0000000..9f65592
--- /dev/null
+++ b/android_widget/src/main/java/com/pinger/test/activity/GifIconTransformation.java
@@ -0,0 +1,58 @@
+package com.pinger.test.activity;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+
+import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
+import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
+import com.pinger.test.app.TestApplication;
+import com.pinger.widget.R;
+
+public class GifIconTransformation extends BitmapTransformation {
+ private boolean isGif = false;
+ private static Bitmap gifbmp;
+
+ public GifIconTransformation(Context context, String url) {
+ super(context);
+
+ if (url.toLowerCase().endsWith(".gif")) isGif = true;
+ }
+
+ public GifIconTransformation(Context context, boolean isGif) {
+ super(context);
+ this.isGif = isGif;
+ }
+
+ static {
+ gifbmp = BitmapFactory.decodeResource(TestApplication.getContext().getResources(), R.mipmap.common_image_gif);
+ }
+
+ @Override
+ protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
+ if (isGif) return addGifIcon(toTransform);
+ else return toTransform;
+ }
+
+ @Override
+ public String getId() {
+ return "org.a8sport.com.GifIconTransformation";
+ }
+
+ // 绘制水印
+ private Bitmap addGifIcon(Bitmap oldbitmap) {
+ int width = oldbitmap.getWidth();
+ int height = oldbitmap.getHeight();
+
+ int gifbmpWidth = gifbmp.getWidth();
+ int gifbmpHeight = gifbmp.getHeight();
+
+ Canvas canvas = new Canvas(oldbitmap);
+ canvas.drawBitmap(oldbitmap, 0, 0, null);
+ canvas.drawBitmap(gifbmp, width - gifbmpWidth, height - gifbmpHeight, null);
+
+
+ return oldbitmap;
+ }
+}
\ No newline at end of file
diff --git a/android_widget/src/main/java/com/pinger/test/activity/MainActivity.java b/android_widget/src/main/java/com/pinger/test/activity/MainActivity.java
index 2676d8f..28b098f 100644
--- a/android_widget/src/main/java/com/pinger/test/activity/MainActivity.java
+++ b/android_widget/src/main/java/com/pinger/test/activity/MainActivity.java
@@ -5,7 +5,9 @@
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
+import android.widget.ImageView;
+import com.bumptech.glide.Glide;
import com.pinger.widget.R;
/**
@@ -18,6 +20,9 @@ public class MainActivity extends AppCompatActivity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ ImageView imageView = (ImageView) findViewById(R.id.imageView);
+ String gifUrl = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1493782876&di=d47acc012cb81467eb7ee9e239fb50e5&imgtype=jpg&er=1&src=http%3A%2F%2Fwww.zlcool.com%2Fd%2Ffile%2F2013%2F12%2F15%2F54d4df8b42e5c0b56b1224bfac906248.gif";
+ Glide.with(this).load(gifUrl).transform(new GifIconTransformation(this, true)).into(imageView);
}
public void imagePreview(View view) {
diff --git a/android_widget/src/main/java/com/pinger/test/app/TestApplication.java b/android_widget/src/main/java/com/pinger/test/app/TestApplication.java
index 2b136b2..7803a70 100644
--- a/android_widget/src/main/java/com/pinger/test/app/TestApplication.java
+++ b/android_widget/src/main/java/com/pinger/test/app/TestApplication.java
@@ -16,6 +16,8 @@
*/
public class TestApplication extends Application {
+ private static Context mContext;
+
@Override
public void onCreate() {
super.onCreate();
@@ -34,5 +36,12 @@ public Bitmap getCacheImage(String url) {
return null;
}
});
+
+ mContext = getApplicationContext();
+ }
+
+
+ public static Context getContext(){
+ return mContext;
}
}
diff --git a/android_widget/src/main/res/layout/activity_main.xml b/android_widget/src/main/res/layout/activity_main.xml
index 6373ded..c5416b0 100644
--- a/android_widget/src/main/res/layout/activity_main.xml
+++ b/android_widget/src/main/res/layout/activity_main.xml
@@ -17,4 +17,10 @@
android:text="Banner"/>
+
+
+
\ No newline at end of file
diff --git a/android_widget/src/main/res/mipmap-xxhdpi/common_image_gif.png b/android_widget/src/main/res/mipmap-xxhdpi/common_image_gif.png
new file mode 100644
index 0000000..9be8f23
Binary files /dev/null and b/android_widget/src/main/res/mipmap-xxhdpi/common_image_gif.png differ
diff --git a/android_widget/src/main/res/values/colors.xml b/android_widget/src/main/res/values/colors.xml
index 029b904..9bda66e 100644
--- a/android_widget/src/main/res/values/colors.xml
+++ b/android_widget/src/main/res/values/colors.xml
@@ -1,8 +1,8 @@
- #33000000#3F51B5#303F9F#FF4081
+ #33000000#F7F7F7
\ No newline at end of file
diff --git a/photoview/build/intermediates/incremental/mergeDebugAndroidTestResources/compile-file-map.properties b/photoview/build/intermediates/incremental/mergeDebugAndroidTestResources/compile-file-map.properties
index 1a76b69..ffd54db 100644
--- a/photoview/build/intermediates/incremental/mergeDebugAndroidTestResources/compile-file-map.properties
+++ b/photoview/build/intermediates/incremental/mergeDebugAndroidTestResources/compile-file-map.properties
@@ -1 +1 @@
-#Sat Apr 01 20:23:04 CST 2017
+#Sun Jun 18 23:52:22 CST 2017
diff --git a/photoview/build/intermediates/incremental/mergeDebugAndroidTestResources/merger.xml b/photoview/build/intermediates/incremental/mergeDebugAndroidTestResources/merger.xml
index 0b0389b..a35a7e7 100644
--- a/photoview/build/intermediates/incremental/mergeDebugAndroidTestResources/merger.xml
+++ b/photoview/build/intermediates/incremental/mergeDebugAndroidTestResources/merger.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/photoview/build/intermediates/incremental/mergeDebugResources/compile-file-map.properties b/photoview/build/intermediates/incremental/mergeDebugResources/compile-file-map.properties
index 5fa15bc..ffd54db 100644
--- a/photoview/build/intermediates/incremental/mergeDebugResources/compile-file-map.properties
+++ b/photoview/build/intermediates/incremental/mergeDebugResources/compile-file-map.properties
@@ -1 +1 @@
-#Sat Apr 01 20:23:03 CST 2017
+#Sun Jun 18 23:52:22 CST 2017
diff --git a/photoview/build/intermediates/incremental/mergeDebugResources/merger.xml b/photoview/build/intermediates/incremental/mergeDebugResources/merger.xml
index 457613c..391e315 100644
--- a/photoview/build/intermediates/incremental/mergeDebugResources/merger.xml
+++ b/photoview/build/intermediates/incremental/mergeDebugResources/merger.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/photoview/build/intermediates/incremental/packageDebugResources/compile-file-map.properties b/photoview/build/intermediates/incremental/packageDebugResources/compile-file-map.properties
index 5fa15bc..ffd54db 100644
--- a/photoview/build/intermediates/incremental/packageDebugResources/compile-file-map.properties
+++ b/photoview/build/intermediates/incremental/packageDebugResources/compile-file-map.properties
@@ -1 +1 @@
-#Sat Apr 01 20:23:03 CST 2017
+#Sun Jun 18 23:52:22 CST 2017
diff --git a/photoview/build/intermediates/incremental/packageReleaseResources/compile-file-map.properties b/photoview/build/intermediates/incremental/packageReleaseResources/compile-file-map.properties
index cefe2de..ffd54db 100644
--- a/photoview/build/intermediates/incremental/packageReleaseResources/compile-file-map.properties
+++ b/photoview/build/intermediates/incremental/packageReleaseResources/compile-file-map.properties
@@ -1 +1 @@
-#Sat Apr 01 20:22:36 CST 2017
+#Sun Jun 18 23:52:22 CST 2017
diff --git a/photoview/build/outputs/aar/photoview-debug.aar b/photoview/build/outputs/aar/photoview-debug.aar
index ee75529..c482327 100644
Binary files a/photoview/build/outputs/aar/photoview-debug.aar and b/photoview/build/outputs/aar/photoview-debug.aar differ
diff --git a/photoview/build/outputs/aar/photoview-release.aar b/photoview/build/outputs/aar/photoview-release.aar
index 02d366a..4f8e01e 100644
Binary files a/photoview/build/outputs/aar/photoview-release.aar and b/photoview/build/outputs/aar/photoview-release.aar differ
diff --git a/settings.gradle b/settings.gradle
index f1c3755..b2433b4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':android_framework', ':android_transition', ':android_widget', ':android_develop', ':android_test', ':photoview'
+include ':android_framework', ':android_transition', ':android_widget', ':android_develop', ':android_test', ':photoview', ':android_utils'