最新写项目的时候,看到搜索界面的跳转基本都是点击搜索然后跳转到下个页面,android 微信上则是 类似toolbar的效果,而ios 上则是一个搜索框上移然后显示新界面的一个效果。仔细研究了下发现和android 的 共享元素的过渡实现 的效果很像,所以在此模仿下。但是 共享元素的过渡实现 是5.0以后才有的,兼容5.0一下需要自定义动画效果,查了些资料发现也是可以实现的。下面是效果图:


1.实现思路:

实现的思路也比较简单,大概的步骤如下:

1.确定第一个界面的共享元素,将其信息传递个第二个界面
2.第二个界面接收信息,开始的时候将界面设置为透明,并只显示共享元素。
3.将第二个界面的共享元素进行动画处理。

2.获取共享元素位置信息:

在第一个界面的xml 里面,搜索框直接用一个自定义的imageView 代替

2.1 自定义imageView

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;/*** 自定义image,用于在4.x上实现仿5.0上分享元素的动画* Created by lh on 2016/11/4.*/
public class CustomImage extends ImageView {private int mResId;public CustomImage(Context context) {this(context, null, 0);}public CustomImage(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CustomImage(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);if (attrs != null) {String namespace = "http://schemas.android.com/apk/res/android";String attribute = "src";mResId = attrs.getAttributeResourceValue(namespace, attribute, 0);}}public int getImageId() {return mResId;}@Overridepublic void setImageResource(int resId) {super.setImageResource(resId);mResId = resId;}
}

2.2 点击事件的处理

在第一个界面中,我们需要获取到共享元素的位置信息,并将其传递给下一个界面。

