当前位置: 首页 > news >正文

Android裁剪图片为波浪形或者曲线形的ImageView

如果需要做一个自定义的波浪效果的进度条,裁剪图片,对ImageView的图片进行裁剪,比如下面2张图,如何实现?

高亮

先看下面的效果,看到其实只需要对第一张高亮的图片进行处理即可,灰色状态的作为背景图。

1、实现原理

这里首先想到的是自定义View,在Android中,使用二阶贝塞尔曲线可以实现我们想要的效果,关键的API就是Path的rQuadTo()方法。

        path.reset()path.moveTo(startX, startY)path.quadTo(currentX, currentY, endX, endY)canvas.drawPath(path, curvePaint)

startX和startY,endX和endY为两个固定点,currentX和currentY就是控制点,通过改变控制点的位置来改变二阶贝塞尔曲线的形状。

a点和b点就是固定点,c点是控制点,我们可以改变c点的位置来改变曲线的形状。

在Android中,使用cubicTo来实现三阶贝塞尔。上面的需求方案使用二阶即可实现,三阶的可以自行了解。

2、事例分析

首先可以通过自定义一个贝赛尔曲线来了解一下:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;public class BezierCurveView extends View {private Paint paint;private Path path;public BezierCurveView(Context context) {super(context);init();}public BezierCurveView(Context context, AttributeSet attrs) {super(context, attrs);init();}public BezierCurveView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {paint = new Paint();paint.setColor(Color.BLUE);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(5f);path = new Path();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int height = getHeight();int width = getWidth();float dx = width / 4f;float dy = height / 4f;path.reset();path.moveTo(0, height / 2f); // 起点path.rQuadTo(dx, -dy, 2 * dx, 0f); // 控制点、终点path.rQuadTo(dx, dy, 2 * dx, 0f); // 控制点、终点path.rQuadTo(dx, -dy, 2 * dx, 0f); // 控制点、终点path.rQuadTo(dx, dy, 2 * dx, 0f); // 控制点、终点path.lineTo(width, height);path.lineTo(0f, height);path.close();canvas.drawPath(path, paint);}
}

要使用这个自定义View,你需要在布局文件中引用一下:

<com.example.myapp.BezierCurveViewandroid:layout_width="match_parent"android:layout_height="200dp" />

看下效果:

3、使用贝塞尔裁剪ImageView

1)自定义ImageView

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Path;
import android.util.AttributeSet;import androidx.annotation.Nullable;/*** 图片裁剪为贝赛尔曲线边缘ImageView*/
public class BezierImageView extends androidx.appcompat.widget.AppCompatImageView {private static final String TAG = "ArcImageView";public BezierImageView (Context context) {this(context, null);}public BezierImageView (Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public BezierImageView (Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);path = new Path();}private final Path path;/*** 进度值(0~100),默认100*/private int progress = 100;public void setProgress(int progress) {this.progress = progress;postInvalidate();}@Overrideprotected void onDraw(Canvas canvas) {final int width = getWidth();final int height = getHeight();float dx = width / 4f;float dy = height / 8f;float yOffset = (100 - progress) / 100f * height;float[] p1 = {0f, yOffset};float[] p2 = {dx, -dy};float[] p3 = {2 * dx, 0f};float[] p4 = {dx, dy};float[] p5 = {2 * dx, 0f};float[] p6 = {dx, -dy};float[] p7 = {2 * dx, 0f};float[] p8 = {dx, dy};float[] p9 = {2 * dx, 0f};path.reset();path.moveTo(p1[0], p1[1]);path.rQuadTo(p2[0], p2[1], p3[0], p3[1]);path.rQuadTo(p4[0], p4[1], p5[0], p5[1]);path.rQuadTo(p6[0], p6[1], p7[0], p7[1]);path.rQuadTo(p8[0], p8[1], p9[0], p9[1]);path.lineTo(width, height);path.lineTo(0f, height);path.close();canvas.clipPath(path);super.onDraw(canvas);}
}

2)如何使用?

    <com.....BezierImageView android:id="@+id/bg"android:layout_width="200dp"android:layout_height="200dp"android:layout_centerInParent="true"android:scaleType="fitCenter"android:src="@drawable/bg_cover" />
bg.setProgress(50);

直接调用setProgress()方法,传入要裁剪的百分比即可。

效果如下所示:

4、使用sin()正弦函数实现波浪/曲线效果

基于3中,直接修改onDraw()中的关键代码即可:

@Overrideprotected void onDraw(Canvas canvas) {final int width = getWidth();final int height = getHeight();// 变量描述,可自己调整:// offset:Y轴偏移量// yHeight:可控制Y轴高度(值越小百分比显示越大)// countF:控制波数(越大波数越少)// xOffset:可控制波长幅度(值越大幅度越大,越小越平缓)float offset = 0.1f, yHeight = 1.0f, countF = 60.0f, xOffset = 0.04f;// 方案1:path.moveTo(0, height);for (int i = 0; i < width; i++) {path.lineTo(i, (float) (height * ((yHeight - offset) + Math.sin(i / countF + Math.PI) * xOffset)));}path.lineTo(width, height);path.lineTo(0f, height);path.close();canvas.clipPath(path);super.onDraw(canvas);}

使用sin()函数结合lineTo()方法,同样可以实现波浪曲线效果:

相关文章:

  • C++就业方向
  • Vue——案例01(查询用户)
  • c语言中动态内存管理
  • go中函数与方法的区别与go中关于面向对象理解
  • Bun安装与使用
  • Vant Weapp小程序 van-uploader 文件上传点击无反应,删除无反应
  • Android Q(10)黑暗模式适配的实现
  • A Little Is Enough: Circumventing Defenses For Distributed Learning
  • HTML——1.简介、基础、元素
  • 封装性练习
  • react native hooks 页面出现重绘问题,如何解决
  • 机器视觉系列之【硬件知识】-光源(三)
  • HTML网站的概念
  • 【常见面试题】Golang中,协程数最多可以开多少个?
  • 免费SSL证书和付费SSL证书的区别点
  • .pyc 想到的一些问题
  • CentOS7简单部署NFS
  • happypack两次报错的问题
  • HTTP--网络协议分层,http历史(二)
  • java2019面试题北京
  • Java教程_软件开发基础
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • JS学习笔记——闭包
  • Mac转Windows的拯救指南
  • ng6--错误信息小结(持续更新)
  • ucore操作系统实验笔记 - 重新理解中断
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 翻译--Thinking in React
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 开源SQL-on-Hadoop系统一览
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 码农张的Bug人生 - 见面之礼
  • 如何编写一个可升级的智能合约
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 详解移动APP与web APP的区别
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • #每天一道面试题# 什么是MySQL的回表查询
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (1) caustics\
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (多级缓存)缓存同步
  • (三)docker:Dockerfile构建容器运行jar包
  • (十)T检验-第一部分
  • (转)3D模板阴影原理
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (转载)CentOS查看系统信息|CentOS查看命令
  • ./configure、make、make install 命令
  • .cfg\.dat\.mak(持续补充)
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .NET 读取 JSON格式的数据
  • .NET 药厂业务系统 CPU爆高分析
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .NET/MSBuild 中的发布路径在哪里呢?如何在扩展编译的时候修改发布路径中的文件呢?