HarmonyOS用Matrix实现各种图片ScaleType缩放

想了解更多内容,请访问:

目前成都创新互联公司已为数千家的企业提供了网站建设、域名、网站空间绵阳服务器托管、企业网站设计、工农网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。

和华为官方合作共建的鸿蒙技术社区

https://harmonyos.

本文将从零开始实现一个图片组件,并展示如何使用 Matrix 实现图片的各种 ScaleType 缩放效果。

背景知识:

Matrix 内部通过维护一个 float[9] 的数组来构成 3x3 矩阵的形式,从底层原理来看,所有的变换方法就是更改数组中某个或某几个位置的数值;

Matrix提供了Translate(平移)、Scale(缩放)、Rotate(旋转)、Skew(扭曲)四中变换操作,这四种操作实质上是调用了setValues()方法来设置矩阵数组来达到变换效果。除Translate(平移)外,Scale(缩放)、Rotate(旋转)、Skew(扭曲)都可以围绕一个中心点来进行,如果不指定,在默认情况下是围绕(0, 0)来进行相应的变换的。

Matrix提供的四种操作,每一种都有pre、set、post三种形式。原因是矩阵乘法不满足乘法交换律,因此左乘还是右乘最终的效果都不一样。我们可以把Matrix变换想象成一个队列,队列里面包含了若干个变换操作,队列中每个操作按照先后顺序操作变换目标完成变换,pre相当于向队首增加一个操作,post相当于向队尾增加一个操作,set相当于清空当前队列重新设置。

鸿蒙 Image 组件没有对外公开 setMatrix 接口,如果项目中需要通过 setMatrix 来控制图片显示,可参考本文,自己实现自绘式 Image 组件。

创建图片组件

先创建一个组件类 MyImageComponent,因为是从零开始,所以我们从 Component 继承,包含以下三个属性:

 
 
 
 
  1. public class MyImageComponent extends Component implements Component.DrawTask {   
  2.     // 图片资源,从 src 属性读取
  3.     private Element element;
  4.     // 读取 scaleType 属性
  5.     private ScaleType scaleType = ScaleType.fitCenter;
  6.     // 用于实现 scaleType 的 Matrix 
  7.     private final Matrix matrix = new Matrix();
  8.     
  9.     // ...其他构造函数略
  10.     public MyImageComponent(Context context, AttrSet attrSet, int resId) {
  11.         super(context, attrSet, resId);
  12.         init(attrSet);
  13.     }
  14. }

然后执行初始化流程:

 
 
 
 
  1. // 初始化,包括读取属性,根据 scaleType 设置 matrix,添加绘制方法     
  2.    private void init(AttrSet attrSet) {
  3.        readAttrSet(attrSet);      
  4.        dealScaleType();
  5.        addDrawTask(this);
  6.    }
  7.    // 读取 xml 属性,包括 src 和 scaleType
  8.    private void readAttrSet(AttrSet attrSet) {
  9.        element = attrSet.getAttr("src").get().getElement();
  10.        
  11.        if (attrSet.getAttr("scaleType").isPresent()) {
  12.            String scaleTypeString = attrSet.getAttr("scaleType").get().getStringValue();
  13.            scaleType = Utils.getEnumFromString(ScaleType.class, scaleTypeString, ScaleType.center);
  14.        }
  15.    }
  16.    // 根据 scaleType 属性实现对应的缩放效果
  17.    private void dealScaleType() {
  18.        switch (scaleType) {
  19.            default:
  20.            case fitCenter:
  21.                fitCenter();
  22.                break;
  23.            case center:
  24.                center();
  25.                break;
  26.            case fitXY:
  27.                fitXY();
  28.                break;
  29.            case fitStart:
  30.                fitStart();
  31.                break;
  32.            case fitEnd:
  33.                fitEnd();
  34.                break;
  35.            case centerCrop:
  36.                centerCrop();
  37.                break;
  38.            case centerInside:
  39.                centerInside();
  40.                break;
  41.        }
  42.    }
  43.    private int getDisplayWidth() {
  44.        return getWidth() - getPaddingLeft() - getPaddingRight();
  45.    }
  46.  
  47.    private int getDisplayHeight() {
  48.        return getHeight() - getPaddingLeft() - getPaddingRight();
  49.    }
  50. private int getElementWidth() {
  51.        return element.getWidth();
  52.    }
  53.    private int getElementHeight() {
  54.        return element.getHeight();
  55.    }

ScaleType 效果展示和对应源码

以下逐个展示各种 ScaleType 效果及其实现代码,为方便对比不同大小的图片的 ScaleType 差异,准备了一大一小两张图片。

用于预览的 xml 布局代码如下:

 
 
 
 
  1.     xmlns:ohos="http://schemas.huawei.com/res/ohos"
  2.     xmlns:app="http://schemas.ohos.com/apk/res-auto"
  3.     ohos:height="match_parent"
  4.     ohos:width="match_parent"
  5.     ohos:alignment="center"
  6.     ohos:orientation="vertical">
  7.     
  8.         ohos:width="200vp"
  9.         ohos:height="200vp"
  10.         ohos:background_element="#4682B4"
  11.         ohos:margin="6vp"
  12.         app:src="$media:big"
  13.         app:scaleType="center"
  14.         />
  15.     
  16.         ohos:width="200vp"
  17.         ohos:height="200vp"
  18.         ohos:margin="6vp"
  19.         ohos:background_element="#4682B4"
  20.         app:src="$media:small"
  21.         app:scaleType="center"
  22.         />

