Added Transitions and minor code clean up

Added support for the DetailView Activity
transition. The DetailView can now be started
from the launcher or the Cards example.

Added support for Browse entrance transition.

Minor code clean up such as renaming
GridExample fragment to GridExampleFragment
and removing unused methods.

Change-Id: Ib1c11af82be5b858960e243acd7f11ce8dbd06f7
This commit is contained in:
Robert Hahn
2015-08-18 11:46:53 -07:00
committed by Dake Gu
parent 2faa311941
commit e6b72719a8
16 changed files with 95 additions and 55 deletions

View File

@@ -41,10 +41,10 @@
android:theme="@style/Theme.Example.LeanbackDialog"></activity>
<activity
android:name=".app.details.DetailViewExampleActivity"
android:theme="@style/Theme.Example.LeanbackDetailView"></activity>
android:theme="@style/Theme.Example.LeanbackDetails"></activity>
<activity
android:name=".app.cards.CardExampleActivity"
android:theme="@style/Theme.Example.Leanback"></activity>
android:theme="@style/Theme.Example.LeanbackBrowse"></activity>
<activity
android:name=".app.grid.GridExampleActivity"
android:theme="@style/Theme.Example.Leanback"></activity>

View File

@@ -164,8 +164,7 @@ public class MainFragment extends BrowseFragment {
break;
}
if (intent != null) {
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
((ImageCardView) itemViewHolder.view).getMainImageView(), "transition")
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity())
.toBundle();
startActivity(intent, bundle);
}

View File

