分类:C#、Android、VS2015;  创建日期:2016-02-04

本例子演示如何添加一个简单的单页导航,在此基础上,再演示如何在第2个页面中显示第1个页面中拨打过的所有电话号码。

(1)通过该例子理解Android App的基本架构。

(2)通过该例子理解实现Android多屏幕导航的基本技术。

本例子只是为了让我们对Android App开发有一个较全面的感性认识,读者不必一开始就纠结于代码中的细节问题,涉及到的相关概念在后面还会分别介绍。

运行截图

运行截图(Api19、Api21、Api23的实现代码都相同):

界面操作

单击“将文本转换为数字”,观察结果。

单击【转换】按钮,如果转换成功,则【拨号】按钮可用,单击【拨号】按钮,观察弹出的对话框。

如果单击【拨号】按钮,就会自动拨号。

下面介绍主要设计步骤。

1、新建项目

选择模板:Blank App (Android),项目名:PhonewordApp。

项目创建成功后,删除GettingStarted.Xamarin(广告文件)。

2、界面设计

(1)双击打开Main.axml,分别观察设计界面【Design】和源码【Source】的内容。

(2)按Delete键删除【Hello World,Click Me】按钮。

(3)从【工具箱】中拖放一个【Text (Large)】到设计界面,修改下面的属性:

id:@+id/PhoneText

text:电话

注:此时系统会自动在【Source】中添加对应的代码(下同)。

(4)从【工具箱】中拖放一个【Plain Text】到设计界面,放到【Text (Large)】的下方,修改下面的属性:

id:@+id/PhoneNumberText

text:138 4912 2599

(5)从【工具箱】中拖放一个【Button】到设计界面,放到【Plain Text】的下方,修改下面的属性:

id:@+id/buttonTranslate

text:转换

(6)从【工具箱】中拖放一个【Button】到设计界面放到上一个按钮的下方,修改属性:

id:@+id/buttonCall

text:拨号

经过以上步骤后,即得到下图所示的设计界面:

(7)保存文件,并单击【解决方案资源管理器】上方的【刷新】按钮。

注意:这一步的目的是为了让系统能找到设计界面内的资源并自动生成对应的ID,以便在后面键入C#代码时能看到与设计界面资源相关的智能提示。

3、编写C#代码

(1)鼠标右击项目名à添加类,在弹出的窗口中,选择【Class】模板,名称:PhoneTranslator.cs,如下图所示,单击【添加】按钮。

然后将PhoneTranslator.cs改为下面的代码:

using System.Text;
namespace PhonewordApp
{
public static class PhonewordTranslator
{
public static string ToNumber(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
return "";
}
else
{
raw = raw.ToUpperInvariant();
}
var newNumber = new StringBuilder();
foreach (var c in raw)
{
if ("- 0123456789".Contains(c))
newNumber.Append(c);
else
{
var result = TranslateToNumber(c);
if (result != null)
newNumber.Append(result);
}
}
return newNumber.ToString();
} static bool Contains(this string keyString, char c)
{
return keyString.IndexOf(c) >= ;
} static int? TranslateToNumber(char c)
{
if ("ABC".Contains(c))
return ;
else if ("DEF".Contains(c))
return ;
else if ("GHI".Contains(c))
return ;
else if ("JKL".Contains(c))
return ;
else if ("MNO".Contains(c))
return ;
else if ("PQRS".Contains(c))
return ;
else if ("TUV".Contains(c))
return ;
else if ("WXYZ".Contains(c))
return ;
return null;
}
}
}

