2015-01-27 16:46:46 iosHot 阅读数 2063

前言

随着腾讯QQ的普及,现在越来越多的社交类APP在显示好友头像时,都选择用圆形头像,效果如下(不包括黑底):


在ios开发中,大致有以下三种方案来实现圆形头像效果。

方案一:用Quartz2D绘制

具体代码如下:

+ (UIImage *)circleImageWithName:(NSString *)name borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor
{
    // 1.加载原图
    UIImage *oldImage = [UIImage imageNamed:name];
    
    // 2.开启上下文
    CGFloat imageW = oldImage.size.width + 2 * borderWidth;
    CGFloat imageH = oldImage.size.height + 2 * borderWidth;
    CGSize imageSize = CGSizeMake(imageW, imageH);
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
    
    // 3.取得当前的上下文,这里得到的就是上面刚创建的那个图片上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    // 4.画边框(大圆)
    [borderColor set];
    CGFloat bigRadius = imageW * 0.5; // 大圆半径
    CGFloat centerX = bigRadius; // 圆心
    CGFloat centerY = bigRadius;
    CGContextAddArc(ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0);
    CGContextFillPath(ctx); // 画圆。As a side effect when you call this function, Quartz clears the current path.
    
    // 5.小圆
    CGFloat smallRadius = bigRadius - borderWidth;
    CGContextAddArc(ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0);
    // 裁剪(后面画的东西才会受裁剪的影响)
    CGContextClip(ctx);
    
    // 6.画图
    [oldImage drawInRect:CGRectMake(borderWidth, borderWidth, oldImage.size.width, oldImage.size.height)];
    
    // 7.取图
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    // 8.结束上下文
    UIGraphicsEndImageContext();
    
    return newImage;
}

方案二:使用CALayer

CALayer是屏幕上的一个具有可见内容的矩形区域,每个UIView都有一个根CALayer,其所有的绘制(视觉效果)都是在这个layer上进行的。

通过UIView的layer属性可以访问这个层。

代码如下:

	self.imageView2.image = [UIImage imageNamed:@"xxx"];

	//告诉layer将位于它之下的layer都遮盖住
	self.imageView2.layer.masksToBounds = YES;

	//设置layer的圆角,刚好是自身宽度的一半,这样就成了圆形
	self.imageView2.layer.cornerRadius = self.imageView2.bounds.size.width * 0.5;

	//设置边框的宽度为20
	self.imageView2.layer.borderWidth = 5.0;

	//设置边框的颜色
	self.imageView2.layer.borderColor = [UIColor whiteColor].CGColor;


方案三:在storyboard或xib中设置。

Inspector面板中找到User Defined Runtime Attributes,添加如下键值对,如下图

可以看出这些键值对,其实就是方案二中所写的代码。

总结:

方案一虽然代码写的比较多,但是可扩展性高。

方案二代码简洁,便于维护,推荐使用此方案。

方案三优点是在控制器里不用写一行代码,但是在键值对里写死了cornerRadius的值,缺点是不便于后期维护。






2012-03-23 15:55:35 tyygming 阅读数 34

随着市场上iphone4s、newipad的推出,越来越多人加入到了苹果迷大军的队伍中,本文推荐29个用户常用小技巧,需要提出说明的是,有些部分需要达到iOS5.0.1的状态下才能实现。请大家注意一下咯~

一、升级到iOS5.0.1的用户们肯定发现了,屏幕锁定后, 在滑动解锁旁出现相机的图标。连按两次手机的home键,点击该图标,便可实现照相机功能。

推荐29个iphone/ipad 常用小技巧

二、 省电模式,进入手机的主屏幕, 连按两次home键,会显示出你最近使用过的应用程序,这些图标看似已经退出,但实际它们在后台仍然在运行着,这是iphone、ipad长期耗电理由之 一,长按想要关闭图标,图标会颤抖起来,点击图标上方的红箭头,便可以删除它们,这是一个非常显著的达到省电的目的方法。

推荐29个iphone/ipad 常用小技巧

三、在拍照的状态下,按音量也可以拍哦。

推荐29个iphone/ipad 常用小技巧

四、使用照相机拍照时,从左至右滑动屏幕,便可以预览图片。

推荐29个iphone/ipad 常用小技巧

 

read more

2018-12-10 23:00:09 weixin_43010562 阅读数 3510

界面初始化

初始化就是把一切程序设为默认状态,把没准备的准备好。
mui框架将很多功能配置都集中在mui.init方法中,要使用某项功能,只需要在mui.init方法中完成对应参数配置即可,目前支持在mui.init方法中配置的功能包括:创建子页面、关闭页面、手势事件配置、预加载、下拉刷新、上拉加载。

H5plus初始化

在我们APP的开发中,如果我们用到了H5+的一些API或者接口,我们需要初始化另外一个函数,类属于 JS 中的window.onload 或者 window.ready

Mui.plusReady(); 所有涉及到H5+的东西,建议写到这个里面

mui.plusReady(function(){		
			
    var  w = plus.webview.currentWebview();
    console.log(w);		
			
});

创建子页面

为防止APP运行过程中内容滚动出现卡顿的现象,所以部分页面我们采用头部和内容分离的形式进行实现,比如头部导航和底部导航

 mui.init({
  subpages:[{
  url:your-subpage-url,//子页面HTML地址,支持本地地址和网络地址
  id:your-subpage-id,//子页面标志
  styles:{
    top:subpage-top-position,//子页面顶部位置
    bottom:subpage-bottom-position,//子页面底部位置
    width:subpage-width,//子页面宽度,默认为100%
    height:subpage-height,//子页面高度,默认为100%
    ......
  },
     extras:{
	name:'zxd学院'//子页面通过plus.webview.currentWebview().name能拿到这个值
		}//额外扩展参数
    }]
  });

打开界面

//打开新窗口
mui.openWindow({ 
	url:'target.html', //需要打开页面的url地址 
	id:'target',  //需要打开页面的url页面id
	styles:{ 
		top:'0px',//新页面顶部位置 
		bottom:'0px',//新页面底部位置 
//					width:newpage-width,//新页面宽度,默认为100% 
//					height:newpage-height,//新页面高度,默认为100% ...... 
	}, 
	extras:{ 
		name:'aries',
		age:'18',
//					.....//自定义扩展参数,可以用来处理页面间传值 
	},show:{ //控制打开页面的类型
		autoShow:true,
//					//页面loaded事件发生后自动显示,默认为true 
		aniShow:'zoom-fade-out',//页面显示动画,默认为”slide-in-right“;  页面出现的方式 左右上下
		duration:'1000'//页面动画持续时间,Android平台默认100毫秒,iOS平台默认200毫秒; 
	}, waiting:{ // 控制 弹出转圈框的信息
		autoShow:true,//自动显示等待框,默认为true 
		title:'东翌学院...',//等待对话框上显示的提示内容 
		options:{ 
			width:'300px',//等待框背景区域宽度,默认根据内容自动计算合适宽度 
			height:'300px',//等待框背景区域高度,默认根据内容自动计算合适高度 ...... 
		} 
	}
});

参数传递

mui.plusReady(function(){
	var self = plus.webview.currentWebview(); //获得当前页面的对象
	var name = self.name; //name 和 age 为传递的参数的键
	var age = self.age;
	
	console.log(name);
	console.log(age);
	
	// 获得首页  专用的
	var index = plus.webview.getLaunchWebview();
	
	// 获得指定页面的对象 注意,要确保你的这个页面是存在的, 就是打开过的
	var target = plus.webview.getWebviewById('目标页面的id');
	
});

控制页面load显示

show:{  // openwindow 函数内设置
    autoShow:false 
} 
 
// 目标页面
//从服务器获取数据 ....   
这里是业务逻辑
//业务数据获取完毕,并已插入当前页面DOM; 
//注意:若为ajax请求,则需将如下代码放在处理完ajax响应数据之后;
mui.plusReady(function(){ 
    //关闭等待框               
    plus.nativeUI.closeWaiting();
     
    //显示当前页面          
    mui.currentWebview.show(); 
});

