先看一下我的效果图吧:

好大的图啊!!!

百度音乐由一个很酷的功能,当前的UI可以滑动,然后看见上一个活动的UI,当时顿时觉得百度的牛人好多啊,能将如此前沿的技术应用到app上。当然如果你熟悉了Android的框架,熟知Activity的布局原理,那么实现起来还是很简单的。本人粗略的实现过,用的是View.layout(l, t, r, b)方法移动布局,总觉得有点山寨,但终究还是实现了嘛。好了不多说了,看我自己实现的方式吧。

首先准备创建两个Activity,至于布局xml文件怎么写,大家随便了,两个活动用一个xml布局即可。

为了方便大家copy(PS:本来我不想全部代码包括xml文件都粘贴在这里的,但是鉴于有些人实在太懒,连布局文件都不愿意随便写一个,然后在评论里喊,楼主,源码!我还是贴出来吧!)

一个简单的布局xml文件:layout_value_animation_layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" /> <ToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ToggleButton" /> <CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox" /> <RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RadioButton" /> <SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content" /> <RatingBar
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> <TextView
android:id="@+id/layout_value_animation_layout_text"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center"
android:text="A"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="80sp" /> </LinearLayout>

第一个活动:LayoutValueAnimationExampleA

package org.mrchen.commlib.example;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView; public class LayoutValueAnimationExampleA extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View root = getLayoutInflater().inflate(R.layout.layout_value_animation_layout, null);
setContentView(root); //
root.setBackgroundColor(Color.parseColor("#978856"));
TextView text = (TextView) findViewById(R.id.layout_value_animation_layout_text);
text.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25);
text.setText("A\n Click Me go to Activity LayoutValueAnimationExampleB");
text.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
startActivity(new Intent(LayoutValueAnimationExampleA.this, LayoutValueAnimationExampleB.class));
}
});
}
}

第二个活动:LayoutValueAnimationExampleB

package org.mrchen.commlib.example;

import org.mrchen.commlib.animation.LayoutValueAnimation;
import org.mrchen.commlib.animation.LayoutValueAnimation.LayoutValueParams;
import org.mrchen.commlib.animation.SmoothInterpolator;
import org.mrchen.commlib.helper.LogHelper;
import org.mrchen.commlib.helper.ScreenHelper; import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView; /**
* 注意当前的Activity在AndroidManifest.xml中的注册信息,主题应用了透明主题:AppTheme.Transparent
*
* @author chenjianli
*
*/
public class LayoutValueAnimationExampleB extends Activity { private final String TAG = "LayoutValueAnimationExampleB"; private View mRootView;
private LayoutValueAnimation mLayoutValueAnimation; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mRootView = getLayoutInflater().inflate(R.layout.layout_value_animation_layout, null);
setContentView(mRootView); //
mRootView.setBackgroundColor(Color.parseColor("#46b525"));
TextView text = (TextView) findViewById(R.id.layout_value_animation_layout_text);
text.setText("B");
mRootView.setOnTouchListener(movingEventListener);
} private OnTouchListener movingEventListener = new OnTouchListener() { int lastX, lastY; public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
// TODO
dy = 0; int left = v.getLeft() + dx;
int top = v.getTop() + dy;
int right = v.getRight() + dx;
int bottom = v.getBottom() + dy; v.layout(left, top, right, bottom); lastX = (int) event.getRawX();
lastY = (int) event.getRawY(); } if (event.getAction() == MotionEvent.ACTION_UP) { int left = v.getLeft();
int top = v.getTop();
int right = v.getRight();
int bottom = v.getBottom(); LogHelper.d(TAG, "l:" + left + ",t:" + top + ",r:" + right + ",b:" + bottom);
finishActivity(v, ScreenHelper.mScreenWidth - left);
}
return true;
}
}; public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
if (!isFinishing()) {
finishActivity(mRootView, ScreenHelper.mScreenWidth);
return true;
}
return super.onKeyDown(keyCode, event);
}; private void finishActivity(View v, int size) {
int duration = 666;
if (mLayoutValueAnimation == null) {
ScreenHelper.initialize(LayoutValueAnimationExampleB.this);
mLayoutValueAnimation = new LayoutValueAnimation(new LayoutValueParams(size,
LayoutValueParams.DIRECTION_RIGHT), duration);
mLayoutValueAnimation.setInterpolator(new SmoothInterpolator());
}
mLayoutValueAnimation.startAnimation(v); v.postDelayed(new Runnable() {
@Override
public void run() {
LayoutValueAnimationExampleB.this.finish();
}
}, duration);
}
}

