安卓5.0系统引入了共享元素,能做出非常炫酷的场景切换效果,这让人非常兴奋同时非常蛋疼,因为低版本没法使用啊,所以今天就跟大家分享一下自己写的一个库,其实只有2个文件而已就可以兼容安卓5.0以下的版本。


重要的工具类

import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.ViewTreeObserver; import java.util.ArrayList; /**
* Tool for transition between two activities
* <br/>
* Created by huzn on 2017/5/8.
*/
public class EasyTransition { public static final String EASY_TRANSITION_OPTIONS = "easy_transition_options";
public static final long DEFAULT_TRANSITION_ANIM_DURATION = 1000; /**
* Start Activity with transition options
*
* @param intent The intent to start
* @param options Transition options, using {@link EasyTransitionOptions#makeTransitionOptions(Activity, View...)}
* to build your options
*/
public static void startActivity(Intent intent, EasyTransitionOptions options) {
options.update();
intent.putParcelableArrayListExtra(EASY_TRANSITION_OPTIONS, options.getAttrs());
Activity activity = options.getActivity();
activity.startActivity(intent);
activity.overridePendingTransition(0, 0);
} /**
* Start Activity for result, with transition options
*
* @param intent The intent to start
* @param requestCode If >= 0, this code will be returned in onActivityResult() when the activity exits,
* see {@link Activity#startActivityForResult(Intent, int)}
* @param options Transition options, using {@link EasyTransitionOptions#makeTransitionOptions(Activity, View...)}
* to build your options
*/
public static void startActivityForResult(Intent intent, int requestCode, EasyTransitionOptions options) {
options.update();
intent.putParcelableArrayListExtra(EASY_TRANSITION_OPTIONS, options.getAttrs());
Activity activity = options.getActivity();
activity.startActivityForResult(intent, requestCode);
activity.overridePendingTransition(0, 0);
} /**
* Enter the Activity, invoking this method to start enter transition animations
*
* @param activity The Activity entering
* @param duration The duration of enter transition animation
* @param interpolator The TimeInterpolator of enter transition animation
* @param listener Animator listener, normally you can do your initial after animation end
*/
public static void enter(Activity activity, long duration, TimeInterpolator interpolator, Animator.AnimatorListener listener) {
Intent intent = activity.getIntent();
ArrayList<EasyTransitionOptions.ViewAttrs> attrs =
intent.getParcelableArrayListExtra(EASY_TRANSITION_OPTIONS);
runEnterAnimation(activity, attrs, duration, interpolator, listener);
} /**
* The same as {@link EasyTransition#enter(Activity, long, TimeInterpolator, Animator.AnimatorListener)}
* with no interpolator
*/
public static void enter(Activity activity, long duration, Animator.AnimatorListener listener) {
enter(activity, duration, null, listener);
} /**
* The same as {@link EasyTransition#enter(Activity, long, TimeInterpolator, Animator.AnimatorListener)}
* with default duration
*/
public static void enter(Activity activity, TimeInterpolator interpolator, Animator.AnimatorListener listener) {
enter(activity, DEFAULT_TRANSITION_ANIM_DURATION, interpolator, listener);
} /**
* The same as {@link EasyTransition#enter(Activity, long, TimeInterpolator, Animator.AnimatorListener)}
* with default duration and no interpolator
*/
public static void enter(Activity activity, Animator.AnimatorListener listener) {
enter(activity, DEFAULT_TRANSITION_ANIM_DURATION, null, listener);
} /**
* The same as {@link EasyTransition#enter(Activity, long, TimeInterpolator, Animator.AnimatorListener)}
* with default duration, no interpolator and no listener
*/
public static void enter(Activity activity) {
enter(activity, DEFAULT_TRANSITION_ANIM_DURATION, null, null);
} private static void runEnterAnimation(Activity activity,
ArrayList<EasyTransitionOptions.ViewAttrs> attrs,
final long duration,
final TimeInterpolator interpolator,
final Animator.AnimatorListener listener) {
if (null == attrs || attrs.size() == 0)
return; for (final EasyTransitionOptions.ViewAttrs attr : attrs) {
final View view = activity.findViewById(attr.id); if (null == view)
continue; view.getViewTreeObserver()
.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this); int[] location = new int[2];
view.getLocationOnScreen(location);
view.setPivotX(0);
view.setPivotY(0);
view.setScaleX(attr.width / view.getWidth());
view.setScaleY(attr.height / view.getHeight());
view.setTranslationX(attr.startX - location[0]); // xDelta
view.setTranslationY(attr.startY - location[1]); // yDelta view.animate()
.scaleX(1)
.scaleY(1)
.translationX(0)
.translationY(0)
.setDuration(duration)
.setInterpolator(interpolator)
.setListener(listener);
return true;
}
});
}
} /**
* Exit the Activity, invoke this method to start exit transition animation,
* the shared views must have same ids, or it will throws NullPointerException
*
* @param activity The Activity Exiting
* @param interpolator The TimeInterpolator of exit transition animation
* @param duration The duration of exit transition animation
* @throws NullPointerException throws if shared views not found in The Activity Exiting
*/
public static void exit(Activity activity, long duration, TimeInterpolator interpolator) {
Intent intent = activity.getIntent();
ArrayList<EasyTransitionOptions.ViewAttrs> attrs = intent.getParcelableArrayListExtra(EASY_TRANSITION_OPTIONS);
runExitAnimation(activity, attrs, duration, interpolator);
} /**
* The same as {@link EasyTransition#exit(Activity, long, TimeInterpolator)}
* with default duration
*/
public static void exit(Activity activity, TimeInterpolator interpolator) {
exit(activity, DEFAULT_TRANSITION_ANIM_DURATION, interpolator);
} /**
* The same as {@link EasyTransition#exit(Activity, long, TimeInterpolator)}
* with no interpolator
*/
public static void exit(Activity activity, long duration) {
exit(activity, duration, null);
} /**
* The same as {@link EasyTransition#exit(Activity, long, TimeInterpolator)}
* with default duration and no interpolator
*/
public static void exit(Activity activity) {
exit(activity, DEFAULT_TRANSITION_ANIM_DURATION, null);
} private static void runExitAnimation(final Activity activity,
ArrayList<EasyTransitionOptions.ViewAttrs> attrs,
long duration,
TimeInterpolator interpolator) {
if (null == attrs || attrs.size() == 0)
return; for (final EasyTransitionOptions.ViewAttrs attr : attrs) {
View view = activity.findViewById(attr.id);
int[] location = new int[2];
view.getLocationOnScreen(location);
view.setPivotX(0);
view.setPivotY(0); view.animate()
.scaleX(attr.width / view.getWidth())
.scaleY(attr.height / view.getHeight())
.translationX(attr.startX - location[0])
.translationY(attr.startY - location[1])
.setInterpolator(interpolator)
.setDuration(duration);
} activity.findViewById(attrs.get(0).id).postDelayed(new Runnable() {
@Override
public void run() {
activity.finish();
activity.overridePendingTransition(0, 0);
}
}, duration);
}
}
import android.app.Activity;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.View; import java.util.ArrayList; /**
* Transition options, using {@link EasyTransitionOptions#makeTransitionOptions(Activity, View...)}
* to build your options
* <br/>
* Created by huzn on 2017/5/8.
*/
public class EasyTransitionOptions { private Activity activity;
private View[] views;
private ArrayList<ViewAttrs> attrs; public EasyTransitionOptions(Activity activity, View[] views) {
this.activity = activity;
this.views = views;
} /**
* Make options for transition
*
* @param activity The activity who contains shared views
* @param views Shared views, which must contains same id between two activities
* @return A new transition options that will be used to build our transition animations
*/
public static EasyTransitionOptions makeTransitionOptions(Activity activity, View... views) {
return new EasyTransitionOptions(activity, views);
} public void update() {
if (null == views)
return; attrs = new ArrayList<>();
for (View v : views) {
int[] location = new int[2];
v.getLocationOnScreen(location);
attrs.add(new ViewAttrs(
v.getId(),
location[0],
location[1],
v.getWidth(),
v.getHeight()
));
}
} public Activity getActivity() {
return activity;
} public ArrayList<ViewAttrs> getAttrs() {
return attrs;
} public static class ViewAttrs implements Parcelable {
public int id;
public float startX;
public float startY;
public float width;
public float height; public ViewAttrs(int id, float startX, float startY, float width, float height) {
this.id = id;
this.startX = startX;
this.startY = startY;
this.width = width;
this.height = height;
} // Parcelable
@Override
public int describeContents() {
return 0;
} @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.id);
dest.writeFloat(this.startX);
dest.writeFloat(this.startY);
dest.writeFloat(this.width);
dest.writeFloat(this.height);
} protected ViewAttrs(Parcel in) {
this.id = in.readInt();
this.startX = in.readFloat();
this.startY = in.readFloat();
this.width = in.readFloat();
this.height = in.readFloat();
} public static final Parcelable.Creator<ViewAttrs> CREATOR = new Parcelable.Creator<ViewAttrs>() {
@Override
public ViewAttrs createFromParcel(Parcel source) {
return new ViewAttrs(source);
} @Override
public ViewAttrs[] newArray(int size) {
return new ViewAttrs[size];
}
};
}
}

