Android学习之可滑动当前的Activity视图看见上一个活动的视图

先看一下我的效果图吧:


好大的图啊!!!

百度音乐由一个很酷的功能,当前的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>


 

 

 

posted on 2013-11-01 19:17  you Richer  阅读(353)  评论(0编辑  收藏  举报