Статьи

Создание пользовательского интерфейса NativeScript для разработчиков .NET

NativeScript — это фреймворк для создания кроссплатформенных собственных мобильных приложений с использованием JavaScript. Возможность создавать кроссплатформенные действительно нативные приложения из единой кодовой базы JavaScript / TypeScript, XML и CSS может быть захватывающей. Как мы видели в первой части этой серии, NativeScript имеет много полезного для разработчиков .NET: надежная поддержка Visual Studio на протяжении всего жизненного цикла приложения; простые абстракции JavaScript над нативными API; и полная поддержка TypeScript для построения бизнес-логики.

Возможно, вы еще не уверены в том, что вас больше всего беспокоит пользовательский интерфейс (UI). Неужели создание абстрактного кроссплатформенного интерфейса не может быть простым? Может быть, ваш фон находится в XAML или других разметках композиции пользовательского интерфейса в .NET, и вы просто привыкли к богатой экосистеме разработчиков инструментов. Это действительные проблемы, но расслабьтесь.

NativeScript поддерживает вас, когда дело доходит до композиции пользовательского интерфейса. Он сочетает в себе простую разметку с абстрактным рендерингом для конкретной платформы. Если вы привыкли к богатству XAML, я думаю, вы будете чувствовать себя как дома, создавая собственные интерфейсы с помощью NativeScript. В этой статье я расскажу вам о создании пользовательского интерфейса NativeScript с точки зрения разработчика .NET — думаю, вы будете в восторге от того, что мы нашли.

Пользовательский интерфейс через XML

XML может плохо работать с передачей данных, но он очень прост в описании разметки. Если подумать, XAML и HTML — это типы XML со спецификой для соответствующих механизмов рендеринга. Поэтому NativeScript выбирает XML для вас, чтобы создать кроссплатформенный интерфейс для ваших мобильных приложений.

Кроссплатформенный интерфейс

You begin with an assortment of UI widgets for your apps and describe the UI in XML markup. NativeScript parses your markup, and at runtime, turns around to render the corresponding native UI elements on respective platforms. This means that when you specify to use a ListView, NativeScript is actually rendering the corresponding native ListView for each mobile platform. This is one huge reason why your NativeScript app looks native – because it truly is!

Let’s look at a simple example of what NativeScript UI markup looks like in XML:

<?xml version="1.0" encoding="UTF-8" ?>
<Page xmlns="http://www.nativescript.org/tns.xsd">
  <StackLayout>
    <Label text="Tap the button" style="horizontal-align: center"/>
    <Button text="TAP" />
    <Label text="message" textWrap="true" style="horizontal-align: center"/>
  </StackLayout>
</Page>

See the XML NameSpace (xmlns) pointing to NativeScript? That little pointer gets you XML Intellisense in Visual Studio or other editors. And here’s the UI produced by the above UI XML markup, with the label showing a counter message, after a few taps.

TNSiOSTNSAndroid

Keep in mind that you are simply building up a visual tree that is rendered after NativeScript parses your markup. If you choose, you can actually build your visual tree entirely in code, through JavaScript or TypeScript. This may be helpful if your app is trying to create some portions of the UI dynamically. The bottom line is that you get complete flexibility.

Here’s a simple UI rendered through code:

var pagesModule = require("ui/page");
var labelModule = require("ui/label");
function createPage() {
    var label = new labelModule.Label();
    label.text = "Hello, world!";
    var page = new pagesModule.Page();
    page.content = label;
    return page;
}
exports.createPage = createPage;

Native UI Rendering

Now, what if you want to customize the UI widgets that NativeScript offers? What if you were really fond of one particular native UI element that’s only available on a single platform? No worries.

NativeScript allows you to render any native UI element through code behind – the JavaScript or TypeScript file with the same name as your XML UI markup. You can simply create an appropriate placeholder in your markup and add the native UI element to the placeholder.

Here’s how to render a native iOS Alert in a NativeScript app, along with the corresponding result. The JavaScript code is interpreted at runtime, and NativeScript magically know what you were referring to with the iOS specific UIAlertView.

var alert = new UIAlertView();
alert.message = "Hello World";
alert.addButtonWithTitle("OK");
alert.show();