关闭界面

1,点击包含.mui-action-back类的控件

2,在页面上,向右快速滑动

3, Android手机按下back按键

mui框架封装的页面右滑关闭功能,默认未启用,若要使用右滑关闭功能,需要在mui.init();方法中设置swipeBack参数,如下:

mui.init({
 	swipeBack:true //启用右滑关闭功能
});

mui框架默认会监听Android手机的back按键,然后执行页面关闭逻辑; 若不希望mui自动处理back按键,可通过如下方式关闭mui的back按键监听:

mui.init({
	keyEventBind: {
	 	backbutton: false //关闭back按键监听 
	}
});

底部导航切换界面

HTML部分:

<nav class="mui-bar mui-bar-tab">
	    <a id="defaultTab" class="mui-tab-item mui-active" href="a.html">
	        <span class="mui-icon mui-icon-videocam"></span>
	        <span class="mui-tab-label">社区</span>
	    </a>
	    <a class="mui-tab-item" href="b.html">
	        <span class="mui-icon mui-icon-chatboxes"><span style="display: none;" class="mui-badge">1</span></span>
	        <span class="mui-tab-label">群组</span>
	    </a>
	    <a class="mui-tab-item" href="c.html">
	        <span class="mui-icon mui-icon-home"></span>
	        <span class="mui-tab-label">我的</span>
	    </a>
</nav>

JavaScript部分:

//mui初始化
mui.init();
var subpages = ['a.html', 'b.html', 'c.html'];
var subpage_style = {
	top:'0px',
	bottom: '51px'
};	
var aniShow = {};	
 //创建子页面,首个选项卡页面显示,其它均隐藏;
mui.plusReady(function() {
	var self = plus.webview.currentWebview();
	for (var i = 0; i < subpages.length; i++) {
		var temp = {};
		var sub = plus.webview.create(subpages[i], subpages[i], subpage_style);
		if (i > 0) {
			sub.hide();
		}else{
			temp[subpages[i]] = "true";
			mui.extend(aniShow,temp);
		}
		self.append(sub);
	}
});
 //当前激活选项
var activeTab = subpages[0];

 //选项卡点击事件
mui('.mui-bar-tab').on('tap', 'a', function(e) {
	var targetTab = this.getAttribute('href');
	if (targetTab == activeTab) {
		return;
	}
	//显示目标选项卡
	//若为iOS平台或非首次显示,则直接显示
	if(mui.os.ios||aniShow[targetTab]){
		plus.webview.show(targetTab);
	}else{
		//否则,使用fade-in动画,且保存变量
		var temp = {};
		temp[targetTab] = "true";
		mui.extend(aniShow,temp);
		plus.webview.show(targetTab,"fade-in",300);
	}
	//隐藏当前;
	plus.webview.hide(activeTab);
	//更改当前活跃的选项卡
	activeTab = targetTab;
});
 //自定义事件,模拟点击“首页选项卡”
document.addEventListener('gohome', function() {
	var defaultTab = document.getElementById("defaultTab");
	//模拟首页点击
	mui.trigger(defaultTab, 'tap');
	//切换选项卡高亮
	var current = document.querySelector(".mui-bar-tab>.mui-tab-item.mui-active");
	if (defaultTab !== current) {
		current.classList.remove('mui-active');
		defaultTab.classList.add('mui-active');
	}
});

自定义事件

监听自定义事件 - 目标页

window.addEventListener('shijian',function(event){
  //通过event.detail可获得传递过来的参数内容
  ....
  var name = event.detail.namel
  console.log(name);
  shijian();    
})

触发自定义事件 - 本页

//首先获得目标页面的对象
var targetPage = plus.webview.getWebviewById('目标页面id'); 

mui.fire(targetPage,'shijian',{
  //自定义事件参数
  name:'dongyixueyuan'
});

页面预加载

所谓的预加载技术就是在用户尚未触发页面跳转时,提前创建目标页面,这样当用户跳转时,就可以立即进行页面切换,节省创建新页面的时间,提升app使用体验。mui提供两种方式实现页面预加载。

方式一:通过mui.init方法中的preloadPages参数进行配置

mui.init({  // 可同时加载一个或者多个界面
	preloadPages:[ //加载一个界面
	{ 
		url:'a.html', 
		id:'a', 
		styles:{},//窗口参数 
		extras:{},//自定义扩展参数
		subpages:[{},{}]//预加载页面的子页面 
	},{ // 可加载另外一个界面,不需要可直接删除
		url:'b.html', 
		id:'b', 
		styles:{},//窗口参数 
		extras:{},//自定义扩展参数
		subpages:[{},{}]//预加载页面的子页面 
	}
	]
});

方式二:通过mui.preload方法预加载,一次只能预加载一个页面,若需加载多个webview,则需多次调用mui.preload()方法;

mui.plusReady(function(){
    var productView = mui.preload({
        url: 'list.html',
        id: 'list',
    });
    console.log(productView); //获得预加载界面的对象
});

消息框

警告消息框

mui.alert('欢迎使用Hello 东翌学院','东翌学院',function(){
	alert('你刚关闭了警告框');
});

消息提示框

var btnArray = ['是','否'];
	mui.confirm('东翌学院是专业跨平台APP培训学院,赞?','Hello 东翌学院',btnArray,function(e){
	if(e.index==0){
		alert('点击了- 是');
		//自己的逻辑	 	 			 	 	
	}else{
		alert('点击了- 否');
	}
});

输入对话框

var btnArray = ['确定','取消'];
	mui.prompt('请输入你对东翌学院的评语:','内容好','东翌学院',btnArray,function(e){
		if(e.index==0){
			alert('点击了 - 确认');
			var  value = e.value; // value 为输入的内容

		}else{
			alert('点击了 - 取消');
		}
});

自动消息对话框

mui.toast('显示内容');

日期选择框

//js里的月份 是从0月开始的,也就是说,js中的0月是我们1月
			
var dDate=new Date(); //默认显示的时间
dDate.setFullYear(2015,5,30);
var minDate=new Date(); //可选择的最小时间
minDate.setFullYear(2010,0,1);
var maxDate=new Date(); //课选择的最大的时间
maxDate.setFullYear(2016,11,31); 
				
				
plus.nativeUI.pickDate( function(e) {
	
		var d=e.date;
		alert('您选择的日期是:'+d.getFullYear()+"-"+(d.getMonth()+1)+"-"+ d.getDate());
	
	},function(e){
		
		alert('您没有选择日期');
		
},{title:"请选择日期",date:dDate,minDate:minDate,maxDate:maxDate});

时间选择框

var dTime=new Date();
dTime.setHours(20,0); //设置默认时间
plus.nativeUI.pickTime(function(e){
		
		var d=e.date;
		alert("您选择的时间是:"+d.getHours()+":"+d.getMinutes());
		
	},function (e){
		
		alert('您没有选择时间');
		
},{title:"请选择时间",is24Hour:true,time:dTime});

原生模式ActionSheet

var btnArray = [{title:"分享到微信"},{title:"分享到新浪微博"},{title:"分享到搜狐微博"}]; //选择按钮  1 2 3
plus.nativeUI.actionSheet( {
	title:"分享到",
	cancel:"取消", // 0
	buttons:btnArray
	}, 
	function(e){
		var index = e.index; // 
		alert(index);
		switch (index){
			case 1:
				//写自己的逻辑
			
			break;
			case 2:
			break;
		}
} );

下拉刷新

为实现下拉刷新功能,大多H5框架都是通过DIV模拟下拉回弹动画,在低端android手机上,DIV动画经常出现卡顿现象(特别是图文列表的情况); 通过双webview解决这个DIV的拖动流畅度问题;拖动时,拖动的不是div,而是一个完整的webview(子webview),回弹动画使用原生动画;在iOS平台,H5的动画已经比较流畅,故依然使用H5方案。两个平台实现虽有差异,但经过封装,可使用一套代码实现下拉刷新。

