腊月的季节

2016第52周总结

探索ionic轮播

ionic轮播自带标签
在ionic做的第一个轮播

1
2
3
4
5
6
7
8
9
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
<ion-view view-title="欢迎">
<ion-slide-box on-slide-changed="slideChanged(index)">
<ion-slide>
<h3>欢迎使用EffectWork</h3>
<div id="logo">
<img src="img/effectwork.jpeg" alt="加载失败">
</div>
<p>
专门为时间打造
</p>
<p>
开始我们每天的任务
</p>
</ion-slide>
<ion-slide>
<h3>我们一起出发</h3>

<div id="list">
<h5>时间</h5>
<ol>
<li>生活要以快乐为基准爱情要以互惠为原则</li>
<li>爱情不是空中楼阁,它是需要强大的物质基础来做地基做保障的。</li>
<li>时间一直在这里,流逝的是我们自己。</li>
</ol>
</div>
</ion-slide>
<ion-slide>
<h3>来到我的时间</h3>
<p>
不要浪费你的生命在你一定会后悔的地方上。
</p>
<div class="login">
<button class="button button-outline button-positive" ng-click="log()">登录</button>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<button class="button button-outline button-positive" ng-click="reg()">注册</button>
</div>

</ion-slide>
</ion-slide-box>
</ion-view>

利用了 标签来制作ionic轮播。

探索ionic视图设定

这个可以称前端的视图路由
我采用了$urlRouterProvider,$stateProvider两个服务进行视图路由及视图与控制器的绑定。
具体代码如下

1
2
3
4
5
6
7
8
9
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
angular.module('EffectWork.routes',[])
.config(function($urlRouterProvider,$stateProvider){
$stateProvider
//欢迎界面
.state('splash', { //splash路由名称
url: '/splash', //前端路由一般就是#/splash
cache: false, //是否缓存
templateUrl: 'views/splash_screen/splash.html', //视图
controller: 'splashCtrl' //控制器
})
.state('login',{
url:'/login',
templateUrl:'views/login.html',
controller:'loginCtrl'
})
.state('register',{
url:'/register',
templateUrl:'views/register.html',
controller:'registerCtrl'
})
.state('forget',{
url:'/forget',
templateUrl:'views/forget.html',
controller:'forgetCtrl'
})
.state("tab", {
url: "/tab",
abstract: true,
templateUrl: "views/tabs.html",
controller:"tabCtrl"
})
.state('tab.home', {
url: '/home',
views: {
'tab-home': {
templateUrl: 'views/tab-home.html',
controller: "homeCtrl"
}
}
})
$urlRouterProvider.otherwise("/splash"); //默认前端路由/splash
})

路由跳转

采用$state服务
利用$state服务的go()方法,参数为指定路由名称。
具体代码如下:

1
2
3
4
5
6
7
8
9
angular.module('EffectWork.controllers')
.controller('splashCtrl',['$scope','$state',function($scope,$state){
$scope.log=function(){
$state.go('login');
};
$scope.reg=function(){
$state.go('register');
};
}])

关于键盘窗口挡住输入框

我所有的输入表单都用包括,然后加上属性delegate-handle=””即可进行页面滑动,可以不挡住输入框,至于还有另一种方法,就是利用keyboard插件,进行键盘事件监控。我采用了第一种,目前还没出现问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<ion-view view-title="找回密码">
<div class="bar bar-header bar-calm">
<h1 class="title">找回密码</h1>
</div>
<ion-content class="rj-stable-content" delegate-handle="findPwd" id="findPassword">
<div class="list list-inset has-header">
<label class="item item-input">
<input type="text" placeholder="手机号">
</label>
<label class="item item-input">
<input type="password" placeholder="密码">
</label>
<label class="item item-input">
<input type="password" placeholder="再次输入密码">
</label>
<label class="item item-input item-input-inset">
<input type="text" placeholder="输入验证码">
<button class="button button-outline button-calm" style="height:10px;">
获取验证码
</button>
</label>
<button class="button button-block button-calm" ng-click="findPwd()">
找回密码
</button>
<button class="button button-clear button-positive" style="text-decoration:underline;" ng-click="backLogin()">
返回
</button>
</div>
</ion-content>
</ion-view>

关于ionic上拉菜单样式问题

ionic上拉菜单样式会有一些问题,导致很不好看,具体做法是把我下面的代码加入style.css

