Android的官方开发者博客发了一份幻灯片,介绍了一些Android UI设计的小贴士,Roger在这里以看图说话的形式发出来,有兴趣的读者就继续往下翻吧。整个PPT共分5个部分,Part I 翻译的是前两个部分。
作为开发者,为啥我们要关心UI,前面的一堆通通可以忽略掉,直接跳到最后一条。因为好的UI设计可以帮助我们卖出更多拷贝,赚到更多钱。
Don’t:
1>不要照搬你在其它平台的UI设计,应该让用户感觉是在真正使用一个 Android 软件,在你的商标显示和平台整体观感之间做好平衡
2>不要过度使用模态对话框
3>不要使用固定的绝对定位的布局
4>不要使用px单位,使用dp或者为文本使用sp
5> 不要使用太小的字体
Do:
1> 为高分辨率的屏幕创建资源(缩小总比放大好)
2> 需要点击的元素要够大
3> 图标设计遵循 Android 的准则
4> 使用适当的间距(margins, padding)
5> 支持D-pad和trackball导航
6> 正确管理活动(activity)堆栈
7> 正确处理屏幕方向变化
8> 使用主题/样式,尺寸和颜色资源来减少多余的值
9>和视觉交互设计师合作!!!
设计哲学:
1> 干净而不过于简单
2> 关注内容而非修饰
3> 保存一致,让用户容易投入其中,可附加少许变化
4> 使用云端服务(存储和同步用户资料)来加强用户体验
优秀界面的设计准则:
1> 关注用户
2> 显示正确的内容
3> 给予用户适当的回馈
4> 有章可循的行为模式
5> 容忍错误
关注用户:
1> 了解你的用户(年龄,技能,文化,对你的应用的需求,使用的设备,何时何地如何使用设备)
2> ‘用户优先’的设计心态 (用户通常是任务导向的行为模式)
3> 更早,更频繁的由真实用户来测试
显示正确的内容:
1> 最常用的操作需要最快被用户看到并且可用
2> 不太常用的功能可以放到菜单里面
给予用户适当的回馈:
1> 交互式的UI元素最少需要反映出4种不同的状态 (default,disabled,focused,pressed)
2> 保证操作的结果是清晰可见的
3> 多给予用户进度提示,但是不要干扰他们当前的操作
有章可循的行为模式:
1> 行为模式遵循用户的期望(正确的操作活动堆栈,显示用户期望看到的信息和动作)
2> 使用合适的方式来加强功能可见性(可点击的元素就应该看起来是可以点击的)
3> 如果用户完成一项任务需要复杂的操作,重新思考你的设计!!!
容忍错误:
1> 只允许有意义的操作(适当禁用一些按钮)
2> 尽量减少不可回退的操作
3> 允许回退(undo)比使用确定对话框更好(实际上,应该尽量少用确定对话框,它对用户是一种干扰)
如果错误是可能发生的,那它就一定会发生。
设计考量:
1>屏幕的物理尺寸
2>屏幕密度
3> 屏幕的方向(竖向和横向)
4>主要的UI交互方式(触屏还是使用D-pad/trackball)
5>软键盘还是物理键盘
6>了解不同设备之间的相异之处是非常重要的!
7>阅读CDD,学习设备可能差异的地方
8>了解屏幕尺寸和密度分类
第一种:
textView.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);//设置下划线
//getpaint方法中有很多设置text字体的方法
第二种:
textView.setText(Html.fromHtml("<u>我有下划线</u>"));
第三种:在资源文件里实现:
<resources>
<string name="hello"><u>phone: 1390123456</u></string> <string name="app_name">MyLink</string>
</resources>
<resources> <string name="hello"><u>phone: 1390123456</u></string> <string name="app_name">MyLink</string>
</resources>
先看下效果:
[img]
[/img]
[img]
[/img]
[img]
[/img]
[img]
[/img]
工程结构图:
[img]
[/img]
主类:
package com.amaker.list; import android.app.Activity; import android.graphics.Camera; import android.graphics.Matrix; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.AnticipateInterpolator; import android.view.animation.AnticipateOvershootInterpolator; import android.view.animation.BounceInterpolator; import android.view.animation.CycleInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import android.view.animation.OvershootInterpolator; import android.view.animation.Transformation; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; /** * @Title: ListViewAnimationDemoActivity.java * @Package com.xiaoma.listviewanimation.demo * @Description: ListView控件动画学习测试 * @author MZH * * */ public class ListViewAnimationDemoActivity extends Activity implements OnClickListener { private ListView listview; private Button btn; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); init(); } /** * 初始化方法实现 */ private void init() { btn = (Button) findViewById(R.id.button); btn.setOnClickListener(this); String items[] = { "还记得", "那一年", "那一天", "有个人", "爱过我", "洗刷刷", "爱拉拉", "哇吼吼", "咔酷伊", "咔哇伊", "哦吼吼", "小马果"}; listview = (ListView) findViewById(R.id.listview); //适配器我就用最简单的,要用复杂的,大家可以自定义适配器 ArrayAdapter<String> adapter = new ArrayAdapter<String>( getApplicationContext(), android.R.layout.simple_list_item_1, items); listview.setAdapter(adapter); } /** * 布局内所有点击事件监听 */ public void onClick(View v) { // 因为只有一个按钮,小x就直接写个if简单的判断下了,多个老规矩用分支判断 if (v.getId() == R.id.button) { //开始播放ListView动画 startPlayAnimation(); } } /** * 开始播放ListView动画方法实现 */ private void startPlayAnimation() { // ListViewAnimationChange为矩阵控制类 listview.startAnimation(new ListViewAnimationChange()); } /** * @Title: ListViewAnimationChange.java * @Package com.xiaoma.listviewanimation.demo * @Description: ListView控件的矩阵内部控制类 * @author MZH * 在这个地方讲下,要自行控制屏幕矩阵的话必须实现现在两个方法 */ private class ListViewAnimationChange extends Animation { @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { // 将动画播放时间设置为5秒 setDuration(5000); // 设置缩放完成后,效果不消失 setFillAfter(true); // 设置线性插值器,这个地方new出来的对象跟在scale.xml中的插值器没什么区别,也可以用别的 /** * 顺带着讲下在2D动画中常用的插值器吧,小x先给自己及大伙提醒下:插值器,就是告诉Android,播放动画时 * 是从快到慢还是从慢到快,从左到右的旋转还是其它的方式的动画,刚开始很怕这个词,试了下效果,其实不太吓人... * 吼吼,类型如下面的八种,跟scale.xml或alpha.xml中使用的插值器一样的,只是写的形式不一样而已 * */ /** * 所有的插值器都实现Interpolator接口中的 getInterpolation(float input)方法,好奇的朋友 * Ctrl跟进下....只注意一点,插值器不能同时set多个,不然最前面的会被覆盖,即:无效果.. * new AccelerateDecelerateInterpolator(); * new AccelerateInterpolator(); * new CycleInterpolator(1.0f); * new DecelerateInterpolator(); * new AnticipateInterpolator(); * new AnticipateOvershootInterpolator(); * new BounceInterpolator(); * new OvershootInterpolator(); * new LinearInterpolator(); * 与以上几种插值器相对应的方法在xml文件中的使用方式大家可以自动ALT+/试下,换汤不换药 */ //下面是小x试的效果,好奇的朋友们可以打开效果试下,小x不一一解释 // setInterpolator(new LinearInterpolator()); // setInterpolator(new CycleInterpolator(1.0f) ); // setInterpolator(new AccelerateDecelerateInterpolator()); // setInterpolator(new DecelerateInterpolator()); /** * 这两个好玩就选了,这个效果类似于Android 4.0的那个左右摆动..效果可以自己打开注释试下.. * 要用自己效果的可以重新改下矩阵的控制 */ setInterpolator(new AnticipateOvershootInterpolator()); //setInterpolator(new OvershootInterpolator()); super.initialize(width, height, parentWidth, parentHeight); } /** * 这个重写是控制矩阵中关键的一步 * 介绍一个参数:interpolatedTime 安卓系统在模拟动画时会反复的调用这个方法 * 所以这个值是一直变化的,从0-1变化.... * 这个方法就是在某一个时间点上将动画添加到指定的控件上 */ @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); /* * final Matrix matrix = t.getMatrix(); * matrix.setScale(interpolatedTime, interpolatedTime); * matrix.preTranslate(-50f, -50f); matrix.postTranslate(50f, 50f); */ // matrix.setRotate(45f); // matrix.setTranslate(40f,50f); /** * Camera小x犯的错:导相机包...大家注意下就可以了, * 我们应该导入graphics包 */ Camera camera = new Camera(); //取得屏幕矩阵对象 final Matrix matrix = t.getMatrix(); camera.save(); /** * 下面方法中的参数大家自己CTRL跟下,小x不一一解说, * 不跟进的自己改改看下效果就知道是什么意思了.. */ camera.translate(0.0f, 0.0f, (1300 - 1300.0f * interpolatedTime)); camera.rotateY(360 * interpolatedTime); camera.getMatrix(matrix); //设置矩阵播放动画前的位置.原点为:0,0 matrix.preTranslate(-50f, -50f); //设置矩阵播放完动画后的位置 matrix.postTranslate(50f, 50f); camera.restore(); // 如果用了以下的效果,则上面Camera做的矩阵变换将被覆盖 // matrix.setScale(interpolatedTime, interpolatedTime); } } }
alpha
<?xml version="1.0" encoding="utf-8"?> <!-- alpha 这个地方说几句,android:interpolator 大家自行换换别的试下 --> <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/bounce_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="1000" />
list_layout_controller.xml
<?xml version="1.0" encoding="utf-8"?> <!-- 动画控制器,这个文件只是把要添加的动画与我们的动画资源关联起来 下面这个属性来控制控制动画的方向,如:比底部到顶部,或别的... 我们在主布局文件中控件的属性里面使用这个地方的动画控制器 android:animationOrder="reverse" --> <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="30%" android:animationOrder="reverse" android:animation="@anim/scale" />
scale
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator"> <scale android:fromXScale="1" android:toXScale="1" android:fromYScale="0.1" android:toYScale="1.0" android:duration="500" android:pivotX="50%" android:pivotY="50%" /> </set>
translate_scale.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" /> <translate android:fromYDelta="-100%" android:toYDelta="0%" /> </set>
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="播放ListView动画" /> <ListView android:id="@+id/listview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layoutAnimation="@anim/list_layout_controller" android:persistentDrawingCache="animation|scrolling" /> </LinearLayout>
配置文件:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.amaker.list" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name" > <activity android:name=".ListViewAnimationDemoActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>