第一步: 创建子页面,因为拖动的其实是个子页面的整体

mui.init({ 
	subpages:[{ 
	url:pullrefresh-subpage-url,//下拉刷新内容页面地址 
	id:pullrefresh-subpage-id,//内容页面标志
	 styles:{ top:subpage-top-position,//内容页面顶部位置,需根据实际页面布局计算,若使用标准mui导航,顶部默认为48px; .....//其它参数定义 
	 } 
	}] 
});

第二步:内容页面需按照如下DOM结构构建

<!--下拉刷新容器-->
 <div id="pullrefresh" class="mui-content mui-scroll-wrapper">
     <div class="mui-scroll">
         <!--数据列表-->
         <ul class="mui-table-view mui-table-view-chevron">
             <li class="mui-table-view-cell">1</li>
         </ul>
     </div>
 </div> 
第三步:通过mui.init方法中pullRefresh参数配置下拉刷新各项参数

mui.init({ 
   	pullRefresh : { 
   		container:"#pullrefresh",//下拉刷新容器标识,querySelector能定位的css选择器均可,比如:id、.class等 	
   		down : {
   			contentdown : "下拉可以刷新",//可选,在下拉可刷新状态时,下拉刷新控件上显示的标题内容 
   			contentover : "释放立即刷新",//可选,在释放可刷新状态时,下拉刷新控件上显示的标题内容 
   			contentrefresh : "正在刷新...",//可选,正在刷新状态时,下拉刷新控件上显示的标题内容 
   			callback : fn //必选,刷新函数,根据具体业务来编写,比如通过ajax从服务器获取新数据;
   		 } } 
    });

第四步:设置执行函数

function fn() {
	 //业务逻辑代码,比如通过ajax从服务器获取新数据; ...... //注意,加载完新数据后,必须执行如下代码,注意:若为ajax请求,则需将如下代码放置在处理完ajax响应数据之后 	
	 
	 mui('#pullrefresh').pullRefresh().endPulldownToRefresh();  //这行代码会隐藏掉 正在加载... 容器
	 
}

上拉加载

第一步,第二步 和下拉刷新的一样

第三步:通过mui.init方法中pullRefresh参数配置下拉刷新各项参数

mui.init({ 
    pullRefresh : { 
        container:"#pullrefresh",//待刷新区域标识,querySelector能定位的css选择器均可,比如:id、.class等 
        up : { 
            contentrefresh : "正在加载...",//可选,正在加载状态时,上拉加载控件上显示的标题内容 
            contentnomore:'没有更多数据了',//可选,请求完毕若没有更多数据时显示的提醒内容; 
            callback : fn //必选,刷新函数,根据具体业务来编写,比如通过ajax从服务器获取新数据; 
        } 
    } 
});

第四步:设置执行函数

function fn() { 
    //业务逻辑代码,比如通过ajax从服务器获取新数据; ...... //注意,加载完新数据后,必须执行如下代码,true表示没有更多数据了,
    两个注意事项: //1、若为ajax请求,则需将如下代码放置在处理完ajax响应数据之后 //
    2、注意this的作用域,若存在匿名函数,需将this复制后使用
     
    var _this = this;
      
    _this.endPullupToRefresh(true|false); 
}

上拉下拉整合

第一步,第二步和下拉刷新一样

第三步:在mui.init()内同时设置上拉加载和下拉刷新

mui.init({
	pullRefresh: {
		container: '#pullrefresh',
		down: {
			contentdown : "下拉可以刷新",//可选,在下拉可刷新状态时,下拉刷新控件上显示的标题内容
		    contentover : "释放立即刷新",//可选,在释放可刷新状态时,下拉刷新控件上显示的标题内容
		    contentrefresh : "正在刷新...",//可选,正在刷新状态时,下拉刷新控件上显示的标题内容
			callback: downFn // 下拉执行函数
		},
		up: {
			contentrefresh: '正在加载...',
			callback: upFn // 上拉执行函数
		}
	}
});

注意: 给获取元素加onclick点击事件不行,需要加addEventListener自定义事件

手势

在开发移动端的应用时,会用到很多的手势操作,比如滑动、长按等,为了方便开放者快速集成这些手势,mui内置了常用的手势事件,目前支持的手势事件见如下列表:

分类 参数描述

点击 tap 单击屏幕

doubletap 双击屏幕

长按 longtap 长按屏幕

 hold            按住屏幕       

  release           离开屏幕

滑动 swipeleft 向左滑动

swiperight 向右滑动

swipeup 向上滑动

swipedown 向下滑动

拖动 dragstart 开始拖动

drag 拖动中

dragend 拖动结束

mui.init({ 
	gestureConfig:{
		tap: true, //默认为true 
		doubletap: true, //默认为false 
		longtap: true, //默认为false 
		swipe: true, //默认为true 
		drag: true, //默认为true 
		hold:false,//默认为false,不监听 
		release:false//默认为false,不监听 
	} 
});

注意:dragstart、drag、dragend共用drag开关,swipeleft、swiperight、swipeup、swipedown共用swipe开关

你要监听的对象.addEventListener("swipeleft",function(){ 
	console.log("你正在向左滑动"); 
});

遮罩

在popover、侧滑菜单等界面,经常会用到蒙版遮罩;比如popover弹出后,除popover控件外的其它区域都会遮罩一层蒙版,用户点击蒙版不会触发蒙版下方的逻辑,而会关闭popover同时关闭蒙版;再比如侧滑菜单界面,菜单划出后,除侧滑菜单之外的其它区域都会遮罩一层蒙版,用户点击蒙版会关闭侧滑菜单同时关闭蒙版。

遮罩蒙版常用的操作包括:创建、显示、关闭,如下代码:

var mask = mui.createMask(callback);//callback为用户点击蒙版时自动执行的回调; 
mask.show();//显示遮罩
mask.close();//关闭遮罩

遮罩css样式:   .mui-backdrop

滑动导航选择

mui提供了图片轮播、可拖动式图文表格、可拖动式选项卡、左右滑动9宫格组件,这些组件都用到了mui框架的slide插件,有较多共同点。首先,Dom内容构造基本相同,都必须有一个.mui-slider的父容器;其次,当拖动切换显示内容时,均会触发slide事件(可拖动式选项卡在点击选项卡标题时,也会触发slide事件),通过该事件的detail.slideNumber参数可以获得当前显示项的索引(第一项索引为0,第二项为1,以此类推),利用该事件,可在显示内容切换时,动态处理一些业务逻辑。

HTML部分:

<div class="mui-slider">
	<!--选项卡标题区-->
	<div class="mui-slider-indicator mui-segmented-control mui-segmented-control-inverted">
	  <a class="mui-control-item" href="#item1">待办公文</a>
	  <a class="mui-control-item" href="#item2">已办公文</a>
	  <a class="mui-control-item" href="#item3">全部公文</a>
	</div>
	<div class="mui-slider-progress-bar mui-col-xs-4"></div>
	<div class="mui-slider-group">
	  <!--第一个选项卡内容区-->
	  <div id="item1" class="mui-slider-item mui-control-content mui-active">
	    <ul class="mui-table-view">
	      <li class="mui-table-view-cell">待办公文1</li>
	      <li class="mui-table-view-cell">待办公文2</li>
	      <li class="mui-table-view-cell">待办公文3</li>
	    </ul>
	  </div>
	  <!--第二个选项卡内容区,页面加载时为空-->
	  <div id="item2" class="mui-slider-item mui-control-content"><ul class="mui-table-view">
	      <li class="mui-table-view-cell">待办公文1</li>
	      <li class="mui-table-view-cell">待办公文2</li>
	      <li class="mui-table-view-cell">待办公文3</li>
	    </ul></div>
	  <!--第三个选项卡内容区,页面加载时为空-->
	  <div id="item3" class="mui-slider-item mui-control-content"></div>
	</div>
</div>

JavaScript部分:

