利用Fragment设计能够兼容不同屏幕的应用

这里我们先围观下最后的成果图,给读者打打气:

普通手机上显示的结果:

在平板上显示的结果:

笔者要郑重声明下,虽然看似是两种不同的显示效果,但是同一个应用,而下面笔者将逐步教会大家如何利用Fragment制作出能够兼容不同屏幕的应用。

准备工作

创建一个项目是必不可少的,并且Android SDK的版本要在3.0以上,建议是4.0因为笔者设定的就是4.0,新建完成之后项目会自动帮我们创建好MainActivity,当然靠这一个还不足够,我们还要新建一个Activity,并命名为DetailsActivity,另外还有两个Fragment分为命名为DetailsFragmentTitlesFragment,最后的目录结构应该如下图所示:

创建兼容视图

现在我们先把呈现部分的功能完成,我们打开Resources\Layout下的Main.axml将下面的xml代码写入:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:orientation="horizontal"
 4     android:layout_width="fill_parent"
 5     android:layout_height="fill_parent">
 6     <fragment
 7         class="fragmentwalkthrough.TitlesFragment"
 8         android:id="@+id/titles_fragment"
 9         android:layout_width="fill_parent"
10         android:layout_height="fill_parent" />
11 </LinearLayout>

这里我们就利用了fragment作为占位符,从而显示TitlesFragment,笔者还要注意class的完整路径,要按照自己实际项目的名称来,一般都是解决方案的名字的小写加上点然后就是对应的类名了。

光有这个视图只能应付小屏幕的显示,我们还需要为大屏幕设计一个视图。但是我们不能在layout下继续新建,那样我们就要用代码负责控制了,其实Android本身就已经提供了这些功能,我们只要在Resources下新建一个文件夹并且命名为layout-large,然后在该文件夹下新建一个Main.axml,这里的视图文件命名必须要和layout下的一致,然后将下面的内容写入其中:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:orientation="horizontal"
 4     android:layout_width="fill_parent"
 5     android:layout_height="fill_parent">
 6     <fragment
 7         class="fragmentwalkthrough.TitlesFragment"
 8         android:id="@+id/titles_fragment"
 9         android:layout_weight="1"
10         android:layout_width="0px"
11         android:layout_height="match_parent" />
12     <FrameLayout
13         android:id="@+id/details"
14         android:layout_weight="3"
15         android:layout_width="0px"
16         android:layout_height="match_parent" />
17 </LinearLayout>

这里多了一个FrameLayout这个就是作为内容的容器,最后我们可以看到在我们选择不同的项的时候,都会在这个占位符中切换碎片(Fragment),这里提示下我们还要把MainActivity.cs中的自动生成的代码删除,最后只要剩下以下的内容即可:

1         protected override void OnCreate(Bundle bundle)
2         {
3             base.OnCreate(bundle);
4             SetContentView(Resource.Layout.Main);
5         }

完成了上面的内容,我们下面就开始从下而上来开始。

完善DetailsFragment

唯一需要学习的就是OnCreateView方法,这个方法就是来用指定碎片的视图的,最后显示的是返回的视图,具体的代码如下所示:

 1     public class DetailsFragment : Fragment
 2     {
 3         public static DetailsFragment NewInstance(int playId)
 4         {
 5             var detailsFrag = new DetailsFragment
 6             {
 7                 Arguments = new Bundle()
 8             };
 9             detailsFrag.Arguments.PutInt("current_play_id", playId);
10             return detailsFrag;
11         }
12
13         public int ShowPlayId
14         {
15             get
16             {
17                 return Arguments.GetInt("current_play_id", 0);
18             }
19         }
20
21         public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
22         {
23             if (container == null)
24             {
25                 return null;
26             }
27             var scroller = new ScrollView(Activity);
28             var text = new TextView(Activity);
29             text.SetPadding(4, 4, 4, 4);
30             text.TextSize = 24;
31             text.Text = "you select " + ShowPlayId;
32             scroller.AddView(text);
33             return scroller;
34         }
35 }

我们仅仅只是对选择的项的id保存了,提供还提供了一个快捷方法NewInstance用来实例化这个碎片,最后的内容仅仅只是通过TextView呈现的,笔者后面也可以设计一个视图,然后利用inflater参数实例化并返回。

完善DetailsActivity

这个活动纯粹只是为了兼容小屏幕的,因为它只是一个躯壳,负责将发送给它的参数在转发给DetailsFragment,并显示DetailFragment。具体的代码如下所示:

 1     [Activity(Label = "DetailsActivity")]
 2     public class DetailsActivity : Activity
 3     {
 4         protected override void OnCreate(Bundle bundle)
 5         {
 6             base.OnCreate(bundle);
 7             var index = Intent.Extras.GetInt("current_play_id", 0);
 8             var details = DetailsFragment.NewInstance(index);
 9             var ft = FragmentManager.BeginTransaction();
10             ft.Add(Android.Resource.Id.Content, details);
11             ft.Commit();
12         }
13 }

