Monthly Archives: December 2014

iPhone 6和6Plus屏幕、UI设计和适配那些事

且看iPhone几个系列的屏幕数据:

 iPhone 4*iPhone 5*iPhone 6iPhone 6P
物理大小 - 对角(inch)3.544.75.5
物理大小 - 宽高(inch)1.94*2.911.96*3.482.3*4.12.7*4.79
PPI329.65325.97325.61400.53
物理分辨率(px)640*960640*1136750*13341080*1920
逻辑分辨率(pt)320*480320*568375*667414*736
渲染分辨率(px)640*960640*1136750*13341242*2208
像素/点比率2222.6

首先要看到的事实是6P的ppi变大了,也就是像素更小了。如果还是按1:2的点像比,那么这块1080*1920像素分辨率的屏幕应该有540*960的点分辨率。但实际计算用到点分辨率却是414*736,点像比是1:2.6,不到1:3。
那么问题来了,为什么苹果不沿用326ppi左右屏幕,而要用401ppi的屏幕?为什么6P的点分辨率是414*736?

关于这些问题可以参考知乎iPhone 6 Plus的逻辑分辨率为什么是414×736?
大概就是保证:
1.6P屏幕必须6大,5.5英寸为前提;
2.显示更多内容,所以点分辨率必须大于375*667;
3.ppi不能比之前低;
4.同样逻辑单位(点)的内容,如字体、按钮物理尺寸不能比之前小,否者会造成视觉、操作不便。
5.在现有工艺可达到。
所以最终401ppi、414*736、1080*1920、1:2.6的配置更像是一种折中的非完美方案。

问题又来了,为什么不是326ppi、880*1560(880≈2.7”*326ppi,1560≈4.79”*326ppi)、440*780、1:2这种尺寸呢?

这样还可以继续用2x图。这里就略过不研究了。

如有2.6对于开发、设计来说都不是一个特好的数字,所以苹果把它约等了一下变成3,又搞了个渲染分辨率的概念。
414*736的3倍正是1242*2208,在这个分辨率计算界面的样式,然后把最终的画面下采样(downsampling)缩小1.15显示到1080*1920上。渲染分辨率还用在未专门适配4.7英寸的iPhone 6的时,把4英寸的640*1136画面上采样(upsampling)放大1.171875倍显示在750*1334屏幕上,当然会看起来比较模糊。采用3的话以后如果采用461ppi屏幕也更容易兼容。

iPhone 6 plus downsampingiphone 6 upsampling

更全更详细的图示请参见:The Ultimate Guide To iPhone Resolutions

PPI计算和常见手机PPI信息:https://www.sven.de/dpi/

以主屏幕分辨率的app图标为例,大小为60pt*60pt,为什么@3x下icon的尺寸180*180就是正确的呢?在@2x下120*120的icon,物理尺寸是0.36”≈120px*1.96”/640px,而@3x下180*180的icon物理尺寸是0.39≈(180px/11.5)*2.7”/1080px。可见他们的物理尺寸基本一致。

对于6P,@2x素材的大小乘以1.5便是@3x图的大小。

对于iPhone 5系,屏幕只是变长了,垂直方向上的适配很简单。然后对于6和6p来说,不仅边长变宽,点像比率也变大了。那么在设计iPhone UI时就不再像以前一样了。应该结合使用point、autolayout的“相对”布局,什么时候该用固定point大小,什么时候该用相对尺寸,具体并没有可套用的准则。

比如主屏icon图标保证尺寸是60point,横向平分间隔;相册里每行4张缩略图,4等分,没有具体point大小;nav bar是同一Point大小;tab bar图标统一point大小,间隔均分。

在出设计图给程序员时的标注也不再全部是绝对的像素或pt,像间隔应该表明是横向均分。

用markman标注

