您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)怎么在Android中使用PhotoView實(shí)現(xiàn)頭像/圓形裁剪控件,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
public class CircleCropView extends View { public final int CIRCLE_MARGIN = 50; public CircleCropView(Context context) { super(context); } public CircleCropView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public CircleCropView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public CircleCropView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); } @RequiresApi(api = Build.VERSION_CODES.O) @Override protected void onDraw(Canvas canvas) { canvas.save(); Path path = new Path(); Rect viewDrawingRect = new Rect(); getDrawingRect(viewDrawingRect); float radius = viewDrawingRect.width() / 2 - CIRCLE_MARGIN; path.addCircle(viewDrawingRect.left + radius + CIRCLE_MARGIN, viewDrawingRect.top + radius + CIRCLE_MARGIN, radius, Path.Direction.CW); Paint outsidePaint = new Paint(); outsidePaint.setAntiAlias(true); outsidePaint.setARGB(151, 0, 0, 0); canvas.clipPath(path, Region.Op.DIFFERENCE); canvas.drawRect(viewDrawingRect, outsidePaint); canvas.restore(); } }
SquarePhotoView只是在PhotoView的基礎(chǔ)上改了長寬,重寫一下onMeasure方法即可:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); }
那么現(xiàn)在最關(guān)鍵的一步,就是從PhotoView獲取當(dāng)前圖片顯示區(qū)域的Drawable或Bitmap了。粗略看了一下PhotoView的函數(shù),并沒有找到能用的(囧)。解決第一個(gè)坑的笨辦法就是,自己動(dòng)手豐衣足食——直接拿原圖的bitmap,然后問PhotoView要當(dāng)前圖片的變形矩陣,自個(gè)兒通過矩陣一步步變形拿到對(duì)應(yīng)的位圖。
思路其實(shí)是沒問題的,然而第二個(gè)坑又出現(xiàn)了(囧)。這里的變形矩陣,我最早百度的結(jié)果是getSuppMatrix,源碼我沒有細(xì)看,但掉坑的過程中據(jù)我觀察,猜測應(yīng)該是對(duì)應(yīng)最新一次的手勢變形結(jié)果(不確定= =,也可能是其他坑綜合導(dǎo)致的錯(cuò)誤結(jié)果)??傊詈笪也榱艘粫?huì)源碼,最終確定用的是getDisplayMatrix。
緊接著是第三個(gè)坑,坑多了就習(xí)慣了。矩陣中的XY位移量,我起初以為是顯示區(qū)域中心相對(duì)于原圖中心的位移,即如果僅有縮放操作的話,位移應(yīng)該為0。但實(shí)際通過特殊位置(例如取四個(gè)頂點(diǎn))的裁剪結(jié)果來看,這里的XY位移量實(shí)際最后顯示區(qū)域左上角的點(diǎn)相對(duì)原點(diǎn)(即原圖左上角)的位移,簡單點(diǎn)說,可以把位移量作為最終顯示區(qū)域左上角的坐標(biāo)。
然后我就迎來了第四個(gè)坑(?)。這個(gè)坑現(xiàn)在回頭看其實(shí)是很簡單不應(yīng)該栽進(jìn)去的,然而當(dāng)時(shí)還沒想通的時(shí)候確實(shí)很慌(唉)。這個(gè)坑的問題就出在,Matrix里的值是基于手勢的,也就是說,是基于屏幕像素(換句話說,是基于實(shí)際顯示的圖片)的。而對(duì)位圖進(jìn)行裁剪時(shí),是基于原圖像素的。那么這里還存在一個(gè)為了正常顯示而導(dǎo)致的縮放比例的問題,例如原圖是3000x4000,由于屏幕分辨率是1080*1920,那么實(shí)際顯示時(shí),圖片是縮小了的,這個(gè)比例是9/25。所以在裁剪的過程中,需要把位移量再放大25/9倍進(jìn)行還原。
下面是裁剪部分的關(guān)鍵代碼(最后偷了一下懶,沒有裁圓形,只是用CIrcleImageView顯示):
fun cropImage(){ var degree = ImageUtils.readPictureDegree(imagePath) var bitmap = ImageUtils.getRotatedBitmap(BitmapFactory.decodeFile(imagePath),degree) var width: Int = 0 var startX: Int = 0 var startY: Int = 0 if (bitmap.width < bitmap.height){ startY = (bitmap.height - bitmap.width) / 2 width = bitmap.width }else{ startX = (bitmap.width - bitmap.height) / 2 width = bitmap.height } var matrix = Matrix() photo_preview.getDisplayMatrix(matrix)//獲取變形矩陣,直接取scaleX或translationX沒用 var values = FloatArray(9, {0.0f}) matrix.getValues(values) var expWidth = Math.round(bitmap.width * values[0])//縮放x var expHeight = Math.round(bitmap.height * values[4])//縮放y var bitmap1 = Bitmap.createScaledBitmap(bitmap, expWidth, expHeight, false) val ratio = width * 1.0f / photo_preview.width startX = Math.round(startX * values[0] - values[2] * ratio) startY = Math.round(startY * values[4] - values[5] * ratio) var bitmap2 = Bitmap.createBitmap(bitmap1, startX, startY, width, width, null, false) saveImage(bitmap2) }
這里還有幾個(gè)小坑需要解釋一下:
讀取bitmap時(shí)需要注意一下角度。這個(gè)是我在裁剪本地圖片和網(wǎng)絡(luò)圖片的時(shí)候發(fā)現(xiàn)的,有些是正的有些就是轉(zhuǎn)了90度。每個(gè)手機(jī)也不一定一樣,所以保險(xiǎn)起見,需要從圖片的EXIF信息里面獲取需要旋轉(zhuǎn)的角度,然后再進(jìn)一步處理。
我這里因?yàn)樽罱K顯示的是正方形,而且選的scaleType是centerCrop。所以默認(rèn)就是顯示中間的那一塊。所以裁減時(shí)的原點(diǎn)也需要從正方形的左上角開始。這里是計(jì)算兩種情況下的原點(diǎn)坐標(biāo):
var startX: Int = 0 var startY: Int = 0 if (bitmap.width < bitmap.height){ startY = (bitmap.height - bitmap.width) / 2 width = bitmap.width }else{ startX = (bitmap.width - bitmap.height) / 2 width = bitmap.height }
上述就是小編為大家分享的怎么在Android中使用PhotoView實(shí)現(xiàn)頭像/圓形裁剪控件了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。