布局,绘制,触摸反馈
Android framework 处理是从根节点开始,对布局进行measure和draw ,整个View树的绘制流程在ViewRoot.java类的performTraversals()函数展开
performTraversals:
1.是否需要重新计算视图大小measure,2.是否需要重新安置视图的位置layout,3.是否需要重新绘制draw
(measure测量)大小 -->(layout安排)位置 --> (draw绘制)内容
measure 过程传递的两个类
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void layout(int l, int t, int r, int b) {
...省略
boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
...省略
}
onLayout: layoutVertical(l, t, r, b);或者 layoutHorizontal(l, t, r, b);
setChildFrame,遍历子布局
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
/*
// 把 onDraw() 换成了 dispatchDraw()
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
... // 绘制斑点,覆盖在原有的图片上
}
*/
View.draw(Canvas canvas)
ViewGrop没有复写,需要View.draw,但是自定义view一般是用onDraw进行绘制,也可以先进行super.draw进行系统的draw绘制,在进行自定义的onDraw绘制
canvas的绘制:
canvas.drawCircle(3,3,5,p);//画一个圆,(坐标,半径,颜料)Paint:颜色风格都可以,绘制非常关键
canvas.drawBitmap();
canvas.drawPath();
canvas.drawRect();矩形
canvas.drawText();
View.onDraw()
默认空实现自定义需要自己复写方法,自己绘制
dispachDraw
viewGrop对子视图的绘制,自定义的ViewGrop不应该对dispachDraw进行复写
drawChild(cavans,this,drawingTime)
调用了 View 的child.draw(canvas, this,drawingTime)方法,
invalidate
重绘draw树
dispatchDraw()–>drawChild()–>view.draw()
https://blog.csdn.net/u010216743/article/details/77744597
https://blog.csdn.net/u010216743/article/details/77744602
View坐标系
Android的角度与弧度
View绘制机制
一个Activity里最外层包含PhoneWindow,而PhoneWindow里包含DecorView,然后DecorView里包含有TitleView和ContentView,对于ContentView,我们立马就会联想到setContentView()方法有木有,其实这个方法就是设置ContentView的布局
View事件分发
Android动画机制
Canvas类
Path类
View绘制大致可以分为三个流程,分别是measure(测量),layout(布局),draw(绘制),这三者的顺序就是measure(测量)->layout(布局)->draw(绘制)。
listData 是一个list,加载到getApplicationContext这个上下文的 r.layout.xxx布局下
listAdapter = new ListAdapter(getApplicationContext(), listview(r.layout.xxx), listData);
listview.setAdapter(listAdapter);
重点
继承重写 BaseAdapter 类
自定义 ViewHolder 和 convertView 一起完成复用优化工作
addHeaderView()方法:主要是向listView的头部添加布局
addFooterView()方法:主要是向listView的底部添加布局
static class ViewHolder{
TextView textView;
ImageView imageView;
Button button;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(mContext);
ViewHolder holder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item, null);
holder = new ViewHolder();
holder.button = (Button) convertView.findViewById(R.id.button);
holder.textView = (TextView) convertView.findViewById(R.id.textView);
holder.imageView = (ImageView) convertView.findViewById(R.id.imageView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.imageView.setImageResource(R.mipmap.ic_launcher);
holder.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("click","button");
}
});
holder.textView.setText(data[position]);
return convertView;
}
1.3.1 ViewHolder机制
使用ViewHolder,不要在getView方法中写findViewById方法,因为getView方法会执行很多遍,这样也可以节省时间,节约内存。
1.3.2 convertView重用机制
在Adapter中的getView方法中使用ConvertView,即ConvertView的复用,不需要每次都inflate一个View出来,这样既浪费时间,又浪费内存。
1.3.3 三级缓冲/滑动监听事件
1.3.4 使用分页加载,讲真实际开发中,ListView的数据肯定不止几百条,成千上万条数据你不可能一次性加载出来,所以这里需要用到分页加载,一次加载几条或者十几条,但是如果数据量很大的话,像qq,微信这种,如果顺利加载到最后面的话,那么你的list中也会有几万甚至几十万的数据,这样可能也会导致OOM,所以你的数据集List中也不能有那么多数据,所以每加载一页的时候你可以覆盖前一页的数据。
1.3.5 如果数据当中有图片的话,使用第三方库来加载(也就是缓存),如果你的能力强大到能自己维护的话,那也不是不可以。
1.3.6 当你手指在滑动列表的时候,尽可能的不加载图片,这样的话滑动就会更加流畅。
// 第一步:继承重写 RecyclerView.Adapter 和 RecyclerView.ViewHolder
public class AuthorRecyclerAdapter extends RecyclerView.Adapter<AuthorRecyclerAdapter.AuthorViewHolder> {
...
@Override
public AuthorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
...
return viewHolder;
}
@Override
public void onBindViewHolder(AuthorViewHolder holder, int position) {
...
}
@Override
public int getItemCount() {
if (mData == null) {
return 0;
}
return mData.size();
}
class AuthorViewHolder extends RecyclerView.ViewHolder {
...
public AuthorViewHolder(View itemView) {
super(itemView);
...
}
}
}
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerAdapter = new AuthorRecyclerAdapter(mData);
// 第二步:设置布局管理器,控制布局效果
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(RecyclerDemoActivity.this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(linearLayoutManager);
mRecyclerView.setAdapter(mRecyclerAdapter);
ListView只支持列表,支持set空页面
RecyclerView支持三中布局,网格,列表,瀑布,不支持set空页面
结合三星云的,图片和视频的缩略图的加载分析
三星云的Recent的不同区域的Adapter,只是通过设置四个(today,yesterday,7,30,90),这几个Adapter的clear和 set来放入到display中,然后 再把display放入到 driveRecyclerAdapter中,最后recyclerView.set(driveRecyclerAdapter)
动态加载视图,惰性加载,节约内存,提高性能,只加载一次
绘制的时候不会绘制到view树中,代码执行inflate之后才会被添加到视图中,是一个宽高都为0的View,默认Gone,需要SetVisibility或者inflate函数加载设置才能显现,达到延迟效果,提高加载速度
适用范围:网络请求页面失败
第一次加载会把viewStub从父布局中移除,parent.addView()把我们的view加载到父布局Linearlayout中
第二次加载会报错,以为已经移除了,所以不包含viewStub的parent,可以直接findViewById
属性动画
缓速,监听器反馈
运用属性动画的api
imageView.setTranslateX(500),向右移动500