Android - 如何创建从列表视图中的项目到整个项目的过渡 activity?
Android - How to create a transition from an item in listview to a whole activity?
我想要的是,当用户单击 ListView 中的列表项时,它会转换为一个整体 activity(如您在以下示例中所见),但我无法找到解释这个的教程,实际上,我不知道这个运动是怎么叫的。
也就是说,我要实现的是:
单击时增加列表项的高度(如右侧 gif 所示)
展开列表项并将其转换为下一个 fragment/activity 布局,其中包含有关所单击项目的详细信息
我尝试了很多转换,但都没有成功。谁能帮我完成这个?
试试这个.. Material-Animations
blueIconImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this, SharedElementActivity.class);
View sharedView = blueIconImageView;
String transitionName = getString(R.string.blue_name);
ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
startActivity(i, transitionActivityOptions.toBundle());
}
});
您需要的动画称为 Activity 共享元素之间的过渡。
通过研究,我发现您应该:
- 将您的 ListView 视图放在相对布局中
- 单击时,膨胀渲染器的副本
- 找到渲染器所在位置的全局坐标
与 ListView 的父级的关系
- 将复制的渲染器添加到 RelativeLayout(ListView 的父级)
- 使 listView 动起来
- 在该动画结束时,为您的新渲染器制作动画
盈利!
public class MainActivity extends Activity {
private RelativeLayout layout;
private ListView listView;
private MyRenderer selectedRenderer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new RelativeLayout(this);
setContentView(layout);
listView = new ListView(this);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
layout.addView(listView, rlp);
listView.setAdapter(new MyAdapter());
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// find out where the clicked view sits in relationship to the
// parent container
int t = view.getTop() + listView.getTop();
int l = view.getLeft() + listView.getLeft();
// create a copy of the listview and add it to the parent
// container
// at the same location it was in the listview
selectedRenderer = new MyRenderer(view.getContext());
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(view.getWidth(), view
.getHeight());
rlp.topMargin = t;
rlp.leftMargin = l;
selectedRenderer.textView.setText(((MyRenderer) view).textView.getText());
layout.addView(selectedRenderer, rlp);
view.setVisibility(View.INVISIBLE);
// animate out the listView
Animation outAni = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, -1f, Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, 0f);
outAni.setDuration(1000);
outAni.setFillAfter(true);
outAni.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
ScaleAnimation scaleAni = new ScaleAnimation(1f,
1f, 1f, 2f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scaleAni.setDuration(400);
scaleAni.setFillAfter(true);
selectedRenderer.startAnimation(scaleAni);
}
});
listView.startAnimation(outAni);
}
});
}
public class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return 10;
}
@Override
public String getItem(int position) {
return "Hello World " + position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
MyRenderer renderer;
if (convertView != null)
renderer = (MyRenderer) convertView;
else
renderer = new MyRenderer(MainActivity.this);
renderer.textView.setText(getItem(position));
return renderer;
}
}
public class MyRenderer extends RelativeLayout {
public TextView textView;
public MyRenderer(Context context) {
super(context);
setPadding(20, 20, 20, 20);
setBackgroundColor(0xFFFF0000);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
rlp.addRule(CENTER_IN_PARENT);
textView = new TextView(context);
addView(textView, rlp);
}
} }
试试这个壮观的网页@ Getting Started with Activity & Fragment Transitions (part 1)。他们在这里讨论了 Activity 和 Fragment Transitions。我没试过。我的观点是 Fragment Transitions 更好,而且计算机密集度更低,因此这是一个好的开始。而且您可能不需要更改工具栏,您可以 show/hide 它们。
另一个好的SOlink是@Animate the transition between fragments,看最佳答案。在那post中,他们谈到了objectAnimator。
另一个意见是关于您 post 编辑的示例动画,它没有显示从一种艺术到另一种艺术的流畅动画。当动画不流畅时,它就不那么令人印象深刻了。
祝你好运,玩得开心,让我们都posted。
我构建了一个小型示例应用程序,它可以在两个活动之间转换并达到预期效果:
但是,提供的 gif 中的过渡略有不同。这
左侧 gif 中的过渡将列表元素过渡到第二个 activity 的内容区域(工具栏保持原位)。在右侧的 gif 中,转换将列表元素转换为第二个 activity 的完整屏幕。下面的代码提供了左侧 gif 中的效果。但是,应该可以通过稍作修改来调整解决方案,以实现正确 gif 中的过渡。
请注意,这仅适用于 Lollipop。但是,可以在旧设备上模拟不同的效果。
此外,提供的代码的唯一目的是展示它是如何完成的。不要直接在您的应用中使用它。
主要活动:
public class MainActivity extends AppCompatActivity {
MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
ListView listView = (ListView) findViewById(R.id.list_view);
myAdapter = new MyAdapter(this, 0, DataSet.get());
listView.setAdapter(myAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) {
startTransition(view, myAdapter.getItem(position));
}
});
}
private void startTransition(View view, Element element) {
Intent i = new Intent(MainActivity.this, DetailActivity.class);
i.putExtra("ITEM_ID", element.getId());
Pair<View, String>[] transitionPairs = new Pair[4];
transitionPairs[0] = Pair.create(findViewById(R.id.toolbar), "toolbar"); // Transition the Toolbar
transitionPairs[1] = Pair.create(view, "content_area"); // Transition the content_area (This will be the content area on the detail screen)
// We also want to transition the status and navigation bar barckground. Otherwise they will flicker
transitionPairs[2] = Pair.create(findViewById(android.R.id.statusBarBackground), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME);
transitionPairs[3] = Pair.create(findViewById(android.R.id.navigationBarBackground), Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME);
Bundle b = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, transitionPairs).toBundle();
ActivityCompat.startActivity(MainActivity.this, i, b);
}
}
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:transitionName="toolbar" />
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
详细活动:
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
long elementId = getIntent().getLongExtra("ITEM_ID", -1);
Element element = DataSet.find(elementId);
((TextView) findViewById(R.id.title)).setText(element.getTitle());
((TextView) findViewById(R.id.description)).setText(element.getDescription());
// if we transition the status and navigation bar we have to wait till everything is available
TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar(this);
// set a custom shared element enter transition
TransitionHelper.setSharedElementEnterTransition(this, R.transition.detail_activity_shared_element_enter_transition);
}
}
activity_detail.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:transitionName="toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#abc"
android:orientation="vertical"
android:paddingBottom="200dp"
android:transitionName="content_area"
android:elevation="10dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
detail_activity_shared_element_enter_transition.xml (/res/transition/):
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionOrdering="together">
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
<changeImageTransform/>
<transition class="my.application.transitions.ElevationTransition"/>
</transitionSet>
my.application.transitions.ElevationTransition:
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class ElevationTransition extends Transition {
private static final String PROPNAME_ELEVATION = "my.elevation:transition:elevation";
public ElevationTransition() {
}
public ElevationTransition(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
private void captureValues(TransitionValues transitionValues) {
Float elevation = transitionValues.view.getElevation();
transitionValues.values.put(PROPNAME_ELEVATION, elevation);
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
}
Float startVal = (Float) startValues.values.get(PROPNAME_ELEVATION);
Float endVal = (Float) endValues.values.get(PROPNAME_ELEVATION);
if (startVal == null || endVal == null || startVal.floatValue() == endVal.floatValue()) {
return null;
}
final View view = endValues.view;
ValueAnimator a = ValueAnimator.ofFloat(startVal, endVal);
a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setElevation((float)animation.getAnimatedValue());
}
});
return a;
}
}
过渡助手:
public class TransitionHelper {
public static void fixSharedElementTransitionForStatusAndNavigationBar(final Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
final View decor = activity.getWindow().getDecorView();
if (decor == null)
return;
activity.postponeEnterTransition();
decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onPreDraw() {
decor.getViewTreeObserver().removeOnPreDrawListener(this);
activity.startPostponedEnterTransition();
return true;
}
});
}
public static void setSharedElementEnterTransition(final Activity activity, int transition) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
activity.getWindow().setSharedElementEnterTransition(TransitionInflater.from(activity).inflateTransition(transition));
}
}
那么这里有哪些不同的部分:
我们有两个活动。在转换期间,四个视图在活动之间转换。
工具栏:如左侧 gif 所示,工具栏不会随其他内容移动。
ListView元素View -> 成为DetailActivity的内容视图
StatusBar 和 NavigationBar 背景:如果我们不将这些视图添加到过渡视图集中,它们将在过渡期间淡出并返回。然而,这需要延迟进入转换(参见:TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar
)
在 MainActivity
中,转换后的视图被添加到用于启动 DetailActivity
的 Bundle 中。此外,转换后的视图需要在两个活动中命名 (transitionName
)。这可以在布局中完成 xml 也可以通过编程方式完成。
在共享元素过渡期间使用的默认过渡集会影响视图的不同方面(例如:视图边界 - 请参阅 2)。然而,视图的高度差异不是动画的。这就是所提出的解决方案使用自定义 ElevationTransition 的原因。
我想要的是,当用户单击 ListView 中的列表项时,它会转换为一个整体 activity(如您在以下示例中所见),但我无法找到解释这个的教程,实际上,我不知道这个运动是怎么叫的。
也就是说,我要实现的是:
单击时增加列表项的高度(如右侧 gif 所示)
展开列表项并将其转换为下一个 fragment/activity 布局,其中包含有关所单击项目的详细信息
我尝试了很多转换,但都没有成功。谁能帮我完成这个?
试试这个.. Material-Animations
blueIconImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this, SharedElementActivity.class);
View sharedView = blueIconImageView;
String transitionName = getString(R.string.blue_name);
ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
startActivity(i, transitionActivityOptions.toBundle());
}
});
您需要的动画称为 Activity 共享元素之间的过渡。 通过研究,我发现您应该:
- 将您的 ListView 视图放在相对布局中
- 单击时,膨胀渲染器的副本
- 找到渲染器所在位置的全局坐标 与 ListView 的父级的关系
- 将复制的渲染器添加到 RelativeLayout(ListView 的父级)
- 使 listView 动起来
- 在该动画结束时,为您的新渲染器制作动画
盈利!
public class MainActivity extends Activity { private RelativeLayout layout; private ListView listView; private MyRenderer selectedRenderer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); layout = new RelativeLayout(this); setContentView(layout); listView = new ListView(this); RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT); layout.addView(listView, rlp); listView.setAdapter(new MyAdapter()); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // find out where the clicked view sits in relationship to the // parent container int t = view.getTop() + listView.getTop(); int l = view.getLeft() + listView.getLeft(); // create a copy of the listview and add it to the parent // container // at the same location it was in the listview selectedRenderer = new MyRenderer(view.getContext()); RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(view.getWidth(), view .getHeight()); rlp.topMargin = t; rlp.leftMargin = l; selectedRenderer.textView.setText(((MyRenderer) view).textView.getText()); layout.addView(selectedRenderer, rlp); view.setVisibility(View.INVISIBLE); // animate out the listView Animation outAni = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, -1f, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f); outAni.setDuration(1000); outAni.setFillAfter(true); outAni.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { ScaleAnimation scaleAni = new ScaleAnimation(1f, 1f, 1f, 2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scaleAni.setDuration(400); scaleAni.setFillAfter(true); selectedRenderer.startAnimation(scaleAni); } }); listView.startAnimation(outAni); } }); } public class MyAdapter extends BaseAdapter { @Override public int getCount() { return 10; } @Override public String getItem(int position) { return "Hello World " + position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { MyRenderer renderer; if (convertView != null) renderer = (MyRenderer) convertView; else renderer = new MyRenderer(MainActivity.this); renderer.textView.setText(getItem(position)); return renderer; } } public class MyRenderer extends RelativeLayout { public TextView textView; public MyRenderer(Context context) { super(context); setPadding(20, 20, 20, 20); setBackgroundColor(0xFFFF0000); RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); rlp.addRule(CENTER_IN_PARENT); textView = new TextView(context); addView(textView, rlp); } } }
试试这个壮观的网页@ Getting Started with Activity & Fragment Transitions (part 1)。他们在这里讨论了 Activity 和 Fragment Transitions。我没试过。我的观点是 Fragment Transitions 更好,而且计算机密集度更低,因此这是一个好的开始。而且您可能不需要更改工具栏,您可以 show/hide 它们。
另一个好的SOlink是@Animate the transition between fragments,看最佳答案。在那post中,他们谈到了objectAnimator。
另一个意见是关于您 post 编辑的示例动画,它没有显示从一种艺术到另一种艺术的流畅动画。当动画不流畅时,它就不那么令人印象深刻了。
祝你好运,玩得开心,让我们都posted。
我构建了一个小型示例应用程序,它可以在两个活动之间转换并达到预期效果:
但是,提供的 gif 中的过渡略有不同。这 左侧 gif 中的过渡将列表元素过渡到第二个 activity 的内容区域(工具栏保持原位)。在右侧的 gif 中,转换将列表元素转换为第二个 activity 的完整屏幕。下面的代码提供了左侧 gif 中的效果。但是,应该可以通过稍作修改来调整解决方案,以实现正确 gif 中的过渡。
请注意,这仅适用于 Lollipop。但是,可以在旧设备上模拟不同的效果。 此外,提供的代码的唯一目的是展示它是如何完成的。不要直接在您的应用中使用它。
主要活动:
public class MainActivity extends AppCompatActivity {
MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
ListView listView = (ListView) findViewById(R.id.list_view);
myAdapter = new MyAdapter(this, 0, DataSet.get());
listView.setAdapter(myAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) {
startTransition(view, myAdapter.getItem(position));
}
});
}
private void startTransition(View view, Element element) {
Intent i = new Intent(MainActivity.this, DetailActivity.class);
i.putExtra("ITEM_ID", element.getId());
Pair<View, String>[] transitionPairs = new Pair[4];
transitionPairs[0] = Pair.create(findViewById(R.id.toolbar), "toolbar"); // Transition the Toolbar
transitionPairs[1] = Pair.create(view, "content_area"); // Transition the content_area (This will be the content area on the detail screen)
// We also want to transition the status and navigation bar barckground. Otherwise they will flicker
transitionPairs[2] = Pair.create(findViewById(android.R.id.statusBarBackground), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME);
transitionPairs[3] = Pair.create(findViewById(android.R.id.navigationBarBackground), Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME);
Bundle b = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, transitionPairs).toBundle();
ActivityCompat.startActivity(MainActivity.this, i, b);
}
}
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:transitionName="toolbar" />
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
详细活动:
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
long elementId = getIntent().getLongExtra("ITEM_ID", -1);
Element element = DataSet.find(elementId);
((TextView) findViewById(R.id.title)).setText(element.getTitle());
((TextView) findViewById(R.id.description)).setText(element.getDescription());
// if we transition the status and navigation bar we have to wait till everything is available
TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar(this);
// set a custom shared element enter transition
TransitionHelper.setSharedElementEnterTransition(this, R.transition.detail_activity_shared_element_enter_transition);
}
}
activity_detail.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:transitionName="toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#abc"
android:orientation="vertical"
android:paddingBottom="200dp"
android:transitionName="content_area"
android:elevation="10dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
detail_activity_shared_element_enter_transition.xml (/res/transition/):
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionOrdering="together">
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
<changeImageTransform/>
<transition class="my.application.transitions.ElevationTransition"/>
</transitionSet>
my.application.transitions.ElevationTransition:
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class ElevationTransition extends Transition {
private static final String PROPNAME_ELEVATION = "my.elevation:transition:elevation";
public ElevationTransition() {
}
public ElevationTransition(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
private void captureValues(TransitionValues transitionValues) {
Float elevation = transitionValues.view.getElevation();
transitionValues.values.put(PROPNAME_ELEVATION, elevation);
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
}
Float startVal = (Float) startValues.values.get(PROPNAME_ELEVATION);
Float endVal = (Float) endValues.values.get(PROPNAME_ELEVATION);
if (startVal == null || endVal == null || startVal.floatValue() == endVal.floatValue()) {
return null;
}
final View view = endValues.view;
ValueAnimator a = ValueAnimator.ofFloat(startVal, endVal);
a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setElevation((float)animation.getAnimatedValue());
}
});
return a;
}
}
过渡助手:
public class TransitionHelper {
public static void fixSharedElementTransitionForStatusAndNavigationBar(final Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
final View decor = activity.getWindow().getDecorView();
if (decor == null)
return;
activity.postponeEnterTransition();
decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onPreDraw() {
decor.getViewTreeObserver().removeOnPreDrawListener(this);
activity.startPostponedEnterTransition();
return true;
}
});
}
public static void setSharedElementEnterTransition(final Activity activity, int transition) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
activity.getWindow().setSharedElementEnterTransition(TransitionInflater.from(activity).inflateTransition(transition));
}
}
那么这里有哪些不同的部分: 我们有两个活动。在转换期间,四个视图在活动之间转换。
工具栏:如左侧 gif 所示,工具栏不会随其他内容移动。
ListView元素View -> 成为DetailActivity的内容视图
StatusBar 和 NavigationBar 背景:如果我们不将这些视图添加到过渡视图集中,它们将在过渡期间淡出并返回。然而,这需要延迟进入转换(参见:
TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar
)
在 MainActivity
中,转换后的视图被添加到用于启动 DetailActivity
的 Bundle 中。此外,转换后的视图需要在两个活动中命名 (transitionName
)。这可以在布局中完成 xml 也可以通过编程方式完成。
在共享元素过渡期间使用的默认过渡集会影响视图的不同方面(例如:视图边界 - 请参阅 2)。然而,视图的高度差异不是动画的。这就是所提出的解决方案使用自定义 ElevationTransition 的原因。