1. 简单的控件 View
Imageview Button TextView 共同的父类 View;
2. 控件的容器 ViewGroup
一个容器可以存放多个view对象,并且按照定义的规则去排列这些孩子;
RelativeLayout ,LinearLayout 共同的父类是ViewGroup
如下图:
自定义控件:
1.onDraw() 重要的方法,用于画自定义控件的效果;
2.一般把画图所需要的工具如都放在onCreate初始化
new Matrix();
new Paint();
View
View自定义控件下的两个构造方法:
//如果采用的是xml布局资源文件 创建view对象,使用两个参数的构造方法. setContentView(R.layout.activity_main); //代码方式new出来view对象,使用的是一个参数的构造方法. MyView myview = new MyView(this);
ViewGroup
ViewGroup的下的构造方法也与View作用一样;
注意:
在控件显示到界面之前,必须要先去计算孩子的宽高;
上下兼容可以使用ViewPager 导用v4包;
ViewGroup重要方法:
OnMeasure()
都是爹调用孩子,
1.用于测量ViewGroup里面,孩子view的宽度和高度;
2.子类如果需要控制自己大小时复写;
注意:
1.measure()后才可以getMeasuredWidth()
2.如果OnMeasure没有调用super.onMeasure()就需要调用下面这句话:
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
// measure(100,200)//父容器调用孩子的
// 参数:widthMeasureSpec,heightMeasureSpec
// 父容器测量孩子时,会给宽高值进来,让孩子自己按照这个宽高布局
// int mode = MeasureSpec.getMode(widthMeasureSpec);//获得模式
// int size = MeasureSpec.getSize(widthMeasureSpec);//获得size
// widthMeasureSpec:组成
// 由 32位的二进制码组成的:0101010110....
// 头两位表示的是模式:
// 1. UNSPECIFIED : 未指定的
// 2. EXACTLY:精确的
// 3.AT_MOST:最大
// 后面的30位表示的是 大小 :010101--->
onLayout()
1.onMeasure方法对控件测量完后调用,用于控制孩子的显示位置;
2. ViewGroup下的onLayout是用于管理它的孩子的,所以ViewGroup会强制子类去复写;而View是没有孩子的,因此复写它也没用(View下的onLayout是空的,不会);
scrollBy()
从当前位置进行移动,每次移动会参照当前坐标而增量;(移动的是手机窗体)
scrollTo()
参照左上角坐标(0,0)进行移动;每次移动都会根据顶点坐标,下次移动还是会根据顶点坐标(0,0)进行移动;(移动的是手机窗体)
注意:左菜单与主页是不会移动的,每次移动的是手机窗体;
ViewGroup分析图:
实例代码如下:
package com.bobo.viewgroup;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.LinearLayout;
public class MyGroupView extends ViewGroup {
private LinearLayout left;
private LinearLayout middle;
private LinearLayout right;
private int measuredWidth;
private int measuredHeight;
/**
*使用XML配置文件显示界面的时候调用
*/
public MyGroupView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
/**
*使用代码显示界面的时候调用
*/
public MyGroupView(Context context) {
super(context);
initView(context);
}
// 初始化界面
private void initView(Context context) {
// 给出孩子的宽高
left = new LinearLayout(context);
left.setBackgroundColor(Color.BLUE);
left.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
middle = new LinearLayout(context);
middle.setBackgroundColor(Color.RED);
middle.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
right = new LinearLayout(context);
right.setBackgroundColor(Color.GREEN);
right.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
// 添加孩子到ViewGroup
this.addView(left);
this.addView(middle);
this.addView(right);
}
// 显示界面之前一定要去测量孩子的宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 测量孩子的宽高
left.measure(widthMeasureSpec, heightMeasureSpec);
middle.measure(widthMeasureSpec, heightMeasureSpec);
right.measure(widthMeasureSpec, heightMeasureSpec);
// 获取测量后的宽高(注意只有 先measure才可以getMeasuredWidth)
measuredWidth = left.getMeasuredWidth();
measuredHeight = left.getMeasuredHeight();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
// 控制孩子的显示位置
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
left.layout(-measuredWidth, 0, 0, measuredHeight);
middle.layout(0, 0, measuredWidth, measuredHeight);
right.layout(measuredWidth, 0, measuredWidth * 2, measuredHeight);
}
int startX;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
int newX = (int) event.getRawX();
int dx = newX - startX;
// 相对当前位置进行移动
scrollBy(-dx, 0);
// 重新获取当前位置
startX = (int) event.getRawX();
invalidate();//更新
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
}