mirror of
https://github.com/material-components/material-components-android.git
synced 2026-02-20 08:39:55 +08:00
Update Catalog to use Container Transform transition for navigation
PiperOrigin-RevId: 307096919
This commit is contained in:
parent
57a8ebdcdd
commit
d5faac589b
@ -18,8 +18,11 @@ package io.material.catalog.feature;
|
||||
|
||||
import io.material.catalog.R;
|
||||
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
@ -28,6 +31,9 @@ import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
import com.google.android.material.transition.MaterialContainerTransform;
|
||||
import com.google.android.material.transition.MaterialContainerTransformSharedElementCallback;
|
||||
import dagger.android.AndroidInjection;
|
||||
import dagger.android.AndroidInjector;
|
||||
import dagger.android.DispatchingAndroidInjector;
|
||||
@ -40,6 +46,11 @@ public abstract class DemoActivity extends AppCompatActivity implements HasAndro
|
||||
|
||||
public static final String EXTRA_DEMO_TITLE = "demo_title";
|
||||
|
||||
static final String EXTRA_TRANSITION_NAME = "EXTRA_TRANSITION_NAME";
|
||||
|
||||
private static final long DURATION_ENTER = 300;
|
||||
private static final long DURATION_RETURN = 275;
|
||||
|
||||
private Toolbar toolbar;
|
||||
private ViewGroup demoContainer;
|
||||
|
||||
@ -47,6 +58,15 @@ public abstract class DemoActivity extends AppCompatActivity implements HasAndro
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle bundle) {
|
||||
String transitionName = getIntent().getStringExtra(EXTRA_TRANSITION_NAME);
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && transitionName != null) {
|
||||
findViewById(android.R.id.content).setTransitionName(transitionName);
|
||||
setEnterSharedElementCallback(new MaterialContainerTransformSharedElementCallback());
|
||||
getWindow().setSharedElementEnterTransition(buildContainerTransform(DURATION_ENTER));
|
||||
getWindow().setSharedElementReturnTransition(buildContainerTransform(DURATION_RETURN));
|
||||
}
|
||||
|
||||
safeInject();
|
||||
super.onCreate(bundle);
|
||||
WindowPreferencesManager windowPreferencesManager = new WindowPreferencesManager(this);
|
||||
@ -96,6 +116,17 @@ public abstract class DemoActivity extends AppCompatActivity implements HasAndro
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(VERSION_CODES.LOLLIPOP)
|
||||
private MaterialContainerTransform buildContainerTransform(long duration) {
|
||||
MaterialContainerTransform transform = new MaterialContainerTransform();
|
||||
transform.setDuration(duration);
|
||||
transform.addTarget(android.R.id.content);
|
||||
transform.setContainerColor(
|
||||
MaterialColors.getColor(findViewById(android.R.id.content), R.attr.colorSurface));
|
||||
transform.setFadeMode(MaterialContainerTransform.FADE_MODE_THROUGH);
|
||||
return transform;
|
||||
}
|
||||
|
||||
private void initDemoActionBar() {
|
||||
if (shouldShowDefaultDemoActionBar()) {
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
@ -26,6 +26,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
@ -86,6 +87,12 @@ public abstract class DemoFragment extends Fragment
|
||||
View view =
|
||||
layoutInflater.inflate(R.layout.cat_demo_fragment, viewGroup, false /* attachToRoot */);
|
||||
|
||||
Bundle arguments = getArguments();
|
||||
if (arguments != null) {
|
||||
String transitionName = arguments.getString(FeatureDemoUtils.ARG_TRANSITION_NAME);
|
||||
ViewCompat.setTransitionName(view, transitionName);
|
||||
}
|
||||
|
||||
toolbar = view.findViewById(R.id.toolbar);
|
||||
// show a memory widget on Kitkat
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
|
||||
@ -180,9 +187,12 @@ public abstract class DemoFragment extends Fragment
|
||||
|
||||
private final FragmentActivity activity = getActivity();
|
||||
|
||||
private final Runnable listener = () -> activity.runOnUiThread(() -> {
|
||||
memoryWidget.refreshMemStats(Runtime.getRuntime());
|
||||
});
|
||||
private final Runnable listener =
|
||||
() ->
|
||||
activity.runOnUiThread(
|
||||
() -> {
|
||||
memoryWidget.refreshMemStats(Runtime.getRuntime());
|
||||
});
|
||||
|
||||
private boolean memoryWidgetShown;
|
||||
|
||||
|
||||
@ -18,10 +18,13 @@ package io.material.catalog.feature;
|
||||
|
||||
import io.material.catalog.R;
|
||||
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.ArrayRes;
|
||||
import androidx.annotation.ColorInt;
|
||||
@ -29,8 +32,10 @@ import androidx.annotation.DimenRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.core.view.MarginLayoutParamsCompat;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.view.LayoutInflater;
|
||||
@ -42,6 +47,7 @@ import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.MarginLayoutParams;
|
||||
import android.widget.TextView;
|
||||
import com.google.android.material.resources.MaterialResources;
|
||||
import com.google.android.material.transition.MaterialContainerTransformSharedElementCallback;
|
||||
import dagger.android.support.DaggerFragment;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -68,6 +74,12 @@ public abstract class DemoLandingFragment extends DaggerFragment {
|
||||
layoutInflater.inflate(
|
||||
R.layout.cat_demo_landing_fragment, viewGroup, false /* attachToRoot */);
|
||||
|
||||
Bundle arguments = getArguments();
|
||||
if (arguments != null) {
|
||||
String transitionName = arguments.getString(FeatureDemoUtils.ARG_TRANSITION_NAME);
|
||||
ViewCompat.setTransitionName(view, transitionName);
|
||||
}
|
||||
|
||||
Toolbar toolbar = view.findViewById(R.id.toolbar);
|
||||
|
||||
AppCompatActivity activity = (AppCompatActivity) getActivity();
|
||||
@ -145,7 +157,9 @@ public abstract class DemoLandingFragment extends DaggerFragment {
|
||||
TextView titleTextView = demoView.findViewById(R.id.cat_demo_landing_row_title);
|
||||
TextView subtitleTextView = demoView.findViewById(R.id.cat_demo_landing_row_subtitle);
|
||||
|
||||
rootView.setOnClickListener(v -> startDemo(demo));
|
||||
String transitionName = getString(demo.getTitleResId());
|
||||
ViewCompat.setTransitionName(rootView, transitionName);
|
||||
rootView.setOnClickListener(v -> startDemo(v, demo, transitionName));
|
||||
|
||||
titleTextView.setText(demo.getTitleResId());
|
||||
subtitleTextView.setText(getDemoClassName(demo));
|
||||
@ -169,26 +183,41 @@ public abstract class DemoLandingFragment extends DaggerFragment {
|
||||
}
|
||||
}
|
||||
|
||||
private void startDemo(Demo demo) {
|
||||
private void startDemo(View sharedElement, Demo demo, String transitionName) {
|
||||
if (demo.createFragment() != null) {
|
||||
startDemoFragment(demo.createFragment());
|
||||
startDemoFragment(sharedElement, demo.createFragment(), transitionName);
|
||||
} else if (demo.createActivityIntent() != null) {
|
||||
startDemoActivity(demo.createActivityIntent());
|
||||
startDemoActivity(sharedElement, demo.createActivityIntent(), transitionName);
|
||||
} else {
|
||||
throw new IllegalStateException("Demo must implement createFragment or createActivityIntent");
|
||||
}
|
||||
}
|
||||
|
||||
private void startDemoFragment(Fragment fragment) {
|
||||
private void startDemoFragment(View sharedElement, Fragment fragment, String transitionName) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(DemoFragment.ARG_DEMO_TITLE, getString(getTitleResId()));
|
||||
args.putString(FeatureDemoUtils.ARG_TRANSITION_NAME, transitionName);
|
||||
fragment.setArguments(args);
|
||||
FeatureDemoUtils.startFragment(getActivity(), fragment, FRAGMENT_DEMO_CONTENT);
|
||||
FeatureDemoUtils.startFragment(
|
||||
getActivity(), fragment, FRAGMENT_DEMO_CONTENT, sharedElement, transitionName);
|
||||
}
|
||||
|
||||
private void startDemoActivity(Intent intent) {
|
||||
private void startDemoActivity(View sharedElement, Intent intent, String transitionName) {
|
||||
intent.putExtra(DemoActivity.EXTRA_DEMO_TITLE, getString(getTitleResId()));
|
||||
startActivity(intent);
|
||||
intent.putExtra(DemoActivity.EXTRA_TRANSITION_NAME, transitionName);
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
||||
// Set up shared element transition and disable overlay so views don't show above system bars
|
||||
FragmentActivity activity = getActivity();
|
||||
activity.setExitSharedElementCallback(new MaterialContainerTransformSharedElementCallback());
|
||||
activity.getWindow().setSharedElementsUseOverlay(false);
|
||||
|
||||
ActivityOptions options =
|
||||
ActivityOptions.makeSceneTransitionAnimation(activity, sharedElement, transitionName);
|
||||
startActivity(intent, options.toBundle());
|
||||
} else {
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void setMarginStart(View view, @DimenRes int marginResId) {
|
||||
@ -231,9 +260,9 @@ public abstract class DemoLandingFragment extends DaggerFragment {
|
||||
/**
|
||||
* Whether or not the feature shown by this fragment should be flagged as restricted.
|
||||
*
|
||||
* Examples of restricted feature could be features which depends on an API level that is
|
||||
* greater than MDCs min sdk version. If overriding this method, you should also override
|
||||
* {@link #getRestrictedMessageId()} and provide information about why the feature is restricted.
|
||||
* <p>Examples of restricted feature could be features which depends on an API level that is
|
||||
* greater than MDCs min sdk version. If overriding this method, you should also override {@link
|
||||
* #getRestrictedMessageId()} and provide information about why the feature is restricted.
|
||||
*/
|
||||
public boolean isRestricted() {
|
||||
return false;
|
||||
@ -242,10 +271,10 @@ public abstract class DemoLandingFragment extends DaggerFragment {
|
||||
/**
|
||||
* The message to display if a feature {@link #isRestricted()}.
|
||||
*
|
||||
* This message should provide insight into why the feature is restricted for the device it
|
||||
* is running on. This message will be displayed in the description area of the demo fragment
|
||||
* instead of the the provided {@link #getDescriptionResId()}. Additionally, all demos, both the
|
||||
* main demo and any additional demos will not be shown.
|
||||
* <p>This message should provide insight into why the feature is restricted for the device it is
|
||||
* running on. This message will be displayed in the description area of the demo fragment instead
|
||||
* of the the provided {@link #getDescriptionResId()}. Additionally, all demos, both the main demo
|
||||
* and any additional demos will not be shown.
|
||||
*/
|
||||
@StringRes
|
||||
public int getRestrictedMessageId() {
|
||||
|
||||
@ -20,25 +20,76 @@ import io.material.catalog.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import android.view.View;
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
import com.google.android.material.transition.Hold;
|
||||
import com.google.android.material.transition.MaterialContainerTransform;
|
||||
|
||||
/** Utils for feature demos. */
|
||||
public abstract class FeatureDemoUtils {
|
||||
|
||||
static final String ARG_TRANSITION_NAME = "ARG_TRANSITION_NAME";
|
||||
|
||||
private static final int MAIN_ACTIVITY_FRAGMENT_CONTAINER_ID = R.id.container;
|
||||
private static final String DEFAULT_CATALOG_DEMO = "default_catalog_demo";
|
||||
|
||||
public static void startFragment(FragmentActivity activity, Fragment fragment, String tag) {
|
||||
activity
|
||||
.getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.setCustomAnimations(
|
||||
R.anim.abc_grow_fade_in_from_bottom,
|
||||
R.anim.abc_fade_out,
|
||||
R.anim.abc_fade_in,
|
||||
R.anim.abc_shrink_fade_out_from_bottom)
|
||||
startFragmentInternal(activity, fragment, tag, null, null);
|
||||
}
|
||||
|
||||
public static void startFragment(
|
||||
FragmentActivity activity,
|
||||
Fragment fragment,
|
||||
String tag,
|
||||
View sharedElement,
|
||||
String sharedElementName) {
|
||||
startFragmentInternal(activity, fragment, tag, sharedElement, sharedElementName);
|
||||
}
|
||||
|
||||
public static void startFragmentInternal(
|
||||
FragmentActivity activity,
|
||||
Fragment fragment,
|
||||
String tag,
|
||||
@Nullable View sharedElement,
|
||||
@Nullable String sharedElementName) {
|
||||
FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP
|
||||
&& sharedElement != null
|
||||
&& sharedElementName != null) {
|
||||
Fragment currentFragment = getCurrentFragment(activity);
|
||||
currentFragment.setExitTransition(new Hold());
|
||||
|
||||
MaterialContainerTransform transform = new MaterialContainerTransform();
|
||||
transform.setContainerColor(MaterialColors.getColor(sharedElement, R.attr.colorSurface));
|
||||
transform.setFadeMode(MaterialContainerTransform.FADE_MODE_THROUGH);
|
||||
fragment.setSharedElementEnterTransition(transform);
|
||||
transaction.addSharedElement(sharedElement, sharedElementName);
|
||||
|
||||
if (fragment.getArguments() == null) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ARG_TRANSITION_NAME, sharedElementName);
|
||||
fragment.setArguments(args);
|
||||
} else {
|
||||
fragment.getArguments().putString(ARG_TRANSITION_NAME, sharedElementName);
|
||||
}
|
||||
} else {
|
||||
transaction.setCustomAnimations(
|
||||
R.anim.abc_grow_fade_in_from_bottom,
|
||||
R.anim.abc_fade_out,
|
||||
R.anim.abc_fade_in,
|
||||
R.anim.abc_shrink_fade_out_from_bottom);
|
||||
}
|
||||
|
||||
transaction
|
||||
.replace(MAIN_ACTIVITY_FRAGMENT_CONTAINER_ID, fragment, tag)
|
||||
.addToBackStack(null /* name */)
|
||||
.commit();
|
||||
|
||||
@ -19,6 +19,7 @@ package io.material.catalog.tableofcontents;
|
||||
import io.material.catalog.R;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -40,6 +41,7 @@ class TocViewHolder extends ViewHolder {
|
||||
|
||||
private FragmentActivity activity;
|
||||
private FeatureDemo featureDemo;
|
||||
private String transitionName;
|
||||
|
||||
TocViewHolder(FragmentActivity activity, ViewGroup viewGroup) {
|
||||
super(
|
||||
@ -54,7 +56,9 @@ class TocViewHolder extends ViewHolder {
|
||||
void bind(FragmentActivity activity, FeatureDemo featureDemo) {
|
||||
this.activity = activity;
|
||||
this.featureDemo = featureDemo;
|
||||
this.transitionName = activity.getString(featureDemo.getTitleResId());
|
||||
|
||||
ViewCompat.setTransitionName(itemView, transitionName);
|
||||
titleView.setText(featureDemo.getTitleResId());
|
||||
imageView.setImageResource(featureDemo.getDrawableResId());
|
||||
itemView.setOnClickListener(clickListener);
|
||||
@ -63,5 +67,7 @@ class TocViewHolder extends ViewHolder {
|
||||
}
|
||||
|
||||
private final OnClickListener clickListener =
|
||||
v -> FeatureDemoUtils.startFragment(activity, featureDemo.createFragment(), FRAGMENT_CONTENT);
|
||||
v ->
|
||||
FeatureDemoUtils.startFragment(
|
||||
activity, featureDemo.createFragment(), FRAGMENT_CONTENT, v, transitionName);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user