以下是各种 scaleType 的效果和源码:

center

 
 
 
 
  1. /**
  2.     * 图片居中显示在组件中,不对图片进行缩放
  3.     */
  4.    private void center() {
  5.        float wTranslate = (getDisplayWidth() - getElementWidth()) * 0.5f;
  6.        float hTranslate = (getDisplayHeight() - getElementHeight()) * 0.5f;
  7.        matrix.postTranslate(wTranslate, hTranslate);
  8.    }

fitCenter

保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满组件,缩放后的图片居中显示在组件中。

 
 
 
 
  1. private void fitCenter() {
  2.         float wPercent = (float)getDisplayWidth() / (float)getElementWidth();
  3.         float hPercent = (float)getDisplayHeight() / (float)getElementHeight();
  4.         float minPercent = Math.min(wPercent, hPercent);
  5.         float targetWidth = minPercent * getElementWidth();
  6.         float targetHeight = minPercent * getElementHeight();
  7.         float wTranslate = (getDisplayWidth() - targetWidth) * 0.5f;
  8.         float hTranslate = (getDisplayHeight() - targetHeight) * 0.5f;
  9.         matrix.setScale(minPercent, minPercent);
  10.         matrix.postTranslate(wTranslate, hTranslate);
  11.     }

fitXY

对X和Y方向独立缩放,直到图片铺满组件。这种方式可能会改变图片原本的宽高比,导致图片拉伸变形。

 
 
 
 
  1. private void fitXY(){
  2.        float wPercent = (float)getDisplayWidth() / (float)getElementWidth();
  3.        float hPercent = (float)getDisplayHeight() / (float)getElementHeight();
  4.        matrix.setScale(wPercent, hPercent);
  5.    }

fitStart

保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满组件,缩放后的图片与组件左上角对齐进行显示。

 
 
 
 
  1. private void fitStart() {
  2.       float wPercent = (float)getDisplayWidth() / (float)getElementWidth();
  3.       float hPercent = (float)getDisplayHeight() / (float)getElementHeight();
  4.       float minPercent = Math.min(wPercent, hPercent);
  5.       
  6.       matrix.setScale(minPercent, minPercent);
  7.   }

fitEnd

保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满组件,缩放后的图片与组件右下角对齐进行显示。

 
 
 
 
  1. private void fitEnd() {
  2.      float wPercent = (float)getDisplayWidth() / (float)getElementWidth();
  3.      float hPercent = (float)getDisplayHeight() / (float)getElementHeight();
  4.      float minPercent = Math.min(wPercent, hPercent);
  5.      float targetWidth = minPercent * getElementWidth();
  6.      float targetHeight = minPercent * getElementHeight();
  7.      float wTranslate = getDisplayWidth() - targetWidth;
  8.      float hTranslate = getDisplayHeight() - targetHeight;
  9.      matrix.setScale(minPercent, minPercent);
  10.      matrix.postTranslate(wTranslate, hTranslate);
  11.  }

centerCrop

保持图片的宽高比,等比例对图片进行X和Y方向缩放,直到每个方向都大于等于组件对应的尺寸,缩放后的图片居中显示在组件中,超出部分做裁剪处理。

 
 
 
 
  1. private void centerCrop() {
  2.       float scale;
  3.       float dx;
  4.       float dy;
  5.       if (getElementWidth() * getDisplayHeight() > getDisplayWidth() * getElementHeight()) {
  6.           scale = (float)getDisplayHeight() / (float)getElementHeight();
  7.           dx = (getDisplayWidth() - getElementWidth() * scale) * 0.5f;
  8.           dy = 0f;
  9.       } else {
  10.           scale = (float)getDisplayWidth() / (float)getElementWidth();
  11.           dx = 0f;
  12.           dy = (getDisplayHeight() - getElementHeight() * scale) * 0.5f;
  13.       }
  14.       matrix.setScale(scale, scale);
  15.       matrix.postTranslate(dx + 0.5f, dy + 0.5f);
  16.   }

centerInside

如果图片宽度<= 组件宽度&&图片高度<= 组件高度,不执行缩放,居中显示在组件中。其余情况按 fitCenter 处理。

 
 
 
 
  1. private void centerInside() {
  2.        if (getElementWidth() <= getDisplayWidth() && getElementHeight() <= getElementHeight()){
  3.            float wTranslate = (getDisplayWidth() - getElementWidth()) * 0.5f;
  4.            float hTranslate = (getDisplayHeight() - getElementHeight()) * 0.5f;            
  5.            matrix.setTranslate(wTranslate, hTranslate);
  6.        } else {
  7.            fitCenter();
  8.        }
  9.    }

绘制图片组件

关键是这句 canvas.concat(matrix)

 
 
 
 
  1. @Override
  2.     public void onDraw(Component component, Canvas canvas) {
  3.         // 以下是关键代码,将 matrix 应用到 canvas
  4.         canvas.concat(matrix);        
  5.         // 将图片绘制到 canvas
  6.         element.drawToCanvas(canvas);
  7.     }

项目地址:my-image-component

想了解更多内容,请访问:

和华为官方合作共建的鸿蒙技术社区

https://harmonyos.

分享标题:HarmonyOS用Matrix实现各种图片ScaleType缩放
标题URL:http://www.mswzjz.com/qtweb/news6/202706.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联