View绘制

1 View树的绘制流程

measure -> layout -> draw  树形递归遍历

2 measure

ViewGroup.LayoutParams     设定宽高,match_parent, wrap_content
MeasureSpec  32位int,最高两位表示测量模式,后30位表示该模式下的尺寸大小
MeasureSpecMode
EXACTLY  父容器为子视图确定容器的大小
AT_MOST 父容器为子视图指定一个最大尺寸
UNSPECIFIED
measure() -> onMeasure() -> setMeasuredDimension()

3 layout

树形结构递归遍历,位置摆放

4 onDraw

invalidate() 请求系统重新渲染,触发onDraw()
requestLayout()  绘画过程中手动调用该方法,触发onMeasure(), onLayout()
当更新View时,如果尺寸大小位置和内容均发生改变,推荐先调用requestLayout(),再invalidate()


事件分发机制

DecorView是PhoneWindow的内部类,PhoneWindow继承抽象类Window.
Activity -> PhoneWindow -> DecorView = StatusBar + RootView -> ViewGroup -> View
dispatchTouchEvent(VG) -> onInterceptTouchEvent(VG) -> onTouchEvent (V)
Android View相关笔记

ListView
Android View相关笔记

recycleBin机制
recycleBin是AbsListView的内部类
Android View相关笔记

ListView优化

  1. convertView重用,添加ViewHolder
  2. getView少做耗时操作
  3. 三级缓存
  4. 开启硬件加速
  5. 减少半透明元素
    public View getView(.., View covertView, ..) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = LayoutInflator….
                … ...
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag(); 
        }

    }

    class ViewHolder {  // 避免多次findViewById()
        private ImageView image;
        private TextView title;
    }




解决在onCreate()过程中获取View的宽高为0的方法
1.监听draw/layout事件
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
2         @Override
3         public void onGlobalLayout() {
4             mScrollView.post(new Runnable() {
5                 public void run() {
6                     view.getHeight(); //height is ready
7                 }
8             });
9         }
10 });

2.View.post推荐
UI事件队列会按顺序处理事件。在setContentView()被调用后,事件队列中会包含一个要求重新layout的message,所以任何你post到队列中的东西都会在Layout发生变化后执行。
view.post(new Runnable() {
4             @Override
5 public void run() {
6                 view.getHeight(); //height is ready
7             }
8         });
Android View相关笔记



大房子左右滑动,可点击空白区域
HorizontalScrollView
bitmap.getPixel
android:scrollX

UI线程和工作线程中刷新UI
postInvalidate() invalidate()

雾霾不用于多fragment间切换,并及时销毁
mHazeImage.recycle();

自定义控件的属性
<declare-styleable name="ScrollLayout">
    <attr name="defaultScreen" format="integer"/>
    <attr name="customScreen" format="integer"/>
    <attr name="customScreenHeight" format="integer"/>
    <attr name="customScreenScale" format="integer"/>
</declare-styleable>

<com.honeywell.hch.airtouchv2.framework.view.ScrollLayout
    android:id="@+id/control_filter_scroll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    app:customScreen="1"
    app:customScreenHeight="70"
    app:defaultScreen="0>

帧动画
ImageView loadingImageView = (ImageView) findViewById(R.id.enroll_loading_iv);
AnimationDrawable animationDrawable = (AnimationDrawable) loadingImageView.getDrawable();
animationDrawable.start();


<animation-list
    android:oneshot="false">

    <item android:drawable="@drawable/enroll_loading_1" android:duration="1000"></item>
    <item android:drawable="@drawable/enroll_loading_2" android:duration="1000"></item>
    <item android:drawable="@drawable/enroll_loading_3" android:duration="1000"></item>

</animation-list>

属性动画
AnimatorSet popAnimation = new AnimatorSet();
popAnimation.playTogether(ObjectAnimator.ofFloat(view, "alpha", 0, 1), ObjectAnimator
        .ofFloat(view, "translationY", screenHeight - positionY, 0));
popAnimation.setInterpolator(new OvershootInterpolator());
popAnimation.setDuration(mPopUpDuration[index]);
popAnimation.start();

popAnimation.addListener(new Animator.AnimatorListener() {

动态加载View
<LinearLayout
    android:id="@+id/all_group_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <LinearLayout
        android:id="@+id/group_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    </LinearLayout>
    <LinearLayout
        android:id="@+id/un_group_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    </LinearLayout>
</LinearLayout>

// add DIY views to one group
LinearLayout oneGroup = new LinearLayout(this);
oneGroup.setOrientation(LinearLayout.VERTICAL);
AllDeviceGroupTitleView groupTitleView = new AllDeviceGroupTitleView(mContext); // 自定义控件
groupTitleView.setBackgroundResource(R.drawable.all_device_group_bg);
groupTitleView.setGroupName(groupName);
oneGroup.addView(groupTitleView);

// add one group to group list
mGroupLayout = (LinearLayout) findViewById(R.id.group_layout);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams
        (LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.bottomMargin = DensityUtil.dip2px(20);
oneGroup.setLayoutParams(params);
mGroupLayout.addView(oneGroupLayout);   // 注意区分点击Group还是Device

onTouchEvent()/onTouch() /onLongClick()返回true/false问题
返回true表示该事件已消费,不会被传导下去。
返回false表示事件没有完全消费,将继续传递到子控件处理。




相关文章:

  • 2021-05-15
  • 2021-11-28
  • 2021-07-13
  • 2021-06-08
  • 2022-01-01
  • 2021-11-29
  • 2021-09-05
  • 2021-12-29
猜你喜欢
  • 2021-09-29
  • 2021-07-31
  • 2021-08-07
  • 2021-08-04
  • 2021-07-27
  • 2021-08-01
  • 2021-06-17
相关资源
相似解决方案