我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android 仿QQ头像自定义截取功能

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android 仿QQ头像自定义截取功能

看了Android版QQ的自定义头像功能,决定自己实现,随便熟悉下android绘制和图片处理这一块的知识。

先看看效果:

杩欓噷鍐欏浘鐗囨弿杩? title= @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawMask(canvas); } private void drawMask(Canvas canvas) { //画背景颜色 Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas c1 = new Canvas(bitmap); c1.drawARGB(150, 0, 0, 0); Paint strokePaint = new Paint(); strokePaint.setAntiAlias(true); strokePaint.setColor(Color.WHITE); strokePaint.setStyle(Paint.Style.STROKE); strokePaint.setStrokeWidth(STROKE_WIDTH); c1.drawCircle(getWidth() / 2, getHeight() / 2, getRadius(), strokePaint); //画圆 Bitmap circleBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas c2 = new Canvas(circleBitmap); Paint circlePaint = new Paint(); circlePaint.setStyle(Paint.Style.FILL); circlePaint.setColor(Color.RED); circlePaint.setAntiAlias(true); c2.drawCircle(getWidth() / 2, getHeight() / 2, getRadius(), circlePaint); //两个图层合成 Paint paint = new Paint(); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); c1.drawBitmap(circleBitmap, 0, 0, paint); paint.setXfermode(null); canvas.drawBitmap(bitmap, 0, 0, null); }

使用了setXfermode,Mode为DST_OUT,如下图:

杩欓噷鍐欏浘鐗囨弿杩? title= public class ClipPhotoView extends ImageView implements View.OnTouchListener, ScaleGestureDetector.OnScaleGestureListener { private static final String TAG = ClipPhotoView.class.getSimpleName(); //最大缩放比例 private static final float MAX_SCALE = 4.0f; //最小缩放比例 private static float MIN_SCALE = 1.0f; //matrix array private static final float MATRIX_ARR[] = new float[9]; private static final class Mode { // 初始状态 private static final int NONE = 0; //托动 private static final int DRAG = 1; //缩放 private static final int ZOOM = 2; } //当前状态 private int mMode = Mode.NONE; //缩放手势 private ScaleGestureDetector mScaleDetector; //矩阵 private Matrix mMatrix = new Matrix(); //托动时手指按下的点 private PointF mPrevPointF = new PointF(); //截取的圆框的半径 private int mRadius; //第一次 private boolean firstTime = true; public ClipPhotoView(Context context) { this(context, null); } public ClipPhotoView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ClipPhotoView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mScaleDetector = new ScaleGestureDetector(context, this); mRadius = Util.getRadius(getContext()); // 必须设置才能触发 setOnTouchListener(this); setScaleType(ScaleType.MATRIX); } private void init() { Drawable drawable = getDrawable(); if (drawable == null) { //throw new IllegalArgumentException("drawable can not be null"); return; } initPosAndScale(); } private void initPosAndScale() { if (firstTime) { Drawable drawable = getDrawable(); int width = getWidth(); int height = getHeight(); //初始化 int dw = drawable.getIntrinsicWidth(); int dh = drawable.getIntrinsicHeight(); float scaleX = 1.0f; float scaleY = 1.0f; //是否已经做过缩放处理 boolean isScaled = false; if (width < getDiameter()) { scaleX = getDiameter() * 1.0f / width; isScaled = true; } if (height < getDiameter()) { scaleY = getDiameter() * 1.0f / height; isScaled = true; } float scale = Math.max(scaleX, scaleY); if (isScaled) { MIN_SCALE = scale; } else { MIN_SCALE = Math.max((getDiameter() * 1.0f) / dw, getDiameter() * 1.0f / dh) + 0.01f; } Log.d(TAG, "scale=" + scale); mMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2); mMatrix.postTranslate((width - dw) / 2, (height - dh) / 2); setImageMatrix(mMatrix); firstTime = false; } } @Override public boolean onScale(ScaleGestureDetector detector) { float scale = getScale(); float scaleFactor = detector.getScaleFactor(); if ((scale >= MIN_SCALE && scaleFactor > 1.0f) || (scale <= MAX_SCALE && scaleFactor < 1.0f)) { if (scale * scaleFactor <= MIN_SCALE) { scaleFactor = MIN_SCALE / scale; } else if (scale * scaleFactor >= MAX_SCALE) { scaleFactor = MAX_SCALE / scale; } mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); checkTrans(); setImageMatrix(mMatrix); } return true; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { mMode = Mode.ZOOM; return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { mMode = Mode.NONE; } @Override public boolean onTouch(View v, MotionEvent event) { if (getDrawable() == null) { return false; } mScaleDetector.onTouchEvent(event); switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: mMode = Mode.DRAG; mPrevPointF.set(event.getX(), event.getY()); break; case MotionEvent.ACTION_UP: mMode = Mode.NONE; break; case MotionEvent.ACTION_MOVE: if (mMode == Mode.DRAG && event.getPointerCount() == 1) { float x = event.getX(); float y = event.getY(); float dx = event.getX() - mPrevPointF.x; float dy = event.getY() - mPrevPointF.y; RectF rectF = getMatrixRectF(); // 如果宽度小于屏幕宽度,则禁止左右移动 if (rectF.width() <= getDiameter()) { dx = 0; } // 如果高度小雨屏幕高度,则禁止上下移动 if (rectF.height() <= getDiameter()) { dy = 0; } mMatrix.postTranslate(dx, dy); checkTrans(); //边界判断 setImageMatrix(mMatrix); mPrevPointF.set(x, y); } break; } return true; } private void checkTrans() { RectF rect = getMatrixRectF(); float deltaX = 0; float deltaY = 0; int width = getWidth(); int height = getHeight(); int horizontalPadding = (width - getDiameter()) / 2; int verticalPadding = (height - getDiameter()) / 2; // 如果宽或高大于屏幕,则控制范围 ; 这里的0.001是因为精度丢失会产生问题 if (rect.width() + 0.01 >= getDiameter()) { if (rect.left > horizontalPadding) { deltaX = -rect.left + horizontalPadding; } if (rect.right < width - horizontalPadding) { deltaX = width - horizontalPadding - rect.right; } } if (rect.height() + 0.01 >= getDiameter()) { if (rect.top > verticalPadding) { deltaY = -rect.top + verticalPadding; } if (rect.bottom < height - verticalPadding) { deltaY = height - verticalPadding - rect.bottom; } } mMatrix.postTranslate(deltaX, deltaY); } public int getDiameter() { return mRadius * 2; } private float getScale() { return getMatrixValue(Matrix.MSCALE_X); } private float getMatrixValue(int index) { mMatrix.getValues(MATRIX_ARR); return MATRIX_ARR[index]; } private RectF getMatrixRectF() { Matrix matrix = mMatrix; RectF rect = new RectF(); Drawable d = getDrawable(); if (null != d) { rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); matrix.mapRect(rect); } return rect; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); init(); } Bitmap clip() { Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); draw(canvas); int x = (getWidth() - getDiameter()) / 2; int y = (getHeight() - getDiameter()) / 2; return Bitmap.createBitmap(bitmap, x, y, getDiameter(), getDiameter()); } }

缩放和移动使用了Matrix的方法postScale()和postTranslate,要注意控制边界。

截图的代码在clip()方法中,原理:新建一个空白Bitmap,和屏幕一样大的尺寸,然后将当前View绘制的内容复制到到这个Bitmap中,然后截取该Bitmap的一部分。

ClipPhotoLayout代码:


public class ClipPhotoLayout extends FrameLayout {
private ClipPhotoCircleView mCircleView;
private ClipPhotoView mPhotoView;
public ClipPhotoLayout(Context context) {
this(context, null);
}
public ClipPhotoLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ClipPhotoLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mCircleView = new ClipPhotoCircleView(getContext());
mPhotoView = new ClipPhotoView(getContext());
android.view.ViewGroup.LayoutParams lp = new LinearLayout.LayoutParams(
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.MATCH_PARENT);
addView(mPhotoView, lp);
addView(mCircleView, lp);
}
public void setImageDrawable(Drawable drawable) {
mPhotoView.setImageDrawable(drawable);
}
public void setImageDrawable(int resId) {
setImageDrawable(getContext().getDrawable(resId));
}
public Bitmap clipBitmap() {
return mPhotoView.clip();
}
}

测试MainActivity:


public class MainActivity extends Activity {
private ClipPhotoLayout mClipPhotoLayout;
private int[] pictures = {R.drawable.mingren, R.drawable.cute, R.drawable.tuxi};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scale);
setTitle("移动和缩放");
mClipPhotoLayout = (ClipPhotoLayout) findViewById(R.id.clip_layout);
mClipPhotoLayout.setImageDrawable(pictures[0]);
}
public void doClick(View view) {
Bitmap bitmap = mClipPhotoLayout.clipBitmap();
Intent intent = new Intent(this, ResultActivity.class);
intent.putExtra("photo", bitmap);
startActivity(intent);
}
}