var item2Show = false,item3Show = false;//子选项卡是否显示标志
document.querySelector('.mui-slider').addEventListener('slide', function(event) {
  if (event.detail.slideNumber === 1&&!item2Show) {
    //切换到第二个选项卡
    //根据具体业务,动态获得第二个选项卡内容;
    var content = 'er';
    //显示内容
    document.getElementById("item2").innerHTML = content;
    //改变标志位,下次直接显示
    item2Show = true;
  } else if (event.detail.slideNumber === 2&&!item3Show) {
    //切换到第三个选项卡
    //根据具体业务,动态获得第三个选项卡内容;
    var content = 'san';
    //显示内容
    document.getElementById("item3").innerHTML = content;
    //改变标志位,下次直接显示
    item3Show = true;
  }
});

图片轮播

1, 支持循环

HTML部分:

<div class="mui-slider">
  <div class="mui-slider-group mui-slider-loop">
    <!--支持循环,需要重复图片节点-->
    <div class="mui-slider-item mui-slider-item-duplicate"><a href="#"><img src="images/2.jpg" /></a></div>
    <div class="mui-slider-item"><a href="#"><img src="images/0.jpg" /></a></div>
    <div class="mui-slider-item"><a href="#"><img src="images/1.jpg" /></a></div>
    <div class="mui-slider-item"><a href="#"><img src="images/2.jpg" /></a></div>
    <!--支持循环,需要重复图片节点-->
    <div class="mui-slider-item mui-slider-item-duplicate"><a href="#"><img src="images/0.jpg" /></a></div>
  </div>
</div>

2, 不支持循环 和循环不同的是没有再第一条和最后一条后面加入内容

HTML部分:

<div class="mui-slider">
  <div class="mui-slider-group">
    <div class="mui-slider-item"><a href="#"><img src="images/0.jpg" /></a></div>
    <div class="mui-slider-item"><a href="#"><img src="images/1.jpg" /></a></div>
    <div class="mui-slider-item"><a href="#"><img src="images/2.jpg" /></a></div>
    <!--<div class="mui-slider-item"><a href="#"><img src="4.jpg" /></a></div>-->
  </div>
</div>

JavaScript部分相同:

//获得slider插件对象
var gallery = mui('.mui-slider');
gallery.slider({
  interval:5000//自动轮播周期,若为0则不自动播放,默认为0;
});

document.querySelector('.mui-slider').addEventListener('slide', function(event) {
  //注意slideNumber是从0开始的;
  alert("你正在看第"+(event.detail.slideNumber+1)+"张图片");
});

注意:如果ajax获得图片后,需要在写入图片以后,需要从新调用一下

gallery.slider();

自定义导航

第一步: 将一下代码写在header(mHeader) 和 content(mBody) 之间

首页	        
科技	        
娱乐	        
财经        
北京        
军事	        
社会	        
汽车	        
视频        
美女

第二步: 引入dongyi_nav.css 和dongyi_nav.js

第三步: 执行函数

dongyi_nav(function(index,data){ // index 为点击索引 data为点击导航的文本内容

	console.log(index);
	console.log(data);	

});

Ajax-get请求

// get测试请求地址 http://test.dongyixueyuan.com/link_app/get?state=index&num=0

mui.get('接口地址',{ //请求接口地址
	state:'index'   // 参数  键 :值
	num:'0'
	},function(data){ // data为服务器端返回数据
	//获得服务器响应 ... 

		console.log(data);
	
	},'json' 
);

Ajax-post请求

// post测试请求地址 http://test.dongyixueyuan.com/link_app/post
mui.post('接口地址',{  //请求接口地址
	   state:'index', // 参数  键 :值
	   num:'0' 
	},
	function(data){ //data为服务器端返回数据
		
		//自己的逻辑
	
	},'json'
);

照相机

var cmr = plus.camera.getCamera();
cmr.captureImage( function ( p ) {
		//成功
		plus.io.resolveLocalFileSystemURL( p, function ( entry ) {
	
		    var img_name = entry.name;//获得图片名称
		    var img_path = entry.toLocalURL();//获得图片路径
		
		}, function ( e ) {
			console.log( "读取拍照文件错误:"+e.message );
		} );
		
	}, function ( e ) {
		console.log( "失败:"+e.message );
}, {filename:'_doc/camera/',index:1} ); //  “_doc/camera/“  为保存文件名

访问相册

plus.gallery.pick( function(path){
    
    img.src = path;//获得图片路径
    
}, function ( e ) {
    console.log( "取消选择图片" );
}, {filter:"image"} );

蜂鸣提示音

switch ( plus.os.name ) { //判断设备类型
    case "iOS":
	    if ( plus.device.model.indexOf("iPhone") >= 0 ) { //判断是否为iPhone
	        plus.device.beep();
	        console.log = "设备蜂鸣中...";
	    } else {
	        console.log = "此设备不支持蜂鸣";
	    }
    break;
    default:
	    plus.device.beep();
	    console.log = "设备蜂鸣中...";
    break;
}

手机震动

switch ( plus.os.name ) { //判断设备类型
    case "iOS":
            if ( plus.device.model.indexOf("iPhone") >= 0 ) { //判断是否为iPhone
                plus.device.vibrate();
                console.log("设备振动中...");
            } else {
                console.log("此设备不支持振动");
            }
    break;
    default:
    	plus.device.vibrate();
            console.log("设备振动中...");
    break;
}

弹出菜单

弹出菜单的原理主要是通过锚点进行的,如果需要多个弹出菜单,可以在a标签内设置锚点,对应相应的div的id即可

<a href="#popover">打开弹出菜单</a> // href 定义锚点
<div id="popover" class="mui-popover"> //id 对应锚点
  <ul class="mui-table-view">
    <li class="mui-table-view-cell"><a href="#">Item1</a></li>
    <li class="mui-table-view-cell"><a href="#">Item2</a></li>
    <li class="mui-table-view-cell"><a href="#">Item3</a></li>
    <li class="mui-table-view-cell"><a href="#">Item4</a></li>
    <li class="mui-table-view-cell"><a href="#">Item5</a></li>
  </ul>
</div>

设备信息

plus.device.model  //设备型号
plus.device.vendor  //设备的生产厂商
plus.device.imei  // IMEI 设备的国际移动设备身份码
plus.device.uuid  // UUID 设备的唯一标识
// IMSI 设备的国际移动用户识别码
var str = '';
for ( i=0; i<plus.device.imsi.length; i++ ) {
     str += plus.device.imsi[i];
}
plus.screen.resolutionWidth*plus.screen.scale + " x " + plus.screen.resolutionHeight*plus.screen.scale ; 
//屏幕分辨率
plus.screen.dpiX + " x " + plus.screen.dpiY; //DPI每英寸像素数

手机信息

plus.os.name //名称
plus.os.version //版本
plus.os.language //语言
plus.os.vendor //厂商
//网络类型
var types = {};
types[plus.networkinfo.CONNECTION_UNKNOW] = "未知";
types[plus.networkinfo.CONNECTION_NONE] = "未连接网络";
types[plus.networkinfo.CONNECTION_ETHERNET] = "有线网络";
types[plus.networkinfo.CONNECTION_WIFI] = "WiFi网络";
types[plus.networkinfo.CONNECTION_CELL2G] = "2G蜂窝网络";
types[plus.networkinfo.CONNECTION_CELL3G] = "3G蜂窝网络";
types[plus.networkinfo.CONNECTION_CELL4G] = "4G蜂窝网络";
var network = types[plus.networkinfo.getCurrentType()];

发送短信

<a href=“sms:10086">发送短信

var msg = plus.messaging.createMessage(plus.messaging.TYPE_SMS);
msg.to = ['13800138000', '13800138001'];
msg.body = '东翌学院http://www.dongyixueyuan.com';
plus.messaging.sendMessage( msg );

拨打电话

<a href="tel:10086">拨打电话</a>

发送邮件

<a href="mailto:dongyixueyuan@qq.com">发送邮件到东翌学院</a>

本地存储

