用户交互设计师 —— 给想法和具体UI设计草图
视觉设计师(美工) —— 实现想法 -> 真正的界面效果图
界面实践 —— 程序员 —— 视觉设计师(编码能力强的)
为何我们界面要用XML?
可以分离,程序员可以不用去管xml的layout,由视觉设计师来实现
WP开发中通用
UI component
一、UI的呈现和布局
1、呈现的两种方式
(1)XML Layout的呈现(最后也会被转换为View界面)
(2)动态编码呈现:动态布局、画动态空间
2、呈现的核心,牢牢把握住onDraw(平面图像Graphic——Canvas&Drawable简单介绍)
我们可以通过hierarchyviewer.bat来查看一下应用的界面层级关系
最根部的是PhoneWindow的DevorView
他下面的LinearLayout包含两个FrameLayout
上面的FrameLayout是默认的应用程序的标题栏(NOTITLE隐藏的那部分)
下面的FrameLayout是用户定义的界面的父界面,用户定义的界面都在这棵树下
我们查看一下PhoneWindow的源码,我们知道PhoneWindow是对Window的一个实现
我们可以看到DecorView是PhoneWindow的一个内部类,也是一个FrameLayout
实际上显示是需要下层的支持的,看下下层是什么样子
最下面是Surface,是一个平滑过渡的类库(机制),称为SurfaceFlinger(界面显示的基础)
需要FrameBuffer驱动的支持,都是在内核里实现的
Skia是2D图形界面的显示引擎(图形显示库),再次基础上封装View、Widget和Canvas等
OpenGL是3D图形界面的显示引擎
二、UI的事件
1、Android界面事件分类
·KeyEvent
·TouchEvent
·TrackableEvent(轨迹球)
2、Android界面事件的出发及分发
(一)事件触发的两种方法
·扩展View的时候回调事件函数(内部)
·注册事件监听器(外部)
(二)时间分发dispatchKeyEvent
(1)KeyEvent分发
·消息发到当前上下文
·Context发到Window
·Window优先发给输入法窗体
·发给rootView(DecorView)
·发给焦点子View
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER){
Log.i("log", "center clicked");
}
// If you handled the event, return true.
// If you want to allow the event to be handled by the next receiver, return false.
return super.onKeyUp(keyCode, event);
}
注意:按钮的点击需要View获得焦点,需要在构造其中获取焦点
setFocusable(true);
setFocusableInTouchMode(true);
(2)touchEvent分发
·从下往上
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
Log.i("log", "on clicked");
} else if (event.getAction() == MotionEvent.ACTION_UP){
if(event.getActionTime() - event.getDownTime() > 3000){
Log.i("log", "long click");
}
}
return super.onTouchEvent(event);
}
对事件进行处理时,两种事件的处理方式不同
·
根据这些,我们就可以判断事件到底应该由Activity处理,还是在View内处理
一定要理解分发和上传的概念
Canvas & Drawable
用Canvas画图
基本的Canvas用法
1、常用的draw**方法
drawRect长方形
drawCircle圆
drawOval椭圆
drawPath路径
drawLine线
drawPoint点
drawText文字
drawColor颜色、背景色
drawBitmap图片
2、clip & matrix
3、save & restore
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.RED);
// drawColor
canvas.drawColor(Color.LTGRAY);
// drawRect
canvas.drawRect(10, 10, 90, 90, paint);
paint.setColor(Color.Black);
// drawText
canvas.drawText("hello", 20, 20, paint);
paint.setColor(Color.BLUE);
paint.setAntiAlias(true); // 抗锯齿
//drawOval
RectF oval = new RectF(20, 20, 120, 120);
canvas.drawOval(oval, paint);
}
变形和裁剪
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Matrix matrix = new Matrix();
matrix.setRotate(15.0f); // 旋转
matrix.setScale(2, 2); // 缩放
canvas.setMatrix(matrix); // 画布被变形
// clip 裁剪
canvas.clipRect(20, 20, 80, 70);
}
如果不想整个画布都旋转,而是旋转某些部件,怎么办
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.RED);
// drawColor
canvas.drawColor(Color.LTGRAY);
// drawRect
canvas.drawRect(10, 10, 90, 90, paint);
canvas.rotate(45.0f); // 画布旋转45度
canvas.save(); // 保存一下画布
paint.setColor(Color.Black);
// drawText
canvas.drawText("hello", 20, 20, paint);
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
//drawOval
RectF oval = new RectF(20, 20, 120, 120);
canvas.drawOval(oval, paint);
canvas.restore(); // 恢复画布
}
了解SurfaceView:双缓存机制
Drawable
常用Drawable
BitmapDrawable,ShapreDrawable,PictureDrawable,LayoutDrawable,……,自定义Drawable
定义和实现Drawable的方法
1、用资源文件中的图片
Android中支持的图片格式:png(推荐),jpg(可接受),gif(不推荐)
public class DrawableView extends View {
BitmapDrawable mBitmapDrawable;
public DrawableView(Context context) {
super(context);
mBitmapDrawable = (BitmapDrawable)getResources().getDrawable(R.drawable.image);
mBitmapDrawable.setBounds(10, 10, 135, 160);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// mBitmapDrawable最终要画到画布上
// 方法1:可以用getBitmap()得到图片
canvas.drawBitmap(mBitmapDrawable.getBitmap(), ...);
// 方法2:可以把canvas画布当做参数传给BitmapDrawable对象
mBitmapDrawable.draw(canvas);
}
}
注意:BitmapDrawable必须设置setBounds属性!!!
例如TransitionDrawable可以将两张图片放到XML文件中,然后使用
res/drawable/transition.xml
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/on" />
<item android:drawable="@drawable/off" />
</transition>
<ImageButton
android:id="@+id/button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/transition" />
ImageButton button = (ImageButton) findViewById(R.id.button);
TransitionDrawable drawable = (TransitionDrawable) button.getDrawable();
drawable.startTransition(500);
3、编码构造,自定义Drawable
Nine-Patch (draw9pathc.bat工具)
Nine-Patch是一个标准的PNG图像,它包括额外的1个像素的边界
你必须保存它为9.png并且保持到工程的res/drawable目录中
如果是从apk解压后得到的*.9.png文件,注意它是已将周围的空白像素去掉了的,
再使用时必须加上
注意:
左边跟顶部的线定义的是伸缩区域,定义哪些图像的像素允许在伸缩时被复制
右边跟底部的线是可选的,定义的是相对位置内的图像,视图内容放在这部分区域内