Introduction
HarmonyOS is a future-proof distributed operating system open to you as part of the initiatives for the all-scenario strategy, adaptable to mobile office, fitness and health, social communication, and media entertainment, to name a few. Unlike a legacy operating system that runs on a standalone device, HarmonyOS is built on a distributed architecture designed based on a set of system capabilities. It is able to run on a wide range of device forms, including smartphones, tablets, wearables, smart TVs and head units.
In this article, we will create a simple pedometer application for lite wearable which will count each step user takes, distance covered and Heart rate. Also, for every 1000 steps completion, wearable device will vibrate.
Pedometer app will have 2 UI screens, first screen will have start button. Once user clicks on Start button, app will route to second screen which will show STEPS, BPM (heart rate) and METER/KM (total distance) covered.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Requirements
1) DevEco IDE
2) Lite wearable simulator (or lite wearable watch)
Implementation
First page, index.hml contains start button.
Code:
<div class="container">
<text class="title">Pedometer</text>
<text class="subtitle">Step Counter</text>
<image class= "image" src='/common/pedometer.png' ></image>
<input class="button" type="button" value="Start" onclick="start"></input>
</div>
index.css has style defined for first page.
Code:
.container {
display: flex;
justify-content: center;
align-items: center;
left: 0px;
background-color: #192841;
top: 0px;
flex-direction: column;
width: 454px;
height: 454px;
}
.title {
font-size:38px;
font-family: HYQiHei-65S;
justify-content: center;
}
.subtitle {
font-size:30px;
justify-content: center;
}
.button {
width: 200px;
height: 50px;
font-size: 30px;
margin-top: 15px;
background-color: indigo;
}
.image {
width: 128px;
height: 143px;
justify-content: center;
margin-bottom: 15px;
margin-left: 10px;
margin-top: 20px;
}
index.js contains the implementation of start button. Once user clicks on start button, app will route to second page stepcounter.hml
Code:
import router from '@system.router'
export default {
data: {
title: 'World'
},
start() {
router.replace({
uri: 'pages/stepcounter/stepcounter'
});
}
}
Second page, stepcounter.hml contains UI design for displaying step count, heart beat count and total distance covered.
Code:
<div class="container" onswipe="touchMove">
<image class= "image" src='/common/stepscount.png' ></image>
<text class="subtitle">{{stepcount}}</text>
<div class="seperator" ></div>
<image class= "image" src='/common/heartbeat.png' ></image>
<text class="subtitle">{{heartbeatcount}}</text>
<div class="seperator" ></div>
<image class= "image1" src='/common/jogging.png' ></image>
<text class="subtitle">{{distance}}</text>
</div>
stepcounter.css has style defined for second page.
Code:
.container {
flex-direction: column;
justify-content: center;
align-items: center;
left: 0px;
top: 0px;
width: 454px;
height: 454px;
background-color: #192841;
}
.title {
font-size:38px;
font-family: HYQiHei-65S;
justify-content: center;
}
.subtitle {
font-size:30px;
color: lightgrey;
margin: 15px;
justify-content: center;
}
.seperator {
height: 1px;
width: 454px;
margin-bottom: 5px;
margin-top: 5px;
background-color: white;
}
.image {
width: 48px;
height: 48px;
justify-content: center;
margin-bottom: 5px;
}
.image1 {
width: 48px;
height: 48px;
justify-content: center;
margin-bottom: 5px;
margin-top: 15px;
}
stepcounter.js has implementation of various APIs.
1. Body state API
This API is used to listen for changes of the sensor wearing state. We will use this API to know if user is wearing wearable device or not.
Code:
// to listen the sensor wearing state, returns true if wear is in wrist
sensor.subscribeOnBodyState({
success: function(response) {
console.log('get on-body state value:' + response.value);
if(response.value === true) {
// get the heart rate
_this.getHeartBeatCount();
}
},
fail: function(data, code) {
console.log('fail to get on body state, code:' + code + ', data: ' + data);
},
});
For more, you can check https://forums.developer.huawei.com/forumPortal/en/topic/0202458325873420042
Related
More information like this, you can visit HUAWEI Developer Forum
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
In our previous article we have discussed regarding how we can integrate Banner Ads and Splash Ads.
We have also discussed on how you can integrate Ads kit sdk into flutter project. If you have missed the project then i would recommend you to give it a read. Here is the link.
In this article we will be discussing about how we can integrate Interstitial Ads, Reward Ads and Native Ads
Plugin for Ads Kit: https://developer.huawei.com/consumer/en/doc/development/HMS-Plugin-Library/flutter-sdk-download-0000001050196675
Application: In case you want to try the demo yourself please download Calculate BMI app form AppGallery. This application helps you calculate your Body Mass Index and shows you Banner and Interstitial Ads at the same time.
Below is the demo
Interstitial Ads:
These are full Screen Ads. In these ads the control to close the ads is given to customer.
The ideal place to add these kind of ads is transition between activities or if there is a level up then you can insert these ads.
These ads can be configured to redirect to a particular URL as well.
Let us see how to add these ads in flutter.
Code:
import 'package:flutter/material.dart';
import 'package:huawei_ads/adslite/interstitial/interstitial_ad.dart';
class InterstitialAds extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topCenter,
child: RaisedButton(
child: Text(
'Load Interstitial Ads',
),
onPressed: () {
InterstitialAd _interstitialAd = createInterstitialAd();
_interstitialAd
..loadAd()
..show();
},
),
);
}
}
InterstitialAd createInterstitialAd() {
return InterstitialAd(
adUnitId: "teste9ih9j0rc3",
);
}
Below is the result you will get after running it.
Rewarded Ads:
These are also full screen ads but they provide some kind of reward to customer if he watches full add.
Example – User can get extra life in a game if he watches full video.
These are explicitly chosen by customer but user have full control to close the ads. User can anytime close these ads but in that case he won’t get any reward.
These ads are always singleton ads hence we need to check whether the ad is showing or not.
Code:
import 'package:flutter/material.dart';
import 'package:huawei_ads/hms_ads_lib.dart';
import 'package:huawei_ads/adslite/ad_param.dart';
import 'package:huawei_ads/adslite/reward/reward_verify_config.dart';
import 'package:flutter/cupertino.dart';
import 'package:huawei_ads/hms_ads.dart';
typedef void RewardAdListener(RewardAdEvent event,
{Reward reward, int errorCode});
class RewardedAds extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topCenter,
child: RaisedButton(
child: Text(
'Load Rewarded Ads',
),
onPressed: () {
RewardAd.instance
.loadAd(adUnitId: "testx9dtjwj8hp", adParam: AdParam.build());
RewardAd.instance.isLoaded().then((isLoaded) {
if (isLoaded) {
RewardAd.instance.show();
}
});
RewardAd.instance.setRewardAdListener =
(RewardAdEvent event, {Reward reward, int errorCode}) {
print("RewardedVideoAd event $event");
if (event == RewardAdEvent.rewarded) {
print('Received reward : ');
}
};
},
),
);
}
}
As you can see in above code we are checking whether Rewarded as is loaded or not by isLoading() method.
If it is not loaded we will show it. Also we have applied listener to it so we can listen to user events.
Below are example of some events:
Opened - RewardAdEvent.opened
Started - RewardAdEvent.started
Completed - RewardAdEvent.completed
Closed - RewardAdEvent.closed
While adding reward ads make sure validation is done at client side so there is no delay in providing reward to user.
Below is the result you will get after running it.
Native Ads:
These ads fit into the surrounding into which they are added.
Here Native ads acts like a widget which you can add into a child, loading and displaying the ads is handled by plugin itself. Images and videos both are supported here. We also need to use a controller in order to set properties of native ads.
We can also add listener in order to see the user interaction with the ads.
Below is the code to add native add.
Code:
import 'package:flutter/material.dart';
import 'package:huawei_ads/adslite/nativead/native_ad.dart';
import 'package:huawei_ads/adslite/nativead/native_ad_configuration.dart';
import 'package:huawei_ads/adslite/nativead/native_ad_controller.dart';
import 'package:huawei_ads/adslite/nativead/native_styles.dart';
import 'package:huawei_ads/utils/constants.dart';
class NativeAds extends StatelessWidget {
@override
Widget build(BuildContext context) {
NativeStyles stylesSmall = NativeStyles();
stylesSmall.setCallToAction(fontSize: 8);
stylesSmall.setFlag(fontSize: 10);
stylesSmall.setSource(fontSize: 11);
NativeAdConfiguration configuration = NativeAdConfiguration.build();
configuration.setChoicesPosition = NativeAdChoicesPosition.bottomRight;
return Align(
alignment: Alignment.topCenter,
child: Column(
children: <Widget>[
Container(
height: 100,
margin: EdgeInsets.only(bottom: 20.0),
child: NativeAd(
adUnitId: "testu7m3hc4gvm",
controller: NativeAdController(
adConfiguration: configuration,
listener: (AdEvent event, {int errorCode}) {
print("NativeAd event $event");
}),
type: NativeAdType.small,
styles: stylesSmall,
),
),
],
),
);
}
}
Below is the result you will get after running it.
Github Link:
Ads Kit: https://github.com/DTSE-India-Community/Flutter/tree/master/add_kit_flutter
BMI Calculator: https://github.com/DTSE-India-Community/Flutter/tree/master/calculate_bmi
Conclusion:
I hope with this article you will find some ease in integrating Ads kit in flutter project., In case you want to see any other kit integration or sample code then make sure to give the feedback.
Banner and Splash Ads: https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201286813113710087&fid=0101187876626530001
Below is the official documentation: https://developer.huawei.com/consumer/en/doc/development/HMS-Plugin-Guides/publisher-service-0000001050196431
In this and your previous 'projects' you discuss ways of pushing ads.
How about not discussing ad development and instead doing something actually beneficial and useful .
If you can ?
Article Introduction
In this article, I have explained how to use chart UI component to develop a health application for Huawei Lite Wearable device using Huawei DevEco Studio and using JS language in Harmony OS. Chart Component has basically two major styles line graph and bar graph. In case of Health applications like pedometer, steps tracker or any fitness application, the results are well presented if they are represented in charts daily/weekly/monthly. Here I explore how to show the accumulated health data in UI chart components.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Huawei Lite Wearable
Requirements
1) DevEco IDE
2) Lite wearable watch (Can use simulator also)
New Project (Lite Wearable)
After installation of DevEco Studio, make new project.
Select Lite Wearable in Device and select Empty Feature Ability in Template.
After the project is created, its directory as shown in below image.
Purpose of charts, why should we use it?
Charts are important UI component of the modern UI design. There are many ways to use them in watch UIs. Charts can provide information to user more clear and precise, thereby enriches the user experience. Due to space constraint of the watch UI design, charts are the most sought component for representing data visually.
Use case scenarios
We will create sample health application which will record steps and heart rate, and we will focus more on how to use the charts UI.
Show steps count per hour in a day
Show steps covered day-wise for entire week.
Show heart rate bpm per hour in a day
Step 1: Create entry page for health application using index.html
Create and add the background image for index screen using stack component.
index.html
Code:
<stack class="stack" onswipe="touchMove">
<image src='/common/wearablebackground.png' class="background"></image>
<div class="container">
<div class="pedoColumn">
<text class="data-steps">
</text>
</div>
<text class="app-title">STEPS METER</text>
<div class="pedoColumn" onclick="clickSteps">
<text class="content-title">
Today's Steps
</text>
<div class= "pedoRow">
<image src='/common/steps.png' class="stepsbackground"></image>
<text class="container-steps" >
{{stepCounterValue}}
</text>
<text class="data-steps">
Steps
</text>
</div>
</div>
<div class="pedoColumn" onclick="clickHeart">
<text class="content-title">
Current Heart rate
</text>
<div class= "pedoRow">
<image src='/common/heart.png' class="stepsbackground"></image>
<text class="container-steps">
{{hearRateValue}}
</text>
<text class="data-steps">
BPM
</text>
</div>
</div>
<div class="pedoColumn">
</div>
</div>
</stack>
index.css
Code:
.pedoColumn {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
width: 380px;
height: 150px;
margin: 5px;
background-color: #3b3b3c;
border-radius: 10px;
}
.pedoRow {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
width: 380px;
height: 100px;
margin: 5px;
background-color: #3b3b3c;
border-radius: 10px;
}
.container {
flex-direction: column;
justify-content: center;
align-items: center;
left: 0px;
top: 0px;
width: 454px;
height: 454px;
background-color: transparent;
}
.data-steps{
text-align: left;
width: 190px;
height: 52px;
padding-left: 10px;
color: #c73d3d;
padding-top: 10px;
border-radius: 10px;
background-color: transparent;
}
.content-title{
text-align: left;
width: 290px;
height: 52px;
padding-left: 10px;
color: #d4d4d4;
padding-top: 10px;
border-radius: 10px;
background-color: transparent;
}
.container-steps{
text-align: left;
width: 70px;
height: 52px;
padding-left: 10px;
color: #d4d4d4;
padding-top: 10px;
border-radius: 10px;
margin-left: 20px;
background-color: transparent;
}
.app-title{
text-align: center;
width: 290px;
height: 52px;
color: #c73d3d;
padding-top: 10px;
border-radius: 10px;
background-color: transparent;
}
.stepsbackground {
width:76px;
height:76px;
}
Types of chart
1. Bar chart : To express large variations in data, how individual data points relate to a whole, comparisons and ranking
2. Line chart : To express minor variations in data.
Desired chart can be create with field “type” in chart class as show below.
Code:
<chart class="chartContainer" type="bar" options="{{chartOptions}}"
datasets="{{arrayData}}"></chart>
Chart class takes two important attributes options and data sets. Line graph provides with more flexibility with options section when compared to bar charts.
Step 2: Show steps count per hour in a day
The average person accumulates 3,000 to 4,000 steps per day. Regular physical activity has been shown to reduce the risk of certain chronic diseases, including high blood pressure, stroke and heart diseases. Most performed physical activity by an average human is walking. There is always eagerness to keep track of steps thereby keep track of our activeness in day.
In general steps count shows always a pattern in day, like more number of steps in morning 8.00-10.00 am hours and evening 5.00-7.00 pm hours, this readings mostly depends on the profession you are in. We can use the bar charts to track then hourly in a day or compare hourly among the days in week. Bar charts is great tool to have it in your wrist accessible at any time.
Code:
<stack class="stack" onswipe="touchMove">
<image src='/common/werablebackground.png' class="background"></image>
<div class="container">
<div class="chartRow">
<text class="date-title">{{dateString}}</text>
<image src='/common/steps.png' class="stepsbackground"></image>
</div>
<div class="chartAxisRow">
<text class="x-title">{{yAxisMaxRange}}</text>
<chart class="chartContainer" type="bar" options="{{chartOptions}}"
datasets="{{arrayData}}"></chart>
</div>
<div class="calcRow">
<text class="item-title">6am</text>
<text class="item-title" ></text>
<text class="item-title" >6pm</text>
</div>
<div class="chartBottomRow">
<text class="date-title">{{totalSteps}}</text>
<text class="item-title">{{distanceKms}} </text>
</div>
</div>
</stack>
Here we track the steps count hourly in day starting from 6.00 am hours to 9.00 pm hours. To visually represent we need x axis and y axis information. X axis will have the time range from 6.00 am hours to 9.00 pm hours. Y axis will range from 0 to maximum number steps (it is around 150 here).
Chart class has options attribute with paramters xAxis and yAxis.
xAxis - X-axis parameters. You can set the minimum value, maximum value, and scale of the x-axis, and whether to display the x-axis
yAxis - Y-axis parameters. You can set the minimum value, maximum value, and scale of the y-axis, and whether to display the y-axis
Code:
chartOptions: {
xAxis: {
min: 0,
max: 25,
axisTick: 18,
display: true,
color: "#26d9fd",
},
yAxis: {
min: 0,
max: 200,
axisTick: 10,
display: true,
color: "#26d9fd",
}
},
min - corresponds to minimum value of the axis should start
max - corresponds to minimum value of the axis should end
color – color of the axis
display – true/false visibility of the x/y axis line
axisTick - Number of scales displayed on the x-axis. The value ranges from 1 to 20. The display effect depends on the calculation result of Number of pixels occupied by the image width/(max-min).
Lite wearables support integer calculation, and an error may occur in the case of inexhaustible division. Specifically, a segment of space may be left at the end of the x-axis.
In the bar chart, the number of bars in each group of data is the same as the number of scales, and the bars are displayed at the scales.
Chart class has datasets which takes the data required for graph. It has parameters like data, gradient, strokeColor and fillColor
Code:
arrayData: [{
data: [10, 0, 20, 101, 44, 56, 1, 10, 153, 41, 111, 30, 39, 0, 0, 10, 0, 13],
gradient: true,
strokeColor: "#266571",
fillColor: "#26d9fd",
},
],
Step 3: Show steps covered day-wise for entire week.
To compare steps count across the days in a week, we can use bar charts. This will let us know which days in the week the user is more active. In general the data in weekends and weekdays will have common pattern.
If the user has set steps goals for week, then we can show progress of the steps count with a progress bar too.
Code:
<progress class="progressHorizontal" type="horizontal" percent="{{progressNumber}}"></progress>
As we have seen before we can use chart class with different options. Since here the comparison is among the days in a week. The X Axis will have days Monday to Sunday.
Code:
<stack class="stack" onswipe="touchMove">
<image src='/common/wearablebackground.png' class="background"></image>
<div class="container">
<text class="date-title">
Weekly summary
</text>
<text class="date-title">
{{totalSteps}}
</text>
<div class="chartRow">
<text class="date-content">
{{goalString}}
</text>
</div>
<progress class="progressHorizontal" type="horizontal" percent="{{progressNumber}}"></progress>
<chart class="chartContainer" type="bar" options="{{chartOptions}}" datasets="{{arrayData}}"></chart>
<div class="calcRow">
<text class="item-title">
M
</text>
<text class="item-title">
T
</text>
<text class="item-title">
W
</text>
<text class="item-title">
T
</text>
<text class="item-title">
F
</text>
<text class="item-title">
S
</text>
<text class="item-title">
S
</text>
</div>
</div>
</stack>
Chart class has options attribute with paramters xAxis and yAxis.
Code:
chartOptions: {
xAxis: {
min: 0,
max: 10,
axisTick: 7,
display: true,
color: "#8781b4",
},
yAxis: {
min: 0,
max: 1200,
axisTick: 10,
display: false,
color: "#8781b4",
},
},
Chart class has datasets which takes the data required for graph
Code:
arrayData: [{
data: [1078, 209, 109, 1011, 147, 560, 709],
gradient: true,
strokeColor: "#266571",
fillColor: "#8781b4",
},
],
Step 3: Show heart rate in bpm per hour in a day
Heart rate can be recorded from wrist watch sensor APIs and saved to watch storage. Then this weekly or daily data can be visually represented in line graph.
We can use line graph for heart rate visuals, because the heart rate has less variations in an entire day.
Code:
<chart class="chartContainer" type="line" options="{{chartOptions}}"
datasets="{{arrayData}}"></chart>
We are taking the x axis as the time ranging from 6.00am hours to 12.00 pm hours. Y axis has the heart rate bpm.
Code:
<stack class="stack">
<image src='/common/werablebackground.png' class="background"></image>
<div class="container" onswipe="touchMove">
<text class="item-title">
{{todayString}} Wednesday
</text>
<div class="pedoColumn" onclick="clickHeart">
<div class="pedoRow">
<text class="x-title">
{{yAxislabel}}
</text>
<chart class="chartContainer" type="line " options="{{chartOptions}}" datasets="{{arrayData}}"></chart>
</div>
</div>
<text class="content-title">
Avg bpm {{averagebpm}}
</text>
</div>
</stack>
Chart class has options attribute with paramters xAxis and yAxis.
Code:
chartOptions: {
xAxis: {
min: 0,
max: 18,
axisTick: 18,
display: true,
color: "#26d9fd",
},
yAxis:{
min: 50,
max: 110,
axisTick: 10,
display: false,
color: "#26d9fd",
},
We have attribute called series which is specific to line graph series has parameters like lineStyle, headPoint, topPoint, bottomPoint and loop.
Code:
series: {
lineStyle: {
width: 5,
smooth: true
},
headPoint:{
shape: "circle",
size: 5,
strokeWidth:2,
strokeColor:"#ff0000",
fillColor:"#26d9fd",
display:true
},
topPoint:{
shape: "circle",
size: 5,
strokeWidth:3,
strokeColor:"#ff0000",
fillColor:"#ffffff",
display:true
},
bottomPoint:{
shape: "circle",
size: 5,
strokeWidth:3,
strokeColor:"#ff0000",
fillColor:"#000100",
display:true
}
},
lineStyle- Line style, such as the line width and whether the line is smooth.
headPoint - Style and size of the white point at the start of the line.
topPoint - Style and size of the top point.
bottomPoint - Style and size of the bottom point.
Loop - Whether to start drawing again when the screen is looped
Append attribute can be adding data dynamically. Data is dynamically added to an existing data sequence. The target sequence is specified based on serial, which is the subscript of the datasets array and starts from 0. datasets[index].data is not updated. The value is incremented by 1 based on the horizontal coordinate and is related to the xAxis min/max setting.
Tips and Tricks
In this article the data for the chart UI is hardcoded in the javascript object. To create full-fledged application, the data has to come from the accumulated storage, which is updated by the sensor APIs from the watch or the mobile devices connected to the watch could be the source of the data.
Conclusion
In this article, we have learnt how to use chart UI for any health or fitness application in Harmony OS. We have seen how the graph type selection can done based on the use-case and requirement. We have seen basic UI enriching options in the chart.
References
Document
developer.harmonyos.com
Article Introduction
In this article, I have explained to develop a Tic-Tac-Toe application for Huawei Lite wearable device using Huawei DevEco studio and using JS language in Harmony OS. Tic-Tac-Toe is a game for two players, X and O, who take turns marking the spaces in a 3×3 grid. The player who succeeds in placing three of their marks in a diagonal, horizontal, or vertical row will be a winner.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Huawei Lite Wearable
Requirements
1) DevEco IDE
2) Lite wearable watch (Can use simulator also)
New Project (Lite Wearable)
After installation of DevEco Studio, make new project.
Select Lite Wearable in Device and select Empty Feature Ability in Template.
After the project is created, its directory as shown in below displayed image.
hml files describe the page layout.
css files describe the page style.
js files process the interactions between pages and users.
The app.js file manages global JavaScript logics and application lifecycle.
The pages directory stores all component pages.
The common directory stores public resource files, such as media resources and .js files.
Integration process
Design the UI
Step 1: Add background image.
As the first step, we can create a UI that contains tictactoe cell boxes which will be filled by the user entries. Create and add the background image for tictactoe screen using stack component.
index.html
HTML:
<stack class="stack">
<image src='/common/wearablebackground.png' class="background"></image>
index.css
CSS:
.background {
width:454px;
height:454px;
}
.stack {
width: 454px;
height: 454px;
justify-content: center;
}
Step 2: Add title for game. Add the display text for the current player.
Add the storage text for player and gameOver string to display that is game over after the game is completed. Here we use conditional UI rendering that when the Boolean gameOver is true, then display the gameOverString.
index.html
HTML:
<text class="app-title">{{title}} </text>
<text class="sub-title">{{playerString}}
</text>
<div class="uiRow"if="{{gameOver}}" >
<text if="{{gameOver}}" class="app-title">{{gameOverString}}</text>
</div>
index.css
CSS:
.app-title{
text-align: center;
width: 290px;
height: 52px;
color: #c73d3d;
padding-top: 10px;
margin-bottom: 30px;
border-radius: 10px;
background-color: transparent;
}
.sub-title{
text-align: center;
width: 290px;
height: 52px;
color: #26d9fd;
padding-top: 10px;
border-radius: 10px;
background-color: transparent;
}
index.js
JavaScript:
title: "Tic Tac Toe",
playerString: "Player One - O",
Step 3: Add UI 3x3 grid call for application.
We need 3x3 matrix of text boxes. Use loop rendering for the boxes since all are similar boxes. I have added animation for the boxes to make it more appealing.
HTML:
<div class="boxRow" for="{{cellValue in gameEntries}}" tid="id" else>
<text class="cell" onclick="handleCellClick($idx, 0)" >{{cellValue[0]}}</text>
<text class="cell" onclick="handleCellClick($idx, 1)">{{cellValue[1]}}</text>
<text class="cell" onclick="handleCellClick($idx, 2)">{{cellValue[2]}}</text>
</div>
CSS:
.boxRow {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 247px;
height: 64px;
background-color: #000000;
animation-name: Go;
animation-duration: 2s;
animation-delay: 0;
animation-timing-function: linear;
animation-iteration-count: infinite;
border-radius: 5px;
}
.cell {
display: flex;
text-align: center;
width: 75px;
height: 50px;
border-width: 1px;
color: #414343;
background-color: #FFD700;
border-color: #414343;
border-radius: 5px;
margin: 5px;
}
So to check the condition iterate through the entries in 3x3 array. We are converting 3x3 array element location to index of the grid using modulo and math functions.
Read full article
Result
Tips and Tricks
You can use Lite-wearable simulator for development. We can extend 3x3 grid for higher order Tic-Tac-Toe just by increasing game entry matrix to 5x5 or 7x7.
Conclusion
In this article, we have learnt how to create simple game app Tic-Tac-Toe using various Harmony OS UI components of course, there are a lot more things we could do here, like make the game actually multiplayer, so you can play with a friend.
References
https://developer.harmonyos.com/en/...ces/lite-wearable-syntax-hml-0000001060407093
Read full article
Well explained, what are all the limitations in Harmony OS?
Symptom
While developing a card, I used a pseudo-class for a component to implement a color changing effect. However, the color cannot be restored.
For example, the original background color was as follows.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
This figure shows the new background color after using the pseudo-class.
In normal cases, the card’s background color is changed upon tapping, and will return to the original color when you lift your finger.
This problem is caused by incomplete pseudo-classes for cards supported by Huawei Quick App Loader. Even so, there’s still an easy solution.
Solution
Simply add a tap event to the component using the pseudo-class. No logic processing is needed.
Sample code:
CSS:
<div class="sitetype_box" widgetid="8e4bf1ca-f716-46f8-8614-16d1b35002c5" onclick="test">
</div>
CSS style:
.sitetype_box {
flex-direction: column;
background-color:#FFBF00;
padding: dpConvert(0) dpConvert($elementsMarginHorizontalL) dpConvert(0) dpConvert($elementsMarginHorizontalL);
}
/** Pseudo-class */
.sitetype_box :active{
background-color: #E40078;
}
Method:
JavaScript:
test(){
console.log("message");
}
Reference:
Pseudo-classes for quick apps:
https://developer.huawei.com/consumer/en/doc/development/quickApp-References/quickapp-style#h1-1578402521212
New member here
nice
wonderful sharing!!
Thanks
Nice
good
omg, I thought I am the only one with this problem, thanks for providing the solution
Thanks
Hello from pakistan
JessicajK said:
omg, I thought I am the only one with this problem, thanks for providing the solution
Click to expand...
Click to collapse
It's an honor to solve your problem.
Mayism said:
Symptom
While developing a card, I used a pseudo-class for a component to implement a color changing effect. However, the color cannot be restored.
For example, the original background color was as follows.
This figure shows the new background color after using the pseudo-class.
In normal cases, the card’s background color is changed upon tapping, and will return to the original color when you lift your finger.
This problem is caused by incomplete pseudo-classes for cards supported by Huawei Quick App Loader. Even so, there’s still an easy solution.
Solution
Simply add a tap event to the component using the pseudo-class. No logic processing is needed.
Sample code:
CSS:
<div class="sitetype_box" widgetid="8e4bf1ca-f716-46f8-8614-16d1b35002c5" onclick="test">
</div>
CSS style:
.sitetype_box {
flex-direction: column;
background-color:#FFBF00;
padding: dpConvert(0) dpConvert($elementsMarginHorizontalL) dpConvert(0) dpConvert($elementsMarginHorizontalL);
}
/** Pseudo-class */
.sitetype_box :active{
background-color: #E40078;
}
Method:
JavaScript:
test(){
console.log("message");
}
Reference:
Pseudo-classes for quick apps:
https://developer.huawei.com/consumer/en/doc/development/quickApp-References/quickapp-style#h1-1578402521212
Click to expand...
Click to collapse
Mayism said:
Symptom
While developing a card, I used a pseudo-class for a component to implement a color changing effect. However, the color cannot be restored.
For example, the original background color was as follows.
This figure shows the new background color after using the pseudo-class.
In normal cases, the card’s background color is changed upon tapping, and will return to the original color when you lift your finger.
This problem is caused by incomplete pseudo-classes for cards supported by Huawei Quick App Loader. Even so, there’s still an easy solution.
Solution
Simply add a tap event to the component using the pseudo-class. No logic processing is needed.
Sample code:
CSS:
<div class="sitetype_box" widgetid="8e4bf1ca-f716-46f8-8614-16d1b35002c5" onclick="test">
</div>
CSS style:
.sitetype_box {
flex-direction: column;
background-color:#FFBF00;
padding: dpConvert(0) dpConvert($elementsMarginHorizontalL) dpConvert(0) dpConvert($elementsMarginHorizontalL);
}
/** Pseudo-class */
.sitetype_box :active{
background-color: #E40078;
}
Method:
JavaScript:
test(){
console.log("message");
}
Reference:
Pseudo-classes for quick apps:
https://developer.huawei.com/consumer/en/doc/development/quickApp-References/quickapp-style#h1-1578402521212
Click to expand...
Click to collapse
Mayism said:
Symptom
While developing a card, I used a pseudo-class for a component to implement a color changing effect. However, the color cannot be restored.
For example, the original background color was as follows.
This figure shows the new background color after using the pseudo-class.
In normal cases, the card’s background color is changed upon tapping, and will return to the original color when you lift your finger.
This problem is caused by incomplete pseudo-classes for cards supported by Huawei Quick App Loader. Even so, there’s still an easy solution.
Solution
Simply add a tap event to the component using the pseudo-class. No logic processing is needed.
Sample code:
CSS:
<div class="sitetype_box" widgetid="8e4bf1ca-f716-46f8-8614-16d1b35002c5" onclick="test">
</div>
CSS style:
.sitetype_box {
flex-direction: column;
background-color:#FFBF00;
padding: dpConvert(0) dpConvert($elementsMarginHorizontalL) dpConvert(0) dpConvert($elementsMarginHorizontalL);
}
/** Pseudo-class */
.sitetype_box :active{
background-color: #E40078;
}
Method:
JavaScript:
test(){
console.log("message");
}
Reference:
Pseudo-classes for quick apps:
https://developer.huawei.com/consumer/en/doc/development/quickApp-References/quickapp-style#h1-1578402521212
Click to expand...
Click to collapse
SymptomAfter type of the input component is set to button and the border-radius attribute is set, the button does not take effect after being tapped. After the border-radius attribute is deleted, the button can work properly.
The code where the exception occurs is as follows:
Code:
<template>
<div class="page-wrapper">
<input type="button" class="button" value="Animation" />
</div>
</template>
<script>
</script>
<style>
.page-wrapper {
flex-direction: column;
justify-content: center;
align-items: center;
}
.button {
color: #20a0ff;
background-color: red;
padding: 10px 20px;
border-radius: 40px;
}
</style>
Cause AnalysisAfter the border-radius attribute is set, the bottom layer of the quick app engine is restricted. As a result, the tap effect cannot be automatically implemented.
SolutionYou can use the pseudo-class of the quick app to implement the button tap effect.
Optimized code:
Code:
<template>
<div class="page-wrapper">
<input type="button" value="Animation" />
</div>
</template>
<script>
</script>
<style>
.page-wrapper {
flex-direction: column;
justify-content: center;
align-items: center;
}
.button {
color: #20a0ff;
background-color: red;
padding: 10px 20px;
border-radius: 40px;
}
.button:active{
background-color: green;
}
</style>
Checkout in forum