//设置
plus.storage.setItem('键','值'); -> plus.storage.setItem('name','dongyixueyuan');    
//查询
plus.storage.getItem('键'); -> var name = plus.storage.getItem('name');    
//删除
plus.storage.removeItem('键'); -> plus.storage.removeItem('name');    
//全部清除
plus.storage.clear();    

//HTML5自带 - 设置
localStorage.setItem('键','值'); -> localStorage.setItem('name','dongyixueyuan');    
//HTML5自带 - 查询
localStorage.getItem('键'); -> var name = localStorage.setItem('name');

//HTML5自带 - 删除
localStorage.removeItem('键'); -> localStorage.removeItem('name');

图片上传

//初始上传地址  
var server="http://tongle.dongyixueyuan.com/upload_file.php";  // 学员测试使用
var files=[]; //图片存放的数组 可以上传一个,或者多个图片     		
//上传图片
function upload_img(p){
	//又初始化了一下文件数组 为了支持我的单个上传,如果你要一次上传多个,就不要在写这一行了
	//注意 
	files=[];
	var n=p.substr(p.lastIndexOf('/')+1);
	files.push({name:"uploadkey",path:p});    	
	//开始上传
	start_upload();    		
}    		
//开始上传
function start_upload(){
	if(files.length<=0){
		plus.nativeUI.alert("没有添加上传文件!");
		return;
	}
	//原生的转圈等待框
	var wt=plus.nativeUI.showWaiting();
			
	var task=plus.uploader.createUpload(server,
		{method:"POST"},
		function(t,status){ //上传完成
			alert(status);
			if(status==200){    						
				//资源
				var responseText = t.responseText;    						
				//转换成json
				var json = eval('(' + responseText + ')');    					
				//上传文件的信息
				var files = json.files;    				
				//上传成功以后的保存路径
				var img_url = files.uploadkey.url;   						
				//ajax 写入数据库   						
						
				//关闭转圈等待框
				wt.close();
			}else{
				console.log("上传失败:"+status);
				//关闭原生的转圈等待框
				wt.close();
			}
		});    			
	task.addData("client","");
	task.addData("uid",getUid());
	for(var i=0;i<files.length;i++){
		var f=files[i];
		task.addFile(f.path,{key:f.name});
	}
	task.start();    		
}    		
// 产生一个随机数
function getUid(){
	return Math.floor(Math.random()*100000000+10000000).toString();
}

地理位置

//直接获取地理位置

plus.geolocation.getCurrentPosition( geoInfo, function ( e ) {
		alert( "获取位置信息失败:"+e.message );
} );

//监听地理位置

 var watchId; //开关 函数外层定义		
    if ( watchId ) {
    	return;
    }
    watchId = plus.geolocation.watchPosition( function ( p ) {
    	alert( "监听位置变化信息:" );    
    	geoInfo( p );    			
    }, function ( e ) {
    	alert( "监听位置变化信息失败:"+e.message );
    });

//停止监听地理位置

 if ( watchId ) {
    	alert( "停止监听位置变化信息" );    				
    	plus.geolocation.clearWatch( watchId );
    	watchId = null;
    }
//获得具体地理位置
//获取设备位置信息
    function geoInfo(position){    
    	var timeflag = position.timestamp;//获取到地理位置信息的时间戳;一个毫秒数;    
	var codns = position.coords;//获取地理坐标信息;    	
	var lat = codns.latitude;//获取到当前位置的纬度;    
	var longt = codns.longitude;//获取到当前位置的经度    
	var alt = codns.altitude;//获取到当前位置的海拔信息;    
	var accu = codns.accuracy;//地理坐标信息精确度信息;    
	var altAcc = codns.altitudeAccuracy;//获取海拔信息的精确度;    
	var head = codns.heading;//获取设备的移动方向;    
	var sped = codns.speed;//获取设备的移动速度;   			
	//百度地图申请地址
//	http://lbsyun.baidu.com/apiconsole/key
//	http://api.map.baidu.com/geocoder/v2/?output=json&ak=你从百度申请到的Key&location=纬度(Latitude),经度(Longitude)
//	http://api.map.baidu.com/geocoder/v2/?output=json&ak=BFd9490df8a776482552006c538d6b27&location=40.065639,116.419413    
        //详细地址
       //http://api.map.baidu.com/geocoder/v2/?ak=eIxDStjzbtH0WtU50gqdXYCz&output=json&pois=1&location=40.065639,116.419413    			
			
	var baidu_map = "http://api.map.baidu.com/geocoder/v2/?output=json&ak=BFd9490df8a776482552006c538d6b27&location="+lat+','+longt;
	mui.get(baidu_map,{  //请求的地址
	},
	function(data){ //服务器返回响应,根据响应结果,分析是否登录成功; ... 

		var result = data['result'].addressComponent;	
					
		// 国家
		var country = result['country'];    		
		//城市
		var city = result['city'];;    		
		//地址
		var address = result['province'] + result['district'] + result['street'];    		
		//data 有很多信息,大家如果需要可以for in出来看下    	
		},'json'
	);    			
}

设置IOS状态栏

mui.plusReady(function(){
	if(mui.os.ios){
		//UIStatusBarStyleDefault //字体深色 
		//UIStatusBarStyleBlackOpaque //字体浅色
		plus.navigator.setStatusBarStyle('UIStatusBarStyleBlackOpaque');
		plus.navigator.setStatusBarBackground("#007aff"); //背景颜色
	}
			
})

手机通讯录

mui.plusReady(function(){	
	//访问手机通讯录  plus.contacts.ADDRESSBOOK_PHONE
	//访问SIM卡通讯录  plus.contacts.ADDRESSBOOK_SIM	
	plus.contacts.getAddressBook(plus.contacts.ADDRESSBOOK_PHONE,function(addressbook){
		addressbook.find(null,function (contacts){		
			for(var a in contacts){			
			        //这里是安卓手机端的获取方式 ios的不太一样,如果需要这块代码可以联系老师获得
				var user = contacts[a].displayName; //联系人
				var phone = contacts[a].phoneNumbers[0].value; //手机号码							
			}				
		},function ( e ) {alert( "Find contact error: " +e.message );},{multi:true});
	});			
});

启动页设置

设置手动关闭启动页:

manifest.json -> plus -> autoclose 改为 false
关闭启动页:

plus.navigator.closeSplashscreen();

PHP后台搭建

在开发工具内下载 AppServ 和 ThinkPHP,
AppServ是本地服务器,ThinkPHP是后台框架

ThinkPHP采用单入口模式 index -> 控制器 -> 方法

index.php 内书写如下:

define("APP_NAME",'WEB'); //站点名称
define("APP_PATH",'./WEB/'); //站点路径
define("APP_DEBUG",true);//开启调试模式

require("./ThinkPHP/ThinkPHP.php");// 引入框架文件

JSON转换

JSON.parse()和JSON.stringify()
1.parse 用于从一个字符串中解析出json 对象。例如
 
var str='{"name":"zxd学院","age":"23"}'
 
经 JSON.parse(str) 得到:
 
Object: age:"23" 
        name:"zxd学院"
 
ps:单引号写在{}外,每个属性都必须双引号,否则会抛出异常 
2.stringify用于从一个对象解析出字符串,例如 
var a={a:1,b:2} 
经 JSON.stringify(a)得到: 
'{"a":1,"b":2}'

隐藏本页面中滚动条

var self = plus.webview.currentWebview();

self.setStyle({
    bounce: 'none', //禁止弹动
    scrollIndicator: 'none' //隐藏滚动条
});	

首次启动欢迎页

首先引入dongyi_welcome.css 和 dongyi_welcome.js 文件

<div id="slider" class="mui-slider" >
	<div class="mui-slider-group">
		<!-- 第一张 -->
		<div class="mui-slider-item">
			<img src="img/shuijiao.jpg">
		</div>
		<!-- 第二张 -->
		<div class="mui-slider-item">
				<img src="img/muwu.jpg">
		</div>
		<!-- 第三张 -->
		<div class="mui-slider-item">
				<img src="img/cbd.jpg">
		</div>
		<!-- 第四张 -->
		<div class="mui-slider-item">
			<img src="img/yuantiao.jpg">
			<button id="dy_enter">立即进入</button>
		</div>
	</div>
	<div class="mui-slider-indicator">
		<div class="mui-indicator mui-active"></div>
		<div class="mui-indicator"></div>
		<div class="mui-indicator"></div>
		<div class="mui-indicator"></div>
	</div>
