【IOS】从android角度来实现(理解)IOS的UITableView

以下内容为原创,欢迎转载,转载请注明

来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3403124.html

 

本人从在学校开始到现在上班(13年毕业)一直做web和android方面的开发,最近才开学习及ios的开发,所以ios学习中有不当之处,请大家留言赐教啦

以前从来没有接触过Objective-C这门语言,不过我想面向对象编程应该大体思想都差不多

在ios中的UITableView学习中,开发过android的朋友应该马上会联想到ListView和GridView这两个控件,接下来以ListView为例子,跟UITableView做个对比,看看它们实现的方式有什么相同之处。怎么样能让有android开发经验的朋友,马上掌握UITableView这个控件

先新建一个demo,取名TabViewTest(原谅我吧- -,本来要取名TableViewTest,谁知脑抽新建项目的时候写错了,诶。。。算了,将错就错吧- -)

ios没有命名空间的概念,没有包概念(这也是为什么ios中的类都有前缀的原因,比如NS等),所以上面像“包”一样的文件夹都是我自己新建的“group”,只是为了看起来比较有分层的概念而已,打开finder,到项目文件里一看如下图,妈呀- -,所有的类都挤在一个文件夹里面。。。这是我觉得蛋疼的地方之一-。-

 

再回来看看我们项目结构,我分的几个group,如果我把controller这个group的名字改成“activity”,android开发者肯定有种似曾相识的感觉了:

controller:控制层group,相当于android中的activity

layout:布局group,相当于android中res目录下的layout(xml布局文件)

model:这个不用说就知道放了什么东西了,经典的Person这个测试用的数据结构

adapter:为了还念android中的适配器,然后我就取了这么个group名字

 

好了,现在正式开始代码的编写

打开MainAppDelegate.m,它实现了UIApplicationDelegate协议,所以可以在该类中实现应用状态的回调函数

在application:didFinishLaunchingWithOptions:方法(应用程序启动时回调该方法)中来设置它的RootController(根控制器,不知道这样翻译专不专业- -),我的实现是生成一个UINavigationController作为它的root controller,然后把自己新建的一个NaviRootController(在这个Controller中放入一个UITableView,具体下面会讲到)作为UINavigationController的root view,具体代码如下(这个不是我们本次的重点,所以一笔带过):

 1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 2 {
 3     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
 4
 5     // 生成UINavigationController对象,并设置它的RootController
 6     UINavigationController *naviController = [[UINavigationController alloc] initWithRootViewController:[[NaviRootController alloc] init]];
 7     // 然后把NavigationController设置为window的RootViewController
 8     [self.window setRootViewController:naviController];
 9
10     self.window.backgroundColor = [UIColor whiteColor];
11     [self.window makeKeyAndVisible];
12     return YES;
13 }

然后,重点就是NaviRootController这个Controller了,

新建NaviRootController,继承UIViewController,在.h文件中:

声明一个NSMutableArray对象data作为tableView的数据源(相当于在android中经常用到的ArrayList<Person> data。NSMutableArray是数组,ArrayList在java中的底层实现本来用的就是数组,所以很好理解

声明一个用于适配和绑定tableView数据的适配器TableViewAdapter *adapter(这个类是我自己写的,下面会讲到。java中要实现ListView中的数据绑定适配,也要通过一个继承于BaseAdapter的适配器进行数据的适配吧,也很好理解

声明一个UITableView对象(相当于android中,在activity中声明一个private ListView listView;

具体代码如下:

 1 //
 2 //  NaviRootController.h
 3 //  TabViewTest
 4 //
 5 //  Created by WANGJIE on 13-10-31.
 6 //  Copyright (c) 2013年 WANGJIE. All rights reserved.
 7 //
 8
 9 #import <UIKit/UIKit.h>
10 @class TableViewAdapter;
11 @interface NaviRootController : UIViewController
12 {
13     NSMutableArray *data;
14     TableViewAdapter *adapter;
15 }
16
17 @property (weak, nonatomic) IBOutlet UITableView *tableView;
18
19
20 @property NSMutableArray *data;
21 @property(strong, nonatomic) TableViewAdapter *adapter;
22 @end

View Code

好了,声明部分到此为止,接下来看看实现部分

刚刚在MainAppDelegate中,生成了一个NaviRootController对象,然后把这个对象加入到了UINavigationController对象的rootViewController。生成NaviRootController对象的时候,调用了init方法,我们应该在init方法里面去初始化布局,如下:

 1 - (id)init
 2 {
 3     self = [self initWithNibName:@"navi_root" bundle:nil];
 4     return self;
 5 }
 6
 7 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
 8 {
 9     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
10     if (self) {
11         // 获得当前导航栏对象
12         UINavigationItem *item = [self navigationItem];
13         // 设置导航栏左按钮
14         UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:@"leftButton" style:UIBarButtonItemStylePlain target:self action:@selector(buttonClickedAction:)];
15         [leftButton setTag:0];
16         [item setLeftBarButtonItem:leftButton animated:YES];
17         // 设置导航栏右按钮
18         UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"rightButton" style:UIBarButtonItemStyleDone target:self action:@selector(buttonClickedAction:)];
19         [rightButton setTag:1];
20         [item setRightBarButtonItem:rightButton animated:YES];
21
22     }
23     return self;
24 }

View Code

我们在init方法中调用了initWithNibName:bundle:方法,传入了NibName这个字符串,这个是什么?Nib是ios里面的布局文件,也就是相当于android中类似main.xml这种布局文件吧,现在传进去的时nibname,也就是布局文件的名称。所以,没错,传入这个参数后,当前的controller(也就是NaviRootController就跟传入的这个布局文件绑定起来了,类似于android中activity中熟悉的setContentView(R.layout.main)一样!

然后我们顺便看看navi_root.xib这个布局文件:

整个界面就一个UITableView,对了,别忘了在File's Owner中把custom class改成NaviRootController。键盘按住control,用鼠标拖动左边栏的“Table View”到NaviRootController.h中,会自动生成UITableView声明,并自动绑定。

接下来回到NaviRootController的初始化方法中。

initWithNibName:bundle:方法中后面的UINavigationItem相关的代码是用来设置导航栏左边和右边的按钮,既然是个demo,所以也没什么特别的功能,就是点击下,跳出一个UIAlertView提示下,所以一笔带过。

此时界面布局和controller已经绑定起来了,现在的任务应该是初始化UITableView的数据,也就是上面的data属性,但是在哪里初始化比较好呢?

刚开始,我是直接在init方法中直接去初始化数据,但是失败了,不管在init方法中初始化多少次(data调用多少次addObject方法),data的值永远都是nil(相当于在android中,不管调用多少次list.add(...)方法,list中一条数据也没有加入!),猜测是因为在init方法中的时候属性和控件都还没有被初始化。

最后我的解决办法就是在viewDidLoad方法中去加载数据。viewDidLoad这个回调方法是会在控件加载完毕后调用,所以,我认为在这里去加载数据和做控件的初始化操作是比较合理的。

viewDidLoad方法实现如下:

 1 - (void)viewDidLoad
 2 {
 3
 4     // Do any additional setup after loading the view.
 5     [super viewDidLoad];
 6
 7     if (!adapter) {
 8         [self initData];
 9
10         // 生成适配器委托对象
11         adapter = [[TableViewAdapter alloc] initWithSource:data Controller:self];
12
13         // 设置适配器委托对象
14         [[self tableView] setDelegate:adapter];
15         [[self tableView] setDataSource:adapter];
16
17     }
18 }

View Code

如上,在viewDidLoad中,我先去初始化数据(demo中的实现其实就是循环了14次,往data中加了14个Person对象),然后生成一个适配器委托对象,传入data(数据源)和self(当前controller对象),相当于android中的 adapter = new MyAdapter(list, this);有木有??!!

然后,setDelegate用来设置委托对象(相当于android中的listView.setAdapter(adapter)),setDataSource用来设置数据源。

这里,完整地列出NaviRootController的代码:

  1 //
  2 //  NaviRootController.m
  3 //  TabViewTest
  4 //
  5 //  Created by WANGJIE on 13-10-31.
  6 //  Copyright (c) 2013年 WANGJIE. All rights reserved.
  7 //
  8
  9 #import "NaviRootController.h"
 10 #import "Person.h"
 11 #import "TableViewAdapter.h"
 12
 13 @interface NaviRootController ()
 14
 15 @end
 16
 17 @implementation NaviRootController
 18 @synthesize data, adapter;
 19
 20 - (id)init
 21 {
 22     self = [self initWithNibName:@"navi_root" bundle:nil];
 23     return self;
 24 }
 25
 26 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
 27 {
 28     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 29     if (self) {
 30         // Custom initialization
 31         // 获得当前导航栏对象
 32         UINavigationItem *item = [self navigationItem];
 33         // 设置导航栏左按钮
 34         UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:@"leftButton" style:UIBarButtonItemStylePlain target:self action:@selector(buttonClickedAction:)];
 35         [leftButton setTag:0];
 36         [item setLeftBarButtonItem:leftButton animated:YES];
 37         // 设置导航栏右按钮
 38         UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"rightButton" style:UIBarButtonItemStyleDone target:self action:@selector(buttonClickedAction:)];
 39         [rightButton setTag:1];
 40         [item setRightBarButtonItem:rightButton animated:YES];
 41
 42
 43
 44
 45     }
 46     return self;
 47 }
 48
 49 /**
 50  * 初始化列表数据
 51  */
 52 - (void)initData
 53 {
 54     data = [[NSMutableArray alloc] init];
 55     NSLog(@"%@", NSStringFromSelector(_cmd));
 56     Person *person;
 57     for (int i = 0; i < 14; i++) {
 58         person = [[Person alloc] init];
 59         [person setName:[@"name" stringByAppendingString:
 60                          [NSString stringWithFormat:@"%d", i]
 61                          ]
 62          ];
 63
 64         [person setAge:i + 10];
 65
 66         [person setPic:[UIImage imageNamed:@"Hypno.png"]];
 67
 68         [data addObject:person];
 69
 70     }
 71 }
 72
 73
 74 - (void)viewDidLoad
 75 {
 76
 77     // Do any additional setup after loading the view.
 78     [super viewDidLoad];
 79
 80     if (!adapter) {
 81         [self initData];
 82
 83         // 生成适配器委托对象
 84         adapter = [[TableViewAdapter alloc] initWithSource:data Controller:self];
 85
 86         // 设置适配器委托对象
 87         [[self tableView] setDelegate:adapter];
 88         [[self tableView] setDataSource:adapter];
 89
 90     }
 91
 92
 93
 94 }
 95
 96 - (void)viewWillAppear:(BOOL)animated
 97 {
 98     [super viewWillAppear:YES];
 99
100 }
101
102 - (void)didReceiveMemoryWarning
103 {
104     [super didReceiveMemoryWarning];
105     // Dispose of any resources that can be recreated.
106 }
107
108 // 按钮点击事件回调
109 - (void)buttonClickedAction:(id)sender
110 {
111
112     NSString *message;
113     switch ([sender tag]) {
114         case 0:
115             message = @"left button clicked!";
116             break;
117         case 1:
118             message = @"right button clicked!";
119             break;
120         default:
121             message = @"unknow button clicked!";
122             break;
123     }
124
125     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"alert view" message:message delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil];
126     [alert show];
127 }
128
129
130
131
132 @end