许多人可能要崩溃了,怎么回事,这么多类没有,由一些类是我自己库中常用的工具类,比如ScreenHelper,这个类没什么功能,就是得到屏幕的宽度啥的,调用初始化方法

initialize(context)

完成初始化的工作,就可以拿来用了。

这里由必要贴一下

LayoutValueAnimation

类,这个类是拜一位大侠的文章所赐,产生出的属于我自己的衍生品,大家拿来用就好,具体的注释我已经卸载类里面了。

package org.mrchen.commlib.animation;

import org.mrchen.commlib.animation.LayoutValueAnimation.LayoutValueParams;
import org.mrchen.commlib.helper.LogHelper; import android.view.View;
import android.view.animation.AnimationUtils; /**
* 促使调用mTargetView.layout(l,t,r,b); <br>
* 参数配置类:{@link LayoutValueParams}
*
* @author chenjianli
*
*/
public class LayoutValueAnimation extends AbstractAnimation { private final static String TAG = "LayoutValueAnimation"; private int mCurrSize;
private int originalLeft;
private int originalRight;
private int originalTop;
private int originalBottom; private int targetLeft;
private int targetRight;
private int targetTop;
private int targetBottom; /**
* {@link LayoutValueAnimation} 的辅助参数类,用于指定位移和移动方向 <br>
*
* @author chenjianli
*
*/
public static class LayoutValueParams {
public int size; public static final int DIRECTION_LEFT = 1;
public static final int DIRECTION_RIGHT = 2;
public static final int DIRECTION_TOP = 3;
public static final int DIRECTION_BOTTOM = 4; public int direction; /**
*
* @param size
* 只能是正整数
* @param direction
* 指明运动方向,有<br>
* {@link LayoutValueParams.DIRECTION_LEFT},<br>
* {@link LayoutValueParams.DIRECTION_RIGHT},<br>
* {@link LayoutValueParams.DIRECTION_TOP},<br>
* {@link LayoutValueParams.DIRECTION_BOTTOM},<br>
*/
public LayoutValueParams(int size, int direction) {
this.size = size;
this.direction = direction;
}
} private LayoutValueParams mParams; public LayoutValueAnimation(LayoutValueParams params, int duration) {
mParams = params;
mDuration = duration;
} // 启动动画
public void startAnimation(View view) {
if (view != null) {
mTargetView = view;
} else {
LogHelper.e(TAG, "view 不能为空");
return;
} if (isFinished) {
mDurationReciprocal = 1.0f / (float) mDuration;
isFinished = false;
// 记录下动画开始的时间
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDSize = mParams.size;
LogHelper.d(TAG, "mDSize=" + mDSize);
int l = mTargetView.getLeft();
int t = mTargetView.getTop();
int r = mTargetView.getRight();
int b = mTargetView.getBottom();
LogHelper.d(TAG, "startAnimation >原始的> l = " + l + ", t = " + t + ", r = " + r + ", b = " + b);
originalLeft = l;
originalRight = r;
originalTop = t;
originalBottom = b;
mHandler.start();
}
} @Override
public boolean computeSize() {
// TODO Auto-generated method stub
if (isFinished) {
return isFinished;
}
int timePassed = (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed <= mDuration) {
float x = timePassed * mDurationReciprocal;
if (mInterpolator != null) {
x = mInterpolator.getInterpolation(x);
}
switch (mParams.direction) {
case LayoutValueParams.DIRECTION_LEFT:
case LayoutValueParams.DIRECTION_TOP:
mCurrSize = -Math.round(x * mDSize);
break;
case LayoutValueParams.DIRECTION_RIGHT:
case LayoutValueParams.DIRECTION_BOTTOM:
mCurrSize = Math.round(x * mDSize);
break;
}
} else {
isFinished = true;
switch (mParams.direction) {
case LayoutValueParams.DIRECTION_LEFT:
case LayoutValueParams.DIRECTION_TOP:
mCurrSize = -mDSize;
break;
case LayoutValueParams.DIRECTION_RIGHT:
case LayoutValueParams.DIRECTION_BOTTOM:
mCurrSize = mDSize;
break;
}
} // 计算最终目标坐标
switch (mParams.direction) {
case LayoutValueParams.DIRECTION_LEFT:
case LayoutValueParams.DIRECTION_RIGHT:
targetLeft = originalLeft + mCurrSize;
targetRight = originalRight + mCurrSize;
targetTop = originalTop;
targetBottom = originalBottom;
break;
case LayoutValueParams.DIRECTION_TOP:
case LayoutValueParams.DIRECTION_BOTTOM:
targetTop = originalTop + mCurrSize;
targetBottom = originalBottom + mCurrSize;
targetLeft = originalLeft;
targetRight = originalRight;
break;
}
LogHelper.d(TAG, "computeSize >目标> l = " + targetLeft + ", t = " + targetTop + ", r = " + targetRight
+ ", b = " + targetBottom);
applySize();
return isFinished;
} @Override
public void applySize() {
// TODO Auto-generated method stub
if (mTargetView != null && mTargetView.getVisibility() != View.GONE) {
mTargetView.layout(targetLeft, targetTop, targetRight, targetBottom);
}
}
}