1
2
3
4
5
6
7
8
9
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
.platform-android .action-sheet-backdrop {
-webkit-transition: background-color 150ms ease-in-out;
transition: background-color 150ms ease-in-out;
position: fixed;
top: 0;
left: 0;
z-index: 11;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0);
}

.platform-android .action-sheet-backdrop.active {
background-color: rgba(0, 0, 0, 0.4);
}

.platform-android .action-sheet-wrapper {
-webkit-transform: translate3d(0, 100%, 0);
transform: translate3d(0, 100%, 0);
-webkit-transition: all cubic-bezier(0.36, 0.66, 0.04, 1) 500ms;
transition: all cubic-bezier(0.36, 0.66, 0.04, 1) 500ms;
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 100%;
max-width: 500px;
margin: auto;
}

.platform-android .action-sheet-up {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}

.platform-android .action-sheet {
margin-left: 8px;
margin-right: 8px;
width: auto;
z-index: 11;
overflow: hidden;
}

.platform-android .action-sheet .button {
display: block;
padding: 1px;
width: 100%;
border-radius: 0;
border-color: #d1d3d6;
background-color: transparent;
color: #007aff;
font-size: 21px;
}

.platform-android .action-sheet .button:hover {
color: #007aff;
}

.platform-android .action-sheet .button.destructive {
color: #ff3b30;
}

.platform-android .action-sheet .button.destructive:hover {
color: #ff3b30;
}

.platform-android .action-sheet .button.active, .platform-android .action-sheet .button.activated {
box-shadow: none;
border-color: #d1d3d6;
color: #007aff;
background: #e4e5e7;
}

.platform-android .action-sheet-has-icons .icon {
position: absolute;
left: 16px;
}

.platform-android .action-sheet-title {
padding: 16px;
color: #8f8f8f;
text-align: center;
font-size: 13px;
}

.platform-android .action-sheet-group {
margin-bottom: 8px;
border-radius: 4px;
background-color: #fff;
overflow: hidden;
}

.platform-android .action-sheet-group .button {
border-width: 1px 0px 0px 0px;
}

.platform-android .action-sheet-group .button:first-child:last-child {
border-width: 0;
}

.platform-android .action-sheet-options {
background: #f1f2f3;
}

.platform-android .action-sheet-cancel .button {
font-weight: 500;
}

.platform-android .action-sheet-open {
pointer-events: none;
}

.platform-android .action-sheet-open.modal-open .modal {
pointer-events: none;
}

.platform-android .action-sheet-open .action-sheet-backdrop {
pointer-events: auto;
}

.platform-android .action-sheet .action-sheet-title, .platform-android .action-sheet .button {
text-align: center;
}

.platform-android .action-sheet-cancel {
display: block;
}

即可解决

关于标签

利用ionic 即可制作tab导航。
具体代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ion-tabs class="tabs-icon-top tabs-color-active-balanced">
<ion-tab title="首页" icon-on="ion-ios-home positive" icon-off="ion-ios-home-outline" ui-sref="tab.home">
<ion-nav-view animation="slide-left-right" name="tab-home"></ion-nav-view>
</ion-tab>
<ion-tab title="番茄钟" icon-on="ion-ios-clock positive" icon-off="ion-ios-clock-outline" ui-sref="tab.school">
<ion-nav-view animation="slide-left-right" name="tab-school"></ion-nav-view>
</ion-tab>
<ion-tab title="消息" icon-on="ion-ios-chatbubble positive" icon-off="ion-ios-chatbubble-outline" ui-sref="tab.message">
<ion-nav-view animation="slide-left-right" name="tab-message"></ion-nav-view>
</ion-tab>
<!-- <ion-tab title="我的" icon-on="ion-ios-person positive" icon-off="ion-ios-person-outline">
<ion-nav-view animation="slide-left-right" name="tab-me"></ion-nav-view>
</ion-tab> -->
</ion-tabs>

关于ionic侧栏菜单

利用ionic
具体代码如下:

