Android自定义View进阶:基于subsampling-scale-image-view扩展功能

Android自定义View进阶:基于subsampling-scale-image-view扩展功能

【免费下载链接】subsampling-scale-image-view Android library (AAR). Highly configurable, easily extendable deep zoom view for displaying huge images without loss of detail. Perfect for photo galleries, maps, building plans etc. 【免费下载链接】subsampling-scale-image-view 项目地址: https://gitcode.com/gh_mirrors/su/subsampling-scale-image-view

subsampling-scale-image-view是一个专为Android平台设计的高级图片查看库,能够高效显示超大图片而不会出现内存溢出问题。该库支持 pinch 缩放、平移、旋转和动画等功能,并且具有高度的可配置性和可扩展性,非常适合构建照片画廊、地图查看器和建筑平面图等应用场景。项目核心代码位于library/src/main/java/com/davemorrissey/labs/subscaleview/目录,官方使用指南可参考README.md

扩展原理与基础架构

扩展subsampling-scale-image-view的核心在于继承SubsamplingScaleImageView类并重写关键方法。该库的设计遵循开闭原则,允许开发者在不修改原有代码的情况下添加新功能。主要扩展点包括:

  • 绘制扩展:通过重写onDraw()方法添加自定义图形元素
  • 事件扩展:通过实现OnImageEventListener监听图片加载状态变化
  • 交互扩展:通过重写onTouchEvent()添加自定义手势处理

项目提供的示例代码展示了三种典型扩展方式,分别位于sample/src/main/java/com/davemorrissey/labs/subscaleview/test/extension/目录下的ExtensionPinFragmentExtensionCircleFragmentExtensionFreehandFragment

实战案例:实现带标记功能的图片查看器

下面以"在图片上添加可随缩放移动的标记"为例,详细介绍扩展实现过程。

1. 创建自定义View类

首先创建PinView类继承SubsamplingScaleImageView,该类将负责绘制标记图标:

public class PinView extends SubsamplingScaleImageView {
    private final Paint paint = new Paint();
    private final PointF vPin = new PointF();
    private PointF sPin;
    private Bitmap pin;

    public PinView(Context context) {
        this(context, null);
    }

    public PinView(Context context, AttributeSet attr) {
        super(context, attr);
        initialise();
    }

    public void setPin(PointF sPin) {
        this.sPin = sPin;
        initialise();
        invalidate();
    }

    private void initialise() {
        // 初始化标记图标
        float density = getResources().getDisplayMetrics().densityDpi;
        pin = BitmapFactory.decodeResource(this.getResources(), R.drawable.pushpin_blue);
        float w = (density/420f) * pin.getWidth();
        float h = (density/420f) * pin.getHeight();
        pin = Bitmap.createScaledBitmap(pin, (int)w, (int)h, true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 确保图片加载完成后再绘制标记
        if (!isReady()) {
            return;
        }
        paint.setAntiAlias(true);
        if (sPin != null && pin != null) {
            // 将图片坐标系转换为视图坐标系
            sourceToViewCoord(sPin, vPin);
            float vX = vPin.x - (pin.getWidth()/2);
            float vY = vPin.y - pin.getHeight();
            canvas.drawBitmap(pin, vX, vY, paint);
        }
    }
}

关键方法说明:

  • sourceToViewCoord():将图片原始坐标系中的点转换为当前视图坐标系中的点,确保标记随图片缩放和平移保持正确位置
  • isReady():检查图片是否加载完成,避免在图片未准备好时绘制标记

2. 在布局文件中使用自定义View

创建扩展标记功能的布局文件sample/src/main/res/layout/extension_pin_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.davemorrissey.labs.subscaleview.test.extension.views.PinView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <Button
        android:id="@+id/next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="16dp"
        android:background="@drawable/button_standout_pressed"
        android:text="Next"/>

</RelativeLayout>

3. 在Fragment中初始化并使用

创建ExtensionPinFragment类加载图片并设置标记位置:

public class ExtensionPinFragment extends Fragment {
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.extension_pin_fragment, container, false);
        final ExtensionActivity activity = (ExtensionActivity)getActivity();
        if (activity != null) {
            rootView.findViewById(R.id.next).setOnClickListener(v -> activity.next());
        }
        PinView imageView = rootView.findViewById(R.id.imageView);
        imageView.setImage(ImageSource.asset("sanmartino.jpg"));
        // 设置标记在图片坐标系中的位置
        imageView.setPin(new PointF(1602f, 405f));
        return rootView;
    }
}

上述代码通过ImageSource.asset("sanmartino.jpg")加载 assets 目录下的示例图片sample/assets/sanmartino.jpg,并在坐标(1602, 405)处添加标记。

其他扩展案例

除了标记功能,subsampling-scale-image-view还支持多种扩展方式:

圆形标记扩展

CircleView.java演示了如何在图片上绘制可缩放的圆形标记。核心实现是在onDraw()方法中使用canvas.drawCircle()绘制圆形,并通过sourceToViewCoord()方法将原始坐标转换为视图坐标。

自由手绘扩展

FreehandView.java实现了在图片上自由绘制的功能,通过记录触摸轨迹并在onDraw()中重绘实现。该类使用Path对象存储绘制路径,并通过postInvalidate()触发重绘。

扩展功能演示

性能优化建议

在扩展subsampling-scale-image-view时,需要注意以下性能问题:

  1. 避免在onDraw中创建对象:所有Paint、Path等对象应在初始化时创建,避免频繁GC
  2. 合理使用isReady()检查:确保只在图片加载完成后执行绘制操作
  3. 控制绘制复杂度:复杂路径和大量标记应考虑使用缓存或简化算法
  4. 谨慎处理触摸事件:复杂手势识别可能导致性能问题,必要时使用手势识别器

完整的性能优化指南可参考官方文档中的"Advanced configuration"章节。

总结与进阶方向

通过继承SubsamplingScaleImageView并合理利用其提供的坐标转换方法,我们可以轻松扩展出各种高级功能。除了本文介绍的标记和绘制功能外,还可以探索以下进阶方向:

  • 3D模型叠加:结合OpenGL在图片上叠加3D模型
  • 实时测量工具:利用坐标转换实现图片上的尺寸测量
  • AR增强现实:将真实世界物体与图片内容关联

项目提供的示例应用sample/src/main/java/com/davemorrissey/labs/subscaleview/test/包含了更多高级用法,建议开发者下载源码后深入研究。要开始使用该库,可通过Gradle将其添加到项目依赖中,具体方法参见README.md中的"Quick start"部分。

【免费下载链接】subsampling-scale-image-view Android library (AAR). Highly configurable, easily extendable deep zoom view for displaying huge images without loss of detail. Perfect for photo galleries, maps, building plans etc. 【免费下载链接】subsampling-scale-image-view 项目地址: https://gitcode.com/gh_mirrors/su/subsampling-scale-image-view

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值