十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
从事UI设计行业的朋友都知道,每一张设计稿都是有规范尺寸的,并且IOS的和Android还不同,IOS UI设计规范为375*667 1x的尺寸,那么Android UI规范是什么呢,下面让我们一起来了解一下。
站在用户的角度思考问题,与客户深入沟通,找到庆城网站设计与庆城网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都网站建设、网站建设、企业官网、英文网站、手机端网站、网站推广、国际域名空间、虚拟主机、企业邮箱。业务覆盖庆城地区。
01
在做Android UI设计的时候,画布的尺寸我们一般都是选择360*640 1x,也就是说是选择720*1280这个尺寸。
02
我们从上到下来进行了解,最上边的是状态栏,状态栏的高度是25。
03
在状态栏中肯定就是信号、电源以及时间这些了,每个Android定制系统的摆放样式都不同,这一点不用纠结。
04
状态栏下边就是导航栏了,导航栏起到的是导航作用,高度是45px。
05
导航栏中间一般都是有文字来起到提醒作用的,导航文字的大小一般都是18px。
06
在最下方就是我们的标签栏了,标签栏的作用就是给用户提供切换界面的作用,标签栏的高度为50px。
07
在标签栏中摆放的肯定就是我们的ICON图标了,要注意,图标的切图点击区域不能够小于24px。
08
一些ICON图标的下方还会有文本,这里文本的大小一般就是10或者是11px了,因为范围有限。
特别提示
本文尺寸均为1x。
iOS和Android两个不同的平台,肯定是有很多区别的,下面就从交互的角度,谈谈区别。
以前就读过IOS和Android的规范,但是觉得没啥大用处,因为现在APP为了保持一致性,通常在IOS和Android上的设计是一样的,而且一些小公司只设计IOS的交互原型,因为只要IOS上能用,安卓上肯定没问题,前段时间,和一个人聊,问我它俩的区别,当时一脸懵逼,不知从何说起。毕竟是两个不同的平台,肯定是有很多区别的,下面就从交互的角度,谈谈区别。
一、全局导航
IOS:通常放在底部,方便用户点击
Android:通常放在上面,下面有物理按键,防止误操作。
解析:因为Android比IOS多了物理按键,为了防止误操作,所以只能将全局导航放在上面,但是随着屏幕越来越大,上面是手指无法触及的区域,所以切换起来相对成本较高。
二、二级导航
IOS:通常放返回、上一级标题、标题(居中),操作通常只有一个
Android:通常返回控件、logo、下拉菜单、重要操作、更多操作
解析:IOS显示了上一级的名称,让用户点击返回后,心里有预期,Android放了APP的logo,增加了品牌性,但是就使用来讲,用户不知道点击会回到哪,下拉菜单和更多操作都需要点击才能显示,增加了操作步骤。
三、工具栏
IOS:通常放在最下面,方便操作
Android:放在导航栏里,将重要操作放在外面,其他放在更多里。
解析:IOS将操作都放在底部,区域更大,操作更方便。Android将操作放在了顶部,显得很拥挤,并且还收起了一部分,需要用户查找,但是却节省了空间,让内容显示区更大。
四、提示框
IOS:出现在屏幕中间,可以带图标,可以不带,可以是静态的,也可以是动态的。
Android:不可以带图标,不能是动态的,最多只可以带一个操作按钮,最多只能出现一个提示,不能和低端的悬浮按钮重合。
解析:IOS的设计理念是尽量不打扰用户,只要用户能看见变化,轻易不会出现提示,只有一些用户无法感知时,才会出现提示框,所以可以是动态的,像调节音量。Android的提示要比IOS重一些,因为它可以带一个按钮。
五、警示框
IOS:标题和按钮是必须的,可以有内容和输入
Android:主要有四种:用途、内容、事件、表现。
1、用途包含了标题,内容和事件。
六、手势定义
IOS的手势规定有8种,如下:
解析:IOS只有8种手势,Android有14种,但是很多都不常用,个人感觉IOS的8种已经完全够用了,定义那么多种,用户的学习成本就会提高,而且Android的有些手势并没有定义可以做什么,所以给出这么多手势也没有用。
结语
本文对IOS和Android的规范进行了对比,Android的规范那是相当详细,但是IOS的只给出了设计原则,所以,一些是我自己总结的,可能对比的还不够全面,欢迎大家一起讨论。
1.加载Bitmap图片时,inBitmap选项有什么作用?
【正确】
(1)重复利用内存空间
【错误】
(1)图片压缩
(2)限制清晰度
(3)设置位图信息
2.减小图片占用内存的方法
【正确】
(1)本地png图片预先用TinyPNG压缩
(2)使用inBitmap重复利用内存空间
(3)用RGB_565代替RGB_888
(4)根据实际需要对图片进行缩放
3.关于动画,下列说法
【正确】
(1)在动画结束的回调中,应该判断需要用到的资源是否已经被释放了
(2)应该根据设备情况选择性开启复杂动画。
(3)Activity不可见时,应该及时关闭动画。
【错误】
(1)Animation.AnimationListener#onAnimationEnd()回调可以准确可靠地告知动画结束时机。
4.APK中的png图片,应该怎么处理
【正确】
(1)图片用TinyPNG压缩,以减小包大小
【错误】
(1)尽可能使用原图,避免图片失真
(2)尽可能使用高清大图
(3)为了符合Goole的规范,将同一张图片分别放到drawable-hdpi、drawable-xhdpi、drawable-xxhdpi等目录下
5.以下关于定义一个drawable文件的说法
【正确】
(1)为不同屏幕密度的设备都提供一组drawable
(2)为了精简apk整包大小,在满足需求并且了解清楚用户设备分布的情况的前提下,只支持几种屏幕密度的drawable、比如仅定义xhdpi中的drawable文件
(3)在xhdpi目录下定义live_reward_btn_pressed.png
【错误】
(1)所有drawable文件都放在drawable目录,不区分屏幕密度
(2)在xxxhdpi目录下放置不满足设备屏幕密度的小图
6.使用( )代替RGB_888,在不怎么降低视觉效果的前提下,减少内存占用
【正确】
(1)RGB_565
【错误】
(1)ARGB_8888
(2)ALPHA_8
(3)ARGB_4444
7.不建议使用AnimationDrawable的原因是
【正确】
(1)内存消耗过大
【错误】
(1)动画不流畅
(2)不兼容问题
8.关于RGB_565和RGB_888,以下说法
【正确】
(1)若视觉效果相似,应尽可能使用RGB_565
(2)RGB_888比RGB_565清晰
(3)RGB_565占用内存更少
【错误】
(1)RGB_555比RGB_888清晰
9.使用gif要注册什么
【正确】
(1)gif内存占用更大,需要注意控制内存
(2)需要注意单个gif的大小
(3)注意控制单个页面同时播放的gif个数
【错误】
(1)和普通图片一样,没有太多特殊
10.关于监听动画结束事件,以下做法
【正确】
(1)使用Handler.postDelay()来实现
(2)使用Animation.AnimationListener#onAnimationEnd()并加超时机制
【错误】
(1)直接使用Animation.AnimationListener#onAnimationEnd()回调
(20使用Animation.AnimationListener#onAnimationStart()回调
UI设计师在根据原型进行设计稿设计的时候,Android和IOS UI规范都是不同的,最好的条件下就会制作两个版本的设计稿来进行开发,下面我们一起来了解一下Android和IOS UI规范的区别。
01
先从设计稿尺寸开始说,Android的设计稿尺寸我们选择的是360*640,而IOS的设计稿尺寸为375*667。
02
从上到下开始了解,最上方的是状态栏,Android状态栏的高度为25px,IOS状态栏的高度为20px。
03
接下来就是导航栏,Android导航栏的高度为45px,IOS导航栏的高度为49px,两个版本中导航文字都是18px。
04
IOS导航栏有一点不同,那就是下方会多1px的分界,一般我们可用描边,或者是用Y=1的阴影来表示。
05
最下边就是标签栏了,Android标签栏的高度为50px,IOS标签栏的高度为49px。
06
IOS的标签也不同,也有向上的1px分界,用Y=-1的阴影或者是描边来表示。
07
在标签栏中肯定就是ICON图标了,Android和IOS的图标点击范围最小都是24px,IOS±4px调整,Android±8px调整。
08
关于设计的时候排版间距的问题,我的习惯是按照8px的倍数来排版,当然你也可以用10px,看个人习惯了。
特别提示
本文尺寸均为1x。
一、android篇
1、android分辨率
Android的多分辨率,一向是设计师和开发者非常头疼的事儿。尽管如此,对于多分辨造成的复杂问题,也是大家要优先解决的。Android支持多种不同的dpi模式:ldpi 、mdpi 、hdpi 、xhdpi 、xxhdpi 、xxxhdpi
注意,ppi、dpi 是密度单位,不是度量单位 :
dpi主要应用于输出,重点是打印设备上;ppi对于设计师应该比较熟悉,photoshop画布的分辨率常设置为72像素/英寸,这个单位其实就是ppi 。尽管概念不同,但是对于移动设备的显示屏,可以看作ppi=dpi 。
ppi的运算方式是:PPI = √(长度像素数² + 宽度像素数²) / 屏幕对角线英寸数。即:长、宽各自平方之和的开方,再除以屏幕对角线的英寸数。
以iphone5为例,其ppi=√(1136px² + 640px²)/4 in=326ppi(视网膜Retina屏)
对于android手机,一个不确切的分法是,720 x 1280 的手机很可能接近 320 dpi (xhdpi模式),480 x 800 的手机很可能接近 240 dpi (hdpi模式),而320 x 480 的手机则很接近 160 dpi(mdpi模式)。
2、单位换算方法
android开发中,文字大小的单位是sp,非文字的尺寸单位用dp,但是我们在设计稿用的单位是px。这些单位如何换算,是设计师、开发者需要了解的关键。
简单理解的话,px(像素)是我们UI设计师在PS里使用的,同时也是手机屏幕上所显示的,dp是开发写layout的时候使用的尺寸单位。
为什么要把sp和dp代替px? 原因是他们不会因为ppi的变化而变化,在相同物理尺寸和不同ppi下,他们呈现的高度大小是相同。也就是说更接近物理呈现,而px则不行。
根据单位换算方法,可总结出:
当运行在mdpi下时,1dp=1px :也就是说设计师在PS里定义一个item高48px,开发就会定义该item高48dp ;
当运行在hdpi模式下时,1dp=1.5px :也就是说设计师在PS里定义一个item高72px,开发就会定义该item高48dp ;
当运行在xhdpi模式下时,1dp=2px :也就是说设计师在PS里定义一个item高96px,开发就会定义该item高48dp ;
当你的app需要适配多个dpi模式的时候,请参考图1的比例进行换算 。
3、设计稿基本元素的尺寸设置
为了适应多分辨率的手机,理想的方式是为每种分辨率做一套设计稿,包括所用到的icon、设计稿标注等。但在实际开发中,这种方法耗时耗力。所以通常会选择折中的方法。
方法一 :在标准基础上(比如xhdpi)开始,然后放大或缩小,以适应到其他尺寸。不足之处是,对于更高分辨率的手机,图标被放大后会导致质量不高。
方法二: 以最高分辨率为基准设计,然后缩小适应到所需的小分辨率上。缺点是,图标等若都最大尺寸,加载时速度慢且耗费流量较多,对于小分辨率的用户也不够好。
结合友盟的分辨率占比数据、也为了方便换算到android开发中的尺寸单位, 推荐设计稿的画布尺寸选用 720X1280 ,分辨率仍旧为72ppi(像素/英寸)。
在android规范中对于导航栏、工具栏等的尺寸没有明确的规定。但根据48dp原则,以及一些主流的android应用的截图分析,总结一下尺寸要求:
状态栏高度 :50 px
导航栏、操作栏高度 :96 px=48dp x 2
主菜单栏高度 :96 px
内容区域高度 :1038 px (1280-50-96-96=1038)
Android最近出的手机都几乎去掉了实体键,把功能键移到了屏幕中,高度也和菜单栏一样为:96 px
4、图标和字体大小(来自官方规范文档)
a、启动图标(home页或app列表页)
整体大小为48 x 48 dp
b、操作栏图标,代表用户在app中可以使用到的最重要的图标
整体大小为32 x 32 dp ,图形实际区域为 24 x 24 dp
c、小图标/场景图标,提供操作或特定项目的状态。
比如gmail app的星型标记、一些内容展开收起用到的向下向上的图标等。整体大小为16 x 16 dp ,图形实际区域为 12 x 12 dp 。
d、通知图标
如果app有通知,要提供一个有新通知时显示在状态栏的通知图标。整体大小为24 x 24 dp ,图形实际区域为 22 x 22 dp 。
注:android规范提供的尺寸单位是dp,若设计稿尺寸设为720 x 1280 ,图标大小需在规范要求的尺寸数字上乘以2。比如操作栏图标32 x 32 dp ,则设计稿上应该是64 x 64 px 。
e、字体大小
Android规范中的要求如下:
前面提到Android开发中的字号单位是sp,而换算关系是 sp*ppi/160 = px 。所以720 x 1280尺寸的设计稿上,字体大小可选择为 24px 、28px 、32px 、36px ,主要根据文字的重要程度来选择,特殊情况下也可能选择更大或更小的字体。
f、其他尺寸要求
通常把48dp作为可触摸的UI元件的标准。
为什么要用48dp呢?一般来说,48dp转化为一个物理尺寸约9毫米。通常建议目标大小为7-10毫米,以方便用户手指能准确并且舒适触摸目标区域 。
如果你设计的元素高和宽至少48dp,你就可以保证:
(1)触摸目标绝不会比建议的最低目标(7mm)小,无论在什么屏幕上显示。
(2)在整体信息密度和触摸目标大小之间取得了一个很好的平衡。
另外,每个UI元素之间的空白通常是8dp 。
二、iOS篇
1、分辨率
iPhone 界面尺寸:
iPad 界面尺寸:1024×768、2048×1536
(以上单位都是像素,至于分辨率一般网页UI和移动UI基本上都只要 72 ppi)
2、单位换算px、pt
这里需要先区分pt、px,pt(磅值)是物理长度单位,指的是72分之一英寸。手机上看来同一大小的字磅值是一样的,但是换算成不同分辨率手机的字号px值不一样。(px=pt*ppi/72)
iPhone在出retina屏(也就是4S)之前的屏幕像素是320x480px,屏幕密度是163ppi,4S的屏幕像素是640x960px,屏幕密度是326ppi,翻了一倍。iPhone5的ppi没有变化,兼容性方面要增加类似首屏画面等程序上的判断。
在iPhone界面上元素的定位、尺寸是通过一个单位point,而非px,屏幕上固定有320x480pt,retina屏两倍的分辨率改变的只是pt和px之间的比例而已,这样就能实现不改变程序,只上传两套图片就兼容两个分辨率。
****在设计的时候并不是每个尺寸都要做一套,尺寸按自己的手机尺寸来设计,比较方便预览效果,一般用 640×960 或者 640×1136 的尺寸设计。其中设计稿的画布分辨率设为默认的72ppi(此时1px=1pt ),所以设计师可以统一采用px为单位。
开发拿到设计稿时,将上面标注的以px为单位的字号大小、图像尺寸除以2,就是非retina屏上的pt值,这样在retina屏上也可以根据此pt值换算对应的px大小,以确保不同的分辨率下有合适的效果。****
3、基本元素的尺寸设置
iPhone的APP界面一般由四个元素组成,分别是:状态栏、导航栏、主菜单栏以及中间的内容区域。
这里取用 640×960 的尺寸设计,那我们就说说在这个尺寸下这些元素的尺寸:
状态栏:就是我们经常说的信号、运营商、电量等显示手机状态的区域,其高度为:40 px
导航栏:显示当前界面的名称,包含相应的功能或者页面间跳转的按钮,其高度为:88 px
主菜单栏:类似于页面的主菜单,提供整个应用的分类内容的快速跳转,其高度为:98 px
内容区域:展示应用提供的相应内容,整个应用中布局变更最为频繁的,其高度为:734 px=960-40-88-98
以上尺寸适用于 iPhone 4、4S,iPhone5/5s 的 640×11136 的尺寸,其实就是中间的内容区域高度增加到:910 px,其他尺寸也同上。
4、常用图像、图标大小(来自官方规范文档)
单位:像素
5、字体大小
iOS交互设计规范文档上,对字体大小没有做严格的数值规定,只提供了一些指导原则:
单位:点pt
– 即便用户选择了最小文字大小,文字也不应小于 22 点。作为对照,正文样式在大字号下使用 34 点字体大小作为默认文字大小设置。
– 通常来说,每一档文字大小设置的字体大小和行间距的差异是 2 点。例外情况是两个标题样式,在最小、小和中等设置时都使用相同字体大小、行间距和字间距。
– 在最小的三种文字大小中,字间距相对宽阔;在最大的三种文字大小中,字间距相对紧密。
– 标题和正文样式使用一样的字体大小。为了将其和正文样式区分,标题样式使用加粗效果。
– 导航控制器中的文字使用和大号的正文样式文字大小(明确来说,是 34 点)。
– 文本通常使用常规体和中等大小,而不是用细体和粗体。
百度用户体验做过的一个小调查:
单位:像素px
还有个方法就是找你觉得好的APP应用,手机截图后放进PS自己对比调节字体大小。
硬件抽象层模块编写规范
硬件抽象层最终都会生成.so文件,放到系统对应的目录中。在系统使用的时候,系统会去对应目录下加载so文件,实现硬件抽象层的功能。因此硬件抽象层的加载过程就是我们使用so的一个接口。先了解加载过程从源头了解抽象层模块儿的编写规范。
1、硬件抽象层加载过程
系统在加载so的过程中,会去两个目录下查找对应id的so文件。这两个目录分别是/system/lib/hw和/vendor/lib/hw。
so文件的名字分为两个部分例如id.prop.so,第一部分是模块id。第二部分是系统prop的值,获取顺序为“ro.hardware”、“ro.producat.board”、“ro.board.platform”、“ro.arch”,如果prop都找不到的话,就用default。(不是找不到prop的值,是找不到prop值对应的so文件)。
负责加载硬件抽象层模块的函数是hw_get_module,所在的文件是/hardware/libhardware/hardware.c如下:
/** Base path of the hal modules */
#if defined(__LP64__)
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#else
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#endif
/**
* There are a set of variant filename for modules. The form of the filename
* is ".variant.so" so for the led module the Dream variants
* of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
*
* led.trout.so
* led.msm7k.so
* led.ARMV6.so
* led.default.so
*/
static const char *variant_keys[] = {
"ro.hardware", /* This goes first so that it can pick up a different
file on the emulator. */
"ro.product.board",
"ro.board.platform",
"ro.arch"
};
static const int HAL_VARIANT_KEYS_COUNT =
(sizeof(variant_keys)/sizeof(variant_keys[0]));
/**
* Load the file defined by the variant and if successful
* return the dlopen handle and the hmi.
* @return 0 = success, !0 = failure.
*/
static int load(const char *id,
const char *path,
const struct hw_module_t **pHmi)
{
int status;
void *handle;
struct hw_module_t *hmi;
/*
* load the symbols resolving undefined symbols before
* dlopen returns. Since RTLD_GLOBAL is not or'd in with
* RTLD_NOW the external symbols will not be global
*/
handle = dlopen(path, RTLD_NOW);
if (handle == NULL) {
char const *err_str = dlerror();
ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
status = -EINVAL;
goto done;
}
/* Get the address of the struct hal_module_info. */
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
hmi = (struct hw_module_t *)dlsym(handle, sym);
if (hmi == NULL) {
ALOGE("load: couldn't find symbol %s", sym);
status = -EINVAL;
goto done;
}
/* Check that the id matches */
if (strcmp(id, hmi-id) != 0) {
ALOGE("load: id=%s != hmi-id=%s", id, hmi-id);
status = -EINVAL;
goto done;
}
hmi-dso = handle;
/* success */
status = 0;
done:
if (status != 0) {
hmi = NULL;
if (handle != NULL) {
dlclose(handle);
handle = NULL;
}
} else {
ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
id, path, *pHmi, handle);
}
*pHmi = hmi;
return status;
}
/*
* Check if a HAL with given name and subname exists, if so return 0, otherwise
* otherwise return negative. On success path will contain the path to the HAL.
*/
static int hw_module_exists(char *path, size_t path_len, const char *name,
const char *subname)
{
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH2, name, subname);
if (access(path, R_OK) == 0)
return 0;
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH1, name, subname);
if (access(path, R_OK) == 0)
return 0;
return -ENOENT;
}
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module)
{
int i;
char prop[PATH_MAX];
char path[PATH_MAX];
char name[PATH_MAX];
char prop_name[PATH_MAX];
if (inst)
snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
else
strlcpy(name, class_id, PATH_MAX);
/*
* Here we rely on the fact that calling dlopen multiple times on
* the same .so will simply increment a refcount (and not load
* a new copy of the library).
* We also assume that dlopen() is thread-safe.
*/
/* First try a property specific to the class and possibly instance */
snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
if (property_get(prop_name, prop, NULL) 0) {
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* Loop through the configuration variants looking for a module */
for (i=0 ; iHAL_VARIANT_KEYS_COUNT; i++) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* Nothing found, try the default */
if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
goto found;
}
return -ENOENT;
found:
/* load the module, if this fails, we're doomed, and we should not try
* to load a different variant. */
return load(class_id, path, module);
}
int hw_get_module(const char *id, const struct hw_module_t **module)
{
return hw_get_module_by_class(id, NULL, module);
}
找到so文件之后,调用方法load方法去加载对应的so文件,并返回hw_module_t结构体。load方法源码在上面程序中。
load方法首先调用dlopen加载对应的so文件到内存中。然后用dlsym方法找到变量HAL_MODULE_INFO_SYM_AS_STR符号对应的地址,这个地址也就是一个hw_module_t结构体,然后从这个结构体中拿出id比对load方法出入的id是否一致,如果是的话表示打开成功。加载过程完成。
HAL_MODULE_INFO_SYM_AS_STR这个符号值为HMI,也就是必须要保证这个符号之后是一个hw_module_t。接下来的规范中有这个要求。
到此,模块加载完成
2、硬件抽象层模块编写规范
硬件抽象层有两个结构体,一个是hw_module_t和hw_device_t,定义在hardware.h中。
首先说一下hw_module_t的编写规范。
1、必须要有一个“自定义硬件抽象层结构体”,且结构体第一个变量类型要为hw_module_t。
2、必须存在一个HARDWARE_MODULE_INFO_TAG的符号,且指向“自定义硬件抽象层结构体”。在加载的时候根据这个符号找到地址,并把地址的转变为hw_module_t,这也是为什么第一条中hw_module_t必须要在第一个的原因。
3、hw_module_t的tag必须为HARDWARE_MODULE_TAG
4、结构体中要有一个方法列表,其中要有一个open方法。用open方法获得hw_device_t
接下来说一下hw_device_t的编写规范
1、必须要有一个“自定义硬件设备结构体”,且结构体第一个变量类型要为hw_device_t。
2、hw_device_t的tag必须为HARDWARE_DEVICE_TAG
3、要有一个close函数指针,来关闭设备
按照上面规范编写的硬件抽象层就可以由系统加载并正确获取到device。具体的应用层逻辑在device中实现。