@@ -14,21 +14,32 @@
package android.support.v17.leanback.supportleanbackshowcase.app.cards;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v17.leanback.app.BrowseFragment;
import android.support.v17.leanback.supportleanbackshowcase.utils.CardListRow;
import android.support.v17.leanback.supportleanbackshowcase.R;
import android.support.v17.leanback.supportleanbackshowcase.app.details.DetailViewExampleActivity;
import android.support.v17.leanback.supportleanbackshowcase.app.details.DetailViewExampleFragment;
import android.support.v17.leanback.supportleanbackshowcase.app.details.ShadowRowPresenterSelector;
import android.support.v17.leanback.supportleanbackshowcase.utils.Utils;
import android.support.v17.leanback.supportleanbackshowcase.cards.presenters.CardPresenterSelector;
import android.support.v17.leanback.supportleanbackshowcase.models.Card;
import android.support.v17.leanback.supportleanbackshowcase.models.CardRow;
import android.support.v17.leanback.supportleanbackshowcase.cards.presenters.CardPresenterSelector;
import android.support.v17.leanback.supportleanbackshowcase.utils.CardListRow;
import android.support.v17.leanback.supportleanbackshowcase.utils.Utils;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.HeaderItem;
import android.support.v17.leanback.widget.ImageCardView;
import android.support.v17.leanback.widget.ListRow;
import android.support.v17.leanback.widget.OnItemViewClickedListener;
import android.support.v17.leanback.widget.Presenter;
import android.support.v17.leanback.widget.PresenterSelector;
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.RowPresenter;
import android.support.v17.leanback.widget.SearchOrbView;
import android.support.v4.app.ActivityOptionsCompat;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import com.google.gson.Gson;
@@ -52,22 +63,50 @@ public class CardExampleFragment extends BrowseFragment {
setHeadersTransitionOnBackEnabled(true);
setSearchAffordanceColors(
new SearchOrbView.Colors(getResources().getColor(R.color.search_color),
getResources().getColor(R.color.search_bright_color),
getResources().getColor(R.color.search_icon_color)));
getResources().getColor(R.color.search_bright_color),
getResources().getColor(R.color.search_icon_color)));
setBrandColor(getResources().getColor(R.color.fastlane_background));
setTitle(getString(R.string.card_examples_title));
setOnSearchClickedListener(new View.OnClickListener() {
@Override public void onClick(View v) {
@Override
public void onClick(View v) {
Toast.makeText(getActivity(), getString(R.string.implement_search),
Toast.LENGTH_LONG).show();
Toast.LENGTH_LONG).show();
}
});
setOnItemViewClickedListener(new OnItemViewClickedListener() {
@Override
public void onItemClicked(Presenter.ViewHolder viewHolder, Object item, RowPresenter.ViewHolder viewHolder1, Row row) {
if (!(item instanceof Card)) return;
if (!(viewHolder.view instanceof ImageCardView)) return;
ImageView imageView = ((ImageCardView) viewHolder.view).getMainImageView();
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
imageView, DetailViewExampleFragment.TRANSITION_NAME).toBundle();
Intent intent = new Intent(getActivity().getBaseContext(),
DetailViewExampleActivity.class);
Card card = (Card) item;
int imageResId = card.getLocalImageResourceId(getContext());
intent.putExtra(DetailViewExampleFragment.EXTRA_CARD, imageResId);
startActivity(intent, bundle);
}
});
prepareEntranceTransition();
}
private void setupRowAdapter() {
mRowsAdapter = new ArrayObjectAdapter(new ShadowRowPresenterSelector());
createRows();
setAdapter(mRowsAdapter);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
createRows();
startEntranceTransition();
}
}, 500);
}
private void createRows() {

View File

@@ -14,7 +14,10 @@
package android.support.v17.leanback.supportleanbackshowcase.app.details;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.support.v17.leanback.app.DetailsFragment;
import android.support.v17.leanback.supportleanbackshowcase.models.DetailedCard;
import android.support.v17.leanback.supportleanbackshowcase.R;
@@ -27,6 +30,7 @@ import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.ClassPresenterSelector;
import android.support.v17.leanback.widget.DetailsOverviewRow;
import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
import android.support.v17.leanback.widget.FullWidthDetailsOverviewSharedElementHelper;
import android.support.v17.leanback.widget.HeaderItem;
import android.support.v17.leanback.widget.ListRow;
import android.support.v17.leanback.widget.ListRowPresenter;
@@ -47,11 +51,14 @@ import com.google.gson.Gson;
public class DetailViewExampleFragment extends DetailsFragment implements OnItemViewClickedListener,
OnItemViewSelectedListener {
public static final String TRANSITION_NAME = "t_for_transition";
public static final String EXTRA_CARD = "card";
private ArrayObjectAdapter mRowsAdapter;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupUi();
setupEventListeners();
}
@@ -85,6 +92,13 @@ public class DetailViewExampleFragment extends DetailsFragment implements OnItem
return viewHolder;
}
};
FullWidthDetailsOverviewSharedElementHelper mHelper = new FullWidthDetailsOverviewSharedElementHelper();
mHelper.setSharedElementEnterTransition(getActivity(), TRANSITION_NAME);
rowPresenter.setListener(mHelper);
rowPresenter.setParticipatingEntranceTransition(false);
prepareEntranceTransition();
ListRowPresenter shadowDisabledRowPresenter = new ListRowPresenter();
shadowDisabledRowPresenter.setShadowEnabled(false);
@@ -98,6 +112,11 @@ public class DetailViewExampleFragment extends DetailsFragment implements OnItem
// Setup action and detail row.
DetailsOverviewRow detailsOverview = new DetailsOverviewRow(data);
int imageResId = data.getLocalImageResourceId(getActivity());
Bundle extras = getActivity().getIntent().getExtras();
if (extras != null && extras.containsKey(EXTRA_CARD)) {
imageResId = extras.getInt(EXTRA_CARD, imageResId);
}
detailsOverview.setImageDrawable(getResources().getDrawable(imageResId, null));
ArrayObjectAdapter actionAdapter = new ArrayObjectAdapter();
actionAdapter.add(new Action(1, getString(R.string.action_buy) + data.getPrice()));
@@ -120,6 +139,12 @@ public class DetailViewExampleFragment extends DetailsFragment implements OnItem
mRowsAdapter.add(new ListRow(header, listRowAdapter));
setAdapter(mRowsAdapter);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startEntranceTransition();
}
}, 500);
}
private void setupEventListeners() {

View File

@@ -30,7 +30,7 @@ import com.google.gson.Gson;
/**
* An example how to use leanback's {@link VerticalGridFragment}.
*/
public class GridExample extends VerticalGridFragment {
public class GridExampleFragment extends VerticalGridFragment {
private static final int COLUMNS = 4;
private static final int ZOOM_FACTOR = FocusHighlight.ZOOM_FACTOR_MEDIUM;

View File

@@ -52,6 +52,7 @@ public class WizardExample1stStepFragment extends WizardExampleBaseStepFragment
GuidedAction action = new GuidedAction.Builder()
.id(ACTION_ID_BUY_HD)
.title(getString(R.string.wizard_example_rent_hd))
.editable(false)
.description(mMovie.getPriceHd() + " " +
getString(R.string.wizard_example_watch_hd))
.build();
@@ -59,6 +60,7 @@ public class WizardExample1stStepFragment extends WizardExampleBaseStepFragment
action = new GuidedAction.Builder()
.id(ACTION_ID_BUY_SD)
.title(getString(R.string.wizard_example_rent_sd))
.editable(false)
.description(mMovie.getPriceSd() + " " +
getString(R.string.wizard_example_watch_sd))
.build();

View File

@@ -58,6 +58,7 @@ public class WizardExample2ndStepFragment extends WizardExampleBaseStepFragment
getString(R.string.wizard_example_rental_period),
mMovie.getBreadcrump(), null);
return guidance;
}
@Override
@@ -68,12 +69,14 @@ public class WizardExample2ndStepFragment extends WizardExampleBaseStepFragment
.id(ACTION_ID_CONFIRM)
.title(getString(R.string.wizard_example_rent))
.description(rentHighDefinition ? mMovie.getPriceHd() : mMovie.getPriceSd())
.editable(false)
.build();
actions.add(action);
action = new GuidedAction.Builder()
.id(ACTION_ID_PAYMENT_METHOD)
.title(getString(R.string.wizard_example_payment_method))
.description(getString(R.string.wizard_example_visa_balance))
.editable(false)
.build();
actions.add(action);
}