卧槽,又有一个类:AbstractAnimation

package org.mrchen.commlib.animation;

import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.animation.Interpolator; public abstract class AbstractAnimation implements AbstractAnimationImpl { private final int FRAME_TIME = 20;// 一帧的时间 毫秒
protected View mTargetView;// 执行"动画"的目标View
protected Interpolator mInterpolator;// 插值器
protected boolean isFinished = true;// 动画结束标识; protected int mDuration; // 动画运行的时间
protected long mStartTime;// 动画开始时间
protected float mDurationReciprocal;// Reciprocal:相互的,倒数的
protected int mDSize; // 需要改变view大小的增量 private AnimationListener mAnimationListener; public interface AnimationListener {
public void animationEnd(View v);
} public void setOnAnimationListener(AnimationListener listener) {
mAnimationListener = listener;
} public void setInterpolator(Interpolator interpolator) {
mInterpolator = interpolator;
} public boolean isFinished() {
return isFinished;
} public void setDuration(int duration) {
mDuration = duration;
} protected AnimationHandler mHandler = new AnimationHandler(); class AnimationHandler extends Handler {
@Override
public void handleMessage(Message msg) { if (msg.what == 1) {
if (!computeSize()) {
mHandler.sendEmptyMessageDelayed(1, FRAME_TIME);
} else {
if (mAnimationListener != null) {
mAnimationListener.animationEnd(mTargetView);
}
}
}
super.handleMessage(msg);
} public void start() {
sendEmptyMessage(1);
}
} }

没完了:AbstractAnimationImpl

package org.mrchen.commlib.animation;

import android.view.View;

public interface AbstractAnimationImpl {
public boolean computeSize();// 计算变量 public void applySize();// 应用计算的变量 public void startAnimation(View v);// 启动动画
}

好了,代码基本上差不多了,最后贴一下AndroidManifest.xml文件就打工告成了,大家可以运行看下效果。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mrchen.commlib.example"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="14" /> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="org.mrchen.commlib.example.LayoutValueAnimationExampleA"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="org.mrchen.commlib.example.LayoutValueAnimationExampleB"
android:label="@string/app_name"
android:theme="@style/AppTheme.Transparent" >
</activity>
</application> </manifest>

看来还有主题没贴出来:

	<resources>

	    <!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Black.NoTitleBar">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style> <!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme"> <!-- All customizations that are NOT specific to a particular API-level can go here. -->
<item name="android:windowContentOverlay">@null</item>
</style> <style name="AppTheme.Transparent" parent="AppTheme"> <!-- All customizations that are NOT specific to a particular API-level can go here. -->
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>
</resources>
 