View Code

 

好了,UITableView的初始化准备工作到此就做完了,现在干嘛?

当然去编写TableViewAdapter这个类啊。数据源有了(并且初始化完毕),用以显示的控件(UITableView)有了(并且初始化完毕),而且两个还已经绑定起来了。但是还缺的就是一个角色,这个角色可以把数据源中的数据跟控件中某个相应的子控件适配起来。比如数据源中有4个数据,A、B、C、D,控件有one、two、three、four这4个控件,这个角色的任务就是告诉one:你要显示的数据是A;告诉two:你要显示的数据是B;告诉three:你要显示的数据是C;告诉four:你要显示的数据是D!

这个角色就是适配器!也就是下面要说的那个TableViewAdapter

新建TableViewAdapter,实现<UITableViewDataSource, UITableViewDelegate>这两个协议(android中适配器不同的是要继承BaseAdapter类)。声明一个数据源data,这个数据源是从NaviRootController中传过来的已经初始化好了的数据源,还有一个声明是NaviRootController对象传过来的self(需要什么,就让调用者传什么过来,这个应该都懂的-。-),另外还有一个自己写的初始化方法(自己写初始化方法init打头的方法就行,不像java中的构造方法,方法名要跟类名相同,不过这些都是换汤不换药)

然后看看TableViewAdapter的实现类(.m)

