JavaScript使用DeviceOne开发实战(三)仿微信应用



<ignore_js_op>


<ignore_js_op>
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
var viewshower = ui("viewshower");var page = sm("do_Page");// 为viewshower增加4个子页面viewshower.addViews([ { id : "chats",// 页面的标示}, { id : "contacts",}, { id : "discover",}, { id : "me",} ]);// 初始化先显示第一个页面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");}); |

-------------------------------------------------------------
这一节主要是完成底部导航栏的实现。
0. 我们首先来分析一下界面效果图和设计图
<ignore_js_op>
<ignore_js_op>
整个底部导航分4个重复的部分,每个部分由一个图片ImageView和底部标题Label,以及右上角标示,这个标示可以用圆角Label来实现,这个标示缺省的时候应该是隐藏的。
1. 第一步我们得找到对应的图片资源,通常开发这些资源由美工提供,我们现在模仿微信,最好的方式是从微信原生安装包里获取,不能直接靠截图,而是打开微信ios,android安装包,ios的安装包是ipa和android的安装包apk都是一个压缩文件,解开可以获取到一些图片资源。目前我只需要底部8个图标,包括未点中以及点中的高亮图标,外面把这些图标放在image目录下
<ignore_js_op>
2. 先删除先前增加的4个临时按钮,然后按照美工提供的尺寸数据布局好新的组件,包括4个do_ImageView组件和4个Label组件以及4个右上角的Label
简单计算可以得出ImageView的大小是60*60。这里有一个小技巧,设置好一组ImageView和Label后选中2个组件,然后右键“Copy”,然后再"Paste"三次,还可以选中多个组件各种对齐。
<ignore_js_op>
再细调一下,把图片和文字设置好,图片设置就是设置ImageView的source属性,Label需要设置文字居中,设置textAlign属性为center,设置字体,设置背景色,前景色等等,设置右上角三个Label的visible为false。中间添加一个ALayout设置背景为灰色,作为ViewShower和Bottom Bar上下的分割线. 这里要注意,右上角的正圆形Label的实现方式就是设置border属性,border设置为FF0000FF,1,15 表示边界线的颜色是红色,宽度1,圆角半径15(Label的宽高都是30),从而实现正圆。
<ignore_js_op>
在真机上测试一下效果,iPhone和Android手机真机的效果图如下:
<ignore_js_op>
<ignore_js_op>
3. 这个时候会有2个问题,如果给ImageView上添加点击事件的话,用户必须点中这个图片才能触发点击,这样体验不好。第二个问题是图片在Android上稍微有点变形,如果在比如iPhone4上,可能圆形会变成椭圆,这个问题是由于不同手机宽高比的差异。
要解决的办法是:
* 把Bottom Bar所在的ALayout增加4个一样大小的子ALayout,然后把imageview,label都放在对应的子ALayout上,然后给子ALayout增加点击事件,这样用户的手指只要接触到差不多位置都能触发事件
* 把上面的4个子ALayout的isStretch属性改成false,这个原理可以参考文档 ALayout的示例demo
<ignore_js_op>
4. 修改index.ui.js,添加代码主要是在底部bottom bar切换按钮的时候修改所有图标的颜色和字的前景色。
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
var button1 = ui("do_Button_1");var imageview1 = ui("do_ImageView_1");var label1 = ui("do_Label_1");button1.on("touch", function() { showView("chats");});var button2 = ui("do_Button_2");var imageview2 = ui("do_ImageView_2");var label2 = ui("do_Label_2");button2.on("touch", function() { showView("contacts");});var button3 = ui("do_Button_3");var imageview3 = ui("do_ImageView_3");var label3 = ui("do_Label_3");button3.on("touch", function() { showView("discover");});var button4 = ui("do_Button_4");var imageview4 = ui("do_ImageView_4");var label4 = ui("do_Label_4");button4.on("touch", function() { showView("me");});function showView(name) { viewshower.showView(name); if (name == "chats") { label1.fontColor = "09BB07FF"; } else { label1.fontColor = "9F9F9FFF"; } if (name == "contacts") { label2.fontColor = "09BB07FF"; } else { label2.fontColor = "9F9F9FFF"; } if (name == "discover") { label3.fontColor = "09BB07FF"; } else { label3.fontColor = "9F9F9FFF"; } if (name == "me") { label4.fontColor = "09BB07FF"; } else { label4.fontColor = "9F9F9FFF"; }} |
到此为止,底部导航栏基本实现完成,这一节比较简单,主要是一些细致的ui拖拽调整。我们用调试版本看一下Android,iOS的效果都非常不错。源代码下载
我们开始实现ViewShower的第一页主体内容.
---------------------------------------------------------------------------------------
接上一节 底部导航 ,我们这一节主要是完成微信4个主页面的第一个页面“微信”页面,这一节内容比较多,我们分多个跟帖来完成
0 老规矩,先分析一下UI,由三个大部分组成,系统状态栏,工具栏和微信聊天记录列表。
<ignore_js_op>
1. 系统状态栏高度40,背景黑色,我们注意到微信的首页4个子页面都有这个系统状态栏,这样我们需要做一个整体框架的调整,没有必要为4个子页面都添加一个状态栏,只需要在ViewShower上添加一个就可以,对应的ViewShower和子页面的高度都变成1180.
<ignore_js_op>
对应设计器里index.ui, chats/index.ui, contacts/index.ui, discover/index.ui, me/index.ui 都要作相应的height,y属性值的变化。效果如下:
<ignore_js_op>
2. 我们回到chats/index.ui ,先增加工具导航栏(高度80)和里面的标题和工具按钮,这个需要增加加号的资源文件,因为这个文件是chats页面专有的,所以存在image/chats/bar_add.png下。
我们看看真机效果,我们注意到顶部多出一块黑色区域,这是设计器里的增加的状态栏,因为这个页面是从系统状态栏开始往下绘制的,所以会把设计器里这一部分多出来,
<ignore_js_op>
要解决的方法是修改app.js,openPage增加一个statusBarState参数(API文档),设置为transparent表示页面从屏幕最顶端开始绘制。
|
1
2
3
4
5
6
7
8
9
|
var d1 = require("deviceone");var app = d1.sm("do_App");app.on("loaded", function() { this.openPage({ statusBarState : "transparent" });}); |
再来看看真机效果图:
<ignore_js_op>
3. 主体部分是一个do_ListView,接下来设置ListView的cell和数据。
ListView的cell指列表框的每一行,比如ListView有100行数据,实际上可见的屏幕永远只能看到8,9行左右,所以我们手势上下滑动的时候并没有创建100行,而是重复使用这8,9行,只不过替换里面的数据而已。我们称之为行模板,在DeviceOne里这种模板也是一个ui文件,比如这里我们在chats子目录下新建一个chat_cell.ui,这个ui基本界面如下:
<ignore_js_op>
按照美工的设计尺寸我们来拖拽UI
<ignore_js_op>
这里同样需要考虑纯圆变形问题,需要设置好文字大小,前景色等属性,大家可以看到里面有多个do_Label,do_ImageView组件,由于模板ui是靠后期绑定数据的,所以在设计阶段都是空白的。
<ignore_js_op>
接下来我们需要设计chat_cell.ui对应的数据,通常为了用户体验,需要尽可能的减少网络交互,页面打开的时候通常先读取本地的数据文件,把界面显示出来,然后再考虑是否要进行网络连接来获取最新数据,所以App开发需要仔细考虑数据的本地化读写和数据的时效性的平衡。
DeviceOne的传递数据基本上都是标准的JSON格式。如下图,chat_cell.ui里的组件属性和JSON数据结构对应的关系
<ignore_js_op>
对应的映射关系的代码在chat_cell.ui.js如下,我们可以看到映射关系的左边是组件id.组件属性名,右边是数据JSON的key名称:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
//related to chat_cell.uivar 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
<ignore_js_op>
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里添加绑定数据的代码
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
//related to index.uivar storage = sm("do_Storage");var listdata = mm("do_ListData");var listview = ui("listview");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}); |
我们在真机上看看效果
<ignore_js_op>
在运行中有几个细节:
* 上下滑动的时候,图片不断的刷新,原因是我们的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里添加代码
|
01
02
03
04
05
06
07
08
09
10
|
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 { }}); |
其中chat_add_menu.ui 是弹出的菜单对应的ui文件,这个ui文件的根节点大小和chat/index.ui一样,这样确保我点击任何空白处都可以关闭这个菜单(实际上是隐藏这个菜单),我们在这个ui文件里把对应的布局都拖拽好,其中需要添加4个资源png文件。
这里有个小技巧,顶部的三角形标记只能通过一个ImageView加载一个三角形图标来实现。
<ignore_js_op>
我们再给chat_add_menu的根节点添加点击事件,点击的时候把自己隐藏,在chat_add_menu.js
|
1
2
3
4
|
var root = ui("$");root.on("touch",function(){ root.visible = false;}); |
最后我们先看看真机效果,点击加号弹出菜单,点击任何地方都把菜单隐藏。
<ignore_js_op>
这一节暂时先到这里,我们先开始拖拽后几个主页面,那几个页面基本完成后再重新回到这一个页面来细琢。
再附上最新代码zip,源代码也提交到GIT服务上了https://github.com/do-project/Fake-Weixin
JavaScript使用DeviceOne开发实战(三)仿微信应用的更多相关文章
- JavaScript使用DeviceOne开发实战(一) 配置和起步
2015 年 9 月 底,DeviceOne Release发布.至此,DeviceOne 基本完成了对多端的支持.基于 DeviceOne 可以: HTML5.Android.iOS.Windows ...
- JavaScript使用DeviceOne开发实战(四)仿优酷视频应用
开发之前需要考虑系统的差异性,比如ios手机没有回退键,所以在开发时一定要考虑二级界面需要有回退键,否则ios的手机就会陷入到这个页面出不去了.安卓系统有回退键,针对这个情况需要要求用户在3秒钟之内连 ...
- JavaScript使用DeviceOne开发实战(五)仿ZAKER应用
关于index底下切换的的组件,可以用ViewShower实现,详见: do_ViewShower http://bbs.deviceone.net/forum.php?mod=viewthread& ...
- JavaScript使用DeviceOne开发实战(二) 生成调试安装包
生成调试安装包 首先需要说明的是,这个步骤并不是每次调试App都必须的,大部分情况生成一次调试安装包,安装到手机上之后就可以忽略整个这个步骤.因为调试安装包包含了很多原生组件,都是可以定制勾选的,如果 ...
- JavaScript使用DeviceOne开发实战(六)点墨真实案例
qq群里的yan用户开发的App,基本完工大家可以看看 安装二维码是 QQ群:365443130
- 微信公众号开发《三》微信JS-SDK之地理位置的获取,集成百度地图实现在线地图搜索
本次讲解微信开发第三篇:获取用户地址位置信息,是非常常用的功能,特别是服务行业公众号,尤为需要该功能,本次讲解的就是如何调用微信JS-SDK接口,获取用户位置信息,并结合百度地铁,实现在线地图搜索,与 ...
- 微信公众号开发《三》微信JS-SDK之地理位置的获取与在线导航,集成百度地图实现在线地图搜索
本次讲解微信开发第三篇:获取用户地址位置信息,是非常常用的功能,特别是服务行业公众号,尤为需要该功能,本次讲解的就是如何调用微信JS-SDK接口,获取用户位置信息,并结合百度地铁,实现在线地图搜索,与 ...
- Android开发技巧——定制仿微信图片裁剪控件
拍照--裁剪,或者是选择图片--裁剪,是我们设置头像或上传图片时经常需要的一组操作.上篇讲了Camera的使用,这篇讲一下我对图片裁剪的实现. 背景 下面的需求都来自产品. 裁剪图片要像微信那样,拖动 ...
- [deviceone开发]-QQ分享、微信分享和新浪微博分享
一.简介 该demo主要实现QQ分享.微信分享和新浪微博分享.(调试包请到论坛扫描对应二维码下载) 二.效果图 三.相关讨论 http://bbs.deviceone.net/forum.php?mo ...
随机推荐
- free-electrons linux内核和驱动
操作系统的三个作用:1.管理硬件资源:2.提供独立于架构和硬件的可移植的软件接口3.处理不同应用对相同硬件资源的同时访问 系统调用接口是稳定的,系统调用由c函数库封装,用户程序基本不需要直接调用系统函 ...
- js处理匿名函数
首先js 有DOM0 和DOM2级事件 DOM 0级事件处理一般是直接把一个函数分配给一个事件处理程序,既可以在元素中直接分配一个事件处理程序 一个元素可以绑定多个事件 DOM0: <div i ...
- Servlet下载文件和http响应
下载文件等: 1.得到公共的内容ServletContext sc = this.getServletContext(); 2.在链接名字后面加个? 一个参数?参数1=值 两个参数?参数1=值& ...
- freeCodeCamp:Seek and Destroy
金克斯的迫击炮! 实现一个摧毁(destroyer)函数,第一个参数是待摧毁的数组,其余的参数是待摧毁的值. 当你完成不了挑战的时候,记得开大招'Read-Search-Ask'. 这是一些对你有帮助 ...
- LINQ - 在Where條件式中使用in與not in
希望对大家在以后的项目中能用到,我也是在项目中碰到了这个问题: 算算時間,接觸LINQ也有一個月的時間了,可以算是落伍兼新生,不過最近在寫專案的時候,遇到了在LINQ的Where條件式中要如何使用in ...
- Winform中Grid跨行复制一列
Private Sub DataCopyToGrid() '判断剪切板中是否存在内容 If Clipboard.ContainsText Then Dim str = Clipboard.GetTex ...
- ASP.NET Web API 2 入门
本文参考:http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web ...
- JIT动态编译器的原理与实现之Interpreter(解释器)的实现(三)
接下来,就是要实现一个虚拟机了.记得编码高质量的代码中有一条:不要过早地优化你的代码.所以,也本着循序渐进的原则,我将从实现一个解释器开始,逐步过渡到JIT动态编译器,这样的演化可以使原理看起来更清晰 ...
- 读写SD
public class SD_Files_RW extends Activity implements OnClickListener{ private String Text_of_input; ...
- yii打印sql
想打印Sql的话,可以用把你要执行的命令例如queryAll(),queryOne(),execute()换成getRawSql(); 例如 : 要看$result = Yii::$app->d ...