Android学习之可滑动当前的Activity视图看见上一个活动的视图的更多相关文章

  1. Android学习路线(十二)Activity生命周期——启动一个Activity

    DEMO下载地址:http://download.csdn.net/detail/sweetvvck/7728735 不像其他的编程模式那样应用是通过main()函数启动的.Android系统通过调用 ...

  2. Android学习总结——获取被启动的Activity传回的数据

    当前Activity:包含一个Button和一个TextView,用于启动另一个Activity和显示传回的数据,这里重写了onActivityResult()方法. public class Mai ...

  3. 【Android】7.0 Intent向下一个活动传递数据、返回数据给上一个活动

    1.0 可以利用Intent吧数据传递给上一个活动,新建一个叫“hellotest01”的项目. 新建活动FirstActivity,勾选“Generate Layout File”和“Launche ...

  4. 【Android】Intent的使用-返回数据给上一个活动

    第一个Activity  A启动另外一个Activity B,B返回数据给A ============================================================= ...

  5. Android学习笔记之滑动翻页(屏幕切换)

    如何实现手机上手动滑动翻页效果呢?呵呵,在这里我们就给你们介绍一下吧. 一般实现这个特效会用到一个控件:ViewFlipper <1>View切换的控件—ViewFlipper 这个控件是 ...

  6. Android学习之多触点滑动

    知识点: 1.对矩阵:Matrix类熟悉,链接:https://blog.csdn.net/jdsjlzx/article/details/52741445 2.MotionEvent详解:https ...

  7. (Android学习系列)二,窗口(Activity)的生命周期

    在Activity从创建到销毁的过程中需要在不同的阶段调用7个生命周期的方法这7个生命周期方法定义如下: protected void onCreate(Bundle savedInstanceSta ...

  8. Android学习笔记_16_添加多个Activity、参数传递、请求码和结果码使用

    一.添加新的Activity步骤: 第一步:新建一个继承Activity的类,如:NewActivity public class NewActivity extends Activity { @Ov ...

  9. Android学习系列(10)--App列表之拖拽ListView(上)

     研究了很久的拖拽ListView的实现,受益良多,特此与尔共飨.      鉴于这部分内容网上的资料少而简陋,而具体的实现过程或许对大家才有帮助,为了详尽而不失真,我们一步一步分析,分成两篇文章. ...

随机推荐

  1. hdu 2444(二分图) The Accomodation of Students

    http://acm.hdu.edu.cn/showproblem.php?pid=2444 大意是给定n个学生,他们之间可能互相认识,首先判断能不能将这些学生分为两组,使组内学生不认识: 现想将学生 ...

  2. poj 3624 && hdu 2955(背包入门)

    http://poj.org/problem?id=3624 背包中最基础的01背包,大意是有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使价值总 ...

  3. 解决IDEA 配置搞坏的问题

    如果我们把IDEA的配置给搞坏了,或者想重新配置,恢复到默认配置. 1.打开如下的目录(不同用户名目录有差异),如下所示: 2.删除掉config 和 system 目录,重新启动 IDEA会自动生成 ...

  4. ajax异步请求该嵌套还是并列?

    因为要查询两个数据库表才能确定我所需要的数据范围,所以前台js得发两次ajax请求.问题就是,这两个请求是嵌套着写:{发,接{发,接}}:还是并列着写:{发,接},{发,接} 好? 答案:如果2次aj ...

  5. Mysql 注入load_file常用路径

    WINDOWS下: c:/boot.ini //查看系统版本 c:/windows/php.ini //php配置信息 c:/windows/my.ini //MYSQL配置文件,记录管理员登陆过的M ...

  6. swift NSdata 转换 nsstring

    result = NSString(data: data, encoding: NSUTF8StringEncoding) 做HTTP 请求时 遇到 打印结果看  所以~~~

  7. sql 用Group by分组后,取每组的前几条记录

    转自:http://blog.163.com/jeson_lwj/blog/static/135761083201052411115783/ --查询每门课程的前2名成绩 CREATE TABLE S ...

  8. .Net直接将Web页面table导出到Excel

    项目管理系统有个统计表需要导出到Excel表中.常用的方法是在后台C#代码查询数据再写入Excel表中最后保存在目标路径. 为减轻数据库服务器的压力和保持页面的样式,能否直接将页面的表格直接导出到Ex ...

  9. 进制转换(NOIP2000&NOIP水题测试(2017082301))

    题目链接:进制转换 这题得明白其中的数学方法,明白后就不难了. 那么我们应该怎么计算呢? 其实也很简单. 我们依然采取辗转相除法. 但是,对于负的余数,我们需要进行一些处理. 我们怎么处理呢? 很简单 ...

  10. android开发笔记(2)

    我之前完成了SDK的安装,这次需要在eclipse中导入相关的控件. 一.下载ADT 在之前下载的网站上下载相关的ADT的压缩包. 二.在eclipse中进行导入 在eclipse中的Help-> ...