系列學習:https://www.gcssloop.com/customview/CustomViewIndex/
一、View的生命週期
https://www.jianshu.com/p/08e6dab7886e
構造View() --> onFinishInflate() --> onAttachedToWindow() --> onMeasure() --> onSizeChanged() --> onLayout() --> onDraw() --> onDetackedFromWindow()
二、Canvas繪圖
https://blog.csdn.net/CrazyMo_/article/details/48931681
1. 理解Canvas類
Canvas持有很多draw開頭的方法,要想繪製一些東西,需要四個基本的元素:
1)一個保存像素的Bitmap
2)一個Canvas 調用drawxxx方法(畫東西到bitmap)
3)要繪製的東西(矩形,路徑,text,bitmap)
4)一個畫筆
所以最終東西會被畫到一個bitmap上,然後才渲染到屏幕上。
https://blog.csdn.net/u010126792/article/details/85158669
2. 構造方法
1)Canvas canvas = new Canvas();
// 構造一個空的canvas,然後利用setBitmap設置一個bitmap,爲canvas指定畫圖的畫布,最終的東西都被繪製在bitmap上
2)Canvas canvas = new Canvas(Bitmap bitmap); //類似空參構造,這裏直接傳入bitmap構造Canvas
3)通過重寫View.onDraw方法,在這個方法裏可以獲得這個View對應的Canvas對象
3. 成員方法
1)繪製DrawXxxx系列(Xxxx代表Arc、Line、Text、RoundRect、Bitmap、Points等
2)得到畫布中的各種對象getXxxx系列(Matrix、Height、width等)
3)保存和恢復畫布(sace、restore)
4. Paint畫筆
1)Paint paint = new Paint();
2)屬性
setAntiAlias(boolean b); //抗鋸齒
setDither(boolean b); // 防抖
5. 一些輔助類
1)矩形區域Rect和RectF
2)Matrix是一個3 x 3的矩陣,他對圖片的處理分爲四個基本類型:
平移變換Translate、縮放變換Scale、旋轉變換Rotate、錯切變換Skew
三、事件分發機制
1. View結構
2. 事件分發、攔截與消費
類型 | 相關方法 | Activity | VIewGroup | View |
---|---|---|---|---|
事件分發 | dispatchTouchEvent | ✔️ | ✔️ | ✔️ |
事件攔截 | onInterceptTouchEvent | ❌ | ✔️ | ❌ |
事件消費 | onTouchEvent | ✔️ | ✔️ | ✔️ |
-
Activity 作爲原始的事件分發者,如果 Activity 攔截了事件會導致整個屏幕都無法響應事件,這肯定不是我們想要的效果。
-
View最爲事件傳遞的最末端,要麼消費掉事件,要麼不處理進行回傳,根本沒必要進行事件攔截。
3. 事件分發流程
http://wuxiaolong.me/2015/12/19/MotionEvent/
https://www.yuque.com/mr.s/rznwxq/pmmegg#c0cbc06f
事件收集之後最先傳遞給 Activity, 然後依次向下傳遞,大致如下:
Activity -> PhoneWindow -> DecorView -> ViewGroup -> ... -> View
這樣的事件分發機制邏輯非常清晰,可是,你是否注意到一個問題?如果最後分發到View,如果這個View也沒有處理事件怎麼辦,就這樣讓事件浪費掉?
當然不會啦,如果沒有任何View消費掉事件,那麼這個事件會按照反方向回傳,最終傳回給Activity,如果最後 Activity 也沒有處理,本次事件纔會被拋棄:
Activity <- PhoneWindow <- DecorView <- ViewGroup <- ... <- View
4. 常見事件 MotionEvent
事件 | 簡介 |
---|---|
ACTION_DOWN | 手指 初次接觸到屏幕 時觸發。 |
ACTION_MOVE | 手指 在屏幕上滑動 時觸發,會會多次觸發。 |
ACTION_UP | 手指 離開屏幕 時觸發。 |
ACTION_CANCEL | 事件 被上層攔截 時觸發。 |
- View的事件的調度順序是 onTouchListener > onTouchEvent > onLongClickListener > onClickListener
- 不論 View 自身是否註冊點擊事件,只要 View 是可點擊的就會消費事件
- 事件是否被消費由返回值決定,true 表示消費,false 表示不消費,與是否使用了事件無關
- ViewGroup 中可能有多個 ChildView 時,將事件分配給包含點擊位置的 ChildView
- ViewGroup 和 ChildView 同時註冊了事件監聽器(onClick等),由 ChildView 消費
- 一次觸摸流程中產生事件應被同一 View 消費,全部接收或者全部拒絕。
- 只要接受 ACTION_DOWN 就意味着接受所有的事件,拒絕 ACTION_DOWN 則不會收到後續內容
- 如果當前正在處理的事件被上層 View 攔截,會收到一個 ACTION_CANCEL,後續事件不會再傳遞過來