如何在Android中使用PhotoView實現(xiàn)頭像/圓形裁剪控件-創(chuàng)新互聯(lián)

這篇文章主要介紹“如何在Android中使用PhotoView實現(xiàn)頭像/圓形裁剪控件”的相關(guān)知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“如何在Android中使用PhotoView實現(xiàn)頭像/圓形裁剪控件”文章能幫助大家解決問題。

創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、網(wǎng)站設(shè)計、外貿(mào)營銷網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的鳳山網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

代碼如下:


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獲取當前圖片顯示區(qū)域的Drawable或Bitmap了。粗略看了一下PhotoView的函數(shù),并沒有找到能用的(囧)。解決第一個坑的笨辦法就是,自己動手豐衣足食——直接拿原圖的bitmap,然后問PhotoView要當前圖片的變形矩陣,自個兒通過矩陣一步步變形拿到對應(yīng)的位圖。

思路其實是沒問題的,然而第二個坑又出現(xiàn)了(囧)。這里的變形矩陣,我最早百度的結(jié)果是getSuppMatrix,源碼我沒有細看,但掉坑的過程中據(jù)我觀察,猜測應(yīng)該是對應(yīng)新一次的手勢變形結(jié)果(不確定= =,也可能是其他坑綜合導致的錯誤結(jié)果)??傊詈笪也榱艘粫创a,最終確定用的是getDisplayMatrix。

緊接著是第三個坑,坑多了就習慣了。矩陣中的XY位移量,我起初以為是顯示區(qū)域中心相對于原圖中心的位移,即如果僅有縮放操作的話,位移應(yīng)該為0。但實際通過特殊位置(例如取四個頂點)的裁剪結(jié)果來看,這里的XY位移量實際最后顯示區(qū)域左上角的點相對原點(即原圖左上角)的位移,簡單點說,可以把位移量作為最終顯示區(qū)域左上角的坐標。

然后我就迎來了第四個坑(?)。這個坑現(xiàn)在回頭看其實是很簡單不應(yīng)該栽進去的,然而當時還沒想通的時候確實很慌(唉)。這個坑的問題就出在,Matrix里的值是基于手勢的,也就是說,是基于屏幕像素(換句話說,是基于實際顯示的圖片)的。而對位圖進行裁剪時,是基于原圖像素的。那么這里還存在一個為了正常顯示而導致的縮放比例的問題,例如原圖是3000x4000,由于屏幕分辨率是1080*1920,那么實際顯示時,圖片是縮小了的,這個比例是9/25。所以在裁剪的過程中,需要把位移量再放大25/9倍進行還原。

下面是裁剪部分的關(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)
 }

這里還有幾個小坑需要解釋一下:

讀取bitmap時需要注意一下角度。這個是我在裁剪本地圖片和網(wǎng)絡(luò)圖片的時候發(fā)現(xiàn)的,有些是正的有些就是轉(zhuǎn)了90度。每個手機也不一定一樣,所以保險起見,需要從圖片的EXIF信息里面獲取需要旋轉(zhuǎn)的角度,然后再進一步處理。
我這里因為最終顯示的是正方形,而且選的scaleType是centerCrop。所以默認就是顯示中間的那一塊。所以裁減時的原點也需要從正方形的左上角開始。這里是計算兩種情況下的原點坐標:


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
 }

關(guān)于“如何在Android中使用PhotoView實現(xiàn)頭像/圓形裁剪控件”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。

當前名稱:如何在Android中使用PhotoView實現(xiàn)頭像/圓形裁剪控件-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://bm7419.com/article20/ddjijo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供搜索引擎優(yōu)化、商城網(wǎng)站、網(wǎng)頁設(shè)計公司、網(wǎng)站導航、小程序開發(fā)品牌網(wǎng)站設(shè)計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

營銷型網(wǎng)站建設(shè)