private void showShareAnimation(View view) {Intent intent = new Intent(instance, SearchActivity.class);//创建一个rect 对象来存储共享元素的位置信息Rect rect = new Rect();//获取元素的位置信息view.getGlobalVisibleRect(rect);//将位置信息附加到intent 上intent.setSourceBounds(rect);CustomImage customImage = (CustomImage) view;intent.putExtra(ChooseCountry.EXTRA_SEARCH_SHAREIMAGE, customImage.getImageId());startActivity(intent);//用于屏蔽 activity 默认的转场动画效果overridePendingTransition(0, 0);}

其中,getGlobalVisibleRect() 方法的含义是,获取 可见的状态栏高度+可见的标题栏高度+Rect左上角到标题栏底部的距离,如果标题栏被隐藏了,那么可见标题栏高度为0。

接下来,就在在第二个界面接收位置信息并将该图片展示出来了。


3.模拟转场动画:

在第二个界面中,我们需要做如下的操作:

1.获取上共享元素信息。
2.计算共享元素缩放比例和位移距离。
3.调用动画,完成模拟转场效果。
4.隐藏搜索的图片,转变为可编辑的editText


/*** 初始化场景*/private void initial() {// 获取上一个界面传入的信息mRect = getIntent().getSourceBounds();//图片资源 IDint mRescourceId = getIntent().getExtras().getInt(ChooseCountry.EXTRA_SEARCH_SHAREIMAGE);// 获取上一个界面中,图片的宽度和高度mOriginWidth = mRect.right - mRect.left;mOriginHeight = mRect.bottom - mRect.top;// 设置 ImageView 的位置,使其和上一个界面中图片的位置重合LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mOriginWidth, mOriginHeight);params.setMargins(mRect.left, mRect.top - getStatusBarHeight(), mRect.right, mRect.bottom);mImageView.setLayoutParams(params);// 设置 ImageView 的图片和缩放类型mImageView.setImageResource(mRescourceId);mImageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);// 根据上一个界面传入的图片资源 ID,获取图片的 Bitmap 对象。BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(mRescourceId);Bitmap bitmap = bitmapDrawable.getBitmap();// 计算图片缩放比例和位移距离getBundleInfo(bitmap);}/*** 计算图片缩放比例,以及位移距离*/private void getBundleInfo(Bitmap bitmap) {// 计算图片缩放比例,并存储在 bundle 中if (bitmap.getWidth() >= bitmap.getHeight()) {mScaleBundle.putFloat(SCALE_WIDTH, (float) mScreenWidth / mOriginWidth);mScaleBundle.putFloat(SCALE_HEIGHT, (float) bitmap.getHeight() / mOriginHeight);} else {mScaleBundle.putFloat(SCALE_WIDTH, (float) bitmap.getWidth() / mOriginWidth);mScaleBundle.putFloat(SCALE_HEIGHT, (float) mScreenHeight / mOriginHeight);}// 计算位移距离,并将数据存储到 bundle 中mTransitionBundle.putFloat(TRANSITION_X, mScreenWidth / 2 - (mRect.left + (mRect.right - mRect.left) / 2));//        mTransitionBundle.putFloat(TRANSITION_Y, mScreenHeight / 2 - (mRect.top + (mRect.bottom - mRect.top) / 2));mTransitionBundle.putFloat(TRANSITION_Y, -(mRect.top-getStatusBarHeight()));}

我们要将 Rect.top 的值减去状态栏的高度,这样才是相对于屏幕的绝对位置。

入场以及退场动画

/*** 模拟入场动画*/private void runEnterAnim() {mImageView.animate().setInterpolator(DEFAULT_INTERPOLATOR).setDuration(DURATION).scaleX(mScaleBundle.getFloat(SCALE_WIDTH)).scaleY(mScaleBundle.getFloat(SCALE_HEIGHT)).translationX(mTransitionBundle.getFloat(TRANSITION_X)).translationY(mTransitionBundle.getFloat(TRANSITION_Y)).start();mImageView.setVisibility(View.VISIBLE);//add 作用隐藏原来的图片,显示为可编辑的editTextmHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_EDIT,DURATION);mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_KEYBOARD,DURATION*2);}/*** 模拟退场动画*/@SuppressWarnings("NewApi")private void runExitAnim() {//addsearchLine.setVisibility(View.GONE);searchTop.setVisibility(View.GONE);mImageView.setVisibility(View.VISIBLE);mImageView.animate().setInterpolator(DEFAULT_INTERPOLATOR).setDuration(DURATION).scaleX(1).scaleY(1).translationX(0).translationY(0).withEndAction(new Runnable() {@Overridepublic void run() {finish();overridePendingTransition(0, 0);}}).start();}private Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case MESSAGE_SHOW_KEYBOARD:CommonUtil.showKeyboard(instance, searchEdit);break;case MESSAGE_SHOW_EDIT:mImageView.setVisibility(View.GONE);searchTop.setVisibility(View.VISIBLE);searchLine.setVisibility(View.VISIBLE);searchEdit.requestFocus();break;}}};

4.完整代码

4.1 界面一:

xml

<com.accounttools.app.views.customviews.CustomImageandroid:id="@+id/search_total_view"android:layout_width="match_parent"android:layout_height="wrap_content"android:src="@drawable/search_totla_view"android:scaleType="centerInside"/>

activity
该id的点击事件调用的方法如下,获取共享元素的位置信息

private void showShareAnimation(View view) {Intent intent = new Intent(instance, SearchActivity.class);//创建一个rect 对象来存储共享元素的位置信息Rect rect = new Rect();//获取元素的位置信息view.getGlobalVisibleRect(rect);//将位置信息附加到intent 上intent.setSourceBounds(rect);CustomImage customImage = (CustomImage) view;intent.putExtra(ChooseCountry.EXTRA_SEARCH_SHAREIMAGE, customImage.getImageId());startActivity(intent);//用于屏蔽 activity 默认的转场动画效果overridePendingTransition(0, 0);}

4.2 界面二:

xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"android:background="@color/common_view_bg"><com.accounttools.app.views.customviews.CustomImage
            android:id="@+id/activity_search_img"android:layout_width="wrap_content"android:layout_height="wrap_content"android:scaleType="centerInside"android:visibility="invisible"/><RelativeLayout
            android:id="@+id/activity_search_top"android:layout_width="match_parent"android:layout_height="45dp"android:background="@color/status_bar_color"android:orientation="horizontal"android:paddingLeft="10dp"android:paddingRight="10dp"android:visibility="gone"><LinearLayout
                android:id="@+id/search_top_cancel"android:layout_width="50dp"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center"android:layout_alignParentRight="true"><TextView
                    android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="18sp"android:textColor="@color/common_red"android:text="@string/cancel"/></LinearLayout><LinearLayout
                android:layout_toLeftOf="@id/search_top_cancel"android:layout_marginRight="10dp"android:layout_width="match_parent"android:layout_height="28dp"android:orientation="horizontal"android:paddingLeft="8dp"android:paddingRight="8dp"android:background="@drawable/drawable_search_layout"android:layout_centerVertical="true"android:gravity="center_vertical"><ImageView
                    android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/search_icon"/><EditText
                    android:id="@+id/search_content"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginLeft="5dp"android:background="@color/transparent"android:textSize="15sp"android:hint="@string/search"android:textCursorDrawable="@drawable/drawable_search_cursor"/></LinearLayout></RelativeLayout><TextView
            android:id="@+id/activity_search_line"android:layout_width="match_parent"android:layout_height="0.5dp"android:background="@color/common_line_color"android:visibility="gone"/></LinearLayout>

activity
handler 的作用是当第二个界面显示动画结束后,隐藏imageView,显示可编辑的editText

/*** 搜索界面* Created by lh on 2016/11/3.*/
public class SearchActivity extends BaseActivity {private static final int MESSAGE_SHOW_KEYBOARD = 1;private static final int MESSAGE_SHOW_EDIT = 2;public static final int DURATION = 300;private static final AccelerateDecelerateInterpolator DEFAULT_INTERPOLATOR = new AccelerateDecelerateInterpolator();private static final String SCALE_WIDTH = "SCALE_WIDTH";private static final String SCALE_HEIGHT = "SCALE_HEIGHT";private static final String TRANSITION_X = "TRANSITION_X";private static final String TRANSITION_Y = "TRANSITION_Y";private Activity instance = SearchActivity.this;/*** 存储图片缩放比例和位移距离*/private Bundle mScaleBundle = new Bundle();private Bundle mTransitionBundle = new Bundle();/*** 屏幕宽度和高度*/private int mScreenWidth;private int mScreenHeight;/*** 上一个界面图片的宽度和高度*/private int mOriginWidth;private int mOriginHeight;/*** 上一个界面图片的位置信息*/private Rect mRect;private CustomImage mImageView;private EditText searchEdit;private RelativeLayout searchTop;private TextView searchLine;@Overridepublic void onBackPressed() {// 使用退场动画runExitAnim();}@Overrideprotected int getLayoutResId() {return R.layout.activity_search_layout;}@Overrideprotected void initView() {// 获得屏幕尺寸getScreenSize();// 初始化界面mImageView = (CustomImage) findViewById(R.id.activity_search_img);searchEdit = (EditText)findViewById(R.id.search_content);searchTop = (RelativeLayout)findViewById(R.id.activity_search_top);searchLine = (TextView)findViewById(R.id.activity_search_line);// 初始化场景initial();// 设置入场动画runEnterAnim();//动态显示搜索结果showSearchResult();}private Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case MESSAGE_SHOW_KEYBOARD:CommonUtil.showKeyboard(instance, searchEdit);break;case MESSAGE_SHOW_EDIT:mImageView.setVisibility(View.GONE);searchTop.setVisibility(View.VISIBLE);searchLine.setVisibility(View.VISIBLE);searchEdit.requestFocus();break;}}};/*** 初始化场景*/private void initial() {// 获取上一个界面传入的信息mRect = getIntent().getSourceBounds();//图片资源 IDint mRescourceId = getIntent().getExtras().getInt(ChooseCountry.EXTRA_SEARCH_SHAREIMAGE);// 获取上一个界面中,图片的宽度和高度mOriginWidth = mRect.right - mRect.left;mOriginHeight = mRect.bottom - mRect.top;// 设置 ImageView 的位置,使其和上一个界面中图片的位置重合LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mOriginWidth, mOriginHeight);params.setMargins(mRect.left, mRect.top - getStatusBarHeight(), mRect.right, mRect.bottom);mImageView.setLayoutParams(params);// 设置 ImageView 的图片和缩放类型mImageView.setImageResource(mRescourceId);mImageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);// 根据上一个界面传入的图片资源 ID,获取图片的 Bitmap 对象。BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(mRescourceId);Bitmap bitmap = bitmapDrawable.getBitmap();// 计算图片缩放比例和位移距离getBundleInfo(bitmap);}/*** 计算图片缩放比例,以及位移距离*/private void getBundleInfo(Bitmap bitmap) {// 计算图片缩放比例,并存储在 bundle 中if (bitmap.getWidth() >= bitmap.getHeight()) {mScaleBundle.putFloat(SCALE_WIDTH, (float) mScreenWidth / mOriginWidth);mScaleBundle.putFloat(SCALE_HEIGHT, (float) bitmap.getHeight() / mOriginHeight);} else {mScaleBundle.putFloat(SCALE_WIDTH, (float) bitmap.getWidth() / mOriginWidth);mScaleBundle.putFloat(SCALE_HEIGHT, (float) mScreenHeight / mOriginHeight);}// 计算位移距离,并将数据存储到 bundle 中mTransitionBundle.putFloat(TRANSITION_X, mScreenWidth / 2 - (mRect.left + (mRect.right - mRect.left) / 2));//        mTransitionBundle.putFloat(TRANSITION_Y, mScreenHeight / 2 - (mRect.top + (mRect.bottom - mRect.top) / 2));mTransitionBundle.putFloat(TRANSITION_Y, -(mRect.top-getStatusBarHeight()));}/*** 模拟入场动画*/private void runEnterAnim() {mImageView.animate().setInterpolator(DEFAULT_INTERPOLATOR).setDuration(DURATION).scaleX(mScaleBundle.getFloat(SCALE_WIDTH)).scaleY(mScaleBundle.getFloat(SCALE_HEIGHT)).translationX(mTransitionBundle.getFloat(TRANSITION_X)).translationY(mTransitionBundle.getFloat(TRANSITION_Y)).start();mImageView.setVisibility(View.VISIBLE);//addmHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_EDIT,DURATION);mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_KEYBOARD,DURATION*2);}/*** 模拟退场动画*/@SuppressWarnings("NewApi")private void runExitAnim() {//addsearchLine.setVisibility(View.GONE);searchTop.setVisibility(View.GONE);mImageView.setVisibility(View.VISIBLE);mImageView.animate().setInterpolator(DEFAULT_INTERPOLATOR).setDuration(DURATION).scaleX(1).scaleY(1).translationX(0).translationY(0).withEndAction(new Runnable() {@Overridepublic void run() {finish();overridePendingTransition(0, 0);}}).start();}/*** 获取屏幕尺寸*/private void getScreenSize() {Display display = getWindowManager().getDefaultDisplay();Point size = new Point();display.getSize(size);mScreenWidth = size.x;mScreenHeight = size.y;}/*** 获取状态栏高度*/private int getStatusBarHeight() {//获取status_bar_height资源的IDint resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");if (resourceId > 0) {//根据资源ID获取响应的尺寸值return getResources().getDimensionPixelSize(resourceId);}return -1;}private void showSearchResult(){searchEdit.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {//搜索的匹配算法Log.d("SearchActivity"," afterTextChanged 调用了 s="+s.toString());}});}
}

5.参考资料:

1.Android 中的转场动画及兼容处理

2.https://github.com/wl9739/UITransitionDemo

3.用 Transition 完成 Fragment 共享元素的切换

https://github.com/hehonghui/android-tech-frontier/blob/master/issue-35/%E7%94%A8Transition%E5%AE%8C%E6%88%90Fragment%E5%85%B1%E4%BA%AB%E5%85%83%E7%B4%A0%E7%9A%84%E5%88%87%E6%8D%A2.md

android 仿 ios 搜索界面跳转效果相关推荐

  1. android 仿ios动画效果代码,Android仿IOS上拉下拉弹性效果的实例代码

    用过iphone的朋友相信都体验过页面上拉下拉有一个弹性的效果,使用起来用户体验很好:Android并没有给我们封装这样一个效果,我们来看下在Android里如何实现这个效果.先看效果,感觉有些时候还 ...

  2. android 密码解锁程序,android 仿ios数字密码解锁界面的实例

    如下所示: 每个Android开发人员都知道,现在android的解锁最常用的就是九宫格解锁,ios的解锁常用的是数字密码解锁.而我们在开发工程中,很多时候,都需要android和ios进行结合.有的 ...

  3. Android仿IOS解锁密码界面-自定义view系列(6)

    Android仿IOS解锁密码界面-自定义view系列 功能简介 主要实现步骤-具体内容看github项目里的代码 xml相关属性设置 Android Studio 代码 Android技术生活交流 ...

  4. android 按钮回弹效果,Android仿IOS回弹效果 支持任何控件

    本文实例为大家分享了Android仿IOS回弹效果的具体代码,供大家参考,具体内容如下 效果图: 导入依赖: dependencies { // ... compile 'me.everything: ...

  5. android 布局回弹,Android仿IOS回弹效果 支持任何控件

    本文实例为大家分享了Android仿IOS回弹效果的具体代码,供大家参考,具体内容如下 效果图: 导入依赖: dependencies { // ... compile 'me.everything: ...

  6. Android仿IOS吸边弹簧阻尼移动组件SpringMovingView-自定义view系列(3)

    () Android仿ios吸边弹簧阻尼效果的移动组件SpringMovingView 功能简介 Android技术生活交流 Gif演示 实现步骤 java代码 Android技术生活交流 更多其他页 ...

  7. android rebound平移,Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout

    Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout 前言 IOS 拖拽回弹给用户的体验不得不赞然后 Android 原生的 API 各种不支持, 于是乎出现的很多仿 IO ...

  8. android仿ios弹框_在“提示”框中:iOS外观(在Android上运行),Google Maps作为Time Machine,下载Wii游戏保存...

    android仿ios弹框 Once a week we round up some great reader tips and share them with everyone. Read on t ...

  9. android 仿微信聊天界面 以及语音录制功能,Android仿微信录制语音功能

    本文实例为大家分享了Android仿微信录制语音的具体代码,供大家参考,具体内容如下 前言 我把录音分成了两部分 1.UI界面,弹窗读秒 2.一个类(包含开始.停止.创建文件名功能) 第一部分 由于6 ...

最新文章

  1. 【CVPR2020】可微分的NAS方法汇总
  2. 皮一皮:一顿操作猛如虎...
  3. 【数据挖掘】基于密度的聚类方法 - OPTICS 方法 ( 核心距离 | 可达距离 | 族序 )
  4. Mybatis一级缓存、二级缓存
  5. 近300万记录的论坛还用这个分页存储过程
  6. Java应用程序中的消息传递主体
  7. XidianOJ 1090 爬树的V8
  8. mybatis主键生成策略和mp主键生成策略
  9. opengl显示英文_OpenGL-Using Shaders(使用Shader)
  10. Game HDU - 5242 树链思想
  11. python编写的心得_Python开发之我的小心得
  12. 数字化时代,需要数据思维!
  13. vue 富文本编辑器 Editor 使用
  14. cad统计面积长度插件vlx_cad计算面积插件免费版
  15. [实战]200类鸟类细粒度图像分类
  16. 莫比乌斯反演专题题解
  17. 1367 二叉树中的列表
  18. 液晶显示器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  19. Android 极光推送华为厂商通道集成问题记录
  20. 搜狗输入法android皮肤,搜狗输入法皮肤盒子app

热门文章

  1. win8系统计算机管理,Win8打不开计算机管理怎么办?
  2. 网络推广团队做网站SEO添加反向链接时的策略!
  3. 计算机能力提升选网络研修,信息技术应用能力提升网络研修心得范文
  4. 基于GmSSL搭建Nginx国密反代服务器
  5. 任旭阳全员邮件:一点资讯融资或将完成
  6. vue 数组中嵌套数组_Vue 嵌套数组 数组更新视图不更新
  7. CAD选中时不能虚线显示中选中状态
  8. 9iDataGurad报ORA12154TNScouldnotresolveservicename
  9. java输出值取后两位小数,java中取小数点后两位(四种步骤)
  10. 双系统主系统重做后另外系统找回