(2)打开MainActivity.cs,将该文件改为下面的代码:

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Collections.Generic;
namespace PhonewordApp
{
[Activity(Label = "PhonewordApp", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
static readonly List<string> phoneNumbers = new List<string>(); protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main); var phoneNumberText = FindViewById<EditText>(Resource.Id.PhoneNumberText);
var buttonTranslate = FindViewById<Button>(Resource.Id.buttonTranslate);
var buttonCall = FindViewById<Button>(Resource.Id.buttonCall);
buttonCall.Enabled = false; //禁用【拨号】按钮 string translatedNumber = string.Empty;
buttonTranslate.Click += (s, e) =>
{
translatedNumber = PhonewordTranslator.ToNumber(phoneNumberText.Text);
if (string.IsNullOrWhiteSpace(translatedNumber))
{
buttonCall.Text = "拨号";
buttonCall.Enabled = false;
}
else
{
buttonCall.Text = "播出号码:" + translatedNumber + ",单击确认!";
buttonCall.Enabled = true;
}
}; var buttonCallHistory = FindViewById<Button>(Resource.Id.buttonCallHistory);
buttonCallHistory.Click += (sender, e) =>
{
var intent = new Intent(this, typeof(CallHistoryActivity));
intent.PutStringArrayListExtra("phone_numbers", phoneNumbers);
StartActivity(intent);
}; buttonCall.Click += (s, e) =>
{
phoneNumbers.Add(translatedNumber);
buttonCallHistory.Enabled = true;
// 当单击【拨号】时,尝试拨号
var callDialog = new AlertDialog.Builder(this);
callDialog.SetMessage("电话:" + translatedNumber + ",拨号吗?");
callDialog.SetNeutralButton("拨号", delegate
{
var callIntent = new Intent(Intent.ActionCall);
callIntent.SetData(Android.Net.Uri.Parse("tel:" + translatedNumber));
StartActivity(callIntent);
});
callDialog.SetNegativeButton("取消", delegate { });
callDialog.Show();
}; }
}
}

(3)重新生成项目,确保无错误。

注:drawable文件夹下的Icon.png是要显示的图标,也可将其换为其他图标文件。

(4)选择主菜单下该项目的属性,在弹出的窗口中,勾选【CALL PHONE】权限:

注:

(1)这一步必须做,否则因该App无拨号权限,拨号功能会失败。

(2)设置后,查看Properties文件夹下AndroidManifest.xml文件中自动添加的代码,理解权限设置的作用。

4、调试运行及代码片段解释

选择一种模拟器,然后按<F5>键调试运行。

注意:如果使用低于API 23的模拟器,必须设置项目属性(主菜单à项目属性),使用对应版本的API来编译应用程序,否则在模拟器上运行时可能会出现应用程序一闪就退出或者显示“应用程序已停止运行”的情况。

下面解释前面已经实现的代码片段的含义:

(1)如何显示Alert对话框

AlertDialog的详细用法见【第6章  UI设计(三)--对话框】。

(2)如何拨号

下面的代码演示了如何调用系统功能实现拨号:

var callIntent = new Intent(Intent.ActionCall);

callIntent.SetData(Android.Net.Uri.Parse("tel:" + translatedNumber));

StartActivity(callIntent);

注意:运行前需要先勾选【CALL PHONE】设置允许拨号权限,否则运行会出现异常:

5、创建第2个屏幕跟踪历史记录

(1)打开values文件夹下的Strings.xml文件,添加下面的代码:

<?xml version="1.0" encoding="utf-8"?>

<resources>

……

<string name="CallHistory">拨号记录</string>

</resources>

(2)单击【解决方案资源管理器】上方的“刷新”按钮,或者重新生成项目。

注:选择其中之一即可,目的是为了让C#代码能识别它。

(3)打开Main.axml,从【工具箱】中拖放一个【Button】到Main.axml设计界面,将其放到上一个按钮的下方,修改属性:

id:@+id/buttonCallHistory

text:@string/CallHistory

enabled:false

注:@string/CallHistory的含义是在values文件夹下的Strings.xml文件中提供该变量的值。

此时,可看到“STRING/CALLHISTORY”会自动变成“拨号记录”。

说明:这一步设置变量值的做法是实际的Android App项目中建议的做法,这样做的好处是能提高安卓App运行的效率。而步骤1的做法是一种硬编码的做法,硬编码在安卓App中不是建议的做法,步骤1只是为了刚入门时理解更容易。

(4)鼠标右击项目名,选择【添加…】à【新建项】,在弹出的窗口中,选择“Activity”模板,文件名:CallHistoryActivity.cs,单击【添加】。然后将该文件改为下面的内容(省略了using……):

