自定義ImageView系列 - 區(qū)域截圖(上)

功能要點(diǎn):

  1. 根據(jù)控件自身大小計(jì)算合適的透明正方形預(yù)覽區(qū)脓鹃;
  2. 截取預(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劳怠伐谈!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市试疙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抠蚣,老刑警劉巖祝旷,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘶窄,居然都是意外死亡怀跛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門柄冲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吻谋,“玉大人,你說我怎么就攤上這事现横±焓埃” “怎么了阁最?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長骇两。 經(jīng)常有香客問我速种,道長,這世上最難降的妖魔是什么低千? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任配阵,我火速辦了婚禮,結(jié)果婚禮上示血,老公的妹妹穿的比我還像新娘棋傍。我一直安慰自己,他們只是感情好难审,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布瘫拣。 她就那樣靜靜地躺著,像睡著了一般剔宪。 火紅的嫁衣襯著肌膚如雪拂铡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天葱绒,我揣著相機(jī)與錄音感帅,去河邊找鬼。 笑死地淀,一個(gè)胖子當(dāng)著我的面吹牛失球,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播帮毁,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼实苞,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了烈疚?” 一聲冷哼從身側(cè)響起黔牵,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爷肝,沒想到半個(gè)月后猾浦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡灯抛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年金赦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片对嚼。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夹抗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纵竖,到底是詐尸還是另有隱情漠烧,我是刑警寧澤杏愤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站沽甥,受9級(jí)特大地震影響声邦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜摆舟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一亥曹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恨诱,春花似錦媳瞪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至厕鹃,卻和暖如春兢仰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剂碴。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工把将, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人忆矛。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓察蹲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親催训。 傳聞我的和親對(duì)象是個(gè)殘疾皇子洽议,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容