开发过程中有个页面需要用到表格,用了RelativeLayout布局实现,没有使用TableLayout。
整个表格需要使用一个圆角样式背景:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape android:shape="rectangle" > <solid android:color="@color/white" /> <corners android:radius="5dp" /> <stroke android:width="1dp" android:color="#e4e2e2" /> </shape> </item> </layer-list>
用水平直线分隔行(horizontal_line.xml):
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#e4e2e2" /> <size android:height="1dp" /> </shape>
用竖直直线分隔列(vertical_line.xml):
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#e4e2e2" /> <size android:width="1dp" /> </shape>
最后做出来的实际效果(截图后发现直线颜色太暗,手机上看起来效果还行):
在进入主题之前,我想先解释一下什么是“第三方登录”。所谓的第三方登录,就是利用用户在第三方平台上已有的账号来快速完成自己应用的登录或者注册的功能。而这里的第三方平台,一般是已经有大量用户的平台,如国内的新浪微博、QQ空间,外国的Facebook、twitter等等。第三方登录不是一个具体的接口,而是一种思想或者一套步骤。
要实现第三方登录,首先你需要选择一个第三方平台。新浪微博和QQ空间都是好的选择,这些平台拥有大量的用户,而且还开放了API,供我们调用接入。但是同样开放API,微信却不是一个好选择,这是因为微信的API只支持分享,不支持授权验证或者获取用户资料。所以要实现第三方登录,你选择的平台至少需要具备:
1、开放了API
2、具备获取用户资料或至少可以进行授权验证
其实Share SDK已经支持了十几种这样子的平台,完全足够你选择使用。
选择好平台以后,现在思考下面的问题:
你的应用是否具备独立账户系统?
这个问题是第三方登录时接口选择的重要标准。如果你选择“是”,则意味着你的应用只是需要第三方平台的用户,而不是他们的账户验证功能——也就是“要数据,不要功能”。而如果你选择“否”,则表示你实际上是“要功能,不要数据(用户)”。对于Share SDK来说,前者你的入口方法是showUser(null),而后者是authorize()。那么下面我分情况解释两种接入方式的步骤。
从简单的说起。对于“要功能,不要数据”的情况,步骤如下:
1、用户触发第三方登录事件
2、调用weibo.getDb().getWeiboId()请求用户在此平台上的ID
3、如果用户ID存在,则认为用户是合法用户,允许进入系统;否则调用authorize()
4、authorize()方法将引导用户在授权页面输入帐号密码,然后目标平台将验证此用户
5、如果onComplete()方法被回调,表示授权成功,引导用户进入系统
6、否则提示错误,调用removeAccount()方法,删除可能的授权缓存数据
然后是“要数据,不要功能”的步骤:
1、用户触发第三方登录事件
2、showUser(null)请求授权用户的资料(这个过程中可能涉及授权操作)
3、如果onComplete()方法被回调,将其参数Hashmap代入你应用的Login流程
4、否则提示错误,调用removeAccount()方法,删除可能的授权缓存数据
5、Login时客户端发送用户资料中的用户ID给服务端
6、服务端判定用户是已注册用户,则引导用户进入系统,否则返回特定错误码
7、客户端收到“未注册用户”错误码以后,代入用户资料到你应用的Register流程
8、Register时在用户资料中挑选你应用的注册所需字段,并提交服务端注册
9、服务端完成用户注册,成功则反馈客户端引导用户进入系统
10、否则提示错误,调用removeAccount()方法,删除可能的授权缓存数据
为了写这篇文章,我自己做了一个基于Share SDK 1.2.0的Demo,选择了新浪微博、QQ空间、Facebook和Twitter作为演示的平台。由于我没有可以使用的服务器和账户系统,因此只是演示了上述的“要功能,不要数据”。但是可以很容易看出来,这种情况,其实是第二种情况的简化,而第二种情况剩余的步骤,更多的是你应用的客户端和服务端之间的登录和注册操作,和Share SDK已经没什么关系了。
看到论坛里有童鞋在问ITeye官方怎么没有手机版的客户端,于是我花时间自己搞了一个,这样看帖就方便了。
客户端集成了ITeye的资讯,论坛,博客的相关内容,支持Android和iPhone手机。
客户端我放到百度网盘上了,点此下载:http://pan.baidu.com/s/1Jhm3
客户端我是在iMAG移动应用开发平台开发的,基于iMAG移动中间件技术。
用中间件开发的好处是开发一次Android和iPhone就都搞定了,而且开发比较简单,会点儿HTML和Javascript就行了。
iMAG的原理是把xml文件翻译成原生代码来执行,因此性能和原生应用差不多,同时因为封装得比较好, 开发很简单,比PhoneGap之类的要好得多。
关于如何用iMAG中间件来开发移动应用,有兴趣的同学可以去iMAG的官网看看:http://imagapp.com
这里附上登录页面的源码
<?xml version="1.0" encoding="utf-8"?> <imag> <script> <![CDATA[ var authenticity_token; function isOnline(html) { if (html && (html.indexOf('>欢迎') != -1)) { return true; } else { return false; } } function login() { var dlg = $page.waiting('用户登录|正在登录系统...'); var username = $('username').value; var password = $('password').value; $http.post('http://xiaote.iteye.com/login', { name: username, password: password, authenticity_token: authenticity_token, remember_me: '1', button: '登 录' }, function(data) { dlg.close(); if (isOnline(data)) { hint('登录成功'); var storage = $phone.localStorage(); storage.setItem('login_online', '1'); storage.setItem('login_username', username); storage.setItem('login_password', password); storage.setItem('login_token', authenticity_token); var regex = /<a\s+id="notifications_count"\s+href="/S/index.html">([^<]+)<\/a>[^收]+收件箱\(([0-9]+)\)/gm; var group = regex.exec(data); if (group != null) { storage.setItem('login_message_count', group[1]); storage.setItem('login_email_count', group[2]); } $page.close(); } else { hint('登录名称或密码错误,请重新登录'); var storage = $phone.localStorage(); storage.removeItem('login_online'); storage.removeItem('login_username'); storage.removeItem('login_password'); } }, function(error) { if (error == 'timeout') { hint('连接服务器超时,请重试'); } else if (error == '401') { alert('您所在的IP地址对ITeye网站访问过于频繁,请您稍后再试或到网站上填写验证码,谢谢!'); } }); } $page.onload = function() { var dlg = $page.waiting('请稍后|正在加载..'); $http.get('http://xiaote.iteye.com/login', function(data) { var regex = /<input\s+name="authenticity_token"\s+type="hidden"\s+value="(\S+)"\s*\/>/mg; var group = regex.exec(data); if (group != null) { dlg.close(); authenticity_token = group[1]; var storage = $phone.localStorage(); } else { $http.get('http://www.iteye.com/logout', function(data) { dlg.close(); var storage = $phone.localStorage(); storage.removeItem('login_online'); storage.removeItem('login_username'); storage.removeItem('login_password'); storage.removeItem('login_message_count'); storage.removeItem('login_email_count'); }); } }, function(error) { if (error == 'timeout') { hint('连接服务器超时,请重试'); } else if (error == '401') { alert('您所在的IP地址对ITeye网站访问过于频繁,请您稍后再试或到网站上填写验证码,谢谢!'); } }); } ]]> </script> <page> <title > <center> <label>用户登录</label> </center> </title> <content > <form action="/blog_article/login.xml" onsubmit="login();return false"> <row > <radios name=""> <item value="iteye" checked="checked">ITeye账号</item> <item value="csdn">csdn账号</item> </radios> </row> <list type="group" > <item > <col> <row><icon src="/blog_article/username.png"/><label >账号</label></row> </col> <col> <row><input type="text" id="username" name="username" placeholder="用户名或邮箱" /></row> </col> </item> <item > <col> <row><icon src="/blog_article/password.png"/><label >密码</label></row> </col> <col> <row><input type="password" id="password" name="passowrd" /></row> </col> </item> </list> <input type="submit" value="登录"/> <validation inputName="username"> <presence errorMessage="请输入账号"/> </validation> <validation inputName="password"> <presence errorMessage="请输入密码"/> </validation> </form> </content> </page> </imag>
完整的客户端源码我在iMAG官网论坛里有分享:
http://bbs.imagapp.com
http://bbs.imagapp.com/forum.php?mod=viewthread&tid=65