View File

@@ -52,11 +52,13 @@ public class WizardExample4thStepFragment extends WizardExampleBaseStepFragment
public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
GuidedAction action = new GuidedAction.Builder()
.id(ACTION_ID_WATCH)
.editable(false)
.title(getString(R.string.wizard_example_watch_now))
.build();
actions.add(action);
action = new GuidedAction.Builder()
.id(ACTION_ID_LATER)
.editable(false)
.title(getString(R.string.wizard_example_later))
.build();
actions.add(action);

View File

@@ -47,6 +47,7 @@ public class CharacterCardView extends BaseCardView {
}
});
setFocusable(true);
setBackground(null);
}
public void updateUi(Card card) {

View File

@@ -16,16 +16,10 @@ package android.support.v17.leanback.supportleanbackshowcase.utils;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.RequestCreator;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
/**
* A collection of utility methods, all static.
@@ -55,37 +49,6 @@ public class Utils {
}
}
/**
* The method uses {@link Picasso} to fetch an image from a given url, resize it (if required)
* and display it inside an {@link ImageView}.
*
* @param context Context which is used to create a {@link Picasso} instance.
* @param uri The {@link URI} to fetch the image from.
* @param target The {@link ImageView} which shall display the image.
* @param resizeWidthInDp The target width of the image. Pass <code>-1</code> if you don't want
* to resize the image.
* @param resizeHeightInDp The target height of the image. Pass <code>-1</code> if you don't
* want to resize the image.
* @param centerCrop Centers and scales an image to fit the requested bounds.
* @param errorDrawable A drawable which will be shown in case the image could not be fetched
* from the server.
* @see {@link Picasso#with(Context)}
* @see {@link RequestCreator#resize(int, int)}
* @see {@link RequestCreator#centerCrop()}
* @see {@link RequestCreator#error(Drawable)}
*/
public static void loadImageFromUri(Context context, URI uri, ImageView target,
int resizeWidthInDp, int resizeHeightInDp,
boolean centerCrop, Drawable errorDrawable) {
if (uri == null) return;
RequestCreator builder = Picasso.with(context).load(uri.toString());
if (resizeHeightInDp != -1 && resizeWidthInDp != -1)
builder.resize(Utils.convertDpToPixel(context, resizeWidthInDp),
Utils.convertDpToPixel(context, resizeHeightInDp));
if (centerCrop) builder.centerCrop();
builder.error(errorDrawable).into(target);
}
public static Uri getResourceUri(Context context, int resID) {
return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
context.getResources().getResourcePackageName(resID) + '/' +

View File

@@ -17,6 +17,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@color/card_examples_background"
android:transitionGroup="false"
android:layout_height="match_parent">
<fragment

View File

@@ -17,6 +17,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@drawable/background_canyon"
android:transitionGroup="false"
android:layout_height="match_parent">
<fragment
android:id="@+id/detailsFragment"

View File

@@ -21,7 +21,7 @@
<fragment
android:id="@+id/cardsFragment"
android:name="android.support.v17.leanback.supportleanbackshowcase.app.grid.GridExample"
android:name="android.support.v17.leanback.supportleanbackshowcase.app.grid.GridExampleFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"></fragment>
</RelativeLayout>

View File

@@ -18,6 +18,7 @@
xmlns:lb="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
lb:cardBackground="@null"
lb:layout_viewType="main">
<LinearLayout

View File

@@ -155,7 +155,7 @@
</style>
<style name="IconCardStyle" parent="DefaultCardStyle">
<item name="android:background">@null</item>
<item name="cardBackground">@null</item>
<item name="android:layout_width">96dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="lbImageCardViewTitleStyle">@style/IconCardTitleStyle</item>

View File

@@ -32,6 +32,9 @@
<item name="browseRowsMarginTop">275dp</item>
</style>
<style name="Theme.Example.LeanbackBrowse" parent="Theme.Leanback.Browse">
</style>
<style name="Theme.Example.LeanbackWizard" parent="Theme.Leanback.GuidedStep">
<item name="guidedActionsContainerStyle">@style/WizardActionsContainerStyle</item>
</style>
@@ -48,7 +51,7 @@
<item name="android:colorPrimary">@color/settings_background</item>
</style>
<style name="Theme.Example.LeanbackDetailView" parent="Theme.Leanback">
<style name="Theme.Example.LeanbackDetails" parent="Theme.Leanback.Details">
<item name="android:colorPrimary">@color/detail_view_actionbar_background</item>
</style>
</resources>