MainActivity的布局文件:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.caocong.image.widget.ClipPhotoLayout
android:id="@+id/clip_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="clip" />
</LinearLayout>

以上所述是小编给大家介绍的Android 仿QQ头像自定义截取功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程网网站的支持!

您可能感兴趣的文章:Android Bitmap的截取及状态栏的隐藏和显示功能Android实现bitmap指定区域滑动截取功能android 手机截取长屏实例代码解析Android截取手机屏幕两种实现方案Android实现拍照截取和相册图片截取Android个人中心的头像上传,图片编码及截取实例Android开发获取短信的内容并截取短信Android中截取当前屏幕图片的实例代码Android截取视频帧并转化为Bitmap示例Android截取指定View为图片的实现方法


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android 仿QQ头像自定义截取功能

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android 仿QQ头像自定义截取功能

看了Android版QQ的自定义头像功能,决定自己实现,随便熟悉下android绘制和图片处理这一块的知识。 先看看效果:思路分析: 这个效果可以用两个View来完成,上层View是一个遮盖物,绘制半透明的颜色,中间挖了一个圆;下层的Vie
2022-06-06

Android自定义控件仿QQ编辑和选取圆形头像

android大家都有很多需要用户上传头像的需求,有的是选方形,有的是圆角矩形,有的是圆形。 首先我们要做一个处理图片的自定义控件,把传入的图片,经过用户选择区域,处理成一定的形状。有的app是通过在图片上画一个矩形区域表示选中的内容,有的
2022-06-06