</div>	

,

dongyi_welcome({
	preLoadUrl:'main.html',//预加载页面url
	preLoadId:'main',//预加载页面id
});

数据库增删改查和接口

Class UserAction extends Action {
		/**
		 * 添加数据
		 */
		public function add(){
			$data['phone'] = '1380013800';
			$data['name'] = 'yidong';
			// M = model M('你要操作的数据表')->方法
			$re = M('user')->add($data);
			//输出
			echo $re;
			// 添加数据返回值 是数据的id
		}
		/**
		 * 修改数据
		 */
		public function mod(){
			$data['phone'] = '130013000';
			$id = 1;
			$re = M('user')->where("`id`='$id'")->save($data);
			echo $re;
			//修改数据 返回值为1是成功 0为失败
		}
		/**
		 * 删除数据
		 */
		public function del(){
			$id = '2';
			$re = M('user')->where("`id`='$id'")->delete();
			echo $re;
			// 删除 返回值为1也是成功 0 为失败
		}
		/**
		 * 查询数据
		 */
		public function select(){
			//单条带条件查询
			$id = '1';
			$arr1 = M('user')->where("`id`='$id'")->find();
			// dump($arr1);
			// 多条不带条件查询  查询数据库内所有的数据 不建议使用
			$arr2 = M('user')->select();
			// dump($arr2);
			// 多条带条件查询 
			$phone = '1380013800';
			$arr3 = M('user')->where("`phone`='$phone'")->select();
			// dump($arr3);
			// 排序
			// asc 正序
			// desc 倒序
			$arr4 = M('user')->where("`phone`='$phone'")->order("id desc")->select();
			// dump($arr4);
			// 分页 limit
			// limit(参数1); 一个参数的情况下 拿多少条数据
			// limit(参数1,参数2); 二个参数的情况下 第一个参数是从多少条开始拿,第二个参数还是拿多少条
			// $arr5 = M('user')->order("id desc")->limit(2)->select();
			// dump($arr5);
			$arr6 = M('user')->order("id desc")->limit(2,2)->select();
			// dump($arr6);
			//返回json数据 给我们APP
			echo json_encode($arr6);
			// 接口地址
			// http://127.0.0.1/www/xianshang14/index.php/User/select
		}
}

推送

  • 注册个推,获得APPKEY,APPID,MASTERSECRET*

  • 推送信息必须打包安装手机后才能使用,主要是通过client_id来进行对每个用户进行推送,首先我们需要在数据库的用户表内添加一个client_id 的字段(在用户注册的时候或者在每次登录的时候存入用户的新client_id,保证推送的有效性),为存放我们用户的client_id,比如这里是个商城,你购买完商品,系统会推送一条信息给你,你只需要告诉程序,你要推送人的手机号码,标题,内容即可(如需要点击信息到达订单页面,需要用透传来实现),服务器获得手机号码以后会在数据库内查找,并获得该用户的client_id,然后实现推送。这里要根据自己的情况来写逻辑,比如东翌课堂的分类,前端,后端,数据库等分类,如果我有一个课程上线,我可以推送给这些对某一类感兴趣的学员。当然更多的逻辑需要你自己来写,群发我们可以理解成,循环发送多个单条的(*单条发送已经测试没问题,群发没测试,大家可以自己测试一下,有问题随时反馈过来)。

  • 由于推送信息的多样性,本次封装仅对本APP注册用户进行推送,如需要全员推送,可直接使用个推官网创建信息的方式直接推送。

推送步骤:

1, 右上角下载 推送包

