做过asp.net或其他web开发的朋友都知道,想要在两个网页间做转换,只要利用超链接就可以实现。但在手机里,要如何实现手机页面之间的转换呢?最简单的方法就是改变Activity的Layout。首先准备两个布局文件Main.axml和Layout2.axml。在Layout1中放置一个按钮,当单击时,显示Layout2,同样地,在Layout2里也放一个按钮,当单击时回到Main.
- <?xml version="1.0" encoding="utf-8"?>
- <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView android:text="这是Layout1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <Button android:text="跳到Layout2"
- android:layout_y="30px"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/btn1"/>
- </AbsoluteLayout>
- <?xml version="1.0" encoding="utf-8"?>
- <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@color/white">
- <TextView android:text="这是Layout2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
- <Button android:text="跳到Layout1"
- android:layout_y="30px"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/btn2"/>
- </AbsoluteLayout>
然后在Activity1.cs中的OnCreate方法里加入如下代码:
- using System;
- using Android.App;
- using Android.Content;
- using Android.Runtime;
- using Android.Views;
- using Android.Widget;
- using Android.OS;
- using MonoDroidTest.Tabs;
- using Android.Util;
- using Java.IO;
- using Android.Database;
- namespace MonoDroidTest
- {
- [Activity(Label = "MonoDroidTest", MainLauncher = true)]
- public class Activity1 : Activity
- {
- protected override void OnCreate(Bundle bundle)
- {
- base.OnCreate(bundle);
- SetContentView(Resource.Layout.Main);
- Button btn1 = FindViewById<Button>(Resource.Id.btn1);
- btn1.Click += (sender, e) =>
- {
- this.SetContentView(Resource.Layout.Activity2);
- Button btn2 = FindViewById<Button>(Resource.Id.btn2);
- btn2.Click += (sender2, e2) =>
- {
- OnCreate(bundle);
- };
- };
- }
- }
- }
运用改变Activity的Layout这个技巧,就可以做出手机页面转换的效果,当然也可以搭配之前介绍的Style设置,进行更加灵活的布局配置运用。再者,利用SetContentView来置换页面还有一个特别的优点,即所有程序里的变量皆存在相同的状态,无论是类成员、类方法等,都在一个Activity的状态中直接取得,并没有参数传递的问题。比如要进行分步导航的页面,从第一个页面得到的信息无需传递到第二个页面,而是一直存放在当前Activity的成员中,可以随时拿来使用。
如果要转换的页面不单只是背景,颜色或文字的内容的不同,而是Activity的置换,那就不是单单改变Layout就能完成的了。尤其是需要传递的数据不像网页可以通过Session或Cache来实现,在程序里移交主控权到另一个Activity,光靠先前的Layout技巧是办不到的。
那要如何解决Activity控制权的移交呢?在MonoDroid里,可以在主程序中使用StartActivity方法来调用另一个Activity(主程序本身就是一个Activity),但当中的关键并不在StartActivity这个方法,而是Intent这个特有的对象。Intent就如同其英文字义,是“想要”或“意图”之意,在主Activity中,告诉程序自己是什么,并想要前往哪里,这就是Intent对象所处理的事情了。
布局文件与刚才一样,不同的是程序代码,修改Activity.cs如下,在这里教大家另外一个绑定控件事件的方法,在.net程序里,我们要绑定事件,只要在事件名后+=事件处理对象或lambda表达式即可,如btn.Click += (sender, e) => { };在MonoDroid里,为了与Java中的写法保持一致,除了上面这种方式之外,还提供了另外一种方式,即SetOnXXXListener方法。如按钮的Click事件,就调用SetOnClickListener,传入的参数是实现View.IOnClickListener的类。另外,要实现Java中的借口,你的类还要继承Java.Lang.Object类,这样就无需实现IObject的Handle属性了。
- using System;
- using Android.App;
- using Android.Content;
- using Android.Runtime;
- using Android.Views;
- using Android.Widget;
- using Android.OS;
- using MonoDroidTest.Tabs;
- using Android.Util;
- using Java.IO;
- using Android.Database;
- namespace MonoDroidTest
- {
- [Activity(Label = "MonoDroidTest", MainLauncher = true)]
- public class Activity1 : Activity
- {
- protected override void OnCreate(Bundle bundle)
- {
- base.OnCreate(bundle);
- SetContentView(Resource.Layout.Main);
- Button btn = FindViewById<Button>(Resource.Id.btn1);
- btn.SetOnClickListener(new ClickListener());
- }
- }
- public class ClickListener : Java.Lang.Object, View.IOnClickListener
- {
- public void OnClick(View v)
- {
- Activity act = v.Context as Activity;
- Intent intent = new Intent();
- intent.SetClass(act, typeof(Activity2));
- act.StartActivity(intent);
- act.Finish();
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Android.App;
- using Android.Content;
- using Android.OS;
- using Android.Runtime;
- using Android.Views;
- using Android.Widget;
- namespace MonoDroidTest
- {
- [Activity(Label = "My Activity")]
- public class Activity2 : Activity
- {
- protected override void OnCreate(Bundle bundle)
- {
- base.OnCreate(bundle);
- SetContentView(Resource.Layout.Activity2);
- Button btn = FindViewById<Button>(Resource.Id.btn2);
- btn.Click += delegate
- {
- Intent intent = new Intent();
- intent.SetClass(this, typeof(Activity1));
- this.StartActivity(intent);
- this.Finish();
- };
- }
- }
- }
在Activity1和Activity2两个类里都调用了Finish()这个方法,它代表这个Activity已经运作完毕,当系统接收到这个命令时,即会关闭此Activity,所以此时单击模拟器的返回(Back)键,并不会回到上一个Activity的画面,如果要让模拟器的返回键有回上一页的效果,可以将此行代码注释掉。同理,在两个Acitivity在切换时,并非真的只有两个Activity在切换,而是在单击按钮时再重新调用一个新的Activity。
若需要在调用另一个Activity的同时传递数据,那么就需要利用Bundle对象来封装数据了。将想要传递的数据或参数通过Bundle来传递不同Intent之间的数据。
我们从Activity1调用Activity2的同时,把一个字符串和一个整型传到Activity2试试,对ClickListener类的OnClick方法增加几行代码:
- public void OnClick(View v)
- {
- Activity act = v.Context as Activity;
- Intent intent = new Intent();
- intent.SetClass(act, typeof(Activity2));
- Bundle b = new Bundle();
- b.PutString("name", "ojlovecd");
- b.PutInt("score", 76195);
- intent.PutExtras(b);
- act.StartActivity(intent);
- act.Finish();
- }
然后在Activity2中进行接收这两个值,为了在Activity2加载后弹出提示,我们先来封装一个信息框提示类。这里要用到AlertDialog窗口,它常用于“程序提示”,“警告”或“确认”等。
- using System;
- using Android.App;
- using Android.Content;
- namespace MonoDroidTest
- {
- public class MessageBox
- {
- public static void Show(Context ctx,string title, string message)
- {
- AlertDialog.Builder dlg = new AlertDialog.Builder(ctx);
- dlg.SetTitle(title);
- dlg.SetMessage(message);
- dlg.SetPositiveButton("确定", delegate { });
- dlg.Show();
- }
- public static void ShowErrorMessage(Context ctx, Exception ex)
- {
- Show(ctx, "错误", ex.Message);
- }
- }
- }
然后我们再在Activity2中使用这个类来显示从Activity1传递过来的参数:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Android.App;
- using Android.Content;
- using Android.OS;
- using Android.Runtime;
- using Android.Views;
- using Android.Widget;
- namespace MonoDroidTest
- {
- [Activity(Label = "My Activity")]
- public class Activity2 : Activity
- {
- protected override void OnCreate(Bundle bundle)
- {
- base.OnCreate(bundle);
- SetContentView(Resource.Layout.Activity2);
- Bundle b = this.Intent.Extras;
- Button btn = FindViewById<Button>(Resource.Id.btn2);
- btn.Click += delegate
- {
- Intent intent = new Intent();
- intent.SetClass(this, typeof(Activity1));
- this.StartActivity(intent);
- this.Finish();
- };
- MessageBox.Show(this, "信息", string.Format("用户名:{0}/n积分:{1}", b.GetString("name"), b.GetInt("score")));
- }
- }
- }
运行结果:
Bundle对象针对不同的数据类型提供了多种方法,例如上面传递string类型的数据,使用了PutString,而要传递double类型的数据,使用PutDouble,反之,要从Bundle对象取出数据,就把Put改为Get即可。我曾经尝试传递非基础类型的数据,即自定义类型的数据,但无论我的对象是实现了Java.IO.ISerializable,然后调用PutSerializable方法,还是实现IParcelable,调用PutParcelable方法,在Get的时候都会报错,实在无奈,如果有哪位朋友能够成功传递自定义类型的数据的话,还请共享一下。
在上一个范例中,好不容易将数据从Activity1传递到Activity2,如果要再回到Activity1,数据该不会要再封装一次吧?而且前一个Activity1早就被destroy了,倘若在Activity1最后以Finish()结束程序,再通过Activity2将数据采用Bundle的方式通过新打开Activity1传递参数,这样的做法虽然也可以恢复用户输入的数据,但并不符合我们的期待,尤其是用户曾经输入过的数据,如果不小心单击回到上一页,数据就消失不见了。
如果要在第二个页面加上一个“回上页”的按钮,而非通过模拟器的返回键,且回上页后又能保留之前的相关信息,那么就必须用StartActivityForResult方法来唤起另一个Activity。要处理Activity2返回的结果,就要在Activity1中重写OnActivityResult方法,程序如下:
- using System;
- using Android.App;
- using Android.Content;
- using Android.Runtime;
- using Android.Views;
- using Android.Widget;
- using Android.OS;
- using MonoDroidTest.Tabs;
- using Android.Util;
- using Java.IO;
- using Android.Database;
- namespace MonoDroidTest
- {
- [Activity(Label = "MonoDroidTest", MainLauncher = true)]
- public class Activity1 : Activity
- {
- protected override void OnCreate(Bundle bundle)
- {
- base.OnCreate(bundle);
- SetContentView(Resource.Layout.Main);
- Button btn = FindViewById<Button>(Resource.Id.btn1);
- btn.SetOnClickListener(new ClickListener());
- }
-
- protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
- {
- if (resultCode == Result.Ok)
- {
- Bundle b = data.Extras;
- string name = b.GetString("name");
- int score = b.GetInt("score");
- string blogUrl = b.GetString("blogUrl");
- int availableScore = b.GetInt("availableScore");
- MessageBox.Show(this, "提示", string.Format("名称:{0}/n积分:{1}/n博客地址:{2}/n可用分:{3}", name, score, blogUrl, availableScore));
- }
- }
- }
- public class ClickListener : Java.Lang.Object, View.IOnClickListener
- {
- public void OnClick(View v)
- {
-
-
- Activity act = v.Context as Activity;
- Intent intent = new Intent();
- intent.SetClass(act, typeof(Activity2));
- Bundle b = new Bundle();
- b.PutString("name", "ojlovecd");
- b.PutInt("score", 76195);
- intent.PutExtras(b);
- act.StartActivityForResult(intent, 0);
-
-
-
-
-
-
-
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Android.App;
- using Android.Content;
- using Android.OS;
- using Android.Runtime;
- using Android.Views;
- using Android.Widget;
- namespace MonoDroidTest
- {
- [Activity(Label = "My Activity")]
- public class Activity2 : Activity
- {
- protected override void OnCreate(Bundle bundle)
- {
- base.OnCreate(bundle);
- SetContentView(Resource.Layout.Activity2);
- Bundle b = this.Intent.Extras;
-
- Button btn = FindViewById<Button>(Resource.Id.btn2);
- btn.Click += delegate
- {
- Intent intent = new Intent();
- b.PutString("blogUrl", "http://blog.csdn.net/ojlovecd");
- b.PutInt("availableScore", 18734);
- intent.PutExtras(b);
- this.SetResult(Result.Ok, intent);
- this.Finish();
- };
- MessageBox.Show(this, "信息", string.Format("用户名:{0}/n积分:{1}", b.GetString("name"), b.GetInt("score")));
- }
- }
- }
运行结果:
就本范例而言,其实使用StartActivity也可以达成相同的效果,仅需在Activity1被Create时判断Intent内有没有数据,有的话,就将数据带入,没有就带入null。但程序还需要做有无值的比较,较为繁琐,既然MonoDroid API提供了更好用的方法,何乐而不为呢?更何况如果系统不是只有几行,而是几百几千行,那不就头大了?
转载http://blog.csdn.net/ojlovecd/article/details/6302307