Dies ist eine Reihe von Dokumenten. Das langfristige Ziel besteht darin, mit DeviceOne einige hochwertige mobile Anwendungen zu entwickeln, die derzeit weit verbreitet sind. Wir werden jede Funktion und jedes Detail dieser Anwendungen maximieren und nicht nur im Einfachen bleiben UI-Nachahmung und Demo-Stufe, aber eine praktische App, die grundsätzlich verwendet werden kann.
Während des Implementierungsprozesses werden Sie feststellen, dass einige Funktionen derzeit nicht unterstützt werden und nicht implementiert werden können. Außerdem werden Sie auf häufige technische Probleme stoßen, die bei verschiedenen mobilen Entwicklungen auftreten. Die schrittweise Bedienung und Problemlösung kann es Entwicklern ermöglichen, intuitiv zu verstehen, wie eine tatsächliche App über DeviceOne entwickelt wird, und kann auch viele technische Details der mobilen Entwicklung selbst verstehen, was App-Entwicklern helfen kann, viele Umwege zu vermeiden.
In diesem Dokument wird hauptsächlich die WeChat-Nachahmung vorgestellt.
Der erste Teil ist der Aufbau des Gerüsts
Üblicherweise erfordert die App-Entwicklung das UE-Design durch das Produktpersonal und das UI-Design durch das Kunstpersonal. Die Implementierung kann erst beginnen, nachdem diese beiden Schritte abgeschlossen sind. Wir ahmen jetzt das vorhandene WeChat nach und können diese Schritte weglassen. Das Bild unten zeigt das vom Künstler bereitgestellte Hauptschnittstellen-UI-Design und die Größe der darin enthaltenen Elemente.
1. Neues Projekt: Wir haben uns für die leere Vorlage entschieden, weil wir den Entwicklungsprozess detaillierter erklären können. Tatsächlich ist es für dieses Projekt besser geeignet, die Vorlage „Mehrfachansicht mit ViewShower“ zu wählen.
2. Eine kurze Analyse der Hauptschnittstelle. Die Größe der gesamten Hauptschnittstelle entspricht der Größe eines iPhone 6, 750 * 1334. Sie ist in zwei Teile unterteilt, den oberen und den unteren Teil Die Navigationsleiste oben enthält 4 unabhängige Schnittstellen. Es wird immer nur eine Schnittstelle angezeigt. Die anderen drei Schnittstellen befinden sich im Speicher und können über die Navigation unten umgeschaltet werden. Dies ist für die Verwendung von do_ViewShower als Hauptteil geeignet des Rahmens wie unten gezeigt:
Entsprechend diesem Design löschen wir die automatisch generierte Schaltfläche im neu erstellten Projekt, fügen eine do_ALayout-Komponente und eine do_ViewShower-Komponente hinzu und legen deren Höhe, Breite, x- und y-Koordinaten fest:
3. Als nächstes fügen wir der ViewShower 4 Seiten hinzu. Ich möchte hier auch betonen, dass unsere Codestruktur bei der Benennung klar und einfach sein muss Es ist nicht möglich, die vollständige chinesische Schreibweise zu verwenden, einschließlich der Erstellung von Unterverzeichnissen mit mehreren Ebenen und nicht deren Vermischung. Hier fügen wir 4 Unterverzeichnisse hinzu: Chats, Kontakte, Discover, Me. Klicken Sie mit der rechten Maustaste auf jedes Unterverzeichnis, wählen Sie „Neu – Andere – DeviceOne – UI-Datei“, erstellen Sie 4 index.ui und die entsprechenden index.ui.js werden automatisch generiert .
Achten Sie hier darauf, die Höhe des Wurzelknotens ALayout, der diesen 4 UI-Dateien entspricht, auf 1220 festzulegen, da diese 4 UI-Dateien alle Unteransichten des ViewShower der Hauptschnittstelle sind und die Größe des ViewShower nicht überschreiten sollten.
Fügen Sie außerdem jeder Benutzeroberfläche eine Beschriftung hinzu, um den chinesischen Namen zu kennzeichnen. Sie können ihn später debuggen, um den tatsächlichen Effekt klarer zu sehen.
4. Fügen Sie einfach 4 Schaltflächen in der unteren Leiste hinzu und fügen Sie dann den entsprechenden js-Code hinzu, um die Seitenwechselfunktion von ViewShower zu implementieren. Hier ist ein Tipp: Wählen Sie 2 oder mehr Komponenten aus und Sie können verschiedene Ausrichtungsfunktionen verwenden, wie unten gezeigt:
5. Fügen Sie den ViewShower-Initialisierungscode und das Schaltflächenklickereignis in index.ui.js hinzu.
var viewshower = ui("viewshower"); var page = sm("do_Page"); // 为viewshower增加4个子页面 viewshower.addViews([ { id : "chats",// 页面的标示 path : "source://view/chats/index.ui"// 页面的路径 }, { id : "contacts", path : "source://view/contacts/index.ui" }, { id : "discover", path : "source://view/discover/index.ui" }, { id : "me", path : "source://view/me/index.ui" } ]); // 初始化先显示第一个页面 viewshower.showView("chats"); var button1 = ui("do_Button_1"); button1.on("touch", function() { viewshower.showView("chats"); }); var button2 = ui("do_Button_2"); button2.on("touch", function() { viewshower.showView("contacts"); }); var button3 = ui("do_Button_3"); button3.on("touch", function() { viewshower.showView("discover"); }); var button4 = ui("do_Button_4"); button4.on("touch", function() { viewshower.showView("me"); });
6. Schauen wir uns den Laufeffekt auf einem realen Computer an, starten Sie den Debugging-Dienst des Designers und starten Sie das Debugging-Programm auf dem Mobiltelefon. Das endgültige Rendering sieht wie folgt aus sind genau gleich. Klicken Sie unten auf die 4 Schaltflächen, und alle Umschalteffekte sind gut:
7. Das ist alles für diesen Abschnitt. Ist die Rahmenarbeit abgeschlossen? Man kann nur sagen, dass der erste Schritt des Frameworks abgeschlossen ist. Wenn wir viele Kollegen haben, die diese App gemeinsam entwickeln, können wir beginnen, die Arbeit parallel zu trennen und sie dann in 5 Teile zu unterteilen:
* Fertigstellung der unteren Leiste
* Fertigstellung von /chats/index.ui
* Vervollständigung von /contacts/index.ui
* Fertigstellung von /discover/index.ui
* Vervollständigung von /me/index.ui
Voraussetzung für die parallele Arbeit mehrerer Personen ist die Codeversionsverwaltung wie SVN und GIT. Die Adresse lautet https://github.com/do-project/Fake-Weixin In jedem Abschnitt werden wir den GIT-Dienst einreichen. Sie können die Codereferenz dieses Knotens herunterladen. Im Anhang fügen wir auch den Projektcode für diesen Abschnitt bei.
Im nächsten Abschnitt schließen wir die erste Teilaufgabe ab, die Implementierung von BottomBar.
--------------------------------- --- --------------
In diesem Abschnitt geht es hauptsächlich darum, die Implementierung der unteren Navigationsleiste abzuschließen.
0. Lassen Sie uns zunächst die Schnittstellen-Renderings und Konstruktionszeichnungen analysieren
Die gesamte untere Navigation ist in 4 wiederholte Teile unterteilt. Jeder Teil besteht aus einer ImageView, einer unteren Titelbeschriftung und einer Beschriftung in der oberen rechten Ecke. Diese Beschriftung kann mit einer abgerundeten Ecke versehen werden standardmäßig ausgeblendet.
1. Der erste Schritt besteht darin, die entsprechenden Bildressourcen zu finden. Jetzt imitieren wir WeChat. Sie können sich nicht direkt auf Screenshots verlassen , aber öffnen Sie sie. WeChat ios, Android-Installationspaket, das iOS-Installationspaket ist ipa und das Android-Installationspaket apk sind beide komprimierte Dateien, die entpackt werden können, um einige Bildressourcen zu erhalten. Derzeit benötige ich nur die 8 Symbole unten, einschließlich der hervorgehobenen Symbole, die nicht angeklickt werden, und derjenigen, die angeklickt werden. Diese Symbole lege ich in das Bildverzeichnis
2. Löschen Sie zunächst die 4 zuvor hinzugefügten temporären Schaltflächen und ordnen Sie dann die neuen Komponenten gemäß den vom Künstler bereitgestellten Größendaten an, einschließlich 4 do_ImageView-Komponenten, 4 Label-Komponenten und 4 Labels in der oberen rechten Ecke
Eine einfache Berechnung kann zeigen, dass die Größe von ImageView 60 * 60 beträgt. Hier ist ein kleiner Trick: Wählen Sie nach dem Einrichten eines Satzes von ImageView und Label zwei Komponenten aus, klicken Sie dann dreimal mit der rechten Maustaste auf „Kopieren“ und dann auf „Einfügen“. Sie können auch mehrere Komponenten für verschiedene Ausrichtungen auswählen.
Optimieren Sie es erneut und legen Sie das Bild und den Text fest. Legen Sie das Quellattribut von ImageView fest. Stellen Sie den Text so ein, dass er zentriert ist, und legen Sie die Schriftart und die Hintergrundfarbe fest , Vordergrundfarbe usw., legen Sie oben rechts fest Die Sichtbarkeit der drei Beschriftungen in der Ecke ist falsch. Fügen Sie ein ALayout in der Mitte hinzu und stellen Sie den Hintergrund auf Grau als Trennlinie zwischen ViewShower und der unteren Leiste ein. Beachten Sie hier, dass das perfekte kreisförmige Label in der oberen rechten Ecke implementiert wird, indem das Randattribut auf FF0000FF gesetzt wird ,1,15 zur Darstellung der Grenzlinie, die Breite beträgt 1 und der Verrundungsradius beträgt 15 (Breite und Höhe des Etiketts betragen jeweils 30), wodurch ein perfekter Kreis erreicht wird.
Testen Sie den Effekt auf einem echten Gerät. Die Darstellungen von echten iPhone- und Android-Telefonen sind wie folgt:
3. Zu diesem Zeitpunkt treten zwei Probleme auf. Wenn Sie der ImageView ein Klickereignis hinzufügen, muss der Benutzer auf das Bild klicken, was keine gute Erfahrung ist. Das zweite Problem besteht darin, dass das Bild auf einem Android beispielsweise leicht verformt ist und der Kreis möglicherweise zu einer Ellipse wird. Dieses Problem ist auf das unterschiedliche Seitenverhältnis verschiedener Mobiltelefone zurückzuführen.
Die Lösung lautet:
* Fügen Sie dem ALayout, in dem sich die untere Leiste befindet, 4 Sub-ALayouts derselben Größe hinzu, platzieren Sie dann die Bildansicht und die Beschriftung auf dem entsprechenden Sub-ALayout und fügen Sie dann ein Klickereignis zum Sub-ALayout hinzu, sodass das Der Finger des Benutzers muss nur die gleiche Position berühren. Ereignisse können ausgelöst werden
* Ändern Sie das isStretch-Attribut der oben genannten vier Sub-ALayouts in false. Weitere Informationen zu diesem Prinzip finden Sie im Dokument ALayout-Beispieldemo
4. 修改index.ui.js,添加代码主要是在底部bottom bar切换按钮的时候修改所有图标的颜色和字的前景色。
var button = ui("do_Button_"); var imageview = ui("do_ImageView_"); var label = ui("do_Label_"); button.on("touch", function() { showView("chats"); }); var button = ui("do_Button_"); var imageview = ui("do_ImageView_"); var label = ui("do_Label_"); button.on("touch", function() { showView("contacts"); }); var button = ui("do_Button_"); var imageview = ui("do_ImageView_"); var label = ui("do_Label_"); button.on("touch", function() { showView("discover"); }); var button = ui("do_Button_"); var imageview = ui("do_ImageView_"); var label = ui("do_Label_"); button.on("touch", function() { showView("me"); }); function showView(name) { viewshower.showView(name); if (name == "chats") { imageview.source = "source://image/tabbar_mainframeHL.png"; label.fontColor = "BBFF"; } else { imageview.source = "source://image/tabbar_mainframe.png"; label.fontColor = "FFFFF"; } if (name == "contacts") { imageview.source = "source://image/tabbar_contactsHL.png"; label.fontColor = "BBFF"; } else { imageview.source = "source://image/tabbar_contacts.png"; label.fontColor = "FFFFF"; } if (name == "discover") { imageview.source = "source://image/tabbar_discoverHL.png"; label.fontColor = "BBFF"; } else { imageview.source = "source://image/tabbar_discover.png"; label.fontColor = "FFFFF"; } if (name == "me") { imageview.source = "source://image/tabbar_meHL.png"; label.fontColor = "BBFF"; } else { imageview.source = "source://image/tabbar_me.png"; label.fontColor = "FFFFF"; } }
到此为止,底部导航栏基本实现完成,这一节比较简单,主要是一些细致的ui拖拽调整。我们用调试版本看一下Android,iOS的效果都非常不错。
我们开始实现ViewShower的第一页主体内容.
---------------------------------------------------------------------------------------
接上一节 底部导航 ,我们这一节主要是完成微信4个主页面的第一个页面“微信”页面,这一节内容比较多,我们分多个跟帖来完成
0 老规矩,先分析一下UI,由三个大部分组成,系统状态栏,工具栏和微信聊天记录列表。
1. 系统状态栏高度40,背景黑色,我们注意到微信的首页4个子页面都有这个系统状态栏,这样我们需要做一个整体框架的调整,没有必要为4个子页面都添加一个状态栏,只需要在ViewShower上添加一个就可以,对应的ViewShower和子页面的高度都变成1180.
对应设计器里index.ui, chats/index.ui, contacts/index.ui, discover/index.ui, me/index.ui 都要作相应的height,y属性值的变化。效果如下:
2. 我们回到chats/index.ui ,先增加工具导航栏(高度80)和里面的标题和工具按钮,这个需要增加加号的资源文件,因为这个文件是chats页面专有的,所以存在image/chats/bar_add.png下。
我们看看真机效果,我们注意到顶部多出一块黑色区域,这是设计器里的增加的状态栏,因为这个页面是从系统状态栏开始往下绘制的,所以会把设计器里这一部分多出来,
要解决的方法是修改app.js,openPage增加一个statusBarState参数(API文档),设置为transparent表示页面从屏幕最顶端开始绘制。
var d1 = require("deviceone"); var app = d1.sm("do_App"); app.on("loaded", function() { this.openPage({ source : "source://view/index.ui", statusBarState : "transparent" }); });
再来看看真机效果图:
3. 主体部分是一个do_ListView,接下来设置ListView的cell和数据。
ListView的cell指列表框的每一行,比如ListView有100行数据,实际上可见的屏幕永远只能看到8,9行左右,所以我们手势上下滑动的时候并没有创建100行,而是重复使用这8,9行,只不过替换里面的数据而已。我们称之为行模板,在DeviceOne里这种模板也是一个ui文件,比如这里我们在chats子目录下新建一个chat_cell.ui,这个ui基本界面如下:
按照美工的设计尺寸我们来拖拽UI
这里同样需要考虑纯圆变形问题,需要设置好文字大小,前景色等属性,大家可以看到里面有多个do_Label,do_ImageView组件,由于模板ui是靠后期绑定数据的,所以在设计阶段都是空白的。
接下来我们需要设计chat_cell.ui对应的数据,通常为了用户体验,需要尽可能的减少网络交互,页面打开的时候通常先读取本地的数据文件,把界面显示出来,然后再考虑是否要进行网络连接来获取最新数据,所以App开发需要仔细考虑数据的本地化读写和数据的时效性的平衡。
DeviceOne的传递数据基本上都是标准的JSON格式。如下图,chat_cell.ui里的组件属性和JSON数据结构对应的关系
对应的映射关系的代码在chat_cell.ui.js如下,我们可以看到映射关系的左边是组件id.组件属性名,右边是数据JSON的key名称:
//related to chat_cell.ui var root = ui("$");;//$是这个ui文件根节点组件的通配符,如果指定组件的id,也可以用id来获取对象 root.setMapping({ "photo_imageview.source" : "photo", "name_label.text" : "name", "lastmessage_label.text" : "lastmessage.message", "lasttime_label.text" : "lastmessage.time", "unread_label.visible" : "unread", "unread_label.text" : "unread-count", "name_label.fontColor" : "isgroup", });
对应的数据本应该是第一次运行从网络上获取之后再缓存到本地的,我们是模拟,所以先手动生成一个文件到data/chats/chat.json
4. 我们回到chats/index.ui,我们需要给这里ui文件里的listview设置模板,绑定数据。
设置index.ui 里的listview的templates属性为 source://view/chats/chat_cell.ui
注意:chat_cell.ui存储在source/default/view/chats/chat_cell.ui,但是source://的根节点指的是 source/default/目录
在index.ui.js里添加绑定数据的代码
//related to index.ui var storage = sm("do_Storage"); var listdata = mm("do_ListData"); var listview = ui("listview"); var json_path = "data://chats/chat.json";//本地缓存的数据 if (storage.fileExist(json_path)) { storage.readFile(json_path, function(data, e) { //deviceone.print(JSON.stringify(data)); listdata.addData(data); listview.bindItems(listdata); listview.refreshItems(); }) } var page = sm("do_Page"); page.on("loaded",function(){ //这个页面加载完显示出来后触发这个事件 //我们可以在这个事件里去获取最新的网络数据,来更新listview和data/chats/chat.json });
我们在真机上看看效果
在运行中有几个细节:
* 上下滑动的时候,图片不断的刷新,原因是我们的ImageView的source是网络图片,每次显示的时候都是从网络上获取的,所以这里需要把chat_cell.ui里的ImageView的cacheType属性换成"always" 意思是只从网络上读取一次就会缓存到本地,下一次不会再从网络上读取了。关于cacheType属性参考API文档
* ImageView也是圆角的,圆角通常可以使用border属性来设置,但是android只有ImageView不能通过border来设置圆角,ImageView还有一个专有属性radius来设置Android才有效,这个我们以后可以改进
5. 处理右上角的add按钮,点击弹出菜单
先给右上角ImageView的enable属性设置为true,才可以处理点击事件,在chats/index.ui.js里添加代码
var add_button = ui("add_imageview"); add_button.on("touch", function() { var menu = ui("menu_id"); if (menu) {//如果已经add过,就只是让这个view显示,而不是add一个新的 if (menu.visible == false) menu.visible = true; } else { main.add("menu_id", "source://view/chats/chat_add_menu.ui"); } });
其中chat_add_menu.ui 是弹出的菜单对应的ui文件,这个ui文件的根节点大小和chat/index.ui一样,这样确保我点击任何空白处都可以关闭这个菜单(实际上是隐藏这个菜单),我们在这个ui文件里把对应的布局都拖拽好,其中需要添加4个资源png文件。
这里有个小技巧,顶部的三角形标记只能通过一个ImageView加载一个三角形图标来实现。
我们再给chat_add_menu的根节点添加点击事件,点击的时候把自己隐藏,在chat_add_menu.js
var root = ui("$"); root.on("touch",function(){ root.visible = false; });
最后我们先看看真机效果,点击加号弹出菜单,点击任何地方都把菜单隐藏。
这一节暂时先到这里,我们先开始拖拽后几个主页面,那几个页面基本完成后再重新回到这一个页面来细琢。