android规范,Android设计规范

Android UI规范是什么

从事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设计规范:6类交互设计规范对比

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的只给出了设计原则,所以,一些是我自己总结的,可能对比的还不够全面,欢迎大家一起讨论。

阿里Android规范-08-Bitmap、Drawable与动画

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()回调

Android和IOS UI规范有什么区别

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自己对比调节字体大小。

Android硬件抽象层模块编写规范

硬件抽象层模块编写规范

硬件抽象层最终都会生成.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中实现。


文章名称:android规范,Android设计规范
URL分享:http://ybzwz.com/article/dscipjd.html