场景使用:

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private ArrayList<String> list; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); list = new ArrayList<>();
for (int i = 0; i < 20; i++) {
list.add("name" + i);
}
ListView listView = (ListView) findViewById(R.id.lv);
listView.setAdapter(new MyAdapter());
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// ready for intent
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
intent.putExtra("name", list.get(position)); // ready for transition options
EasyTransitionOptions options =
EasyTransitionOptions.makeTransitionOptions(
MainActivity.this,
view.findViewById(R.id.iv_icon),
view.findViewById(R.id.tv_name),
findViewById(R.id.v_top_card)); // start transition
EasyTransition.startActivity(intent, options);
}
});
} private class MyAdapter extends BaseAdapter { @Override
public int getCount() {
int count = 0;
if (null != list)
count = list.size();
return count;
} @Override
public Object getItem(int position) {
return list.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (null != convertView) {
view = convertView;
} else {
view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_main_list, null, false);
}
TextView tvName = (TextView) view.findViewById(R.id.tv_name);
tvName.setText(list.get(position));
return view;
}
}
}
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView; public class DetailActivity extends AppCompatActivity { private LinearLayout layoutAbout;
private ImageView ivAdd;
private boolean finishEnter; @Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail); // pre init some views and data
initViews(); // if re-initialized, do not play any anim
long transitionDuration = 800;
if (null != savedInstanceState)
transitionDuration = 0; // transition enter
finishEnter = false;
EasyTransition.enter(
this,
transitionDuration,
new DecelerateInterpolator(),
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// init other views after transition anim
finishEnter = true;
initOtherViews();
}
});
} private void initViews() {
TextView tvName = (TextView) findViewById(R.id.tv_name);
tvName.setText(getIntent().getStringExtra("name"));
} private void initOtherViews() {
layoutAbout = (LinearLayout) findViewById(R.id.layout_about);
layoutAbout.setVisibility(View.VISIBLE);
layoutAbout.setAlpha(0);
layoutAbout.setTranslationY(-30);
layoutAbout.animate()
.setDuration(300)
.alpha(1)
.translationY(0); ivAdd = (ImageView) findViewById(R.id.iv_add);
ivAdd.setVisibility(View.VISIBLE);
ivAdd.setScaleX(0);
ivAdd.setScaleY(0);
ivAdd.animate()
.setDuration(200)
.scaleX(1)
.scaleY(1);
} @Override
public void onBackPressed() {
if (finishEnter) {
finishEnter = false;
startBackAnim();
}
} private void startBackAnim() {
// forbidden scrolling
ScrollView sv = (ScrollView) findViewById(R.id.sv);
sv.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
}); // start our anim
ivAdd.animate()
.setDuration(200)
.scaleX(0)
.scaleY(0); layoutAbout.animate()
.setDuration(300)
.alpha(0)
.translationY(-30)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// transition exit after our anim
EasyTransition.exit(DetailActivity.this, 800, new DecelerateInterpolator());
}
});
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.hzn.easytransition.MainActivity"
> <TextView
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@color/colorPrimary"
android:gravity="center_vertical"
android:paddingLeft="16sp"
android:text="TITLE"
android:textColor="#ffffff"
android:textSize="25sp"
/> <View
android:id="@+id/v_top_card"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="@id/title_bar"
android:background="@color/colorPrimary"
/> <ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/title_bar"
/>
</RelativeLayout>