我们注意到了FragmentManger这个类,它对于我们今后使用碎片都是非常重要的,只要在活动里面切换碎片,删除碎片等都要通过它。这一过程还必须要使用BeginTransaction先开启事务,完成操作后还要通过Commit提交,否则是没有效果的。

完善TitlesFragment

这里我们看到了列表显示的数据,而这些数据都是定义在Strings.xml中的,所以我们先要定义这些资源,代码如下所示:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3     <string name="Hello">Hello World, Click Me!</string>
 4     <string name="ApplicationName">FragmentWalkthrough</string>
 5   <string-array name="TitleList">
 6     <item>First</item>
 7     <item>Second</item>
 8     <item>Third</item>
 9     <item>Fourth</item>
10     <item>Fifth</item>
11     <item>Sixth</item>
12   </string-array>
13 </resources>

完成上面的操作后,我们就要重点学习TitlesFragment中的功能,首先我们删除里面默认重写的方法,然后将继承的类改成ListFragment,并重写OnActivityCreated,因为我们继承了这个类,就跟ListActivity一样,所以不需要在设置界面。

为了能够兼容不同的屏幕,所以我们需要一个bool类型的变量去保存当前的屏幕是属于大还是小,从而决定相关的功能,并且还要有一个int类型的变量保存当前所选的数据的id,然后我们就可以完善OnActivityCreated方法了:

 1         protected int _currentPlayId;
 2         protected bool _isDualPanel;
 3
 4         public override void OnActivityCreated(Bundle savedInstanceState)
 5         {
 6             base.OnActivityCreated(savedInstanceState);
 7             //从Resources将资源取出
 8             string[] strarray = Resources.GetStringArray(Resource.Array.TitleList);
 9
10             //实例化一个适配器并将适配器赋给ListAdapter
11             var adapter = new ArrayAdapter<string>(Activity, Android.Resource.Layout.SimpleListItemChecked, strarray);
12             ListAdapter = adapter;
13
14             //判断是否存在上一次会话的数据
15             if (savedInstanceState != null)
16             {
17                 _currentPlayId = savedInstanceState.GetInt("current_play_id", 0);
18             }
19
20             //获取用于碎片的占位符
21             var detailsFrame = Activity.FindViewById<View>(Resource.Id.details);
22
23             //根据该占位符是否存在以及是否可见,从而决定是否为大屏幕
24             _isDualPanel = detailsFrame != null && detailsFrame.Visibility == ViewStates.Visible;
25
26             //当前屏幕为大屏幕时操作
27             if (_isDualPanel)
28             {
29                 ListView.ChoiceMode = ChoiceMode.Single;
30                 ShowDetails(_currentPlayId);
31             }
32         }

这里只是初始化了列表并判断了当前属于那种情况,下面我们就要介绍重要的ShowDetails方法,该方法将负责用户点击某项后采用那种方式呈现,下面是该代码:

 1         public void ShowDetails(int playid)
 2         {
 3             _currentPlayId = playid;
 4             //判断当前屏幕显示的方案
 5             if (_isDualPanel)
 6             {
 7                 //为大屏幕时显示的方案
 8
 9                 ListView.SetItemChecked(playid, true);
10                 //通过碎片管理器查找对应的碎片  如果是第一次显示则返回的是null
11                 var details = FragmentManager.FindFragmentById(Resource.Id.details) as DetailsFragment;
12
13                 //判断是否存在该碎片的实例化对象或该对象显示的内容是否跟当前选择的内容一致
14                 if (details == null || details.ShowPlayId != playid)
15                 {
16                     //实例化碎片
17                     details = DetailsFragment.NewInstance(playid);
18                     var ft = FragmentManager.BeginTransaction();
19                     //将FrameLayout占位符替换成details碎片
20                     ft.Replace(Resource.Id.details, details);
21                     ft.Commit();
22                 }
23             }
24             else
25             {
26                 //为小屏幕时显示的方案
27                 var intent = new Intent();
28                 intent.SetClass(Activity, typeof(DetailsActivity));
29                 intent.PutExtra("current_play_id", playid);
30                 StartActivity(intent);
31             }
32         }

这面的代码我们通过其中的注释就可以清楚的明白了,当然我们还要重写ListFragment的事件,代码如下所示:

