diff --git a/flowr/src/main/java/com/fueled/flowr/Flowr.java b/flowr/src/main/java/com/fueled/flowr/Flowr.java index d1083cf..555d0a8 100644 --- a/flowr/src/main/java/com/fueled/flowr/Flowr.java +++ b/flowr/src/main/java/com/fueled/flowr/Flowr.java @@ -3,11 +3,13 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.support.annotation.AnimRes; import android.support.annotation.IdRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; @@ -18,6 +20,7 @@ import com.fueled.flowr.internal.FlowrDeepLinkHandler; import com.fueled.flowr.internal.FlowrDeepLinkInfo; import com.fueled.flowr.internal.TransactionData; +import com.fueled.flowr.internal.TransitionConfig; import java.util.ArrayList; import java.util.Collections; @@ -267,6 +270,10 @@ protected void displayFragment(TransactionD Fragment fragment = data.getFragmentClass().newInstance(); fragment.setArguments(data.getArgs()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && data.getTransitionConfig() != null) { + setTransitions(fragment, data.getTransitionConfig()); + } + FragmentTransaction transaction = screen.getScreenFragmentManager().beginTransaction(); if (!data.isSkipBackStack()) { @@ -282,6 +289,11 @@ protected void displayFragment(TransactionD transaction.add(mainContainerId, fragment); } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && data.getTransitionConfig() != null && + data.getSharedElements() != null && data.getSharedElements().length > 0) { + addSharedElements(transaction, data.getSharedElements()); + } + transaction.commit(); if (data.isSkipBackStack()) { @@ -323,6 +335,33 @@ private void injectDeepLinkInfo(Transaction } } + /** + * Set transitions to the destination fragment from @{@link TransitionConfig}. + * + * @param fragment The destination Fragment. + * @param transitionConfig The transition configuration @{@link TransitionConfig}. + */ + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private void setTransitions(Fragment fragment, TransitionConfig transitionConfig) { + fragment.setEnterTransition(transitionConfig.enter); + fragment.setSharedElementEnterTransition(transitionConfig.sharedElementEnter); + fragment.setExitTransition(transitionConfig.exit); + fragment.setSharedElementReturnTransition(transitionConfig.sharedElementExit); + } + + /** + * Add shared elements to a Fragment Transaction. + * + * @param transaction The transaction that will. + * @param views The shared elements. + */ + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private void addSharedElements(FragmentTransaction transaction, View[] views) { + for (View view : views) { + transaction.addSharedElement(view, view.getTransitionName()); + } + } + /** * Set a Custom Animation to a Fragment transaction * @@ -730,6 +769,18 @@ public Builder setCustomTransactionAnimation(@AnimRes int enterAnim, @AnimRes in } + /** + * Set transition between fragments. + * + * @param transitionConfig builder class for configuring fragment transitions + * @param sharedElements array of shared elements + */ + public Builder setTransition(TransitionConfig transitionConfig, View... sharedElements) { + data.setTransitionConfig(transitionConfig); + data.setSharedElements(sharedElements); + return this; + } + /** * Don't use any animations for this transaction */ diff --git a/flowr/src/main/java/com/fueled/flowr/internal/TransactionData.java b/flowr/src/main/java/com/fueled/flowr/internal/TransactionData.java index 2be151c..9b0df3b 100644 --- a/flowr/src/main/java/com/fueled/flowr/internal/TransactionData.java +++ b/flowr/src/main/java/com/fueled/flowr/internal/TransactionData.java @@ -4,6 +4,7 @@ import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; +import android.view.View; import com.fueled.flowr.FlowrFragment; @@ -23,6 +24,8 @@ public final class TransactionData { private int popEnterAnim; private int popExitAnim; private Intent deepLinkIntent; + private View[] sharedElements; + private TransitionConfig transitionConfig; public TransactionData(Class fragmentClass) { this(fragmentClass, FragmentTransaction.TRANSIT_NONE, FragmentTransaction.TRANSIT_NONE); @@ -121,4 +124,20 @@ public int getExitAnim() { public void setExitAnim(int exitAnim) { this.exitAnim = exitAnim; } + + public View[] getSharedElements() { + return sharedElements; + } + + public void setSharedElements(View[] sharedElements) { + this.sharedElements = sharedElements; + } + + public TransitionConfig getTransitionConfig() { + return transitionConfig; + } + + public void setTransitionConfig(TransitionConfig transitionConfig) { + this.transitionConfig = transitionConfig; + } } diff --git a/flowr/src/main/java/com/fueled/flowr/internal/TransitionConfig.java b/flowr/src/main/java/com/fueled/flowr/internal/TransitionConfig.java new file mode 100644 index 0000000..1604990 --- /dev/null +++ b/flowr/src/main/java/com/fueled/flowr/internal/TransitionConfig.java @@ -0,0 +1,74 @@ +package com.fueled.flowr.internal; + +import android.os.Build; +import android.support.annotation.RequiresApi; +import android.transition.ChangeBounds; +import android.transition.Explode; +import android.transition.Fade; +import android.transition.Slide; +import android.transition.Transition; +import android.view.Gravity; + +/** + * Copyright (c) 2017 Fueled. All rights reserved. + * + * @author chetansachdeva on 21/11/17 + */ + +public class TransitionConfig { + + public Transition sharedElementEnter; + public Transition sharedElementExit; + public Transition enter; + public Transition exit; + + private TransitionConfig(Builder builder) { + sharedElementEnter = builder.sharedElementEnter; + sharedElementExit = builder.sharedElementExit; + enter = builder.enter; + exit = builder.exit; + } + + public static final class Builder { + private Transition sharedElementEnter; + private Transition sharedElementExit; + private Transition enter; + private Transition exit; + + public Builder() { + } + + public Builder sharedElementEnter(Transition val) { + sharedElementEnter = val; + return this; + } + + public Builder sharedElementExit(Transition val) { + sharedElementExit = val; + return this; + } + + public Builder enter(Transition val) { + enter = val; + return this; + } + + public Builder exit(Transition val) { + exit = val; + return this; + } + + public TransitionConfig build() { + return new TransitionConfig(this); + } + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public static class Provider { + public static Transition fade = new Fade(); + public static Transition explode = new Explode(); + public static Transition slideRight = new Slide(Gravity.RIGHT); + public static Transition slideLeft = new Slide(Gravity.LEFT); + public static Transition changeBounds = new ChangeBounds(); + } +} diff --git a/sample/src/main/java/com/fueled/flowr/sample/CategoriesFragment.java b/sample/src/main/java/com/fueled/flowr/sample/CategoriesFragment.java index 1d49b12..dc38d09 100644 --- a/sample/src/main/java/com/fueled/flowr/sample/CategoriesFragment.java +++ b/sample/src/main/java/com/fueled/flowr/sample/CategoriesFragment.java @@ -3,12 +3,15 @@ import android.view.View; import com.fueled.flowr.NavigationIconType; +import com.fueled.flowr.annotations.DeepLink; import com.fueled.flowr.sample.core.AbstractFragment; /** * Created by hussein@fueled.com on 18/05/2017. * Copyright (c) 2017 Fueled. All rights reserved. */ + +@DeepLink(value = {"/categories"}) public class CategoriesFragment extends AbstractFragment { @Override diff --git a/sample/src/main/java/com/fueled/flowr/sample/HomeFragment.java b/sample/src/main/java/com/fueled/flowr/sample/HomeFragment.java index 9b0a09d..cd515e9 100644 --- a/sample/src/main/java/com/fueled/flowr/sample/HomeFragment.java +++ b/sample/src/main/java/com/fueled/flowr/sample/HomeFragment.java @@ -1,9 +1,12 @@ package com.fueled.flowr.sample; import android.databinding.DataBindingUtil; +import android.os.Build; +import android.support.annotation.NonNull; import android.view.View; import com.fueled.flowr.NavigationIconType; +import com.fueled.flowr.internal.TransitionConfig; import com.fueled.flowr.sample.core.AbstractFragment; import com.fueled.flowr.sample.databinding.FragmentHomeBinding; @@ -25,6 +28,7 @@ protected void setupView(View view) { binding = DataBindingUtil.bind(view); binding.homeOpenViewButton.setOnClickListener(this); binding.homeOpenLinkButton.setOnClickListener(this); + binding.homeOpenTransitionButton.setOnClickListener(this); } @Override @@ -39,10 +43,18 @@ public NavigationIconType getNavigationIconType() { @Override public void onClick(View view) { - if (view.getId() == R.id.home_open_view_button) { - displayViewFragment(); - } else { - displayLinkFragment(); + switch (view.getId()) { + case R.id.home_open_view_button: + displayViewFragment(); + break; + case R.id.home_open_link_button: + displayLinkFragment(); + break; + case R.id.home_open_transition_button: + displayTransitionFragment(); + break; + default: + break; } } @@ -57,4 +69,24 @@ private void displayLinkFragment() { getFlowr().open("/hello") .displayFragment(); } + + private void displayTransitionFragment() { + getFlowr().open("/transition") + .replaceCurrentFragment(true) + .setTransition(getTransitionConfig(), binding.flowrTextView) + .displayFragment(); + } + + @NonNull + private TransitionConfig getTransitionConfig() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + return new TransitionConfig.Builder() + .sharedElementEnter(TransitionConfig.Provider.changeBounds) + .sharedElementExit(TransitionConfig.Provider.changeBounds) + .enter(TransitionConfig.Provider.fade) + .exit(TransitionConfig.Provider.fade) + .build(); + } + return null; + } } diff --git a/sample/src/main/java/com/fueled/flowr/sample/TransitionFragment.java b/sample/src/main/java/com/fueled/flowr/sample/TransitionFragment.java new file mode 100644 index 0000000..66c3b0e --- /dev/null +++ b/sample/src/main/java/com/fueled/flowr/sample/TransitionFragment.java @@ -0,0 +1,36 @@ +package com.fueled.flowr.sample; + +import android.view.View; + +import com.fueled.flowr.NavigationIconType; +import com.fueled.flowr.annotations.DeepLink; +import com.fueled.flowr.sample.core.AbstractFragment; + +/** + * Created by hussein@fueled.com on 18/05/2017. + * Copyright (c) 2017 Fueled. All rights reserved. + */ + +@DeepLink(value = {"/transition"}) +public class TransitionFragment extends AbstractFragment { + + @Override + public int getLayoutId() { + return R.layout.fragment_transition; + } + + @Override + protected void setupView(View view) { + + } + + @Override + public String getTitle() { + return "Transition Fragment"; + } + + @Override + public NavigationIconType getNavigationIconType() { + return NavigationIconType.HAMBURGER; + } +} diff --git a/sample/src/main/res/layout/fragment_home.xml b/sample/src/main/res/layout/fragment_home.xml index 972d672..6883871 100644 --- a/sample/src/main/res/layout/fragment_home.xml +++ b/sample/src/main/res/layout/fragment_home.xml @@ -9,10 +9,22 @@ android:gravity="center" android:orientation="vertical"> + +