可穿戴指南针: 从示例到优秀应用的旅程
本文将带您从示例 Android 可穿戴应用逐步打造出专业的应用。
1 - 引言
距离我上次在 CodeProject 上发表文章已经很久了,但我经常访问这个社区,现在是时候写一篇了。在本文中,我将重点介绍如何为 Android 可穿戴设备制作一个简单而精美的应用。我必须说,可穿戴设备在未来具有巨大的潜力。目前,它正处于转型阶段,因此关于可穿戴技术开发的资源并不多,我将努力使本文简单易懂,最终完成一个精美的指南针应用。这将对学习者,特别是对 Android 感兴趣并准备尝试可穿戴设备的人有益。作为一名移动开发者,我个人认为,如果您对 Android 有很好的了解,那么制作可穿戴设备应用对您来说会非常容易。在本文中,我将从 Android 可穿戴设备的基础知识开始,然后着手制作一个精美简洁的指南针应用。
2 - 背景
我通常使用 Xamarin 制作 Android 应用(是的!我用 C# 感觉更舒服),所以我选择了 Xamarin 来制作 Android Wear 应用。因为用 Xamarin 制作 Android 应用与在官方 Android Studio 或 Eclipse 中开发 Android 完全相同。优点是您可以使用许多 C# 函数,这是 Xamarin Studio 的真正魅力所在。我可以列举 Xamarin 的许多优点,但这将超出本文的范围。让我给出 Xamarin 的一些高级优点:
- Xamarin 技术允许您在所有三个平台上保持原生 UI。
- Xamarin 集成了所有不同操作系统的 SDK。
- 最佳原生体验应用
- 单一代码库共享到所有移动平台
- 您可以在移动开发中使用 C# 强大的功能,如扩展、委托、Lambda、Linq 等。
关于 Xamarin 就介绍到这里。如果您想了解更多信息,可以点击此处。
附言:正如我所提到的,Xamarin Android 开发与在 Android Studio 或 Eclipse 上的开发类似。因此,您想在哪种 IDE 中制作应用真的无关紧要。
3 - 应用演练
我假设您对 Android 应用开发有基本了解。本文将仅讲解 Android 可穿戴应用开发,从小型应用到精美的指南针应用。
互联网上有很多关于 Android 可穿戴设备的初学者文章,所有文章都以著名的“Hello World”应用开始。但依我看来,如果您想了解新的移动平台,那么请从使用内置 UI 功能开始。这将为您提供 UI 如何与后台代码交互的基本知识。
无论如何,您将要制作的最终应用如下所示——(很棒吧!)
方形可穿戴设备- 圆形可穿戴设备-
4 - 启动可穿戴应用
让我们从简要介绍需求和设置开始。
a) 先决条件 - 您需要以下工具进行可穿戴开发
- 可穿戴开发 IDE(即 Xamarin、Android Studio 或 Eclipse)
- Android SDK 工具版本必须为 23 或更高。
- 从 Android SDK 管理器安装可穿戴模拟器。
- 设置模拟器
额外信息:许多人都知道官方 Android 模拟器,它运行在 GPU 上并且速度慢。因此,有一些免费的极速模拟器可用于 Android 开发。
- Genymotion 模拟器 – 它对个人使用免费,运行在 virtualbox 上。您可以点击此处获取更多信息。
- Xamarin Android 播放器 - 这也是一个免费的模拟器,运行在 virtualbox 上。更多信息请点击此处。
- Visual Studio Android 模拟器 - 这是我最喜欢的模拟器,它运行在 Hyper-V 上。速度非常快,它有多个可用的 Android 设备镜像。它有多种选项来模拟晃动、电池、网络、GPS 等。供您参考,这个模拟器将适用于任何平台,即 Android Studio、Eclipse 等。您可以点击此处获取更多信息。
b) 设置 Android 可穿戴模拟器 - 如上文额外信息中所述,所有模拟器都只适用于 Android 移动应用。因此,对于 Android 可穿戴应用,您必须使用官方模拟器(速度较慢且没有模拟功能),至少在其他可穿戴设备模拟器可用之前。
Android 可穿戴设备的设置很简单。从 Android 管理器安装 Android 可穿戴镜像,然后像创建 AVD(Android 虚拟设备)一样创建即可。
您可以看到可穿戴设备有两种模拟器可用:
- 圆形可穿戴设备
- 方形可穿戴设备
(图片来自谷歌官方穿戴网站)
因此,在制作应用程序时,您必须同时考虑这两种可穿戴设备,以便能够面向市场上的多种设备。
额外信息 - 如果您想将物理设备连接到 Android 模拟器,您必须按照下图所示转发端口:
在命令提示符窗口中,输入:adb -d forward tcp:5601 tcp:5601。然后按 Enter。如果步骤成功,您的命令提示符将如下例所示。如果遇到问题,请确保您的手机已正确连接到计算机。
5 - 创建示例项目(基础学习)
以下是创建示例项目的设置——假设您已在 Visual Studio 中安装 Xamarin,
- 打开 Visual Studio 并在 Android 下创建新的可穿戴应用项目。
- Wear App 有脚手架应用,如果你查看项目层级,它与 Android Studio 和 Eclipse 中的相似。
- 打开 layout 文件夹,你会发现它有三个文件
- Main.axml – 在主活动类中调用
- RectagngleMain.axml - 正如我们已经讨论过的,目前可穿戴设备有两种尺寸——方形和圆形。因此,如果您希望您的应用专用于矩形设备,则相应地修改 Android XML。Android 提供了检测可穿戴设备类型并在运行时渲染适当活动的选项。我稍后会讨论这个问题。目前,如果您的应用 UI 在所有可穿戴设备上都保持一致,那是一个好习惯。
- Roundmain.axml – 同上
- 打开 main.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.WatchViewStub xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/watch_view_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:rectLayout="@layout/RectangleMain"
app:roundLayout="@layout/RoundMain"
tools:context=".MainActivity" />
如您在突出显示部分所看到的,它将根据手表类型呈现特定的 xml——欲了解更多
- 尽管您可以为矩形和圆形设备制作不同的 UI,但为了简化起见,我将在 RectangeMain.axml 和 RoundMain.axml 中使用相同的 xml 配置。
现在只需在 xml 中添加按钮和文本视图,如下所示
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity"
tools:deviceIds="wear_round">
<Button
android:id="@+id/myButton"
android:layout_width="fill_parent"
android:layout_height="80dp"
android:gravity="center"
android:text="Click" />
<TextView
android:id="@+id/myText"
android:text="Sample"
android:layout_height="40dp"
android:gravity="center"
android:layout_centerHorizontal="true"
android:textColor="@android:color/white"
android:layout_width="wrap_content" />
</LinearLayout>
注意:您是否注意到这与 Android 应用开发中完全相同?
- 现在添加一些代码部分,这也很容易理解。
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
var v = FindViewById<WatchViewStub>(Resource.Id.watch_view_stub);
v.LayoutInflated += delegate
{
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.myButton);
TextView headingDegree = FindViewById<TextView>(Resource.Id.myText); ;
button.Click += delegate
{
headingDegree.Text = string.Format("You clicked button at {0}", count);
count++;
};
};
}
}
上述大部分代码都相当不言自明,但我想重点关注 watchviewstub。请记住,主活动只有 WatchViewStub
布局定义文件。您为方形或圆形屏幕指定的布局在 WatchViewStub
检测到屏幕形状之前不会被填充,因此您的应用无法立即访问它们的视图。要访问这些视图,请在您的活动中设置一个监听器,以便在形状特定布局被填充时收到通知。
所以输出像这样
就是这样。请注意,可穿戴开发与 Android 移动应用开发非常相似。
瞧,你已经制作了你的第一个可穿戴应用,尽管它很丑,但希望你能体会到可穿戴开发的乐趣,你也看到了这些简单的开发步骤是如何在 Android Wear 中制作一个简单应用的。事实上,它与制作 Android 移动应用非常相似。
让我们为可穿戴设备制作一个简单、清晰、大胆而美丽的应用程序。
6 - 创建指南针应用(很棒的应用)
在制作一个很棒的指南针应用之前,我想提醒您注意 Android 可穿戴设备的图像尺寸。您必须了解 Android Wear 设备的设计标准。您可以在官方 Wear 网站此处获取更多信息。
对于指南针应用,我将使用多张背景图片,因此您应注意图片尺寸。
目前,使用 320x320 像素的位图应该可以满足您的所有需求。
具体细节如下:
- 华硕 ZenWatch:320x320 像素,密度 1.75,182dpx182dp
- Gear Live:320x320 像素,密度 1.75,182dpx182dp
- LG G Watch:280x280 像素,密度 1.5,186dpx186dp
- LG G Watch R:320x320 像素,密度 1.5,213dpx213dp
- LG Urbane:320x320 像素,密度 1.5,213dpx213dp
- Moto 360:320x290 像素,密度 1.33,240x217dp
- 索尼智能手表:320x320 像素,密度 1.75,182dpx182dp
所以我的指南针背景图片尺寸为 320x320。这张图片来自一个开源社区。 为了制作您自己的指南针,您可以使用任何背景指南针图片。
我还上传了多种颜色主题,以防您有兴趣以自己的方式为可穿戴设备制作自己的指南针应用。
话不多说,现在让我们直接进入编码部分。从上面的图片可以看出,它有两张图片和两个文本视图。
- 使用相同的示例应用,并删除 RectagngleMain.axml 和 RoundMain.axml 中的所有内容。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity"
tools:deviceIds="wear_round">
<ImageView
android:id="@+id/imageViewCompass"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tvHeading"
android:layout_centerHorizontal="true"
android:src="@drawable/scompass" />
<ImageView
android:id="@+id/imageViewDial"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_centerHorizontal="true"
android:src="@drawable/dialbig" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:id="@+id/headingDirection"
android:text="NE"
android:textSize="25dp"
android:textStyle="bold"
android:layout_height="40dp"
android:layout_below="@+id/imageViewDial"
android:gravity="center|top"
android:layout_centerHorizontal="true"
android:textColor="@android:color/white"
android:layout_width="60dp" />
<TextView
android:text="320\u00B0"
android:id="@+id/headingDegree"
android:textSize="15dp"
android:layout_height="50dp"
android:layout_below="@+id/imageViewDial"
android:textColor="@android:color/white"
android:layout_width="60dp"
android:gravity="center|bottom"
android:layout_centerHorizontal="true" />
</RelativeLayout>
这是代码。代码注释良好,非常易懂。
public class MainActivity : Activity,ISensorEventListener
{
//Initialize sensor manager for compass direction
private SensorManager sensorManager;
private float currentDegree = 0f;
//Initilaize global variable for UI view
ImageView outerDialImage;
ImageView dialImage;
TextView headingDirection;
TextView headingDegree;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Initilize system sensor service
sensorManager = (SensorManager)GetSystemService(SensorService);
// WatchViewStub determine wearable type and render view accordinglr from specfic xml defination
var v = FindViewById<WatchViewStub>(Resource.Id.watch_view_stub);
//Infalte watchviewstub
v.LayoutInflated += delegate
{
// Get elemnt from the layout resource,
outerDialImage = FindViewById<ImageView>(Resource.Id.imageViewCompass);
headingDirection = FindViewById<TextView>(Resource.Id.headingDirection);
headingDegree = FindViewById<TextView>(Resource.Id.headingDegree);
dialImage = FindViewById<ImageView>(Resource.Id.imageViewDial);
};
}
protected override void OnResume()
{
base.OnResume();
// Listen sensor manger on resume activity of app
sensorManager.RegisterListener(this, sensorManager.GetDefaultSensor(SensorType.Orientation),SensorDelay.Game);
}
protected override void OnPause()
{
base.OnPause();
// stop listening if app is no longer used. This is importent step otherwise it will drain your watch battery.
sensorManager.UnregisterListener(this);
}
public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
{
}
public void OnSensorChanged(SensorEvent e)
{
//Get sensor degree
float degree = (float)Math.Round(e.Values[0]);
//values[0]: Angle between the magnetic north direction and the y-axis around the z-axis (0 to 359), where 0=North, 90=East, 180=South, 270=West.
//values[1]: Rotation around x-axis (-180 to 180), with positive values when the z-axis moves towards the y-axis.
//values[2]: Rotation around x-axis, (-90 to 90), increasing as the device moves clockwise.
//calculate direction coordinal
headingDirection.Text = CalculateDirection(degree);
// Set text for degree
headingDegree.Text = Convert.ToString(degree) + "\u00B0";
outerDialImage.Rotation = degree;
//currentDegree is updated with the value of -degree so that the next animation will start from the new position.
currentDegree = -degree;
}
private string CalculateDirection(float degree)
{
if (degree > 322 && degree < 54)
return "NE";
if (degree > 235 && degree < 322)
return "NW";
if (degree > 148 && degree < 235)
return "SW";
if (degree > 54 && degree < 148)
return "SE";
if (degree == 322)
return "N";
if (degree == 235)
return "W";
if (degree == 54)
return "E";
if (degree == 148)
return "S";
return "NE"; //Default :)
}
}
- SensorManager 允许您访问设备的传感器。通过调用带有参数
SENSOR_SERVICE
的Context.getSystemService()
来获取此类的实例。 如您所见,outerimage 通过计算传感器中的度数来设置旋转,因此它将根据磁场旋转。 - 正如你在下面的 gif 图像中看到的那样,两个文本视图都正在从以下位置更新:
OnSensorChange
计算出的度数参数值选项为
//values[0]: Angle between the magnetic north direction and the y-axis around the z-axis (0 to 359), where 0=North, 90=East, 180=South, 270=West.
//values[1]: Rotation around x-axis (-180 to 180), with positive values when the z-axis moves towards the y-axis.
//values[2]: Rotation around x-axis, (-90 to 90), increasing as the device moves clockwise.
- 务必禁用您不需要的传感器,尤其是在您的活动暂停时。否则,可能会在短短几小时内耗尽电池电量。请注意,当屏幕关闭时,系统不会自动禁用传感器。
穿戴模拟器中的最终输出
关注点
我希望为 Android 可穿戴设备制作应用程序非常有趣,您可能会对以下几点感兴趣。
- 可穿戴技术将持续发展。我相信本文强调了它的一些功能,可以帮助您理解应用程序构建的现象。此指南针应用程序的图解以及对制作此类应用程序所需的其他基本事物的见解将有助于您进一步理解其他此类可穿戴技术应用程序。希望本文能达到其目的。
- 如果您想使用 Android Studio 或 Eclipse,那么应用程序流程几乎相同。您可以轻松地将文章中的 C# 代码与 Java 相关联。如果您仍然感到困惑,请随时与我联系。
- 如果您有兴趣制作自己的指南针应用,我们已添加了多种指南针主题。
如果你喜欢这篇文章,那么我值得一个5星 :) (这会提高我制作更多类似应用的士气)
如果您确实喜欢本文或有任何建议或问题,请在评论区发布。
历史
- 发布版本:1.0