Android自定义View模仿QQ讨论组头像效果

首先来看看我们模仿的效果图,相信对于使用过QQ的人来说都不陌生,效果图如下:在以前的一个项目中,需要实现类似QQ讨论组头像的控件,只是头像数量和布局有一小点不一样:一是最头像数是4个,二是头像数是2个时的布局是横着排的。其实当时GitHub
2023-05-31

Android自定义ListView实现仿QQ可拖拽列表功能

我们大致的思路,其实是这样子的,也是我的设想,我们可以先去实现一个简单的ListView的数据,但是他的Adapter,我们可以用系统封装好的,然后传递进去一个实体类,最后自定义一个listview去操作,所以我们先把准备的工作做好,比如?
2022-06-06

Android仿微信QQ设置图形头像裁剪功能

最近在做毕业设计,想有一个功能和QQ一样可以裁剪头像并设置圆形头像,额,这是设计狮的一种潮流。 而纵观现在主流的APP,只要有用户系统这个功能,这个需求一般都是在(bu)劫(de)难(bu)逃(xue)! 图片裁剪实现方式有两种,一种是利用
2022-06-06

Android自定义gridView仿头条频道拖动管理功能

项目中遇到这样个需求:app的功能导航需要可拖动排序,类似头条中的频道拖动管理。效果如下,gif不是很顺畅,真机会好很多。虽然类似的文章网上搜一下有很多,但写的都不令人满意,注释不清晰,而且动画还不够流畅。经本人整理优化后,拿出来供后续有需
2022-06-06

使用canvas怎么自定义一个头像功能

使用canvas怎么自定义一个头像功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。实现细节:因为你要对图片所在的区域进行截图,所以你得制作一张canvas,盖
2023-06-09

Android 自定义view仿支付宝咻一咻功能

支付宝上有一个咻一咻的功能,就是点击图片后四周有水波纹的这种效果,今天也写一个类似的功能。 效果如下所示:思路: 就是几个圆的半径不断在变大,这个可以使用动画缩放实现,还有透明动画 还有就是这是好几个圆,然后执行的动画有个延迟效果,其实这些
2022-06-06

Android自定义PopupWindow仿点击弹出分享功能

本文实例自定义PopupWindow,点击弹出PopupWindow,背景变暗,仿点击弹出分享功能,供大家参考,具体内容如下注:参照大神代码写的自定义代码package com.duanlian.popupwindowdemo; impo
2022-06-06

Android自定义View仿支付宝输入六位密码功能

跟选择银行卡界面类似,也是用一个PopupWindow,不过输入密码界面是一个自定义view,当输入六位密码完成后用回调在Activity中获取到输入的密码并以Toast显示密码。效果图如下:自定义view布局效果图及代码如下:
2022-06-06

Android自定义View如何实现QQ运动积分转盘抽奖功能

这篇文章主要讲解了Android自定义View如何实现QQ运动积分转盘抽奖功能,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。因为偶尔关注QQ运动, 看到QQ运动的积分抽奖界面比较有意思,所以就尝试用自定义Vie
2023-05-30

Android自定义View模仿虎扑直播界面的打赏按钮功能

前言 作为一个资深篮球爱好者,我经常会用虎扑app看比赛直播,后来注意到文字直播界面右下角加了两个按钮,可以在直播过程中送虎扑币,为自己支持的球队加油。 具体的效果如下图所示:我个人觉得挺好玩的,所以决定自己实现下这个按钮,废话不多说,先看
2022-06-06

Android 自定义ListView实现QQ空间界面(说说内包含图片、视频、点赞、评论、转发功能)

前端时间刚好需要做一个类似于QQ空间的社区分享功能,说说内容包含文字(话题、内容)、视频、图片,还需包含点赞,评论,位置信息等功能。 就采用LIstview做了一个,先来看下效果,GIF太大,CSDN传不了,请移步Gitee连接:GIF效果
2022-06-06

Android编程实现自定义输入法功能示例【输入密码时防止第三方窃取】

本文实例讲述了Android编程实现自定义输入法功能。分享给大家供大家参考,具体如下: 对于Android用户而言,一般都会使用第三方的输入法。可是,在输入密码时(尤其是支付相关的密码),使用第三方输入法有极大的安全隐患。目前很多网银类的A
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录