iOSAlert

Styling Through CSS

Now that you have chosen the UI widgets to render, your next question would be how to style the UI? If you know CSS for the web, now you can use a subset of that same CSS to style your native mobile apps!

NativeScript allows you to write simple CSS against your UI markup to style your controls and overall UI. For example, given the UI XML markup defined before, here’s how you would go about styling it in CSS. Notice how the CSS selectors simply use the names of the abstracted UI elements (you can also use classes for granularity).

.title {
    font-size: 30;
    horizontal-align: center;
    margin:20;
}

.button {
    font-size: 42;
    horizontal-align: center;
}

.message {
    font-size: 20;
    color: #284848;
    margin:10 40;
    horizontal-align: center;
}

NativeScript UI markup gets rendered as corresponding native UI elements on each platform. This is the reason why your apps already have the look and feel of native UI. If, however, you want to further customize the styling of your app on respective platforms, you could do so with plain CSS. Simply add platform-specific CSS files named like so:

  • platform.ios.css
  • platform.android.css

Then in your app-wide app.css file, simply add the following line of code.

@import url('~/platform.css');

NativeScript is smart enough to figure out platform-specific CSS files and only deploy the corresponding ones for each platform. Conventions for the win!

Similarities With XAML

XAML has been a popular UI markup language in the Microsoft developer world for quite some time now. This popularity isn’t without reason – XAML UI markup is used in a wide range applications ranging from WPF, Silverlight, Windows Phone, Windows 8/8.1 and all the way to the most recent Universal Windows Platform.

If you are coming from a XAML development background, some of the UI XML markup for NativeScript apps may look familiar. This is not by chance – in fact, the UI markup closely resembles XAML syntax and borrows some of XAML’s best features. You will feel right at home.

Seamless Data Binding

One of the big reasons behind XAML’s developer popularity is because of data binding – the seamless stitching together of object model with rendered UI. Gone are the days where you would have to keep refreshing your UI as the underlying object collection changes. Modern data binding should be two way – object updates the UI and vice versa.

NativeScript UI composition is built with the exact same data binding goals in mind. As long as your objects inherit from an Observable class (which implements something similar to the INotifyPropertyChanged event mechanism), you can seamlessly data bind to your rendered UI elements. And yes, the data binding can be one way or two way.

Here’s a simple example to set the Text property of a TextField through data binding:

var observable = require("data/observable");
var source = new observable.Observable();

var textField = require("ui/text-field");
var targetTextField = new textField.TextField();

var bindingOptions = {
    sourceProperty: "textSource",
    targetProperty: "text",
    twoWay: true
};
targetTextField.bind(bindingOptions, source);
source.set("textSource", "Text set via binding");

If the code above seemed a little verbose, don’t worry. You can set data binding directly in your UI XML markup, the same way you do in XAML. Simply assign the value of a UI element’s property through data binding using the {{ ... }} syntax and then set the BindingContext on a parent element or Page.

var observable = require("data/observable");
var source = new observableModule.Observable();
source.set("labelMessage", "Hello World!");

function pageLoaded(args) {
    var page = args.object;
    page.bindingContext = source;
}
exports.pageLoaded = pageLoaded;

<!-- UI Markup -->
<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded">
    <StackLayout>
        <Label text="{{ labelMessage }}" />
    </StackLayout>
</Page>

UI Layouts

Another aspect of XAML UI composition that developers are fond of is Layouts. Predefined layouts allow developers to structure their UI components in a predictive manner, and this predictability stretches across multiple devices with varying screen sizes.

And sure enough, NativeScript UI composition has robust support for several predefined layouts. Here’s a glimpse of built-in layouts that NativeScript provides:

  1. AbsoluteLayout lets you set exact locations (left/top coordinates) for its children.
  2. DockLayout arranges its children at its outer edges and allows its last child to take up the remaining space.
  3. GridLayout defines a rectangular layout area that consists of columns and rows.
  4. StackLayout arranges its children horizontally or vertically. The direction is set with the orientation property.
  5. WrapLayout positions its children in rows or columns, based on the orientation property, until the space is filled and then wraps them on a new row or column.

