Xamarin.Forms-编写一次,到处运行,并且原生?
I worked in Java for a number of years at Nike, writing an order management application that would run on four platforms. We used to joke that we'd "write once, debug everywhere." Now, this was the early days of Java, but the thing was, every form and control was 'owner drawn.' That meant that a button looked the same everywhere because it wasn't a real button as far as the operating system was concerned. It was a picture of a button. We used to use Spy++ and different Windows inspector programs to explore our applications and they could never see a Java program's controls. This meant that the app pretty much worked everywhere, but the app always LOOKED like a Java App. They didn't integrated with the underlying platform.
我在耐克公司使用Java多年,编写了可以在四个平台上运行的订单管理应用程序。 我们曾经开玩笑说我们会“写一次,到处调试”。 现在,这是Java的早期,但事实是,每种形式和控件都是“所有者绘制的”。 这意味着一个按钮在任何地方看起来都一样,因为就操作系统而言,它并不是真正的按钮。 这是一个按钮的图片。 我们曾经使用Spy ++和不同的Windows检查器程序来浏览我们的应用程序,但它们永远看不到Java程序的控件。 这意味着该应用程序几乎可以在任何地方使用,但是该应用程序始终看起来像Java应用程序。 他们没有与基础平台集成。
With MVVM (Model, View, View-Model) patterns, and techniques like the Universal apps work on Windows Phone 8.1 and Windows 8.1, code sharing can get up into the high 90% for some kinds of apps. However, even for simple apps you've still got to create a custom native view for each platform. This is desirable in many cases, but for some app it's just boring, error prone, and tedious.
借助MVVM(模型,视图,视图模型)模式以及通用应用程序之类的技术可在Windows Phone 8.1和Windows 8.1上运行,某些类型的应用程序的代码共享率可高达90%。 但是,即使对于简单的应用程序,您仍然必须为每个平台创建自定义本机视图。 在许多情况下,这是理想的选择,但对于某些应用程序来说,它只是无聊,容易出错且乏味。
Xamarin announced Xamarin.Forms today which (in my words) effectively abstracts away native controls to a higher conceptual level. This, to my old eyes, is very similar to the way I wrote code in Java back in the day - it was all done in a fluent code-behind with layouts and flows. You create a control tree.
Xamarin今天宣布了Xamarin.Forms ,用我的话说,它有效地将本机控件抽象到了更高的概念水平。 在我看来,这与我以前用Java编写代码的方式非常相似-都是用流利的代码完成的-后面有布局和流程。 您创建一个控件树。
"Xamarin.Forms is a new library that enables you to build native UIs for iOS, Android and Windows Phone from a single, shared C# codebase. It provides more than 40 cross-platform controls and layouts which are mapped to native controls at runtime, which means that your user interfaces are fully native."
“ Xamarin.Forms是一个新的库,可让您从一个共享的C#代码库中为iOS,Android和Windows Phone构建本机UI。它提供了40多种跨平台控件和布局,这些控件和布局在运行时映射到了本机控件,这意味着您的用户界面是完全本机的。”
What's interesting about this, to me, is that these "control/concepts" (my term) are coded at a high level but rendered as their native counterparts. So a "tab" in my code is expressed in its most specific and native counterpart on the mobile device, rather than as a generic tab control as in my Java example. Let's see an example.
对我而言,有趣的是,这些“控件/概念”(我的术语)是经过高级编码的,但被渲染为它们的本机副本。 因此,我的代码中的“制表符”是在移动设备上以其最具体的本机形式表示的,而不是像我的Java示例中那样以通用制表符控件表示的。 让我们来看一个例子。
My buddy from Xamarin, James Montemagno, a fellow Chipotle lover, put together the ultimate cross-platform Hanselman application in a caffeinated late night hack to illustrate a few points for me. This little app is written in C# and runs natively on Windows Phone, Android, and iOS. It aggregates my blog and my tweets.
我来自Xamarin的好友,Japotle恋人James Montemagno ,在一个含咖啡因的深夜黑客中,将最终的跨平台Hanselman应用程序整合在一起,为我说明了几点。 这个小应用程序是用C#编写的,可在Windows Phone,Android和iOS上本地运行。 它汇总了我的博客和我的推文。
Here is the menu that switches between views:
这是在视图之间切换的菜单:
And the code that creates it. I've simplified a little for clarity, but the idea is all MVVM:
以及创建它的代码。 为了清楚起见,我已经进行了一些简化,但是所有的想法都是MVVM:
public HomeMasterView(HomeViewModel viewModel)
{
this.Icon = "slideout.png";
BindingContext = viewModel;
var layout = new StackLayout { Spacing = 0 };
var label = new ContentView {
Padding = new Thickness(10, 36, 0, 5),
BackgroundColor = Color.Transparent,
Content = new Label {
Text = "MENU",
Font = Font.SystemFontOfSize (NamedSize.Medium)
}
};
layout.Children.Add(label);
var listView = new ListView ();
var cell = new DataTemplate(typeof(ListImageCell));
cell.SetBinding (TextCell.TextProperty, HomeViewModel.TitlePropertyName);
cell.SetBinding (ImageCell.ImageSourceProperty, "Icon");
listView.ItemTemplate = cell;
listView.ItemsSource = viewModel.MenuItems;
//SNIP
listView.SelectedItem = viewModel.MenuItems[0];
layout.Children.Add(listView);
Content = layout;
}
Note a few things here. See the ListImageCell? He's subclassed ImageCell, which is a TextCell with an Image, and setup data binding for the text and the icon. There's recognition that every platform will have text and an icon, but the resources will be different on each. That's why the blog and Twitter icons are unique to each platform. The concepts are shared and the implementation is native and looks native.
请注意此处的几件事。 看到ListImageCell吗? 他是ImageCell的子类,ImageCell是带有Image的TextCell,并为文本和图标设置了数据绑定。 人们已经认识到每个平台都会有文本和图标,但是每个平台的资源都会不同。 这就是为什么博客和Twitter图标对于每个平台都是唯一的。 这些概念是共享的,实现是本机的,看起来是本机的。
That's the UI side, on the logic side all the code that loads the RSS feed and Tweets is shared across all three platforms. It can use async and await for non-blocking I/O and in the Twitter example, it uses LinqToTwitter as a PCL (Portable Class Library) which is cool. For RSS parsing, it's using Linq to XML.
在UI方面,在逻辑方面,所有加载RSS feed和Tweets的代码在所有三个平台上共享。 它可以使用async并等待非阻塞的I / O,在Twitter示例中,它使用LinqToTwitter作为PCL(可移植类库),这很酷。 对于RSS解析,它使用Linq to XML。
private async Task ExecuteLoadItemsCommand()
{
if (IsBusy)
return;
IsBusy = true;
try{
var httpClient = new HttpClient();
var feed = "http://feeds.hanselman.com/ScottHanselman";
var responseString = await httpClient.GetStringAsync(feed);
FeedItems.Clear();
var items = await ParseFeed(responseString);
foreach (var item in items)
{
FeedItems.Add(item);
}
} catch (Exception ex) {
var page = new ContentPage();
var result = page.DisplayAlert ("Error", "Unable to load blog.", "OK", null);
}
IsBusy = false;
}
And ParseFeed:
和ParseFeed:
private async Task<List<FeedItem>> ParseFeed(string rss)
{
return await Task.Run(() =>
{
var xdoc = XDocument.Parse(rss);
var id = 0;
return (from item in xdoc.Descendants("item")
select new FeedItem
{
Title = (string)item.Element("title"),
Description = (string)item.Element("description"),
Link = (string)item.Element("link"),
PublishDate = (string)item.Element("pubDate"),
Category = (string)item.Element("category"),
Id = id++
}).ToList();
});
}
Again, all shared. When it comes time to output the data in a List on Windows Phone, Android, and iPhone, it looks awesome (read: native) on every platform without having to actually do anything platform specific. The controls look native because they are native. Xamarin.Forms controls are a wrapper on native controls, they aren't new controls themselves.
同样,所有人共享。 当需要在Windows Phone,Android和iPhone上以列表形式输出数据时,在每个平台上看起来都很棒(阅读: native ),而无需实际执行平台特定的任何操作。 控件看起来是本地的,因为它们是本地的。 Xamarin.Forms控件是本机控件的包装,它们本身并不是新控件。
Here's BlogView. Things like ActivityIndicator are from Xamarin.Forms, and it expresses itself as a native control.
这是BlogView。 诸如ActivityIndicator之类的东西都来自Xamarin.Forms,并且将其表示为本地控件。
public BlogView ()
{
BindingContext = new BlogFeedViewModel ();
var refresh = new ToolbarItem {
Command = ViewModel.LoadItemsCommand,
Icon = "refresh.png",
Name = "refresh",
Priority = 0
};
ToolbarItems.Add (refresh);
var stack = new StackLayout {
Orientation = StackOrientation.Vertical,
Padding = new Thickness(0, 8, 0, 8)
};
var activity = new ActivityIndicator {
Color = Helpers.Color.DarkBlue.ToFormsColor(),
IsEnabled = true
};
activity.SetBinding (ActivityIndicator.IsVisibleProperty, "IsBusy");
activity.SetBinding (ActivityIndicator.IsRunningProperty, "IsBusy");
stack.Children.Add (activity);
var listView = new ListView ();
listView.ItemsSource = ViewModel.FeedItems;
var cell = new DataTemplate(typeof(ListTextCell));
cell.SetBinding (TextCell.TextProperty, "Title");
cell.SetBinding (TextCell.DetailProperty, "PublishDate");
cell.SetValue(TextCell.StyleProperty, TextCellStyle.Vertical);
listView.ItemTapped += (sender, args) => {
if(listView.SelectedItem == null)
return;
this.Navigation.PushAsync(new BlogDetailsView(listView.SelectedItem as FeedItem));
listView.SelectedItem = null;
};
listView.ItemTemplate = cell;
stack.Children.Add (listView);
Content = stack;
}
Xamarin Forms is a very clever and one might say, elegant, solution to the Write Once, Run Anywhere, AND Don't Suck problem. What's nice about this is that you can care about the underlying platform when you want to, and ignore it when you don't. A solution that HIDES the native platform isn't native then, is it? That'd be a lowest common denominator solution. This appears to be hiding the tedious and repetitive bits of cross-platform multi-device programming.
Xamarin Forms是一种非常聪明的解决方案,它可以说是一种优雅的解决方案,可以解决“一次写入,随处运行且不吸”的问题。 这样做的好处是,您可以在需要时关心基础平台,而在不需要时可以忽略它。 那么,隐藏本机平台的解决方案不是本机平台,不是吗? 那将是最低的公分母解决方案。 这似乎掩盖了跨平台多设备编程的繁琐而重复的部分。
There's more on Xamarin and Xamarin Forms at http://xamarin.com/forms and sample code here. Check out the code for the Hanselman App(s) at https://github.com/jamesmontemagno/Hanselman.Forms.
有关Xamarin和Xamarin Forms的更多信息,请访问http://xamarin.com/forms ,此处提供示例代码。 在https://github.com/jamesmontemagno/Hanselman.Forms上查看Hanselman应用程序的代码。
关于斯科特 (About Scott)
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
斯科特·汉塞尔曼(Scott Hanselman)是前教授,前金融首席架构师,现在是演讲者,顾问,父亲,糖尿病患者和Microsoft员工。 他是一位失败的单口相声漫画家,一个玉米种植者和一本书的作者。
翻译自: https://www.hanselman.com/blog/xamarinforms-write-once-run-everywhere-and-be-native