1.xml本质
xml不是必须,布局可以代码写
xml是为了开发者开发布局便利,谷歌给开发者开发糖
xml最终还是会转成代码执行
2.View和ViewGroup关系
⑴View
①View是用户界面一个组件(控件)
②View是一个矩形
③View的职责是绘制和事件处理
⑵ViewGroup
①ViewGroup是一个特殊的View,它继承自View
②ViewGroup可包含其他View(孩子)
③ViewGroup常用layout的基类
④ViewGroup定义了孩子的布局参数(带layout_前缀的属性)
⑶View和ViewGroup的关系
①继承关系
②组合关系
3.自定义View及类型
⑴原生控件:SDK已经有,Google提供
⑵自定义控件: 开发者自己开发的控件,分三种
① 组合式控件:将现有控件进行组合,实现功能更加强大控件;
② 继承现有控件: 对其控件的功能进行拓展;
③ 重写View实现全新的控件
4.下拉选择框
实现步骤:
a.继承布局,重写构造;
b.创建布局xml,加入到自定义控件里面;
c.实现对应的功能.
private void pop() {
ListView view = new ListView(getContext());
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),android.R.layout.simple_list_item_1,list);
view.setAdapter(adapter);
popupWindow = new PopupWindow(view, LinearLayout.LayoutParams.MATCH_PARENT, 500);
popupWindow.setFocusable(true);
popupWindow.setOutsideTouchable(true);
popupWindow.setBackgroundDrawable(new BitmapDrawable());
//相对于父容器的下方
// popupWindow.showAtLocation(et, Gravity.BOTTOM,0,0);
//在给定的控件下方
popupWindow.showAsDropDown(et,0,0);
view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String s=list.get(position);
et.setText(s);
//et光标移动到后面
et.setSelection(s.length());
popupWindow.dismiss();
}
});
}
5.View的绘制流程
⑴Measure测量一个View的大小 (onMeasure)
⑵Layout摆放一个View的位置 (onLayout)
⑶Draw画出View的显示内容 (onDraw)
其中measure是final的,无法重写,虽然layout,draw不是final的,但是也不建议重写该方法。
这三个方法都已经写好了View的逻辑,如果我们想实现自身的逻辑,而又不破坏View的工作流程,可以重写onMeasure、onLayout、onDraw方法。
⑴View的测量(measure)
MeasureSpec类
Android系统给我们提供了一个设计小而强的工具类——— MeasureSpec类
①MeasureSpec描述了父View对子View大小的期望。里面包含了测量模式和大小。
②MeasureSpec类把测量模式和大小组合到一个32位的int型的数值中,其中高2位表示模式,低30位表示大小而在计算中使用位运算的原因是为了提高并优化效率。
③我们可以通过以下方式从MeasureSpec中提取模式和大小,该方法内部是采用位移计算。
也可以通过MeasureSpec的静态方法把大小和模式合成,该方法内部只是简单的相加。
⑵View的布局(layout)
layout()
a. layout方法中接受四个参数,是由父View提供,指定了子View在父View中的左、上、右、下的位置。父View在指定子View的位置时通常会根据子View在measure中测量的大小来决定。
b. 子View的位置通常还受有其他属性左右,例如父View的orientation,gravity,自身的margin等等,特别是RelativeLayout,影响布局的因素非常多。
c. layout方法虽然可以被复写,但是不建议去复写,我们可以直接调用layout方法去确定自身的位置, 而且可以去复写onLayout方法去确定子view的位置
setFrame()
a. setFrame方法是一个隐藏方法,所以作为应用层程序员来说,无法重写该方法。该方法体内部通过比对本次的l、t、r、b四个值与上次是否相同来判断自身的位置和大小是否发生了改变。
b. 如果发生了改变,将会调用invalidate请求重绘。
c. 记录本次的l、t、r、b,用于下次比对。
d. 如果大小发生了变化,onSizeChanged方法,该方法在大多数View中都是空实现,我们可以重写该方法用于监听View大小发生变化的事件,在可以滚动的视图中重载了该方法,用于重新根据大小计算出需要滚动的值,以便显示之前显示的区域。
onLayout()
a. onLayout是ViewGroup用来决定子View摆放位置的,各种布局的差异都在该方法中得到了体现。
b. onLayout比layout多一个参数,changed,该参数是在setFrame通过比对上次的位置得出是否发生了变化,通常该参数没有被使用的意义,因为父View位置和大小不变,并不能代表子View的位置和大小没有发生改变。
⑶View的绘制(draw)
draw()
draw是由ViewRoot的performTraversals方法发起,它将调用DecorView的draw方法,并把成员变量canvas传给给draw方法。而在后面draw遍历中,传递的都是同一个canvas。所以android的绘制是同一个window中的所有View都绘制在同一个画布上。等绘制完成,将会通知WMS把canvas上的内容绘制到屏幕上。自定义View时一般不重写该方法。
onDraw()
a. View用来绘制自身的实现方法,如果我们想要自定义View,通常需要重载该方法。
b. 比如TextView中在该方法中绘制文字、光标和CompoundDrawable,
ImageView中相对简单,只是绘制了图片
//画线
canvas.drawLine(50,50,450,800,paint);
//画圆(cx,cy圆心 radius半径)
canvas.drawCircle(450,450,100,paint);
//画空心圆(cx,cy圆心 radius半径)
canvas.drawCircle(600,600,100,paint1);
//画图片
canvas.drawBitmap(bitmap,250,250,paint);
//画三角形
canvas.drawPath(path,paint);
//裁剪
canvas.clipPath(path);
//画椭圆
canvas.drawOval(150,150,800,500,paint1);
//画扇型
canvas.drawArc(rectF,0,80,true,paint1);
6.ViewGroup的绘制流程
ViewGroup继承View, ViewGroup的绘制流程遵循View的绘制的流程
⑴ViewGroup的测量
相同点:measure - > onMeasure
不同点:作为一个父容器,有责任去测量孩子,调用孩子measure方法,传入期望
⑵ViewGroup的布局
相同点:layout(ViewGroup父容器发起布局)
不同点:作为一个父容器,有责任去布局孩子,在onLayout方法里面,调用孩子layout方法,指定孩子上下左右的位置
⑶ViewGroup的绘制
相同点:draw -> onDraw
不同点:ViewGroup默认实现dispatchDraw方法去绘制了孩子
⑷getWidth和getMeasuredWidth的区别
a. getMeasuredWidth:获取测量后宽高
b. getWidth:获取布局之后的宽高
7.小球
实现的功能:手指在屏幕上滑动,小球始终跟随手指移动。
public BallView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ball);
paint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, x, y, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
x = event.getX();
y = event.getY();
invalidate();
return true;
}
8.环形进度条
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制环
canvas.drawArc(rectF, aFloat, aFloat1, false, paint);
canvas.drawCircle(cx, cy, radius, circlePaint);
canvas.drawText(string, cx, cy + dy, textpaint);
}
网友评论