在设计时应该以哪个iPhone为参考呢?画布尺寸为多大呢?
画布应该以iPhone4的点分辨率320px*480px,放大3倍,即960px*1440px为标准。这样既保证了UI对最小屏幕的绝对适配,也方便了@3x素材的导出。
在横向上,6和6P使空白区域拉伸即可。纵向可以结合留白、放大、使用滚动。

 

在编程实现应该使用Autolayout,摒弃过去的绝对pt布局。

使用代码进行布局时可以使用一些对原生NSLayoutConstraints的封装简化库,减少臃肿,提高代码可读性,加快速度。

MasonryPureLayoutKeepLayout

本人使用 PureLayout,虽然语法没 Masonry 那么简单,但是 bug 少。

 

修复cocoapods

在拉下松爷更新的Podfile后,尝试用pod update更新,结果出现下面错误

$pod update
Update all pods
Analyzing dependencies
[!] Unable to satisfy the following requirements:

- `JSQMessagesViewController (~> 6.1.0)` required by `Podfile`

没什么头绪,尝试查一下版本

$pod list | grep JSQM
  JSQMessagesViewController 6.0.0

JSQMessagesViewController主页明明标了已经是6.1.1,是不是版本库有本地缓存,在pod --help加google下,发现命令pod repo update,果断运行一下,卡住,加上–verbose

$pod repo update --verbose
  $ /usr/bin/git rev-parse  >/dev/null 2>&1

Updating spec repo `master`
  $ /usr/bin/git pull --ff-only
  error: Your local changes to the following files would be overwritten by merge:
  	CocoaPods-version.yml
  	Specs/AdMobMediationAdapterMMedia/1.5.0/AdMobMediationAdapterMMedia.podspec.json
  Please, commit your changes or stash them before you can merge.
  error: The following untracked working tree files would be overwritten by merge:
  	Specs/AAShareBubbles/1.1.0/AAShareBubbles.podspec.json
  	...[略去n行]
  	Specs/AQSEvent/0.2.0/AQSE
  Aborting
  Updating da90008..86016e3

[!] CocoaPods was not able to update the `master` repo. If this is an unexpected issue and persists you can inspect it running `pod repo update --verbose`

果然本地有缓存,还是git管理的,更新时冲突,google了一下,找到相关资料:
1.http://stackoverflow.com/questions/19477178/cocoapods-error-during-pod-update
2.http://blog.cocoapods.org/Repairing-Our-Broken-Specs-Repository/

解决方法:删除本地缓存,重新setup

$rm -fr ~/.cocoapods/repos/master
$pod setup

centos 6.5安装git

#yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-devel
#wget https://www.kernel.org/pub/software/scm/git/git-2.2.0.tar.gz
#tar -zxf git-2.2.0.tar.gz 
#cd git-2.2.0
#make prefix=/usr/local all
#make prefix=/usr/local install

如果出错下面错误

/usr/bin/perl Makefile.PL PREFIX='/usr/local' INSTALL_BASE='' --localedir='/usr/local/share/locale'
Can't locate ExtUtils/MakeMaker.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at Makefile.PL line 3.
BEGIN failed--compilation aborted at Makefile.PL line 3.
make[1]: *** [perl.mak] Error 2
make: *** [perl/perl.mak] Error 2

就是没装perl-devel导致

python MySQLdb例子

以下代码使用了torndb(torndb是对mysqldb的简单封装,调用和使用cursor一致)
mysqldb如果查询时传入的参数是值序列,则sql的paramstyle必须是format,即%s作为占位符;
如果传入的参数是键值序列,则sql的paramstyle必须是pyformat,即%(xxx)s作为占位符;

1.count

    def get_all_topics_count_by_node_slug(self, node_slug):
        sql = 'SELECT COUNT(0) FROM topic LEFT JOIN node ON topic.node_id = node.id WHERE node.slug = %s'
        return self.db.get(sql, node_slug)['COUNT(0)']