2,single.php (推送单个普通推送/可透传,点击信息可打开APP,*透传可写逻辑,透传需要) (透传格式:{“path”:“course”,id:“2”}

openPath.php (推送打开页面信息,点击信息可在浏览器打开你传入的URL)

download.php (推送下载信息,点击信息可下载你传入URL的文件)

3,简单粗暴的设置一下这3个文件内的14行APPKEY,15行APPID,16行MASTERSECRET为你在个推得到的APPKEY,APPID,MASTERSECRET

如下我只写了一个实例,单条普通信息推送

PHP端代码:

在PHP Action文件夹内建立了一个 PushAction.class.php 的文件

Class PushAction extends Action {
	//单个信息推送 透传
	public function single(){		
		$title = $_GET['title_data'];
		$content = $_GET['content_data'];
		$phone = $_GET['phone_data'];
		$pass = $_GET['pass_data'];		
		if($title == '' || $content == '' || $phone == ''){
			exit;
		}
		$user = M('user')->where("`phone`='$phone'")->find();
		$cid = $user['client_id'];
		$url = 'http://' .$_SERVER['HTTP_HOST'] .  . '/Push/single?title='.$title.'&content='.$content.'&cid='.$cid.'&pass='.$pass;
		$html = file_get_contents($url);  
		echo $html;  
	}
}

//APP端代码 我在index文件中

// 监听在线消息事件
plus.push.addEventListener( "receive", function( msg ) {
    if ( msg.aps ) {  // Apple APNS message
//		            alert( "接收到在线APNS消息:" );
    } else {
//		            alert( "接收到在线透传消息:" );
    }    
	var login_phone = localStorage.getItem('你存入的登录信息');    

    var content = msg.content;        
    var json = eval('('+content+')');
    var path = json.path;
    var id = json.id;
    //订单
    if(path == 'order'){	
    	if(login_phone){
			dui.jump('./Home/order.html','order');
    	}        	
    }else if(path == 'course'){
    	localStorage.setItem('dongyikecheng_cid',id);
			dui.jump('./Course/course_detail.html','course_detail');
    }else if(path == 'message'){
    	if(login_phone){
			if(id == 'system'){
        		dui.jump('./Message/system_message.html','system_message');
        	}else{
        		dui.jump('./Message/chat_message.html','chat_message');
        	}
		}        	
    }    
}, false );

以上PHP代码可以配合后台,给特定人群推送,逻辑需要大家实现了,因为每个APP的逻辑都不一样

浏览器打开新页面

plus.runtime.openURL( url );

PDF浏览

IOS端内可以直接打开
安卓端方式:
1,调用本地第三方浏览器打开

  mui.plusReady(function(){        
    	plus.runtime.openFile( "./file/node_js.pdf" );
    });

2,引入第三方js类打开

自定义下拉刷新

// 双webview 写到父页面里面

.mui-pull-top-pocket{
	top:100px !important;
	position: absolute;
}
.mui-pull-caption {
      background: red;;
        background-size: contain;
        background-repeat: no-repeat;
        background-position: center;
        width: 144px;
        height: 31px;
        font-size: 0px;
}
/*下拉刷新圆形进度条的大小和样式*/

.mui-spinner {
    width: 32px;
    height: 32px;
}
.mui-spinner:after {
   background: red;
}
/*下拉刷新的箭头颜色*/

.mui-icon-pulldown {
    color: #FF058B;
}

即时聊天

//即时聊天采用野狗无后端模式,野狗: https://www.wilddog.com/

//引入文件

<script src = "https://cdn.wilddog.com/js/client/current/wilddog.js" ></script>

//写入数据

// new Wilddog   message 为自己定义的一个表或者空间,用于放我们的聊天记录
var wd = new Wilddog('https://dongyixueyuan.wilddogio.com/message');


btn.addEventListener('tap',function(){
	var content = text.value;
	//记录发布时间戳
	var date = new Date();
	var time = date.getTime();
	
	//插入数据
	//第一个参数单独的一个空间,比如两个人聊天,他们就是在单独的一个空间聊天, message 里面可以有很多个独立的空间,比如 张三和李四 是一个空间  王五和赵六又是一个空间
	//第二个参数是你发布信息的时间,我们以时间作为信息的依据,通过时间的排序我们的聊天记录
	//第三个参数是一个json,为我们的聊天信息,比如 昵称,头像,内容,表情,时间
	wd.child('1').child(time).set({
		'name':'dongyixueyuan',
		'content':content,
		'time':time
//				...更多
	});
})

//获得数据

// 监听聊天内容变化
var listen = "https://dongyixueyuan.wilddogio.com/message/1";
var listen_wd = new Wilddog(listen);
listen_wd.on('child_added',function(data){
	
	list.innerHTML += ''
						+'	'+data.val().name+' '+data.val().time+''
						+'	'+data.val().content+''
						+'';
	console.log(data.val().name);
})

//删除

//1为空间名,1442293959023为某一条信息
var ref = new Wilddog("https://dongyixueyuan.wilddogio.com/message/1/1442293959023");

ref.remove()

//时间转换函数

function getLocalTime(nS) {     
	var mydate = new Date(nS);
	var today = '';
//			today += mydate.getFullYear() + '年';   //返回年份
//			today += mydate.getMonth()+1 + '月';    //返回月份,因为返回值是0开始,表示1月,所以做+1处理
//			today += mydate.getDate() + '日';	//返回日期
	today += mydate.getHours() + ':';
	
	if(mydate.getMinutes() < 10){
		var min = '0'+mydate.getMinutes();
	}else{
		var min = mydate.getMinutes();
	}
	
	today += min + ':';
	today += mydate.getSeconds();
	return today;
}

//设置滚动条高度

document.body.scrollTop = document.body.offsetHeight;

双击安卓返回键退出

//监听安卓返回键
var first = null;
mui.back = function() {
    if (!first) {
        first = new Date().getTime();
        mui.toast('再按一次退出应用');
        setTimeout(function() {
            first = null;
        }, 1000);
    } else {
        if (new Date().getTime() - first < 1000) {
            plus.runtime.quit();
        }
    }
}

QQ登录

//申请各个开发平台的开发者

微信: https://open.weixin.qq.com/

QQ: http://open.qq.com/

微博: http://open.weibo.com/

//设置 manifest.json -> SDK配置

//初始化QQ登录,微信登录,微博登录

var auths={};
mui.plusReady(function(){
	// 获取登录认证通道
	plus.oauth.getServices(function(services){
		for(var i in services){
			var service=services[i];
			auths[service.id]=service;
		}
	},function(e){
		outLine("获取登录认证失败:"+e.message);
	});
});

//调用认证事件

// id 为 qq,weixin,weibo 
function login(id){
	console.log("----- 登录认证 -----");
	var auth=auths[id];
	if(auth){
		var w=plus.nativeUI.showWaiting();
		document.addEventListener("pause",function(){
			setTimeout(function(){
				w&&w.close();w=null;
			},2000);
		}, false );
		auth.login(function(){
			w&&w.close();w=null;
			console.log("登录认证成功:");
			console.log(JSON.stringify(auth.authResult));
			userinfo(auth);
		},function(e){
			w&&w.close();w=null;
			console.log("登录认证失败:");
			console.log("["+e.code+"]:"+e.message);
			plus.nativeUI.alert("详情错误信息请参考授权登录(OAuth)规范文档:http://www.html5plus.org/#specification#/specification/OAuth.html",null,"登录失败["+e.code+"]:"+e.message);
		});
	}else{
		console.log("无效的登录认证通道!");
		plus.nativeUI.alert("无效的登录认证通道!",null,"登录");
	}
}
// 获取用户信息
function userinfo(a){
	console.log("----- 获取用户信息 -----");
	a.getUserInfo(function(){
		console.log("获取用户信息成功:");
		console.log(JSON.stringify(a.userInfo));
		var nickname=a.userInfo.nickname||a.userInfo.name;
		plus.nativeUI.alert("欢迎“"+nickname+"”登录!");
	},function(e){
		console.log("获取用户信息失败:");
		console.log("["+e.code+"]:"+e.message);
		plus.nativeUI.alert("获取用户信息失败!",null,"登录");
	});
}
// 注销登录
function logoutAll(){
	console.log("----- 注销登录认证 -----");
	for(var i in auths){
		logout(auths[i]);
	}
}
function logout(auth){
	auth.logout(function(){
		outLine("注销\""+auth.description+"\"成功");
	},function(e){
		outLine("注销\""+auth.description+"\"失败:"+e.message);
	});
}
2014-12-25 21:18:18 leikezhu1981 阅读数 464

一、Tips是什么:

Tips应用有以下几个版块:Quickly迅速回复通知、Notify新邮件提醒我、Hey Siri(Siri操作)、Send发送语音信息、Quickly快速管理邮箱(使用手势)、Be拍摄(相机定时模式)。

打开Tips应用界面每条提示占一个版块,左右滑动或者点击底部菜单可以浏览其他提示。每条提示都可以通过信息、邮件、脸谱或推特同他人分享

二、Tips开发相关的:

Xcode 常用编译选项设置

在xcconfig文件中指定即可。

用标准库连接

LINK_WITH_STANDARD_LIBRARIES = YES
如果激活此设置,那么编译器在链接过程中会自动使用通过标准库的链接器。

Info.plist 输出编码

INFOPLIST_OUTPUT_FORMAT = binary
指定Info.plist文件的输出编码(默认情况下,输出与输入的编码保持不变),这个输出编码能指定“binary”或者“XML”。

生成调试符号
GCC_GENERATE_DEBUGGING_SYMBOLS = NO
当启用的时候,详情等级能够通过build的’Level of Debug Symbols’设置去控制。
 
隐藏内联方法
GCC_INLINES_ARE_PRIVATE_EXTERN = YES
 
Objective-C GC
GCC_ENABLE_OBJC_GC = Unsupported
 
优化级别
GCC_OPTIMIZATION_LEVEL = Fastest, Smallest   [-OS]
  • None: 不做优化使用这个设置,编译器的目标是减少编译成本,使调试产生预期的结果。
  • Fast:优化编译将为大函数占用更多的时间和内存使用这个设置,编译器将尝试减少代码的大小和执行时间,不进行任何优化,需要大量编译时间。
  • Faster:编译器执行几乎所有支持的优化,它不考虑空间和速度之间的平衡与“Fast”设置相比,该设置会增加编译时间和生成代码的性能。编译器不进行循环展开、内联函数和寄存器变量的重命名。
  • Fastest:开启“Faster”支持的所有的优化,同时也开启内联函数和寄存器变量的重命名选项
  • Fastest,smallest:优化代码大小这个设置启用“Faster”所有的优化,一般不增加代码大小,它还执行旨在减小代码大小的进一步优化。
C语言方言
GCC_C_LANGUAGE_STANDARD = C89
 
警告
 
检查Switch语句
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
 
隐藏局部变量
GCC_WARN_SHADOW = YES
 
隐式转换成32位的类型
GCC_WARN_64_TO_32_BIT_CONVERSION = YES
 
未完成的Objective-C协议
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES
 
抑制所有的警告
GCC_WARN_INHIBIT_ALL_WARNINGS = NO
 
初始化时没有完整的括号
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
例子(a没有完全的括号,b有):
 
  1. int a[ 2 ][ 2 ] = { 0, 1, 2, 3 };
  
  2. int b[ 2 ][ 2 ] = { { 0, 1 }, { 2, 3 } };  

不匹配的返回类型

GCC_WARN_ABOUT_RETURN_TYPE = YES
 
缺少括号
GCC_WARN_MISSING_PARENTHESES = YES
例子:
  1. {  
  2.     if( a )  
  3.         if( b )  
  4.             foo();  
  5.         else  
  6.             bar();  
  7. }  
  1. {  
  2.     if( a )  
  3.     {  
  4.         if( b )  
  5.             foo();  
  6.         else  
  7.             bar();  
  8.     }  
  9. }  

在结构体初始化时缺少字段
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES

 
缺少函数原型
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
 
在文件结尾缺少新行
GCC_WARN_ABOUT_MISSING_NEWLINE = YES
 
选择了多个定义的类型(@Selector)
GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = NO
 
严格的Selector匹配
GCC_WARN_STRICT_SELECTOR_MATCH = YES
 
把缺少函数原型当作错误
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
 
把所有的警告当作错误
GCC_TREAT_WARNINGS_AS_ERRORS = YES
 
未定义的Selector
GCC_WARN_UNDECLARED_SELECTOR = YES
 
未初始化的自动变量
GCC_WARN_UNINITIALIZED_AUTOS = YES
 
未知的Pragma指令
GCC_WARN_UNKNOWN_PRAGMAS = YES
 
未使用的函数
GCC_WARN_UNUSED_FUNCTION = YES
 
未使用的标签
GCC_WARN_UNUSED_LABEL = YES
 
未使用的参数
GCC_WARN_UNUSED_PARAMETER = YES
 
未使用的值
GCC_WARN_UNUSED_VALUE = YES
当一个语句计算的结果显式的未使用的时候发出警告
 
未使用的变量
GCC_WARN_UNUSED_VARIABLE = YES
 
警告-所有过时的函数
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES
 
offsetof宏未定义使用的警告
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES

iphone 常用的<app>-info.plist设置

Application requires iPhone environment

如果应用程序不能在ipod touch上运行,设置此项为true;
 
Application uses Wi-Fi
如果应用程序需要wi-fi才能工作,应该将此属性设置为true。这么做会提示用户,如果没有打开wi-fi的话,打开wi-fi。为了节省电力,iphone会在30分钟后自动关闭应用程序中的任何wi-fi。设置这一个属性可以防止这种情况的发生,并且保持连接处于活动状态
 
Bundle display name
这用于设置应用程序的名称,它显示在iphone屏幕的图标下方。应用程序名称限制在10-12个字符,如果超出,iphone将缩写名称。
 
Bundle identifier
这个为应用程序在iphone developer program portal web站点上设置的唯一标识符。(就是你安装证书的时候,需要把这里对应修改)。
 
Bundle version
这个会设置应用程序版本号,每次部署应用程序的一个新版本时,将会增加这个编号,在app store用的。
 
Icon already includes gloss and bevel effects
默认情况下,应用程序被设置了玻璃效果,把这个设置为true可以阻止这么做。
 
Icon file(这个不用多说了)
设置应用程序图标的。
 
Main nib file base name
应用程序首次启动时载入的xib文件 这个基本用不到。
 
Initial interface orientation 
确定了应用程序以风景模式还是任务模式启动
 
Localizations
多语言。应用程序本地化的一列表,期间用逗号隔开,例如应用程序支持英语 日语,将会适用 English,Japanese.
 
Status bar is initially hidden 
设置是否隐藏状态栏。你懂的。
 
Status bar style
选择三种不同格式种的一种。
 
URL types
应用程序支持的url标识符的一个数组。

用URL Scheme进行程序跳转

打开info.plist,添加一项URL types
展开URL types,再展开Item1,将Item1下的URL identifier修改为URL Scheme
展开URL Scheme,将Item1的内容修改为myapp
其他程序可通过myapp://访问此自定义URL

参考:http://iphonedevelopertips.com/cocoa/launching-your-own-application-via-a-custom-url-scheme.html

 

IOS后台播放音乐

OS后台播放只是在IOS4.0以后的版本支持。

1,设置后台播放会话

AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];

