Skip to content

Commit 0f15b63

Browse files
committed
[wBasis][feat]Add activity scene transition sample
1 parent 8ab609f commit 0f15b63

14 files changed

+696
-3
lines changed

app-catalog/app/proguard-rules.pro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@
4949
-dontwarn org.joda.time.format.DateTimeFormat
5050
-dontwarn org.joda.time.format.DateTimeFormatter
5151
-dontwarn springfox.documentation.spring.web.json.Json
52+
53+
-dontwarn com.squareup.okhttp.Cache
54+
-dontwarn com.squareup.okhttp.OkHttpClient
55+
-dontwarn com.squareup.okhttp.OkUrlFactory

app-catalog/samples/wBasis/build.gradle

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ dependencies {
5555
implementation libs.androidx.lifecycle.runtime.ktx
5656
implementation libs.androidx.ui.graphics
5757
implementation libs.compose.ui.tooling.preview
58-
androidTestImplementation libs.compose.ui.test.junit4
59-
debugImplementation libs.compose.ui.tooling
60-
debugImplementation libs.compose.ui.test.manifest
58+
59+
implementation 'com.squareup.picasso:picasso:2.4.0'
6160
}

app-catalog/samples/wBasis/src/main/AndroidManifest.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,16 @@
377377
android:name=".transition.CustomTransitionActivity"
378378
android:exported="true"
379379
android:theme="@style/Theme.AppCompat.DayNight" />
380+
381+
<activity
382+
android:name=".transition.SceneTransitionBasicMainActivity"
383+
android:exported="true"
384+
android:theme="@style/Scene_Activity_AppTheme" />
385+
386+
<activity
387+
android:name=".transition.SceneTransitionBasicDetailActivity"
388+
android:exported="true"
389+
android:theme="@style/Scene_Activity_AppTheme" />
380390
</application>
381391