2.select(分页)

    def get_all_topics_by_node_slug(self, node_slug, current_page=1, page_size=36, ):
        sql = '''SELECT topic.*,
                author_user.username as author_username,
                author_user.nickname as author_nickname,
                author_user.avatar as author_avatar,
                author_user.uid as author_uid,
                author_user.reputation as author_reputation,
                node.name as node_name,
                node.slug as node_slug,
                last_replied_user.username as last_replied_username,
                last_replied_user.nickname as last_replied_nickname
                FROM topic
                LEFT JOIN user AS author_user ON topic.author_id = author_user.uid
                LEFT JOIN node ON topic.node_id = node.id
                LEFT JOIN user AS last_replied_user ON topic.last_replied_by = last_replied_user.uid
                WHERE node.slug = %s
                ORDER BY last_touched DESC, created DESC, last_replied_time DESC, id DESC
                LIMIT %s, %s'''

        total_count = self.get_all_topics_count_by_node_slug(node_slug)
        total_page = int(math.ceil(total_count / float(page_size)))
        current_page = current_page if current_page <= total_page else total_page
        current_page = current_page if current_page >= 1 else 1
        previous_page = current_page - 1 if current_page > 1 else 1
        next_page = current_page + 1 if current_page < total_page else total_page

        result = {
            "list": self.db.query(sql, node_slug, (current_page-1)*page_size, page_size),
            "page": {
                "prev": previous_page,
                "next": next_page,
                "current": current_page,
                "pages": total_page,
                "total": total_count,
                "size": page_size
            }
        }
        return result

3.insert(任意字段)

    def add_new_topic(self, topic_info):
        sql = 'INSERT INTO topic ('
        sql += ', '.join(topic_info.keys())
        sql += ') VALUES ('
        sql += ', '.join(['%s'] * len(topic_info.keys()))
        sql += ')'
        return self.db.insert(sql, *topic_info.itervalues())

4.update(任意字段,pyformat)

    def update_topic_by_topic_id(self, topic_id, topic_info):
        sql = 'UPDATE topic SET '
        sql += ', '.join(['%s = %%(%s)s' % (k, k) for k in topic_info.keys()])
        sql += ' WHERE id = %(id)s'
        print sql
        return self.db.update(sql, id=topic_id, **topic_info)

python db api正确使用方式

很多人在用Python DB API时会用以下方式拼接sql

cmd = "update people set name='%s' where id='%s'" % (name, id) curs.execute(cmd)

然后调用cursor.execute执行,这样容易产生sql注入

正确的方法是使用占位符语法

cmd = "update people set name=%s where id=%s" 
curs.execute(cmd, (name, id))

execute语句在执行时会先对元组(name, id)的值转为字符串,进行转义,

不同的数据库支持不同占位符语法,常见占位符包括以下:
1.’qmark’ Question mark style, e.g. ‘…WHERE name=?’
2.’numeric’ Numeric, positional style, e.g. ‘…WHERE name=:1’ ‘named’
3.’named’ Named style, e.g. ‘…WHERE name=:name’
4.’format’ ANSI C printf format codes, e.g. ‘…WHERE name=%s’
5.’pyformat’ Python extended format codes, e.g. ‘…WHERE name=%(name)s’
注意pyformat后的s

常见数据库python链接库实现的默认paramstyle

>>>import MySQLdb; 
print MySQLdb.paramstyle 
format 
>>> import psycopg2; 
>>>print psycopg2.paramstyle 
pyformat
>>> import sqlite3; 
print sqlite3.paramstyle 
qmark

如果你在使用MySQL 或 PostgreSQL, 可以用%s(即使是数字或者非字符)

更全的关于python防止sql注入的资料下载sqlinjection-120205200846-phpapp01

检查安装的Python是否支持UCS-4

>>> import sys
>>> print sys.maxunicode

当用--enable-unicode=ucs4编译安装时,输出的是1114111;
当用--enable-unicode=ucs2编译安装时,输出的是65535.