• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

陈文管的博客

分享有价值的内容

  • Android
  • Affiliate
  • SEO
  • 前后端
  • 网站建设
  • 自动化
  • 开发资源
  • 关于

Android 航线缩略图简易绘制实现

2024年11月21日发布 | 最近更新于 2024年11月21日

记录下在航线列表要显示航线缩略图预览航线,通过经纬度航线数据绘制生成预览图。项目上要求缩略图要带卫星地图背景,需要通过地图TextureView去截图,此方案就没有在实际项目上应用。

一、实现效果预览

以下是不含地图背景的航线缩略图绘制效果,根据经纬度参数来绘制航线。

二、实现代码

绘制实现类


import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import com.ht.airnavi.core.entity.WayPoint;
import java.util.List;

public class FlightPathDrawer {
    private float padding; // 边距
    private Paint mPaint = new Paint();
    private  Path mPath = new Path();

    public FlightPathDrawer(int color, float padding) {
        this.padding = padding;
        mPaint.setColor(color);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(1);
        mPaint.setAntiAlias(true);
    }

    // 计算最小和最大经纬度,确定航线的边界范围
    private float[] calculateBoundingBox(List<WayPoint> flightPathCoordinates) {
        float minLat = Float.MAX_VALUE, minLon = Float.MAX_VALUE;
        float maxLat = Float.MIN_VALUE, maxLon = Float.MIN_VALUE;

        for (WayPoint loc : flightPathCoordinates) {
            float lat = (float) loc.getLatitude();
            float lon = (float) loc.getLongitude();

            if (lat < minLat) minLat = lat;
            if (lat > maxLat) maxLat = lat;
            if (lon < minLon) minLon = lon;
            if (lon > maxLon) maxLon = lon;
        }

        return new float[]{minLat, maxLat, minLon, maxLon};
    }

    // 经纬度转换为屏幕坐标
    private PointF latLngToScreen(float latitude, float longitude, float minLat, float maxLat, float minLon, float maxLon, float mapWidth, float mapHeight) {
        // 将经纬度按范围缩放到图片尺寸内,并预留边距
        float x = (longitude - minLon) / (maxLon - minLon) * (mapWidth - 2 * padding) + padding;
        float y = (maxLat - latitude) / (maxLat - minLat) * (mapHeight - 2 * padding) + padding;
        return new PointF(x, y);
    }

    // 绘制航线并只显示航线范围,四周留边距
    public Bitmap drawFlightPathWithPadding(List<WayPoint> flightPathCoordinates, int outputWidth, int outputHeight) {
        // 创建一个新的 Bitmap,宽高由传入参数指定
        Bitmap resultBitmap = Bitmap.createBitmap(outputWidth, outputHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(resultBitmap);

        // 获取航线的边界范围 (minLat, maxLat, minLon, maxLon)
        float[] boundingBox = calculateBoundingBox(flightPathCoordinates);
        float minLat = boundingBox[0], maxLat = boundingBox[1];
        float minLon = boundingBox[2], maxLon = boundingBox[3];

        // 创建路径
        mPath.reset();

        // 遍历航线的坐标点,将经纬度转换为屏幕坐标并添加到路径中
        for (int i = 0; i < flightPathCoordinates.size(); i++) {
            WayPoint location = flightPathCoordinates.get(i);
            PointF point = latLngToScreen((float) location.getLatitude(), (float) location.getLongitude(),
                    minLat, maxLat, minLon, maxLon, outputWidth, outputHeight);

            if (i == 0) {
                mPath.moveTo(point.x, point.y);  // 移动到路径的起始点
            } else {
                mPath.lineTo(point.x, point.y);  // 绘制线段到下一个点
            }
        }

        // 绘制路径到画布上
        canvas.drawPath(mPath, mPaint);

        return resultBitmap;
    }
}

WayPoint对象类:

data class WayPoint(
    var latitude: Long,
    var longitude: Long,
)

生成缩略图保存到SD卡,调用代码范例:

private fun generateThumbnail(wayPointList: List<WayPoint>?) {
        // 创建航线绘制类
        val drawer = FlightPathDrawer(resources.getColor(android.R.color.holo_green_light), 50f) // 50为边距
        // 输出的Bitmap宽高
        val outputWidth = 128
        val outputHeight = 128
        // 绘制航线到Bitmap上
        try {
            wayPointList?.let {
                val resultBitmap = drawer.drawFlightPathWithPadding(
                    wayPointList,
                    outputWidth,
                    outputHeight
                )
                saveBitmapToPNG(resultBitmap, System.currentTimeMillis().toString())
            }
        } catch (e: Exception) {

        }
    }

    fun saveBitmapToPNG(bitmap: Bitmap, fileName: String): Boolean {
        val sdCard = Environment.getExternalStorageDirectory()
        val dir = File(sdCard.absolutePath + "/naviLine/")

        if (!dir.exists()) {
            dir.mkdirs()
        }

        val file = File(dir, "$fileName.png")
        return try {
            val fOut = FileOutputStream(file)
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut)
            fOut.flush()
            fOut.close()
            true
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

扩展阅读:

  • Android 航线剖面图自定义控件绘制实现
  • Android 自定义棱形样式进度条控件
  • Android 弧形 RecyclerView 实现(Kotlin)
  • 美图手机音乐Widget动画实现
  • Android 心率动画自定义控件实现
  • Android 卡片旋转切换动效实现详解
  • Android 残影数字动画实现详解
  • Android 自定义菱形横向滑动指示器控件
博客公众号

微信公众号

转载请注明出处:陈文管的博客 – Android 航线缩略图简易绘制实现

博客公众号

闽ICP备18001825号-1 · Copyright © 2025 · Powered by chenwenguan.com