[session setCategory:AVAudioSessionCategoryPlayback error:nil];

2,在info.plist里面添加

<key>UIBackgroundModes</key>

<array>

<string>audio</string>

</array>

 

静态库没法包含category/分类?

如果你导入一个objc静态库,发现很多objc的category 不能调用,可以尝试在主工程中加入linker选项:

-all_load 加入这个一般就够了

-ObjC

 

让程序最小化再开启时,从头开始:

按下 “Home” 键以后程序可能并没有退出而是转入了后台运行。如果您想让应用直接退出,最简单的方法是:在 info-plist 里面找到 Application does not run in background 一项,勾选即可。

程序退出后任务栏还是有图标,但是程序原来的所有运行状态全部丢失,点击任务栏图标也不过相当于再次启动程序;如果允许后台运行,点击任务栏图标后会恢复程序中断时的界面。

 

本地化字符串:

在infoPlist.strings里面写

“string1″=”水果”

代码里面写 myLabel.text = NSLocalizedString(@”string1″, nil);

 

本地化的Bundle display name:

1)创建一个空文件,取名为InfoPlist.strings

2)对InfoPlist.strings进行本地化(Get Info  -> Make Localization),然后设置需要的语言(如中文zh)

3)编辑不同的InfoPlist.strings文件,设置显示名字

CFBundleDisplayName = “名字”; 

4)(这步不做貌似也可以)编辑Info.plist,添加一个新的属性Application has localized display name, 设置其类型为boolean,并将其value设置为选中状态

 

default图片的衔接问题:

程序开始后,手动加载default图片,然后进行过渡效果即可。

遍历目录:

1
2
3
4
5
6
7
8
9
10
11
12
NSString*appDocDir = [[[[NSFileManagerdefaultManager]URLsForDirectory:NSDocumentDirectoryinDomains:NSUserDomainMask]lastObject]relativePath];
 
NSArray*contentOfFolder = [[NSFileManagerdefaultManager]contentsOfDirectoryAtPath:appDocDirerror:NULL];
for(NSString*aPath in contentOfFolder) {
    NSLog(@"apath: %@", aPath);
    NSString* fullPath = [appDocDir stringByAppendingPathComponent:aPath];
    BOOLisDir;
    if([[NSFileManagerdefaultManager]fileExistsAtPath:fullPathisDirectory:&isDir] && !isDir)
    {
        [fileListaddObject:aPath];
    }
}

IB:

不论写不写property的retain,由IBOutlet都会为对象加一个retainCount,所以只要连接了,就需要在viewDidUnload与dealloc中release并适当置为nil。

预先在IB里面加载好的文件(比如图片),即使释放了Controller,IB中的文件也不会被释放,直至内存警告,解决办法是较大的资源用代码加载。

 

UIWebView:

用代码加载UIWebView的内容,navigationType是UIWebViewNavigationTypeOther

 

CAAnimation:

一定要记得[self.view.layer removeAllAnimations];因为CAAnimation会retain它的delegate

设备型号识别,可通过审核:

1
2
3
4
5
6
7
8
9
10
+ (NSString*)getDeviceVersion
{
    size_t size;
    sysctlbyname("hw.machine",NULL, &size, NULL,0);
    char*machine = (char*)malloc(size);
    sysctlbyname("hw.machine", machine, &size, NULL,0);
    NSString*platform = [NSStringstringWithCString:machineencoding:NSUTF8StringEncoding];
    free(machine);
    returnplatform;
}

输出:
//@”iPad1,1″ 
//@”iPad2,1″ 
//@”i386″

逗号后面数字解释:(i386是指模拟器)
1-WiFi版
2-GSM/WCDMA 3G版
3-CDMA版

AppleTV(2G) (AppleTV2,1)
iPad (iPad1,1)
iPad2,1 (iPad2,1)Wifi版
iPad2,2 (iPad2,2)GSM3G版
iPad2,3 (iPad2,3)CDMA3G版
iPhone (iPhone1,1)
iPhone3G (iPhone1,2)
iPhone3GS (iPhone2,1)
iPhone4 (iPhone3,1)
iPhone4(vz) (iPhone3,3)iPhone4 CDMA版
iPhone4S (iPhone4,1)
iPodTouch(1G) (iPod1,1)
iPodTouch(2G) (iPod2,1)
iPodTouch(3G) (iPod3,1)
iPodTouch(4G) (iPod4,1)

判断ipad/iphone

1
2
UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone

或者

1 [[[UIDevice currentDevice] model] isEqualToString:@"iPad"];

判断设备是否有摄像头

1 [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];

没有更多推荐了,返回首页