382392
</manifest>
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright 2023-2025 wintmain
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.wintmain.wBasis.transition;
18+
19+
import android.os.Build;
20+
import android.os.Bundle;
21+
import android.transition.Transition;
22+
import android.widget.ImageView;
23+
import android.widget.TextView;
24+
import androidx.annotation.RequiresApi;
25+
import androidx.appcompat.app.AppCompatActivity;
26+
import androidx.core.view.ViewCompat;
27+
import com.squareup.picasso.Picasso;
28+
import com.wintmain.wBasis.R;
29+
import com.wintmain.wBasis.transition.util.SceneTransitionBasicItem;
30+
31+
/**
32+
* Our secondary Activity which is launched from {@link SceneTransitionBasicMainActivity}.
33+
* Has a simple detail UI which has a large banner image, title and body text.
34+
*/
35+
public class SceneTransitionBasicDetailActivity extends AppCompatActivity {
36+
37+
// Extra name for the ID parameter
38+
public static final String EXTRA_PARAM_ID = "detail:_id";
39+
40+
// View name of the header image. Used for activity scene transitions
41+
public static final String VIEW_NAME_HEADER_IMAGE = "detail:header:image";
42+
43+
// View name of the header title. Used for activity scene transitions
44+
public static final String VIEW_NAME_HEADER_TITLE = "detail:header:title";
45+
46+
private ImageView mHeaderImageView;
47+
private TextView mHeaderTitle;
48+
49+
private SceneTransitionBasicItem mSceneTransitionBasicItem;
50+
51+
@Override
52+
protected void onCreate(Bundle savedInstanceState) {
53+
super.onCreate(savedInstanceState);
54+
setContentView(R.layout.activity_scene_transition_basic_details);
55+
56+
// Retrieve the correct Item instance, using the ID provided in the Intent
57+
mSceneTransitionBasicItem = SceneTransitionBasicItem.getItem(
58+
getIntent().getIntExtra(EXTRA_PARAM_ID, 0));
59+
60+
mHeaderImageView = findViewById(R.id.imageview_header);
61+
mHeaderTitle = findViewById(R.id.textview_title);
62+
63+
// BEGIN_INCLUDE(detail_set_view_name)
64+
/*
65+
* Set the name of the view's which will be transition to, using the static values above.
66+
* This could be done in the layout XML, but exposing it via static variables allows easy
67+
* querying from other Activities
68+
*/
69+
ViewCompat.setTransitionName(mHeaderImageView, VIEW_NAME_HEADER_IMAGE);
70+
ViewCompat.setTransitionName(mHeaderTitle, VIEW_NAME_HEADER_TITLE);
71+
// END_INCLUDE(detail_set_view_name)
72+
73+
loadItem();
74+
}
75+
76+
private void loadItem() {
77+
// Set the title TextView to the item's name and author
78+
mHeaderTitle.setText(getString(R.string.image_header, mSceneTransitionBasicItem.getName(),
79+
mSceneTransitionBasicItem.getAuthor()));
80+
81+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && addTransitionListener()) {
82+
// If we're running on Lollipop and we have added a listener to the shared element
83+
// transition, load the thumbnail. The listener will load the full-size image when
84+
// the transition is complete.
85+
loadThumbnail();
86+
} else {
87+
// If all other cases we should just load the full-size image now
88+
loadFullSizeImage();
89+
}
90+
}
91+
92+
/**
93+
* Load the item's thumbnail image into our {@link ImageView}.
94+
*/
95+
private void loadThumbnail() {
96+
Picasso.with(mHeaderImageView.getContext())
97+
.load(mSceneTransitionBasicItem.getThumbnailUrl())
98+
.noFade()
99+
.into(mHeaderImageView);
100+
}
101+
102+
/**
103+
* Load the item's full-size image into our {@link ImageView}.
104+
*/
105+
private void loadFullSizeImage() {
106+
Picasso.with(mHeaderImageView.getContext())
107+
.load(mSceneTransitionBasicItem.getPhotoUrl())
108+
.noFade()
109+
.noPlaceholder()
110+
.into(mHeaderImageView);
111+
}
112+
113+
/**
114+
* Try and add a {@link Transition.TransitionListener} to the entering shared element
115+
* {@link Transition}. We do this so that we can load the full-size image after the transition
116+
* has completed.
117+
*
118+
* @return true if we were successful in adding a listener to the enter transition
119+
*/
120+
@RequiresApi(21)
121+
private boolean addTransitionListener() {
122+
final Transition transition = getWindow().getSharedElementEnterTransition();
123+
124+
if (transition != null) {
125+
// There is an entering shared element transition so add a listener to it
126+
transition.addListener(new Transition.TransitionListener() {
127+
@Override
128+
public void onTransitionEnd(Transition transition) {
129+
// As the transition has ended, we can now load the full-size image
130+
loadFullSizeImage();
131+
132+
// Make sure we remove ourselves as a listener
133+
transition.removeListener(this);
134+
}
135+
136+
@Override
137+
public void onTransitionStart(Transition transition) {
138+
// No-op
139+
}
140+
141+
@Override
142+
public void onTransitionCancel(Transition transition) {
143+
// Make sure we remove ourselves as a listener
144+
transition.removeListener(this);
145+
}
146+
147+
@Override
148+
public void onTransitionPause(Transition transition) {
149+
// No-op
150+
}
151+
152+
@Override
153+
public void onTransitionResume(Transition transition) {
154+
// No-op
155+
}
156+
});
157+
return true;
158+
}
159+
160+
// If we reach here then we have not added a listener
161+
return false;
162+
}
163+
164+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright 2023-2025 wintmain
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.wintmain.wBasis.transition;
18+
19+
import android.content.Intent;
20+
import android.os.Bundle;
21+
import android.view.View;
22+
import android.view.ViewGroup;
23+
import android.widget.*;
24+
import androidx.annotation.Nullable;
25+
import androidx.appcompat.app.AppCompatActivity;
26+
import androidx.core.app.ActivityCompat;
27+
import androidx.core.app.ActivityOptionsCompat;
28+
import androidx.core.util.Pair;
29+
import com.google.android.catalog.framework.annotations.Sample;
30+
import com.squareup.picasso.Picasso;
31+
import com.wintmain.wBasis.R;
32+
import com.wintmain.wBasis.transition.util.SceneTransitionBasicItem;
33+
34+
/**
35+
* Displays a grid of items which an image and title.
36+
* When the user clicks on an item, {@link SceneTransitionBasicDetailActivity} is launched,
37+
* using the Activity Scene Transitions framework to animatedly do so.
38+
*/
39+
@Sample(name = "ActivitySceneTransitionBaic",
40+
description = "Activity Scene的变化",
41+
tags = {"android-samples", "animation-samples"}
42+
)
43+
public class SceneTransitionBasicMainActivity extends AppCompatActivity {
44+
45+
private final AdapterView.OnItemClickListener mOnItemClickListener
46+
= new AdapterView.OnItemClickListener() {
47+
48+
/**
49+
* Called when an item in the {@link android.widget.GridView} is clicked. Here will launch
50+
* the {@link SceneTransitionBasicDetailActivity}, using the Scene Transition animation
51+
* functionality.
52+
*/
53+
@Override
54+
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
55+
SceneTransitionBasicItem sceneTransitionBasicItem =
56+
(SceneTransitionBasicItem) adapterView.getItemAtPosition(position);
57+
58+
// Construct an Intent as normal
59+
Intent intent = new Intent(SceneTransitionBasicMainActivity.this,
60+
SceneTransitionBasicDetailActivity.class);
61+
intent.putExtra(SceneTransitionBasicDetailActivity.EXTRA_PARAM_ID,
62+
sceneTransitionBasicItem.getId());
63+
64+
// BEGIN_INCLUDE(start_activity)
65+
/*
66+
* Now create an {@link android.app.ActivityOptions} instance using the
67+
* {@link ActivityOptionsCompat#makeSceneTransitionAnimation(Activity, Pair[])} factory
68+
* method.
69+
*/
70+
@SuppressWarnings("unchecked")
71+
ActivityOptionsCompat activityOptions =
72+
ActivityOptionsCompat.makeSceneTransitionAnimation(
73+
SceneTransitionBasicMainActivity.this,
74+
75+
// Now we provide a list of Pair items which contain the view we can
76+
// transitioning from, and the name of the view it is transitioning to,
77+
// in the launched activity
78+
new Pair<>(view.findViewById(R.id.imageview_item),
79+
SceneTransitionBasicDetailActivity.VIEW_NAME_HEADER_IMAGE),
80+
new Pair<>(view.findViewById(R.id.textview_name),
81+
SceneTransitionBasicDetailActivity.VIEW_NAME_HEADER_TITLE));
82+
83+
// Now we can start the Activity, providing the activity options as a bundle
84+
ActivityCompat.startActivity(SceneTransitionBasicMainActivity.this, intent,
85+
activityOptions.toBundle());
86+
// END_INCLUDE(start_activity)
87+
}
88+
};
89+
90+
/**
91+
* {@link android.widget.BaseAdapter} which displays items.
92+
*/
93+
private class GridAdapter extends BaseAdapter {
94+
95+
@Override
96+
public int getCount() {
97+
return SceneTransitionBasicItem.SceneTransitionBasicITEMS.length;
98+
}
99+
100+
@Override
101+
public SceneTransitionBasicItem getItem(int position) {
102+
return SceneTransitionBasicItem.SceneTransitionBasicITEMS[position];
103+
}
104+
105+
@Override
106+
public long getItemId(int position) {
107+
return getItem(position).getId();
108+
}
109+
110+
@Override
111+
public View getView(int position, View view, ViewGroup viewGroup) {
112+
if (view == null) {
113+
view = getLayoutInflater().inflate(R.layout.activity_scene_transition_basic_grid_item, viewGroup, false);
114+
}
115+
116+
final SceneTransitionBasicItem item = getItem(position);
117+
118+
// Load the thumbnail image
119+
ImageView image = (ImageView) view.findViewById(R.id.imageview_item);
120+
Picasso.with(image.getContext()).load(item.getThumbnailUrl()).into(image);
121+
122+
// Set the TextView's contents
123+
TextView name = (TextView) view.findViewById(R.id.textview_name);
124+
name.setText(item.getName());
125+
126+
return view;
127+
}
128+
}
129+
130+
@Override
131+
protected void onCreate(@Nullable Bundle savedInstanceState) {
132+
super.onCreate(savedInstanceState);
133+
setContentView(R.layout.activity_scene_transition_basic_grid);
134+
135+
GridView gridView = findViewById(R.id.grid);
136+
gridView.setOnItemClickListener(mOnItemClickListener);
137+
138+
// 没有adapter,页面是空白的
139+
GridAdapter mAdapter = new GridAdapter();
140+
gridView.setAdapter(mAdapter);
141+
}
142+
}

0 commit comments

Comments
 (0)