1
2
3
4
5
6
7
8
9
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
<ion-side-menus>
<ion-side-menu-content drag-content="true">
<ion-header-bar align-title="center" class="bar-stable bar-calm">
<div class="buttons">
<button class="button no-animation button-icon icon ion-ios-list-outline" ng-click="toggleLeft()">
</button>
</div>
<div class="wodivh1 title">EffectWork</div>
<div class="buttons">
<button class="button no-animation button-icon icon ion-ios-plus-outline">
</button>
</div>
</ion-header-bar>
<ion-tabs class="tabs-icon-top tabs-color-active-balanced">
<ion-tab title="首页" icon-on="ion-ios-home positive" icon-off="ion-ios-home-outline" ui-sref="tab.home">
<ion-nav-view animation="slide-left-right" name="tab-home"></ion-nav-view>
</ion-tab>
<ion-tab title="番茄钟" icon-on="ion-ios-clock positive" icon-off="ion-ios-clock-outline" ui-sref="tab.school">
<ion-nav-view animation="slide-left-right" name="tab-school"></ion-nav-view>
</ion-tab>
<ion-tab title="消息" icon-on="ion-ios-chatbubble positive" icon-off="ion-ios-chatbubble-outline" ui-sref="tab.message">
<ion-nav-view animation="slide-left-right" name="tab-message"></ion-nav-view>
</ion-tab>
<!-- <ion-tab title="我的" icon-on="ion-ios-person positive" icon-off="ion-ios-person-outline">
<ion-nav-view animation="slide-left-right" name="tab-me"></ion-nav-view>
</ion-tab> -->
</ion-tabs>
</ion-side-menu-content>
<ion-side-menu side="left" width="280" style="background-color:#4a87ee;">
<ion-content class="rj-stable-content" delegate-handle="sideScroll" id="userRegister">
<img class="radioImg" src="img/effectwork.jpeg">
<div class="row">
<div class="col col-33 col-top"></div>
<div class="col col-33 col-center word">{{name}}</div>
<div class="col col-33 col-bottom"><span class="badge badge-calm">签到</span></div>
<div class="col"><br><br><br></br></br></div>
</div>
</br>
<div class="row">
<div class="col word">金币:{{money}}</div>
</div>
<div class="row">
<div class="col word">签名:时间一直在这里,流逝的是我们自己。</div>
</div>
<div class="list">
<button class="item button icon-left ion-ios-cog-outline button-calm button-block">我的资料</button>
<button class="item button icon-left ion-ios-browsers-outline button-calm button-block">任务箱</button>
<button class="item button icon-left ion-ios-filing-outline button-calm button-block">统计情况</button>
<button class="item button icon-left ion-ios-paper-outline button-calm button-block">设置</button>
</div>
</ion-content>
</ion-side-menu>
</ion-side-menus>

关于angularjs控制器传递数据

这个我现在不是特别全面,我目前采用的是\$rootScope和angularjs服务依赖注入传递数据,为什么用这两种,第一是\$rootScope的作用域,第二是服务在整个应用中的生命周期。肯定还有其他方法,可以去尝试。还有一种方法是通过$state传递参数,但是我屡试不爽。这个没做成功。

关于cordova插件制作

我说这个是因为我觉得光用别人的插件,有好多限制啊,所以我想自己做。但是这个要做的话,要对Android,ios,windowsIphone开发要了解一点。
1、先说一下搭建cordova插件开发的环境吧
nodejs肯定是要安装的
然后全局安装cordova

1
npm install -g cordova

另外Android sdk肯定是要安装的,因为我们就是针对Android的sdk进行第三方开发。
如果都安装好了,让我们开始吧!
2、创建第一个应用

1
cordova create hello com.cool.hello HelloWorld

又是helloworld,你好世界!
让我来解释一下参数吧
第一个参数hello表示在工程目录中创建一个 hello 的文件夹
第二个参数com.cool.hello表示包名(反向域名),用于标志不同的 app
第三个参数HelloWorld表示项目的名称,可以在 config.xml 文件中修改
3、添加平台
进入创建的项目目录
查看已有的凭条

1
$ cordova platforms list

添加所需要的平台

1
$ cordova platform add android

如果想移除已经添加的平台的话cordova platform remove android 或者cordova platform rm android
4、编译项目
编译项目命令

1
$ cordova build android

5、运行项目

1
$ cordova run android

6、前面都是测试,我们这才开始插件开发
安装pluman

1
$ npm install -g plugman

plugman安装完之后就可以创建一个插件了

1
$ cordova plugin plugman create --name --plugin_id --plugin_version [--path] [--variableName=VALUE]

解释参数:
pluginName: 插件名字
pluginID: 插件id, egg:coolPlugin
oversion: 版本, egg : 0.0.1
directory:一个绝对或相对路径的目录,该目录将创建插件项目
variable NAME=VALUE: 额外的描述,如作者信息和相关描述
生成插件的目录

1
2
3
4
5
6
7
8
9
ExtraInfo
├── src
| ├── android
| | └── ExtraInfo.java
| ├── ios
| └── ...
├── www
| └── ExtraInfo.js
└── plugin.xml

