Android自定义控件仿QQ编辑和选取圆形头像
程序员文章站
2024-03-05 17:36:01
android大家都有很多需要用户上传头像的需求,有的是选方形,有的是圆角矩形,有的是圆形。
首先我们要做一个处理图片的自定义控件,把传入的图片,经过用户选择区域,处理成...
android大家都有很多需要用户上传头像的需求,有的是选方形,有的是圆角矩形,有的是圆形。
首先我们要做一个处理图片的自定义控件,把传入的图片,经过用户选择区域,处理成一定的形状。
有的app是通过在图片上画一个矩形区域表示选中的内容,有的则是通过双指放大缩小,拖动图片来选取图片。圆形头像,还是改变图片比较好
圆形区域可调节大小。
这个自定义view的图像部分分为三个,背景图片,半透明蒙层,和亮色区域……还是直接贴代码得了
package com.example.jjj.widget; import android.content.context; import android.graphics.bitmap; import android.graphics.canvas; import android.graphics.color; import android.graphics.paint; import android.graphics.porterduff.mode; import android.graphics.porterduffxfermode; import android.graphics.rect; import android.graphics.rectf; import android.util.attributeset; import android.util.log; import android.view.motionevent; import android.view.view; public class roundeditimageview extends view { private bitmap bitmap; rectf clipbounds, dst, src; paint clearpaint; // 控件宽高 private int w, h; // 选区半径 private float radius = 150f; // 圆形选区的边界 private rectf circlebounds; // 最大放大倍数 private float max_scale = 2.0f; // 双指的距离 private float distance; private float x0, y0; private boolean doublepoint; public roundeditimageview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(); } public roundeditimageview(context context, attributeset attrs) { super(context, attrs); init(); } public roundeditimageview(context context) { super(context); init(); } private void init() { clearpaint = new paint(paint.anti_alias_flag); clearpaint.setcolor(color.gray); clearpaint.setxfermode(new porterduffxfermode(mode.clear)); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); if (bitmap != null) { canvas.drawbitmap(bitmap, null, dst, null);//每次invalidate通过改变dst达到缩放平移的目的 } // 保存图层,以免清除时清除了bitmap int count = canvas.savelayer(clipbounds, null, canvas.all_save_flag); canvas.drawcolor(0x80000000); canvas.drawcircle(w / 2, h / 2, radius, clearpaint);// 清除半透明黑色,留下一个透明圆 canvas.restoretocount(count); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); } @override protected void onsizechanged(int w, int h, int oldw, int oldh) { super.onsizechanged(w, h, oldw, oldh); this.w = w; this.h = h; // 记录view所占的矩形 clipbounds = new rectf(0, 0, w, h); float l, r, t, b; if (bitmap != null) { // 判断长宽比,当长宽比太长会太宽是,以fitcenter的方式初始化图片 if (w / (float) h > bitmap.getwidth() / (float) bitmap.getheight()) { // 图片太高 float w_ = h * bitmap.getwidth() / (float) bitmap.getheight(); l = w / 2f - w_ / 2f; r = w / 2f + w_ / 2f; t = 0; b = h; } else { // 图片太长,或跟view一样长 float h_ = w * bitmap.getheight() / (float) bitmap.getwidth(); l = 0; r = w; t = h / 2f - h_ / 2f; b = h / 2f + h_ / 2f; } dst = new rectf(l, t, r, b);// 这个矩形用来变换 src = new rectf(l, t, r, b);// 这个矩形仅为保存第一次的状态 max_scale = math.max(max_scale, bitmap.getwidth() / src.width()); } circlebounds = new rectf(w / 2 - radius, h / 2 - radius, w / 2 + radius, h / 2 + radius); } public void setimagebitmap(bitmap bitmap) { this.bitmap = bitmap; invalidate(); } @override public boolean dispatchtouchevent(motionevent e) { if (e.getpointercount() > 2) {// 不接受多于两指的事件 return false; } else if (e.getpointercount() == 2) { doublepoint = true;// 标志位,记录两指事件处理后,抬起一只手也不处理拖动 handledoublemove(e); } else { // 处理单指的拖动 switch (e.getaction()) { case motionevent.action_down: x0 = e.getx(); y0 = e.gety(); break; case motionevent.action_move: if (doublepoint) { break; } float x = e.getx(); float y = e.gety(); float w = dst.width(); float h = dst.height(); // 不允许拖过圆形区域,不能使圆形区域内空白 dst.left += x - x0; if (dst.left > circlebounds.left) { dst.left = circlebounds.left; } else if (dst.left < circlebounds.right - w) { dst.left = circlebounds.right - w; } dst.right = dst.left + w; // 不允许拖过圆形区域,不能使圆形区域内空白 dst.top += y - y0; if (dst.top > circlebounds.top) { dst.top = circlebounds.top; } else if (dst.top < circlebounds.bottom - h) { dst.top = circlebounds.bottom - h; } dst.bottom = dst.top + h; x0 = x; y0 = y; invalidate(); break; case motionevent.action_up: doublepoint = false;// 恢复标志位 break; } } return true; } // 处理双指事件 private void handledoublemove(motionevent e) { switch (e.getaction() & motionevent.action_mask) { case motionevent.action_pointer_down: distance = sqrt(e); log.d("px", "down:distance=" + distance); break; case motionevent.action_move: scale(e); break; case motionevent.action_up: break; default: break; } } private void scale(motionevent e) { float dis = sqrt(e); // 以双指中心作为图片缩放的支点 float px = e.getx(0) / 2f + e.getx(1) / 2f; float py = e.gety(0) / 2f + e.gety(1) / 2f; float scale = dis / distance; log.d("px", "move:distance=" + dis + ",scale to" + scale); float w = dst.width(); float h = dst.height(); if (w * scale < radius * 2 || h * scale < radius * 2 || w * scale > src.width() * max_scale) { // 无法缩小到比选区还小,或到达最大倍数 return; } // 把dst区域放大scale倍 dst.left = (dst.left - px) * scale + px; dst.right = (dst.right - px) * scale + px; dst.top = (dst.top - py) * scale + py; dst.bottom = (dst.bottom - py) * scale + py; // 缩放同样不允许使圆形区域空白 if (dst.left > circlebounds.left) { dst.left = circlebounds.left; dst.right = dst.left + w * scale; } else if (dst.right < circlebounds.right) { dst.right = circlebounds.right; dst.left = dst.right - w * scale; } if (dst.top > circlebounds.top) { dst.top = circlebounds.top; dst.bottom = dst.top + h * scale; } else if (dst.bottom < circlebounds.bottom) { dst.bottom = circlebounds.bottom; dst.top = dst.bottom - h * scale; } invalidate(); distance = dis; } private float sqrt(motionevent e) { return (float) math.sqrt((e.getx(0) - e.getx(1)) * (e.getx(0) - e.getx(1)) + (e.gety(0) - e.gety(1)) * (e.gety(0) - e.gety(1))); } // 生成目前选区指定大小的圆形bitmap public bitmap extractbitmap(int width) { bitmap outbitmap = bitmap.createbitmap(width, width, bitmap.config.argb_8888); canvas canvas = new canvas(outbitmap); paint p = new paint(paint.anti_alias_flag); p.setcolor(color.gray); canvas.drawcircle(width / 2, width / 2, width / 2, p); float scale = dst.width() / bitmap.getwidth(); int w = (int) (circlebounds.width() / scale); int l = (int) ((circlebounds.left - dst.left) / scale); int r = l + w; int t = (int) ((circlebounds.top - dst.top) / scale); int b = t + w; rect resrect = new rect(l, t, r, b); paint paint = new paint(); paint.setxfermode(new porterduffxfermode(mode.src_in)); canvas.drawbitmap(bitmap, resrect, canvas.getclipbounds(), paint); return outbitmap; } }
activity中用法
@override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_select_header); roundeditimageview imageview = (roundeditimageview) findviewbyid(r.id.roundeditimageview1); bitmap = bitmapfactory.decodefile(imagepath); imageview.setimagebitmap(bitmap); } @override public void onclick(view v) { //生成一个300*300的当前亮圆形中的图片 bitmap result = imageview.extractbitmap(300); //压缩成png fileoutputstream out = new fileoutputstream(new file(filepath)); result.compress(bitmap.compressformat.png, 100, out); //上传与显示 ... }
需求是模仿qq的,本人不太会讲解,做着玩玩。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。