namespace PhonewordApp

{

[Activity(Label = "CallHistoryActivity")]

public class CallHistoryActivity : ListActivity

{

protected override void OnCreate(Bundle bundle)

{

base.OnCreate(bundle);

var phoneNumbers =

Intent.Extras.GetStringArrayList("phone_numbers") ?? new string[0];

this.ListAdapter = new ArrayAdapter<string>(this,

Android.Resource.Layout.SimpleListItem1, phoneNumbers);

}

}

}

其中,c = a??b; 的含义相当于:if (a != null ){ c = a;} else { c = b;}

(5)修改MainActivity.cs文件,目标是收集第1个屏幕界面运行时拨打过的所有电话号码,并将其在第2个屏幕上显示出来。在MainActivity.cs文件中添加下面的代码:

……

using System.Collections.Generic;

namespace E01PhonewordApp

{

[Activity(Label = "E01PhonewordApp", MainLauncher = true, Icon = "@drawable/icon")]

public class MainActivity : Activity

{

static readonly List<string> phoneNumbers = new List<string>();

protected override void OnCreate(Bundle bundle)

{

……

var buttonCallHistory =

FindViewById<Button>(Resource.Id.buttonCallHistory);

buttonCallHistory.Click += (sender, e) =>

{

var intent = new Intent(this, typeof(CallHistoryActivity));

intent.PutStringArrayListExtra("phone_numbers",

phoneNumbers);

StartActivity(intent);

};

buttonCall.Click += (s, e) =>

{

phoneNumbers.Add(translatedNumber);

buttonCallHistory.Enabled = true;

// 当单击【拨号】时,尝试拨号

var callDialog = new AlertDialog.Builder(this);

callDialog.SetMessage("播出号码:" + translatedNumber +

",拨号吗?");

callDialog.SetNeutralButton("拨号", delegate

{

// Create intent to dial phone

var callIntent = new Intent(Intent.ActionCall);

callIntent.SetData(Android.Net.Uri.Parse("tel:" +

translatedNumber));

StartActivity(callIntent);

});

callDialog.SetNegativeButton("取消", delegate { });

callDialog.Show();

};

}

}

}

(6)重新生成项目,确保无错误。

(7)运行,再拨一个号(例如12345678901),然后查看拨号记录。下图是用另一种模拟器查看的运行效果(你可以创建多种不同的模拟器,分别观察同一个项目的运行效果):

到这里,我们就完成了用C#编写的第1个Android应用程序。