这里的 src 对应不同的平台,www 放我们的 javascript 文件,plugin.xml 是插件的配置文件。
接下来就说配置文件plugin.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<plugin id="cn.net.wenzhixin.cordova" version="0.0.1"
xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<name>ExtraInfo</name>
<description>Description</description>
<js-module name="ExtraInfo" src="www/ExtraInfo.js">
<clobbers target="cordova.plugins.ExtraInfo"/>
</js-module>
<platform name="android">
<config-file parent="/*" target="res/xml/config.xml">
<feature name="ExtraInfo">
<param name="android-package" value="cn.net.wenzhixin.cordova.ExtraInfo"/>
</feature>
</config-file>
<source-file src="src/android/ExtraInfo.java" target-dir="src/cn/net/wenzhixin/cordova"/>
</platform>
</plugin>

有几个关键的字段需要解释下:

  • id: 插件的标识,即发布到 plugins.cordova.io 的 ID
  • name:插件的名称
  • description:描述信息
  • js-module:对应我们的 javascript 文件,src 属性指向 www/ExtraInfo.js
  • platform:支持的平台,这里仅仅用到了 android
    下面这句
    1
    2
    3
    <js-module src="www/barcodescanner.js" name="BarcodeScanner">  
    <clobbers target="cordova.plugins.barcodeScanner" />
    </js-module>

这里很重要, 它指明了 插件的原始 js 文件放在哪里,clobbers target有用。等会用到,这会我们把它叫做 clobbers

1
2
3
4
5
6
<config-file parent="/*" target="res/xml/config.xml">
<feature name="ExtraInfo">
<param name="android-package" value="cn.net.wenzhixin.cordova.ExtraInfo"/>
</feature>
</config-file>
<source-file src="src/android/ExtraInfo.java" target-dir="src/cn/net/wenzhixin/cordova"/>

这里是插件的配置信息,最后会添加到 res/xml/config.xml 文件中,并且将我们的 src/android/ExtraInfo.java,复制到 android 的 package 包中。
feature name=”BarcodeScanner” 表示服务名为BarcodeScanner 。 记住这个服务名,有用.
value=”HXBarcodeScanner” 对应的.m文件中插件的类名

helloPlugin.js配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var exec = require('cordova/exec');
var myFunc = function(){};


// arg1:成功回调
// arg2:失败回调
// arg3:将要调用类配置的标识
// arg4:调用的原生方法名
// arg5:参数,json格式
myFunc.prototype.showToast=function(success, error) {
exec(success, error, "CoolToast", "showToast", []);
};


myFunc.prototype.showshowToast=function(text, lenth,success, error) {
exec(success, error, "CoolToast", "showshowToast", [text, lenth]);
};
myFunc.prototype.openActivity=function() {
exec(null, null, "CoolToast", "openActivity", []);
};
var showt = new myFunc();
module.exports = showt;

最后还有一个java类

1
2
3
4
5
6
7
8
9
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
package com.cool.toast;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
import org.json.JSONException;
import com.example.hello.TestActivity;
import android.content.Intent;
import android.widget.Toast;

public class ShowToast extends CordovaPlugin {

@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
// TODO Auto-generated method stub
if("showToast".equals(action)){
Toast.makeText(cordova.getActivity(), "show...", Toast.LENGTH_SHORT).show();
callbackContext.success("success");
return true;
}else if("showshowToast".equals(action)){
String str = args.getString(0);
int len = args.getInt(1);

if(len == 0){
Toast.makeText(cordova.getActivity(), str, Toast.LENGTH_SHORT).show();
callbackContext.success("success" + str);
return true;
}else{
Toast.makeText(cordova.getActivity(), str, Toast.LENGTH_LONG).show();
callbackContext.success("success" + str);
return true;
}
}else if("openActivity".equals(action)){
openActivity();
callbackContext.success("success");
return true;
}
callbackContext.error("error");
return false;
}

private void openActivity() {
Intent intent = new Intent(cordova.getActivity(),TestActivity.class);
cordova.getActivity().startActivity(intent);
}

}

继承了 CordovaPlugin 类,并重写 execute 方法,使用 action 来判断我们在 javascript 中调用的方法名,成功的话调用 callbackContext.success(message),失败调用 callbackContext.error(message) 方法,分别对应 javascript 文件中的 success 和 error 回调函数。
当然,这里只用到 android 平台,其他的平台也是一样的,ios 使用 object-c、wp7 使用 c# 语言,例子见Plugin Development Guide。
7、插件安装
我的插件所在的路径是F:\CoolPlugin