activity_detail.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.hzn.easytransition.MainActivity"
> <TextView
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@color/colorPrimary"
android:gravity="center_vertical"
android:paddingLeft="16sp"
android:text="TITLE"
android:textColor="#ffffff"
android:textSize="25sp"
/> <View
android:id="@+id/v_top_card"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_below="@+id/title_bar"
android:background="@color/colorPrimary"
/> <ImageView
android:id="@+id/iv_icon"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="100dp"
android:src="@mipmap/avatar_male"
/> <TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/iv_icon"
android:layout_centerHorizontal="true"
android:layout_marginLeft="10dp"
android:textColor="#5b5b5b"
android:textSize="50sp"
/> <ScrollView
android:id="@+id/sv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/tv_name"
android:overScrollMode="never"
android:scrollbars="none"
> <LinearLayout
android:id="@+id/layout_about"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:orientation="vertical"
android:paddingBottom="40dp"
android:paddingTop="20dp"
android:visibility="invisible"
> <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="@mipmap/icon_phone"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:text="151-2121-2121"
android:textColor="#446880"
android:textSize="16sp"
/> <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:drawableLeft="@mipmap/icon_email"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:text="243666666@gmail.com"
android:textColor="#446880"
android:textSize="16sp"
/> <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:drawableLeft="@mipmap/icon_location"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:text="China, Guangdong, Shenzhen"
android:textColor="#446880"
android:textSize="16sp"
/>
</LinearLayout>
</ScrollView> <ImageView
android:id="@+id/iv_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:padding="16dp"
android:src="@mipmap/icon_add"
android:visibility="gone"
/>
</RelativeLayout>

