Android平台通过ActivityGroup实现类似IOS的UINavigationController


android程序中最基本的组成部分是activity,一个程序有多个activity,当启动一个新的activity的时候,新的activity会出现在屏幕上覆盖旧的activity;当这个activity finish()的时候,之前的activity重新显示出来.

简单的说,这是一个类似于栈的结构,即原有activity A1:[A1]

现在新开activity A2:[A1 A2]

当A2finish的时候,再显示A1:[A1]

这符合栈的特点,即后入先出,也符合一般人的思考逻辑,及返回键返回到之前的页面.

但是这样的结构有一个局限性,这样启动的activity都是我们通过Activity.startActivity(intent)这种方式启动的,是属于全屏的.

当我们只是想在一个页面的某个部分去启动一个activity,而且还保持这种层次结构,应该如何进行呢?

在ios平台上最基本的元素是ViewController和Controller对应的View,因此ios平台上提供了一个以UIVIEW为元素的栈来时限这样的功能,称为UINavigationController.这里不讨论它的使用,有兴趣的同学可以自己去学习.这里重点说明一下如何用ActivityGroup来实现类似的功能.


package com.zz;

import java.util.Stack;
import java.util.UUID;

import android.app.ActivityGroup;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.LinearLayout;

/**
 * 各个Tab对应的Activity的父类
 * 
 * @author zhouzhe@lenovo-cw.com
 */
public abstract class ActivityStack extends ActivityGroup {

	/** 一个activity的栈用来存放缓存的View */
	Stack<StackElement> stack;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		stack = new Stack<StackElement>();
	}

	/**
	 * 一个抽象方法,返回一个LinearLayout实际上是一个区域用来展示栈内的view
	 * 
	 * @return
	 * @author zhouzhe@lenovo-cw.com
	 * @time 2012-2-20
	 */
	abstract LinearLayout getMainView();

	/**
	 * 用来向栈顶添加一个元素并显示
	 * 
	 * @param intent
	 *            跟启动activity的intent一样
	 * @author zhouzhe@lenovo-cw.com
	 * @time 2012-2-20
	 */
	void addView(Intent intent) {
		// 生成一个字符串,作为启动activity的key,后面在移除了view以后,要通过这个key来finish对应的activity
		String str = UUID.randomUUID().toString();
		getMainView().removeAllViews();
		View view = getLocalActivityManager().startActivity(str, intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
		// 注意layoutParams,否则会造成无法充满的问题
		getMainView().addView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
		getMainView().requestFocus();
		// 生成一个栈内缓存对象,主要包括activity对应的view和对应的key,并压入栈中
		StackElement component = new StackElement(str, view);
		stack.add(component);
	}

	/**
	 * 弹栈操作
	 * 
	 * @return
	 * @author zhouzhe@lenovo-cw.com
	 * @time 2012-2-20
	 */
	int pop() {
		// 先判断是否已经是栈顶元素了
		int size = stack.size();
		StackElement element = null;
		if (size > 1) {
			// 如果不是,获取到栈顶元素,并销毁.然后再获取当前的栈顶元素,显示到activityGroup
			element = stack.pop();
			getLocalActivityManager().destroyActivity(element.getTag(), true);
			element = stack.peek();
		} else if (size == 1) {
			// 如果是栈顶元素,直接显示
			element = stack.peek();
		}
		getMainView().removeAllViews();
		getMainView().addView(element.getView());
		getMainView().requestFocus();
		return stack.size();
	}

	/**
	 * 清空Stack,仅保留最底层的view
	 */
	void clearStack() {
		int size = stack.size();
		if (size > 1) {
			for (int i = 0; i < size - 1; i++) {
				stack.pop();
			}
		}
	}

	void clearAll() {
		int size = stack.size();
		if (size > 0) {
			for (int i = 0; i < size; i++) {
				StackElement element = stack.pop();
				getLocalActivityManager().destroyActivity(element.getTag(), true);
			}
		}
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
	}

	@Override
	public boolean dispatchKeyEvent(KeyEvent event) {
		// 对键盘事件的处理,如果当前activityGroup中已经载入了activity,则分发给子activity处理,如果没有则自己处理.
		if (getCurrentActivity() != null) {
			return getCurrentActivity().dispatchKeyEvent(event);
		} else {
			return super.dispatchKeyEvent(event);
		}

	}

}

这是一个比较简单的类,简单说明一下流程.

activityGroup载入activity,A1的时候,使用addView方法,压入栈中.在加载A2的时候,还是调用activityStack的addView方法,移除A1,加入A2并压入栈中.在finish A2的时候,不能直接finish,这样整个activityGroup都被finish掉了.要调用activityStack的pop方法,移除栈顶元素,销毁,显示移除后的栈顶元素.同时要注意分发键盘的back事件,同样是要用pop方法取代默认的finish方法,这样即可完成一个类似于uinavigationcontroller的栈.


有兴趣的同学看一下吧.

源代码 http://download.csdn.net/detail/zz880329/4076318




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值