首先切换到最初创建的hello目录 cd hello

执行插件安装命令cordova plugin addF:\CoolPlugin

执行完之后你就发现插件已经安装上去了
8、插件的使用

1
2
3
4
5
6
7
8
cool.toast.showToast();
cool.toast.showshowToast("hello",0, function(msg) {
alert(msg);
}, function(msg) {
alert(msg);
});

cool.toast.openActivity();

这样就可以成功调用了。
7、最后还是说说这个插件开发
我认为就分两个
一个是JavaScript interface

1
2
3
4
5
cordova.exec(function(winParam) {},  
function(error) {},
"service",
"action",
["firstArgument", "secondArgument", 42, false]);

参数意义:1.成功的回调函数
2.失败的回调函数
3.native端的名称
4.native端的action名称
5.参数
这是翻译的,看一下原文

  • function(winParam) {}: A success callback function. Assuming yourexec call completes successfully, this function executes alongwith any parameters you pass to it.
  • function(error) {}: An error callback function. If the operationdoes not complete successfully, this function executes with anoptional error parameter.
  • “service”: The service name to call on the native side. Thiscorresponds to a native class, for which more information isavailable in the native guides listed below.
  • “action”: The action name to call on the native side. Thisgenerally corresponds to the native class method. See the nativeguides listed below.
  • [/ arguments /]: An array of arguments to pass into the nativeenvironment.
    官方示例:
    1
    2
    3
    4
    5
    window.echo = function(str, callback) {  
    cordova.exec(callback, function(err) {
    callback('Nothing to echo.');
    }, "Echo", "echo", [str]);
    };
1
2
3
window.echo("echome", function(echoValue) {  
alert(echoValue == "echome"); // should alert true.
});

第二个就是native interface
上面说的都是Android的这里说IOS吧
首先,是config.xml文件中需要配置

1
2
3
4
5
6
7
<platform name="ios">  
<config-file target="config.xml" parent="/*">
<feature name="Echo">
<param name="ios-package" value="Echo" />
</feature>
</config-file>
</platform>

注意点:1.feature name要与exec中的service对应
2.param value要与exec中的action对应
3.param name要写成ios-package
其次,object-c的class要继承CDVPlugin
官方示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/********* Echo.h Cordova Plugin Header *******/  

#import <Cordova/CDV.h>

@interface Echo : CDVPlugin

- (void)echo:(CDVInvokedUrlCommand*)command;

@end

/********* Echo.m Cordova Plugin Implementation *******/

#import "Echo.h"
#import <Cordova/CDV.h>

@implementation Echo

- (void)echo:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* pluginResult = nil;
//获取exec中传过来的参数
NSString* echo = [command.arguments objectAtIndex:0];

if (echo != nil && [echo length] > 0) {
//返回成功,messageAsString将数据返回到JavaScript。
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:echo];
} else {
//返回失败。
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
}
//将结果发送给<code>self.commandDelegate</code>,这样会执行JavaScript side的成功或失败方法。
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
} @end

这就是cordova插件开发。

关于tabs无法置底的问题

在应用的.config

1
2
3
4
$ionicConfigProvider.platform.ios.tabs.style('standard'); 
$ionicConfigProvider.platform.ios.tabs.position('bottom');
$ionicConfigProvider.platform.android.tabs.style('standard');
$ionicConfigProvider.platform.android.tabs.position('standard');

关于ionic退回按钮

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ionicPlatform.registerBackButtonAction(function (e) {
//判断处于哪个页面时双击退出
if ($location.path() == '/tab/home') {
if ($rootScope.backButtonPressedOnceToExit) {
ionic.Platform.exitApp();
} else {
$rootScope.backButtonPressedOnceToExit = true;
$cordovaToast.showLongBottom('再按一次退出系统');
setTimeout(function () {
$rootScope.backButtonPressedOnceToExit = false;
}, 2000);
}
}
else if ($ionicHistory.backView()) {
$ionicHistory.goBack();
} else {
if ($rootScope.backButtonPressedOnceToExit) {
ionic.Platform.exitApp();
} else{
$rootScope.backButtonPressedOnceToExit = true;
$cordovaToast.showLongBottom('再按一次退出系统');
setTimeout(function () {
$rootScope.backButtonPressedOnceToExit = false;
}, 2000);
}
}
e.preventDefault();
return false;
}, 101);

热评文章