功能要點(diǎn):
- 根據(jù)控件自身大小計(jì)算合適的透明正方形預(yù)覽區(qū)脓鹃;
- 截取預(yù)覽區(qū)圖像并按照指定的尺寸縮放毡鉴,生成Bitmap對(duì)象刁标。
本文著重介紹上述第1個(gè)要點(diǎn)井厌。
博主又來更新文章啦蚓庭!
關(guān)于ImageView呢,其實(shí)我之前接觸過一些繼承它來實(shí)現(xiàn)一些功能仅仆。比如雙指縮放彪置,單指移動(dòng)之類。而最近工作中又要用到繼承它來實(shí)現(xiàn)某些功能蝇恶。借此機(jī)會(huì)好好整理一下,也分享給更多需要的朋友們惶桐!
使用本系列文章完成的自定義多功能ImageView可以實(shí)現(xiàn)微信中的頭像選擇的照片調(diào)整功能撮弧。而且,微信的圖片調(diào)整界面會(huì)有不流暢的情況出現(xiàn)姚糊。而用本文中的辦法是不會(huì)出現(xiàn)卡頓現(xiàn)象的贿衍。當(dāng)然,這可能是機(jī)器的原因救恨,不同的機(jī)器可能表現(xiàn)不同贸辈。我使用的測試機(jī)是三星的S6。
廢話不多說肠槽,我們來講一下如何繪制中間的透明框擎淤。
思路是這樣的:為了更好的可移植性,首先通過獲取ImageView的尺寸秸仙,獲得ImageView的尺寸嘴拢;然后通過該尺寸計(jì)算出控件中點(diǎn)和合適的正方形邊長,一般是由寬和高其中最短的一者決定的寂纪;最后席吴,將該正方形外的所有部分給一個(gè)半透明的黑色赌结,再畫出正方形的邊緣即可。
獲取控件的高度不是難事孝冒,繼承了ImageView后柬姚,調(diào)用getWidth()和getHeight()方法即可完成寬高的獲取。
獲取控件的中點(diǎn)的方法是首先獲取控件所在位置的起始點(diǎn)庄涡,也就是左上角的x和y的絕對(duì)像素坐標(biāo)點(diǎn)量承。然后與寬度和高度分別相加,就可得到控件的終止點(diǎn)啼染,也就是控件右下角的x和y的絕對(duì)像素坐標(biāo)點(diǎn)宴合。有了這兩個(gè)值,控件的中點(diǎn)就可以確定下來了迹鹅。
下面再定義預(yù)覽框的邊長卦洽。由于這里我們要采用絕對(duì)像素值,因此需要根據(jù)控件的大小動(dòng)態(tài)計(jì)算出預(yù)覽框的大小斜棚。這里我要提醒各位的就是:一個(gè)正方形阀蒂,只要有兩個(gè)完整的x和y軸的組合坐標(biāo),就可以確定該正方形的位置了弟蚀,即對(duì)角坐標(biāo)蚤霞。我們這里計(jì)算左上和右下的位置。
左上角x坐標(biāo)我是采用了中點(diǎn)x坐標(biāo)減控件起點(diǎn)x位置再除以8確定的义钉。換言之昧绣,就是該值是整個(gè)預(yù)覽框距離左邊的距離,而又由于這是一個(gè)正方形捶闸,因此右上角的坐標(biāo)也就同時(shí)確定了(中點(diǎn)坐標(biāo)x減去左上角x坐標(biāo)再乘以2)夜畴。y軸坐標(biāo)也很容易了,只需用中點(diǎn)y坐標(biāo)減去上述兩個(gè)x軸坐標(biāo)之差的二分之一就可以了删壮。由此贪绘,y軸終點(diǎn)的坐標(biāo)也可以計(jì)算出來了,即用起點(diǎn)y軸坐標(biāo)加上兩個(gè)x軸之差坐標(biāo)即可央碟。
特別注意 - 這里有坑
后面我會(huì)把這部分的代碼貼上税灌,個(gè)人私心想,肯定會(huì)有人直接復(fù)制粘貼亿虽,所以……必須提醒一下各位:猶豫項(xiàng)目需求問題菱涤,我這里只考慮了控件高度大于控件寬度的情況,所以洛勉,諸位在復(fù)制粘貼后狸窘,務(wù)必判斷一下寬高的情況,然后分情況討論坯认。
上述問題分別出現(xiàn)在中點(diǎn)和預(yù)覽區(qū)邊距的計(jì)算上翻擒。
如果這個(gè)坑的問題沒看懂氓涣,沒事,試一次就知道了陋气。方法是:不要限制屏幕旋轉(zhuǎn)劳吠,然后整個(gè)屏幕放這樣一個(gè)ImageView,然后倒轉(zhuǎn)屏幕巩趁,看看正方形會(huì)發(fā)生什么變化痒玩。
祝君好運(yùn)!
最后议慰,我們畫正方形的邊緣蠢古,再在其余的部分給定半透明黑色即可。這里就直接放代碼片段了:
畫正方形邊緣:
if (previewEdge != null) {
//上
canvas.drawLine(previewEdge[0], previewEdge[2], previewEdge[1], previewEdge[2], rectPaint);
//左
canvas.drawLine(previewEdge[0], previewEdge[2], previewEdge[0], previewEdge[3], rectPaint);
//下
canvas.drawLine(previewEdge[0], previewEdge[3], previewEdge[1], previewEdge[3], rectPaint);
//右
canvas.drawLine(previewEdge[1], previewEdge[2], previewEdge[1], previewEdge[3], rectPaint);
}
解釋一下:該部分代碼放在重寫的onDraw()中别凹。previewEdge是一個(gè)有4個(gè)int值的數(shù)組草讶,分別代表左上和右下的x和y坐標(biāo)值。稍后貼出計(jì)算部分代碼炉菲。
填充半透明黑色:
//灰色部分
canvas.drawRect(0, 0, previewEdge[0], myLocationEnd[1], rectBgPaint);
canvas.drawRect(previewEdge[0], 0, previewEdge[1], previewEdge[2], rectBgPaint);
canvas.drawRect(previewEdge[1], 0, myLocationEnd[0], myLocationEnd[1], rectBgPaint);
canvas.drawRect(previewEdge[0], previewEdge[3], previewEdge[1], myLocationEnd[1], rectBgPaint);
各種計(jì)算的代碼片:
//獲取控件自身起始點(diǎn)
myLocationStart = new int[2];
getLocationOnScreen(myLocationStart);
//獲取控件自身終止點(diǎn)
myLocationEnd = new int[2];
myLocationEnd[0] = getWidth() + myLocationStart[0];
myLocationEnd[1] = getHeight() + myLocationStart[1];
//計(jì)算控件自身中點(diǎn)
myLocationMid = new int[2];
myLocationMid[0] = (myLocationStart[0] + myLocationEnd[0]) / 2;
myLocationMid[1] = (myLocationStart[1] + myLocationEnd[1]) / 2 - myLocationStart[1];
//設(shè)置中間預(yù)覽框邊框色
rectPaint = new Paint();
rectPaint.setColor(Color.WHITE);
rectPaint.setStrokeWidth(2);
rectBgPaint = new Paint();
rectBgPaint.setColor(getResources().getColor(R.color.photo_adjust_for_avator_bg));
//計(jì)算中間預(yù)覽邊框位置
previewEdge = new int[4];
previewEdge[0] = (myLocationMid[0] - myLocationStart[0]) / 8;
previewEdge[1] = myLocationEnd[0] - previewEdge[0];
previewEdge[2] = myLocationMid[1] - ((previewEdge[1] - previewEdge[0]) / 2);
previewEdge[3] = myLocationMid[1] + ((previewEdge[1] - previewEdge[0]) / 2);
變量的名字都很容易看懂吧堕战,我這里就不詳述了。
最后說一句拍霜,這個(gè)最好自己練習(xí)一下計(jì)算嘱丢,印象深一些。完整的ImageView類代碼將在整個(gè)系列文章的最后一篇中貼出祠饺。希望大家多多支持越驻,謝謝!5劳怠伐谈!