1         //监听选择事件,在每次选择后重新显示详细内容
2         public override void OnListItemClick(ListView l, View v, int position, long id)
3         {
4             ShowDetails(position);
5         }

至此我们就实现了能够在不同屏幕下显示不同界面的方式,这在很大的程度上可以复用代码,而不需要非要单独去定制专门的应用。

源码下载

Xamarin.Android之Fragment Walkthrough相关推荐

  1. Xamarin.Android开发实践(十八)

    Xamarin.Android之SlidingMenu 一.前言 有位网友在评论中希望能够出个在Xamarin.Android下实现SlidingMenu效果的随笔,刚好昨天在观看官网示例项目的时候也 ...

  2. xamarin.android 控件,Android 库控件 - Xamarin | Microsoft Docs

    Xamarin Android 库控件Xamarin.Android Gallery control 03/15/2018 本文内容 Gallery是一种布局小组件,用于显示水平滚动列表中的项,并将当 ...

  3. Xamarin.Android开发及常见问题的解决

    一.Xamarin.Android开发环境的搭建 (一)所需组件 1.VS2013(VS2010以上即可) 2.JDK(http://www.oracle.com/technetwork/java/j ...

  4. xamarin android tv,Xamarin TV Scripts

    Introduction Do you like watching that old TV show so much that you want to take it with yourself wh ...

  5. Xamarin Android项目运行失败

    Xamarin Android项目运行失败 错误信息:Build Failed: MonoDroid does not support running the previous version.  P ...

  6. android viewpager 嵌套fragment,Android ViewPager+Fragment多层嵌套(使用问题处理)

    之前写了Android ViewPager+Fragment(使用问题处理),封装了一个BaseFragment,对于简单使用ViewPager+Fragment而言,是没有问题的. 不过,ViewP ...

  7. Xamarin.Android使用教程之Android开发所需的模拟器

    2019独角兽企业重金招聘Python工程师标准>>> 如今,在一个模拟器中运行Android应用程序时有很多种选择,今天,我们将为大家介绍当使用Xamarin开发Android应用 ...

  8. Xamarin.Android模拟器提示HAX kernel module is not Installed

    Xamarin.Android模拟器提示HAX kernel module is not Installed 错误信息: emulator : ERROR : x86 emulation curren ...

  9. Xamarin.Android开发实践(十七)

    Xamarin.Android开发实践(十七) 原文:Xamarin.Android开发实践(十七) Xamarin.Android之定位 一.前言 打开我们手中的应用,可以发现越来越多的应用使用了定 ...

最新文章

  1. 腾讯正式加入OCP阵营,拥抱全球开源生态圈
  2. 3分钟搞懂LSI原理
  3. show index mysql_MySQL SHOW INDEX语法的实际应用
  4. Spring Cloud 监控相关
  5. HTML零基础入门教程完整版
  6. 联通屏蔽80端口后利用NAT端口映射穿透解决WEB网站应用发布
  7. 腾讯AI Lab招聘实习生(内推)
  8. 我的第一篇博客——开篇
  9. eMMC的使用寿命分析
  10. Markdown 语法手册 (完整整理版)转抄
  11. 现在的网站无法访问了,如何访问过去的网站
  12. 速卖通教你如何提升店铺转化率——测评补单
  13. SpringBoot: Could not resolve placeholder 'XXXX' in value ${XXXX}
  14. 西门子s7-200smart清除密码西门子plc用SD卡清除密码方法步骤
  15. python_day08:网络编程02(wireshark,tftpd32,客户端怎样从服务器下载文件,tftpd客户端)
  16. Hololens+Vuforia识别图像
  17. Origin平台 建立EA账号时 显示“很抱歉,我们目前发生技术问题,请稍后再试一次”
  18. 如何解决“RuntimeError: CUDA Out of memory”问题
  19. 记录钱德拉望远镜天文软件ciao的一些简单使用,本文能谱拟合基于sherpa
  20. 文本匹配、文本相似度模型之BIMPM

热门文章

  1. 十个隐藏_LOL手游:新版增加42个英雄,大白兔:10个隐藏T0角色
  2. 收汇核销系统无法与服务器连接,出口收汇核销网上报系统一直都无法与服务器建立连接.doc...
  3. mysql安装的根目录_MySql安装及基础配置(一)
  4. 微型计算机实验代码,上师大,微型计算机实验全代码.doc
  5. android 字符串函数,Android JNI开发系列(六)字符串操作
  6. 如何测量PN中的耗散层两边的电位差?
  7. 百度线下赛道报名通知!
  8. SP4062电路接口芯片保护IC
  9. 跨域产生的原因和解决方法_ABS注塑制品产生色差的原因及解决方法
  10. android 多个应用,Android中一个应用实现多个图标的几种方式