实现了这两个协议后,你就能覆写里面的一些UITableView的回调方法了,比如:

tableView:numberOfRowsInSection:方法,返回数据源的数量就行了(类似android的adapter中自己要实现的getCount()方法!

tableView:cellForRowAtIndexPath:这个是方法是这里最关键的一个方法了,就是在这里进行数据的适配工作(类似android的adapter中自己要实现的getView()方法!),这里返回的UITableViewCell就是类表中的一项(类似android中listview的一个item),这个一项的布局,已经在table_cell.xib文件中布局完毕,如下:

设置File's Owner为TableViewAdapter,设置Table View Cell的identifier设置为“MyTableCell”,这个可以任意取名,但是要跟后面的方法实现中统一(跟哪里统一?作用是神马?这些下面会讲到,别急-。-),接着设置ImageView的tag为1,nameLabel的tag为2,ageLabel的tag为3(tag的作用,下面也会讲到)。

接着,回到tableView:cellForRowAtIndexPath:这个方法,它的实现如下所示:

 1 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 2 {
 3     Person *p = [data objectAtIndex:[indexPath row]];
 4     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyTableCell"];
 5     if (!cell) {
 6         NSArray *nibViews = [[NSBundle mainBundle] loadNibNamed:@"table_cell" owner:self options:nil];
 7         cell = [nibViews objectAtIndex:0];
 8     }
 9
10     UIImageView *picIv = (UIImageView *)[cell viewWithTag:1];
11     UILabel *nameLb = (UILabel *)[cell viewWithTag:2];
12     UILabel *ageLb = (UILabel *)[cell viewWithTag:3];
13
14     [nameLb setText:[p name]];
15     [ageLb setText:[NSString stringWithFormat:@"%d", [p age]]];
16     [picIv setImage:[p pic]];
17
18     return cell;
19 }

如上图所示:

第3行,是用于获得所要显示的数据Person对象(这里的[indexPath row]相当于android的adapter的getView方法的position参数。indexPath中有两个参数,row和section,表示行和列,因为我们现在是要显示一个列表,所以只需要row这个参数就可以了)

第4行,是用于资源的重复利用,根据标示符“MyTableCell”去获得一个可再利用的UITableViewCell(这里的标示符就要跟前面在xib文件中设置的标示符要一致,这样才能被识别到,然后在这里被获取到),如果没有获得到,就去新创建一个UITableViewCell。

第6、7行,是创建新的UITableViewCell的代码,通过mianBundle的loadNibNamed:owner:options方法根据xib的名字去创建(android中的LayoutInflater.inflate()方法通过R.layout.xxx的方法创建类似),loadNibNamed:owner:options返回的是一个数组,得到第一个就是UITableViewCell了。

第10、11、12行,是获取到或者新建的cell通过控件之前设置的tag来获得相应地子控件(现在知道之前为什么要设置xib文件中控件的tag了吧?这个跟android中的findViewByTag/findViewById又是很类似的!

第14、15、16行,是为刚刚获得的cell中的子控件适配数据,让它可以把数据显示出来。

第18行,把生成数据适配完毕的UITableViewCell返回出去(这跟android中的也是很类似

TableViewAdapter代码如下:

 1 //
 2 //  TableViewAdapter.m
 3 //  TabViewTest
 4 //
 5 //  Created by WANGJIE on 13-10-31.
 6 //  Copyright (c) 2013年 WANGJIE. All rights reserved.
 7 //
 8
 9 #import "TableViewAdapter.h"
10 #import "Person.h"
11 #import "NaviRootController.h"
12
13 @implementation TableViewAdapter
14
15 - (id)initWithSource:(NSMutableArray *)source Controller:(NaviRootController *)context
16 {
17     NSLog(@"initWithSource...");
18     self = [super init];
19     if (self) {
20         data = source;
21         controller = context;
22     }
23     return self;
24 }
25
26 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
27 {
28
29     return [data count];
30 }
31
32 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
33 {
34     NSLog(@"%@", NSStringFromSelector(_cmd));
35 //    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
36 //    if (!cell) {
37 //        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
38 //    }
39     // 获得当前要显示的数据
40     Person *p = [data objectAtIndex:[indexPath row]];
41 //
42 //    [[cell textLabel] setText:[p name]];
43     // 记得在cell.xib文件中设置identifier以达到重用的目的
44     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyTableCell"];
45     if (!cell) {
46         // 通过mainBundle的loadNibNamed方法去加载布局,类似android中的LayoutInflater.inflate()方法
47         NSArray *nibViews = [[NSBundle mainBundle] loadNibNamed:@"table_cell" owner:self options:nil];
48         cell = [nibViews objectAtIndex:0];
49 //        cell.selectionStyle = UITableViewCellSelectionStyleNone;
50     }
51     // 通过在cell.xib中各控件设置的tag来获得控件,类似android中的findViewByTag/findViewById
52     UIImageView *picIv = (UIImageView *)[cell viewWithTag:1];
53     UILabel *nameLb = (UILabel *)[cell viewWithTag:2];
54     UILabel *ageLb = (UILabel *)[cell viewWithTag:3];
55
56     [nameLb setText:[p name]];
57     [ageLb setText:[NSString stringWithFormat:@"%d", [p age]]];
58     [picIv setImage:[p pic]];
59
60
61     return cell;
62 }
63
64
65 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
66 {
67     Person *person = [data objectAtIndex:[indexPath row]];
68     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"cell clicked!" message:[NSString stringWithFormat:@"%@ clicked!", [person name]]delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil];
69     [alert show];
70
71 }
72
73 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
74 {
75     return [self tableView:tableView cellForRowAtIndexPath:indexPath].frame.size.height;
76 }
77
78
79 @end

View Code

 

好了!到此为止整个UITableView实现的流程基本完成了,可以看出跟android的ListView和GridView的实现流程很相似,理解了其中一个,另一个也能很好的理解它的工作流程。

最后来一张效果图:

时间: 2024-10-26 19:32:23

【IOS】从android角度来实现(理解)IOS的UITableView的相关文章

全面理解iOS开发中的Scroll View[转]

from:http://mobile.51cto.com/hot-430409.htm   可能你很难相信,UIScrollView和一个标准的UIView差异并不大,scroll view确实会多一些方法,但这些方法只是UIView一些属性的表面而已.因此,要想弄懂UIScrollView是怎么工作之前,你需要了解 UIView,特别是视图渲染过程的两步. AD:   可能你很难相信,UIScrollView和一个标准的UIView差异并不大,scroll view确实会多一些方法,但这些方法

一篇文章读懂 iOS 和 Android 的历史起源

智能手机虽说是移动电话,但我们完全可以将其作为小型化的电脑来思考.这样一来也能够显示出智能手机OS的高性能.我们首先一起来回顾下智能手机OS的历史. 其实在很早之前就已经有这样的想法,即在像智能手机这样可以便利携带的小型电脑终端上运行OS. OS的黎明期 大 约20年前左右,在美国的拉斯维加斯举办的世界最大的电脑相关产品展示会"COMDEX"上,日本索尼公司开发的当时称之为"MagicjLink"的携 带型信息终端吸引了很多的关注(图1).这款终端并不仅仅是一款用来

iOS vs Android苹果将重蹈PC业务覆辙?

iPhone凭借着其颠覆式的设计以及极为优秀的体验从诞生以来便吸引了无数人的目光,也成功的奠定了苹果在手机行业的地位.不过随着智能手机行业愈加的趋向于成熟,安卓手机无论是从价位还是功能体验上都给了用户更多的选择,这也让笔者不禁想起了当年苹果在PC市场上败给微软的往事.相信现在很多人心里都有这样一个疑问:苹果的手机业务是否会走上当年PC业务的老路,败给新对手谷歌的Android呢? ● 用户体验方面差距缩小 相较于Android,iOS最大的优势就在用户体验上.封闭的iOS系统在智能机发展初期可谓

iOS及Android 4.1版Chrome发布 HTML5得到进一步发展

本文作者在参加今年在旧金山举办的谷歌I/O大会之后写的一篇文章<Chrome for iOS and Android 4.1 Jelly Bean HTML5 development>,Chrome for iOS和Chrome for Android 4.1的发布必将促进HTML5研发得到进一步发展. 以下为全部译文: ANDROID 4.1"糖豆"浏览器 让我们先从Android 4.1"糖豆"说起吧.我跟大家一样,都曾为谷歌公司发布的Andoird

让数据说话 iOS与Android谁才是真正的赢家

中介交易 SEO诊断 淘宝客 云主机 技术大厅 一直以来,关于 iOS 与 Android 孰强孰弱的争议就没停过.这也是科技媒体最喜欢讨论的一个问题. 当你用单一的数据去论证 iOS 与 Android 到底谁更强,显然不科学.你必须要收集足够多的数据,从不同角度进行思考,才有可能给出一个相对合理的答案. 所以,在这篇文章里,我收集了很多调查机构的数据,且相对来说,这些数据也是比较新的(只有部分数据来自 2012 年第四季度,其他的均来自 2013 年第一季的最新数据.) 首先说点题外话: 1

iOS 和 Android 哪个更利于赚钱?_IOS

一直有一个几乎所有机友都认同的说法:Android 是全球用户数最多的操作系统,市场份额十分惊人.无论是问你的表哥表姐,还是弟弟妹妹,即便他们不是很关注移动领域或不很懂手机,也会给你相同的答案,而且其中大多数人甚至会给予一个个数字,告诉你 Android 拥有约全球 80% 的市场份额.  他们的回答并没有错,就算 Android 的市场份额明显小于 80%,但从全球角度来看,Android 依然独步整个移动操作系统的武林,无论在哪一个国家或地区.不过,故事也有另一面,开发者对 Android

IOS与Android为何能够牢牢掌控移动互联终端系统

中介交易 SEO诊断 淘宝客 云主机 技术大厅 现实就是IOS与Android几乎瓜分了整个移动终端市场,二者超过90%的市场占有率说明了这两个系统都有着庞大而忠实的用户.在果粉眼里,android一无是处;而在果黑心中,IOS不值一提. 苹果凭借iPhone与三星.LG.谷歌等诸多android系统的手机抗衡并不落下风表明了IOS的独到之处,而android设备则凭借强悍的硬件.自由的系统在激烈的市场竞争中给IOS还以颜色,在用户的心中,究竟哪些因素才是制胜的关键所在? 随着iPhone6和i

微软证实Office软件将登陆iOS和Android平台

对于既想利用Office帮助Windows Phone"鹤立鸡群",又想确保Office"无处不在"的微软而言,这是一个棘手的平衡问题. 北京时间10月11日消息,据国外媒体报道,尽管部分否认了捷克分部发表的一份声明,但微软证实Office软件将以某种方式登陆iOS和Android平台. 微软捷克分部在声明中称,Office将于明年初登陆iOS和Android平台. 微软的表态则不太明确,"我们之前就曾公布过,Office Mobile将支持Windows

信息交互设计:iOS与Android间有什么差别

文章描述:如何在iOS与Android间移植APP. 除了像"I am rich"这种定点打击苹果烧包族的APP外,大多数应用都会尽量覆盖包含尽可能多的用户.这就需要考虑在iOS和Android两种主流操作系统间移植的问题.如果为各个平台量身定做界面,就能让用户利用以往的使用习惯快速学习.但为多个平台设计各异的界面毕竟是需要工作量的.如何才能在跨平台移植的时候只做那些最有必要的工作呢?兵不打无准备之仗,先来看看iOS与Android间有什么差别吧. 1.物理键之返回 Android手机