Simply grab one of the predefined layouts and use it as a parent container to house your NativeScript UI widgets. Check out this great resource on NativeScript layouts any time you’re in doubt.

You’ll benefit from having a XAML development background while you feel at home in NativeScript!

Easy Event Handling

Event management is a core part of any UI composition – after all, you want to shoot for the most user interactivity. NativeScript allows for easy event handling from UI elements.

Assign an event handler in your UI XML markup and respond to the event in your code behind:

<!-- UI Markup -->
<Page>
  <StackLayout>
    <Button tap="onTap" />
  </StackLayout>
</Page>

// Code Behind
function onTap(eventData) {
  console.log("Hello World!");
}
exports.onTap = onTap;

You can create custom events tied to your UI elements and handle events through custom event handlers. In essence, you get to control the user interactivity of your UI end to end.

Mobile apps call for lots of touch events and gestures. Any successful mobile app has to respond to user gestures over UI elements. NativeScript is here to help with robust support for gestures. In NativeScript, View – the base class for all UI elements, has an observe method that lets you subscribe to gestures recognized by the UI element.

Here are the gestures you can listen for:

  1. Tap
  2. Double Tap
  3. Long Press
  4. Swipe
  5. Pan
  6. Pinch
  7. Rotation

Let’s look at how simple it is to subscribe to respond to the long press gesture:

var label = new labelModule.Label();
label.observe(gestures.GestureTypes.longPress, function (args) {
    console.log("Long Press");
});

ScreenBuilder

As you can see, NativeScript provides a ton of options to make UI composition simple for your mobile apps. But, you may be coming from a heavy .NET or desktop background, and you are just not sure of how to start building a UI for iOS/Android devices. Wouldn’t it be nice to get a nice starting point to build up from? Wouldn’t it be nice to have a WYSIWYG editor to build up your cross-platform UI?

Enter ScreenBuilder – part of the Telerik Platform. ScreenBuilder aims to give you an easy in-browser WYSIWYG editor to start building up your mobile apps visually, without writing any code. And yes, it works beautifully for NativeScript native apps.

If you have a Telerik Platform subscription, simply head to platform.telerik.com to get started. If not, you can sign up for a free Telerik Platform trial today and come back to the portal.

After logging in, hit the Create app button to create your own application workspace, and then hit the Create project button to add a NativeScript mobile app project to it. Notice how you receive a start from a ScreenBuilder option – go ahead and accept that offer.

SBProject

Once ScreenBuilder loads up, you’ll find yourself managing Views and Navigation in between views, along with a fancy in-browser representation of how your app will look. You’ll start with a default Home page.

SBProjectDash

You could of course, add different types of templated Views and even hook them up to data:

SBAddViews

Say you wanted to add an About Us page to your mobile app… Simply start from the template and customize content or use as a starting point:

SBAboutViews

You can see a preview of your default About Us page in ScreenBuilder and customize it to your heart’s content.

SBAboutInAction

Once you have added your new About Us page, come back to the app’s main page to see both the Home and About pages listed, complete with navigation between them. The ScreenBuilder in-browser representation is interactive – feel free to tweak things until you are satisfied.

SBNavigation

Think your app and its navigation is looking too much like one platform? Simply hit the device dropdown list and switch to another platform and, voila, the same app with its pages and navigation looks markedly different for the chosen platform.

SBAndroid

Once you are satisfied, simply commit your changes and open the same project in AppBuilder – Telerik Platform’s main app development tool. You’ll get a true NativeScript project with the pages and navigation already configured based on your ScreenBuilder choices. You may now continue building your app inside your browser or in any of the AppBuilder IDEs.

SBProjectInAB

Conclusion

NativeScript provides a framework for you to build a single codebase of JavaScript/TypeScript, XML and CSS towards making a cross-platform truly native mobile app. For .NET developers, building out UI compositions in NativeScript can be a breeze. If you are coming from a XAML/.NET or web background, you should feel right at home in building NativeScript UI through rich data binding, CSS and advanced tooling.

Now you have all the pieces needed to build a truly native yet cross-platform mobile app, with technologies you already know. Go build your dream app!