序
- 此Demo單純實(shí)現(xiàn)自定義框的部分
- 初入自定義的伙伴可此來(lái)一觀芽世,應(yīng)有助益挚赊。
- 虛心務(wù)實(shí)、共勉共進(jìn)济瓢。
目錄
簡(jiǎn)介
-
思路分析(理論指導(dǎo)實(shí)踐荠割。不管代碼,從邏輯上先分析,邏輯通透后蔑鹦,在逐步實(shí)現(xiàn)編碼夺克。)
首先,終極目標(biāo)嚎朽,要做什么铺纽,最終的樣子,肯定要爛熟哟忍,畫(huà)貓畫(huà)狗狡门,先定論(這里,我們要使用自定義控件知識(shí)锅很,編寫一個(gè)可手勢(shì)控制的矩形框)
-
其次其馏,目標(biāo)確定了,然而不能一蹴而就,一口吃不成胖子,就需要拆分目標(biāo)胰挑。針對(duì)我們的目標(biāo)怎栽,一個(gè)手勢(shì)控制的矩形框,可拆分如下↓
可控制的意思是,手勢(shì)移動(dòng)、手勢(shì)縮放。
a.點(diǎn)擊框內(nèi)抖僵,拖拽,移動(dòng)矩形缘揪。(此處衍生出兩個(gè)問(wèn)題耍群,1.怎么知道點(diǎn)擊焦點(diǎn)在矩形內(nèi)。2.手勢(shì)移動(dòng)時(shí)找筝,矩形怎么跟隨移動(dòng)蹈垢。)b. 點(diǎn)擊邊框線,拖拽袖裕,單邊縮放矩形(此處衍生出兩個(gè)問(wèn)題曹抬,1.怎么知道點(diǎn)擊焦點(diǎn)在邊框線上。2.手勢(shì)拖拽時(shí)急鳄,矩形怎么單邊縮放谤民。)
c. 點(diǎn)擊邊角,拖拽疾宏,雙邊縮放矩形(此處衍生出兩個(gè)問(wèn)題张足,1.怎么知道點(diǎn)擊焦點(diǎn)在邊角上。2.手勢(shì)拖拽時(shí)坎藐,矩形怎么雙邊縮放为牍。)
最后,理解以上,方向即正確了碉咆,細(xì)節(jié)也明確了抖韩,實(shí)現(xiàn)起來(lái),相信已不是難事吟逝。
-
好帽蝶,接下來(lái)赦肋,我們針對(duì)每一個(gè)細(xì)節(jié)問(wèn)題块攒,逐一擊破。
a .移動(dòng)縮放判斷
矩形怎么移動(dòng)?
1. 矩形是怎么繪制到界面上的佃乘,矩形的位置大小怎么確認(rèn)囱井。經(jīng)了解,一般用坐標(biāo)點(diǎn)確認(rèn)趣避,四個(gè)點(diǎn)(A庞呕、B、C程帕、D)住练,四對(duì)坐標(biāo),分別確認(rèn)矩形的四個(gè)頂點(diǎn)愁拭。當(dāng)然讲逛。函數(shù)中,作為形參的坐標(biāo)點(diǎn)岭埠,事實(shí)上只需要左上點(diǎn)坐標(biāo)盏混,和右下點(diǎn)坐標(biāo)即可。即惜论,兩點(diǎn)確定一個(gè)矩形许赃。如圖,矩形S由點(diǎn)A和點(diǎn)D確認(rèn)馆类。2. 矩形移動(dòng)的本質(zhì)到底是什么混聊。從上面我們能知道,矩形的位置大小皆由一對(duì)坐標(biāo)確認(rèn)乾巧,所以句喜,只要矩形的坐標(biāo)發(fā)生改變,矩形的位置大小也就相應(yīng)改變了卧抗。因而藤滥,移動(dòng)的本質(zhì),就是坐標(biāo)點(diǎn)的變化社裆。
3. 坐標(biāo)點(diǎn)怎么變化拙绊,手勢(shì)點(diǎn)擊屏幕,移動(dòng),自然标沪,手指和屏幕接觸的點(diǎn)也有坐標(biāo)榄攀,而矩形需要跟隨手指移動(dòng),所以金句,只需要檩赢,實(shí)時(shí)獲取手指在屏幕上的當(dāng)前的坐標(biāo)點(diǎn)與在屏幕上的上一次坐標(biāo)點(diǎn)的差值,然后违寞,矩形的左上(A)贞瞒、右下(D)兩點(diǎn)坐標(biāo)分別減去或加上這個(gè)插值,重繪趁曼,即可军浆。如圖,矩形S移動(dòng)至S'的位置挡闰,A點(diǎn)到A'的坐標(biāo)變化是這樣的乒融,我們知道,android的坐標(biāo)系摄悯,原點(diǎn)在左上角赞季,X坐標(biāo),往右為正(增 )奢驯,向左為負(fù)(減)申钩,Y坐標(biāo),向下為正(增 )叨橱,上移為負(fù)(減 )典蜕,遂,A'的X坐標(biāo)=A的X坐標(biāo)+AE'的長(zhǎng)度罗洗。A'的Y坐標(biāo)=A的Y坐標(biāo)-E'A'的長(zhǎng)度愉舔,D到D'依葫蘆畫(huà)瓢。
4. 矩形移動(dòng)的過(guò)程就是不斷計(jì)算重繪的過(guò)程伙菜,每一次移動(dòng)(只要達(dá)到系統(tǒng)認(rèn)為的移動(dòng)最小值)都會(huì)根據(jù)手勢(shì)位置去計(jì)算新矩形的位置(A'和D'的位置)
1. 單邊縮放轩缤,顧名思義,即贩绕,矩形的一邊( 寬或高)的長(zhǎng)度發(fā)生變化火的,變長(zhǎng)或縮短的過(guò)程。如圖淑倾,即是矩形S(ABDC)到矩形S'(A'B'C'D')的過(guò)程馏鹤。我們知道,矩形的位置大小由一對(duì)坐標(biāo)點(diǎn)確定(點(diǎn)A和點(diǎn)D)娇哆,所以湃累,不管如何去單邊縮放勃救,本質(zhì)就是改變這兩點(diǎn)的坐標(biāo),如圖治力,我們發(fā)現(xiàn)D點(diǎn)的坐標(biāo)不變蒙秒,A點(diǎn)坐標(biāo)只改變X值 Y不變,而X值的改變大小就是AA'的長(zhǎng)度宵统。所以晕讲,我們單邊縮放的思路是,實(shí)時(shí)獲取手指在屏幕上的當(dāng)前的坐標(biāo)點(diǎn)與在屏幕上的上一次坐標(biāo)點(diǎn)的X或Y的差值马澈,然后點(diǎn)A或點(diǎn)D的X或Y實(shí)時(shí)加上或減去這個(gè)插值瓢省,重繪即可。2.注意箭券,單邊縮放净捅,只需改變其中一點(diǎn)的X或者Y值就可以了疑枯。同時(shí)改變X辩块、Y值,就是雙邊縮放了
1. 雙邊縮放荆永,顧名思義废亭,即,同矩形的兩邊(一寬和一高)的長(zhǎng)度發(fā)生變化具钥,變成或縮短的過(guò)程豆村,如圖,矩形S到矩形S’骂删,就是一次雙邊縮放掌动,矩形S的邊AB和邊AC同時(shí)改變至邊A'B'和A‘C'位置。本質(zhì)就是點(diǎn)A的X宁玫,Y坐標(biāo)同時(shí)改變粗恢,就是雙邊縮放了,所以我們雙邊縮放的思路是欧瘪,實(shí)時(shí)獲取手指在屏幕上的當(dāng)前的坐標(biāo)點(diǎn)與在屏幕上的上一次坐標(biāo)點(diǎn)的X和Y的差值眷射,然后點(diǎn)A或點(diǎn)D的X和Y實(shí)時(shí)加上或減去這個(gè)插值,重繪即可佛掖。2.注意妖碉,雙邊縮放,需要同時(shí)改變X和Y坐標(biāo)才行芥被。
b. 焦點(diǎn)判斷
怎么知道點(diǎn)擊焦點(diǎn)在矩形內(nèi)?
怎么知道點(diǎn)擊焦點(diǎn)在邊框線上?
怎么知道點(diǎn)擊焦點(diǎn)在邊角上?
-
準(zhǔn)備工作
- 畫(huà)筆
android里面欧宜,畫(huà)筆的關(guān)鍵字是Piant
,構(gòu)造初始化即可(new Paint
),一般作為參數(shù)傳入畫(huà)布(Canvas)中拴魄,繪制的顏色冗茸、透明度猛拴、是否有邊框、邊框粗細(xì)等蚀狰、都由畫(huà)筆確認(rèn)愉昆,可以重復(fù)使用。為了代碼的易于理解麻蹋,這里每種對(duì)象都定義一只對(duì)應(yīng)的畫(huà)筆跛溉,如下
/*畫(huà)筆*/ /*邊框畫(huà)筆*/private Paint mRectPaint; /*邊角線畫(huà)筆*/private Paint mCornerPaint; /*文字畫(huà)筆*/private Paint mTextPaint; /*測(cè)繪線畫(huà)筆*/private Paint mMappingLinePaint;
- 畫(huà)布
Android里面,畫(huà)布的關(guān)鍵字是Canvas
,一般自定義控件的onDraw
方法里持有一個(gè)扮授,可直接使用芳室。這里的畫(huà)布,并非真正意義上的畫(huà)布刹勃,它代表 一組繪制規(guī)則(是點(diǎn)堪侯、還是圓、弧形荔仁、還是圖伍宦,以及繪制的位置、大小等)乏梁,對(duì)應(yīng)的規(guī)則有對(duì)應(yīng)的函數(shù)次洼,調(diào)用傳參即可,圖形就是根據(jù)這組規(guī)則繪制到屏幕上的
@Override protected void onDraw(Canvas mCanvas) { super.onDraw(mCanvas); }
- 矩形繪制函數(shù)
canvas.drawRect(float left, float top, float right, float bottom, Paint paint)
left:矩形左上角以父控件左上角為原點(diǎn)的x坐標(biāo)
top: 矩形左上角以父控件左上角為原點(diǎn)的y坐標(biāo)
right: 矩形右下角以父控件左上角為原點(diǎn)的x坐標(biāo)
bottom: 矩形右下角以父控件左上角為原點(diǎn)的y坐標(biāo)
paint: 畫(huà)筆
/**繪制矩形*/ canvas.drawRect(mRect_FourCorner_coordinate[0][0], mRect_FourCorner_coordinate[0][1], mRect_FourCorner_coordinate[3][0], mRect_FourCorner_coordinate[3][1], mRectPaint);
- 畫(huà)筆
源碼分析
-
變量(注釋應(yīng)該夠是淺顯了)
/*控件寬*/private float mViewWidth; /*控件高*/private float mViewHeight; /*上下文*/private Context mContext; /*自定框相關(guān)*/ /*矩形邊長(zhǎng)*/private float mRectLength = 200f * mDensity; /*矩形四個(gè)邊角坐標(biāo)*/private float[][] mRect_FourCorner_coordinate; /*邊角線長(zhǎng)度*/private float mCornerLength = 30f * mDensity; /*邊角線偏移值*/private float mCornerOffset = 5 * mDensity; /*0-不動(dòng) 1-拖動(dòng) 2-邊角縮放 3-邊框縮放*/ /*矩形操作狀態(tài)*/private int mOperatingStatus = 0; /*0-左 1-上 2-右 3-下*/ /*邊框線點(diǎn)擊-操作狀態(tài)*/private int mBorderlineStatus = -1; /*0-左上角 1-左下角 2-右上角 3-右下角*/ /*邊角點(diǎn)擊-操作狀態(tài)*/private int mCornerStatus = -1; /*是否繪制坐標(biāo)點(diǎn)*/private boolean mIsDrawPonit; /*是否繪制測(cè)繪線*/private boolean mISDrawMapLine; /*是否開(kāi)啟動(dòng)畫(huà)*/private boolean mIsOpenAnima;
-
函數(shù)
-
onSizeChanged
:在這獲取父控件的寬遇骑、高卖毁,用于計(jì)算矩形的四個(gè)坐標(biāo)點(diǎn)。四個(gè)坐標(biāo)點(diǎn)用一個(gè)浮點(diǎn)型二維數(shù)組表示落萎,也在此處初始化亥啦。后面繪制邊角、測(cè)繪線都使用此二維數(shù)組坐標(biāo)值练链,矩形的移動(dòng)翔脱、縮放,也是是通過(guò)改變此二維數(shù)組的元素值來(lái)變化的兑宇。/** * 獲取控件寬碍侦、高 */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); /*獲取控件寬高*/ mViewWidth = getWidth(); mViewHeight = getHeight(); /*初始化矩形四邊角坐標(biāo)*/ mRect_FourCorner_coordinate = new float[][]{ {(mViewWidth - mRectLength) / 2, (mViewHeight - mRectLength) / 2},//左上角 {(mViewWidth - mRectLength) / 2, (mViewHeight + mRectLength) / 2},//左下角 {(mViewWidth + mRectLength) / 2, (mViewHeight - mRectLength) / 2},//右上角 {(mViewWidth + mRectLength) / 2, (mViewHeight + mRectLength) / 2},//右下角 }; }
-
toolDrawCorner
:這個(gè)方法,用以繪制矩形的四個(gè)邊角隶糕,繪制邊角使用canvas.drawLine
方法瓷产,本質(zhì)是畫(huà)線,通過(guò)改變畫(huà)筆的粗細(xì)枚驻,達(dá)到邊角矩形的呈現(xiàn)效果 濒旦。/** * 繪制邊角 */ private void toolDrawCorner(Canvas canvas) { /*繪制邊角*/ /*左上-橫*/ canvas.drawLine(mRect_FourCorner_coordinate[0][0] - mCornerOffset, mRect_FourCorner_coordinate[0][1] , mRect_FourCorner_coordinate[0][0] + mCornerLength, mRect_FourCorner_coordinate[0][1], mCornerPaint); /*左上-豎*/ canvas.drawLine(mRect_FourCorner_coordinate[0][0], mRect_FourCorner_coordinate[0][1] - mCornerOffset , mRect_FourCorner_coordinate[0][0], mRect_FourCorner_coordinate[0][1] + mCornerLength, mCornerPaint); /*左下-橫*/ canvas.drawLine(mRect_FourCorner_coordinate[1][0] - mCornerOffset, mRect_FourCorner_coordinate[1][1] , mRect_FourCorner_coordinate[1][0] + mCornerLength, mRect_FourCorner_coordinate[1][1], mCornerPaint); /*左上下-豎*/ canvas.drawLine(mRect_FourCorner_coordinate[1][0], mRect_FourCorner_coordinate[1][1] - mCornerLength , mRect_FourCorner_coordinate[1][0], mRect_FourCorner_coordinate[1][1] + mCornerOffset, mCornerPaint); /*右上-橫*/ canvas.drawLine(mRect_FourCorner_coordinate[2][0] - mCornerLength, mRect_FourCorner_coordinate[2][1] , mRect_FourCorner_coordinate[2][0] + mCornerOffset, mRect_FourCorner_coordinate[2][1], mCornerPaint); /*右上-豎*/ canvas.drawLine(mRect_FourCorner_coordinate[2][0], mRect_FourCorner_coordinate[2][1] - mCornerOffset , mRect_FourCorner_coordinate[2][0], mRect_FourCorner_coordinate[2][1] + mCornerLength, mCornerPaint); /*右下-橫*/ canvas.drawLine(mRect_FourCorner_coordinate[3][0] - mCornerLength, mRect_FourCorner_coordinate[3][1] , mRect_FourCorner_coordinate[3][0] + mCornerOffset, mRect_FourCorner_coordinate[3][1], mCornerPaint); /*右下-豎*/ canvas.drawLine(mRect_FourCorner_coordinate[3][0], mRect_FourCorner_coordinate[3][1] - mCornerLength , mRect_FourCorner_coordinate[3][0], mRect_FourCorner_coordinate[3][1] + mCornerOffset, mCornerPaint); }
-
toolDrawMapLine
:這個(gè)方法,用以繪制測(cè)繪線條再登。/** * 繪制測(cè)繪線 */ private void toolDrawMapLine(Canvas canvas) { /*繪制橫線*/ /*繪制第一根線-位于矩形框的3分之一處*/ canvas.drawLine(mRect_FourCorner_coordinate[0][0] , mRect_FourCorner_coordinate[0][1] + (mRect_FourCorner_coordinate[1][1] - mRect_FourCorner_coordinate[0][1]) / 3 , mRect_FourCorner_coordinate[2][0] , mRect_FourCorner_coordinate[0][1] + (mRect_FourCorner_coordinate[1][1] - mRect_FourCorner_coordinate[0][1]) / 3 , mMappingLinePaint); /*繪制第二根線-位于矩形框的3分之二處*/ canvas.drawLine(mRect_FourCorner_coordinate[0][0] , mRect_FourCorner_coordinate[0][1] + (mRect_FourCorner_coordinate[1][1] - mRect_FourCorner_coordinate[0][1]) / 3 * 2 , mRect_FourCorner_coordinate[2][0] , mRect_FourCorner_coordinate[0][1] + (mRect_FourCorner_coordinate[1][1] - mRect_FourCorner_coordinate[0][1]) / 3 * 2 , mMappingLinePaint); /*繪制豎線*/ /*繪制第一根線-位于矩形框的3分之一處*/ canvas.drawLine(mRect_FourCorner_coordinate[0][0] + (mRect_FourCorner_coordinate[2][0] - mRect_FourCorner_coordinate[0][0]) / 3 , mRect_FourCorner_coordinate[0][1] , mRect_FourCorner_coordinate[0][0] + (mRect_FourCorner_coordinate[2][0] - mRect_FourCorner_coordinate[0][0]) / 3 , mRect_FourCorner_coordinate[1][1] , mMappingLinePaint); /*繪制第二根線-位于矩形框的3分之二處*/ canvas.drawLine(mRect_FourCorner_coordinate[0][0] + (mRect_FourCorner_coordinate[2][0] - mRect_FourCorner_coordinate[0][0]) / 3 * 2 , mRect_FourCorner_coordinate[0][1] , mRect_FourCorner_coordinate[0][0] + (mRect_FourCorner_coordinate[2][0] - mRect_FourCorner_coordinate[0][0]) / 3 * 2 , mRect_FourCorner_coordinate[1][1] , mMappingLinePaint); }
-
總結(jié)
- 以上
跋
- 初次撰文尔邓,篇幅冗余晾剖,廢話頗多。
- 以上梯嗽,也算是一些心得了
-
可直接看源碼齿尽,注釋詳盡。
源碼鏈接