记录下在航线列表要显示航线缩略图预览航线,通过经纬度航线数据绘制生成预览图。项目上要求缩略图要带卫星地图背景,需要通过地图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 航线缩略图简易绘制实现
发表回复