【Android】2.1 PhonewordApp—第1个Android应用程序的更多相关文章

  1. 【Android自学日记】【转】Android Fragment 真正的完全解析(上)

    自从Fragment出现,曾经有段时间,感觉大家谈什么都能跟Fragment谈上关系,做什么都要问下Fragment能实现不~~~哈哈,是不是有点过~~~ 本篇博客力求为大家说明Fragment如何产 ...

  2. 解决Android中No resource found that matches android:TextAppearance.Material.Widget.Button.Inverse问题

    解决Android中No resource found that matches android:TextAppearance.Material.Widget.Button.Inverse问题http ...

  3. 浅谈Android应用保护(一):Android应用逆向的基本方法

    对于未进行保护的Android应用,有很多方法和思路对其进行逆向分析和攻击.使用一些基本的方法,就可以打破对应用安全非常重要的机密性和完整性,实现获取其内部代码.数据,修改其代码逻辑和机制等操作.这篇 ...

  4. 原生Android App项目调用Untiy导出的Android项目

    背景:采用Google VR SDK for Unity 开发3D场景功能,然后导出Android项目,合并到一个Android App里面,供其它Activity调用. 用Google VR for ...

  5. Failed to apply plugin [id 'com.android.application'] 和 Could not find com.android.tools.build:gradle:2.XX的最正确的解决方法

    发现android studio是真的可爱啊,上一秒还没问题可以build运行,下一秒就出错...好,你任性,你牛逼.. 说下今天又遇到的两个问题:Failed to apply plugin [id ...

  6. android开发环境搭建日记和嵌入式Android开发环境初探

    非常感谢博客园的各位,按照你们的博文,还有利用百度和谷歌逐渐建立了android的开发环境,只是给自己备份参考查看,看过的人可以忽略这篇文章. 本文章大部分参考了:http://www.cnblogs ...

  7. Android系统Surface机制的SurfaceFlinger服务渲染应用程序UI的过程分析

    参考:Android系统Surface机制的SurfaceFlinger服务渲染应用程序UI的过程分析 一句话概括一下Android应用程序显示的过程:Android应用程序调用SurfaceFlin ...

  8. Android学习笔记(二十一)——实战:程序数据共享

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 我们继续在Database项目的基础上继续开发,通过内容提供器来给它加入外部访问接口.首先将 MyDataba ...

  9. 五步搞定Android开发环境部署——非常详细的Android开发环境搭建教程

      在windows安装Android的开发环境不简单也说不上算复杂,本文写给第一次想在自己Windows上建立Android开发环境投入Android浪潮的朋友们,为了确保大家能顺利完成开发环境的搭 ...

  10. [Android] 如何查看apk需要支持的Android版本

    reference to : http://blog.csdn.net/huiguixian/article/details/39928089 如果有一个apk,需要知道他最低安装支持的Android ...

随机推荐

  1. Linux集群监控工具简介:Ganglia和Nagios

    11年时候,曾经对 Ganglia 和 Nagios有一定接触,这是两个用于监视数据中心的工具.这两个工具被大量用于高性能计算(HPC)环境中,但是它们对于其他环境也具有很大的吸引力(例如云.呈现集群 ...

  2. 【DevOps】为什么我们永远疲于奔命?

    作者:范军 (Frank Fan) 新浪微博:@frankfan7   微信:frankfan7 在[DevOps]谁说大象不能跳舞?一文之后,本文对DevOps的理念作进一步探讨. 最近在读一本书& ...

  3. php之快速入门学习-5(常量)

    PHP 5 常量 常量值被定义后,在脚本的其他任何地方都不能被改变. PHP 常量 常量是一个简单值的标识符.该值在脚本中不能改变. 一个常量由英文字母.下划线.和数字组成,但数字不能作为首字母出现. ...

  4. Jetty:配置上下文

    这篇文件讲述配置Jetty上下文的各种选项. 设置上下文路径 上下文路径是一个URL路径的前缀,用于将一个输入请求相应到相应的上下文.Java Servlet Server的URL通常的格式为:htt ...

  5. Throwing cards away I uva1594

     Throwing cards away I Given is an ordered deck of  n  cards numbered 1 to n  with card 1 at the t ...

  6. 算法笔记_211:第七届蓝桥杯软件类决赛部分真题(Java语言A组)

    目录 1 阶乘位数 2 凑平方数 3 棋子换位 4 机器人塔 前言:以下代码仅供参考,若有错误欢迎指正哦~ 1 阶乘位数 阶乘位数 9的阶乘等于:362880 它的二进制表示为:10110001001 ...

  7. mac系统下ionic环境配置

    本人是在mac环境下进行配置的: 下载nodejs:https://nodejs.org/download/ 并双击安装 Cordova and Ionic command-line tools 安装 ...

  8. JVM:垃圾回收机制和调优手段

    转载请注明出处: jiq•钦's technical Blog - 季义钦 引言: 我们都知道JVM内存由几个部分组成:堆.方法区.栈.程序计数器.本地方法栈 JVM垃圾回收仅针对公共内存区域即:堆和 ...

  9. or1200中载入存储类指令说明

    下面内容摘自<步步惊芯--软核处理器内部设计分析>一书 OR1200中实现的载入存储类指令有8条,每条指令的作用与说明如表9.1所看到的. watermark/2/text/aHR0cDo ...

  10. 【翻译自mos文章】使用dbua升级时,须要手工设置CLUSTER_DATABASE參数么?

    使用dbua升级时,须要手工设置CLUSTER_DATABASE參数么? 来源于: Is Manual Setting Of CLUSTER_DATABASE Parameter Required F ...