item_main_list.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
> <ImageView
android:id="@+id/iv_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/avatar_male"
/> <TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/iv_icon"
android:text="name"
android:textColor="#5b5b5b"
android:textSize="20sp"
/> </RelativeLayout>

效果图:


学习来源:http://blog.csdn.net/u012199331/article/details/72137112


 

Android共享元素场景切换动画的实现的更多相关文章

  1. Android的Activity屏幕切换动画(一)-左右滑动切换

    (国内知名Android开发论坛eoe开发者社区推荐:http://www.eoeandroid.com/) Android的Activity屏幕切换动画(一)-左右滑动切换 在Android开发过程 ...

  2. IOS自定义场景切换动画。

    IOS中我们可以通过Storyborad以及segue来实现我们自己的场景切换动画,新建项目使用Single View Application模板并取名为MyCustomSegue. 使用storyb ...

  3. cocos2d-x场景切换动画

    void StartScene::beginGame() {     CCLog("beginGame");          //CCTransitionScene *trans ...

  4. Android的Activity屏幕切换动画-左右滑动切换

    . --> 在Android开发过程中,经常会碰到Activity之间的切换效果的问题,下面介绍一下如何实现左右滑动的切换效果,首先了解一下Activity切换的实现,从Android2.0开始 ...

  5. Android为ViewPager增加切换动画——使用属性动画.

    ViewPager作为Android最常用的的组件之一,相信大家在项目中会频繁的使用到的,例如利用ViewPager制作引导页.轮播图,甚至做整个app的表现层的框架等等. Android3.0以下不 ...

  6. Android开发中activity切换动画的实现

    (1)我们在MainAcitvity中定义两个textview,用于点击触发切换Activity事件,下面是布局文件代码. <LinearLayout android:layout_width= ...

  7. Android至ViewPager添加切换动画——使用属性动画

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/44200623 ViewPager作为Android最经常使用的的组件之中的一个.相 ...

  8. Android为ViewPager添加切换动画——自己定义ViewPager

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/44224517 在上篇博客中,我写了一个使用属性动画为ViewPager加入切换动画 ...

  9. cocos2dx常见场景切换动画(转)

    本文转载自:http://www.cnblogs.com/linux-ios/archive/2013/04/09/3010779.html bool HelloWorld::init() { /// ...

随机推荐

  1. python学习之路入门篇

    本文是up学习python过程中遇到的一些问题及总结归纳,本小节是入门篇. python基本语法 循环.分支不多赘述. 模块:一个.py文件就是一个模块. 文件和异常 模式 含义解释 “r” 读模式 ...

  2. IT经理工作职责

    IT经理工作职责:     1. 管理公司信息技术以及计算机系统.   2. 确保公司信息技术是可访问的并且配备了现有的可用的硬件和软件.   3. 监控并且维护公司信息技术并确保能够得到最大化的使用 ...

  3. ISO/IEC 15444-12 MP4 封装格式标准摘录 2

    目录 Track Media Structure Media Box Media Header Box Handler Reference Box Media Information Box Medi ...

  4. c++ 数组 结构体

    接下来的一点时间我将会记录下我看的c++的一些心得体会,人贵在坚持,希望我可以一直坚持下去!!Go Fighting!   一.c++复合数据类型: 数组类型的一些注意事项: sizeof的用法: 当 ...

  5. new一个有父类的对象时各代码块的执行顺序问题

    public class QQ { public static void main(String[] args) { new B(); } } class A { static { System.ou ...

  6. zencart产品属性dropmenu select只有一个选择项时自动变成radio单选的解决办法

    includes\modules\classic\attributes.php 在大约786行代码 case ($products_options->RecordCount() == 1): 的 ...

  7. magento简化url多级分类去掉父目录

    在Magento模板开发中,有时候需要将多级分类的url简化,Magento的URL默认是显示多级分类的http://afish.cnblogs.com/分类1/分类2/分类3现在需要简化为:分类2的 ...

  8. 关于@wraps(fn)

  9. Python版本号比较函数 LooseVersion 和StrictVersion

  10. Linux服务器安装配置JDK

    一.准备工作: 1.登录服务器,切换到root用户(su - root,然后输入密码,按enter),进入根目录:cd / 2.进入要安装jdk的目录,自己可以创建一个java目录,执行命令如下: c ...