Commit fc1586ea authored by p x's avatar p x
Browse files

加入自实现的导航类

parent 42135beb
package com.sd.maplibrary.factorys
import androidx.core.graphics.toColorInt
import com.amap.api.location.AMapLocationClient
import com.sd.maplibrary.bean.MSLatLng
import com.sd.maplibrary.bean.WayPoi
import com.sd.maplibrary.core.MapReadyView
......@@ -198,5 +197,23 @@ interface IMapBasic {
// onDriveRoute: OnDriveRoute
)
/**
* 开始导航
* @param navType 1=自己实现回调 2=直接调用导航组件
* @param starPoint 起点坐标
* @param startName 起点名称
* @param endPoint 终点坐标
* @param endName 终点名称
* @param ways 途经点集合
*/
fun startNavi(
mapReadView: MapReadyView?, navType: Int,
starPoint: MSLatLng,
startName: String = "当前位置",
endPoint: MSLatLng,
endName: String = "",
ways: List<WayPoi>
)
}
\ No newline at end of file
......@@ -12,6 +12,7 @@ import com.sd.maplibrary.core.basic.mine.MineDrawInMap
import com.sd.maplibrary.core.basic.mine.MineGpsLocation
import com.sd.maplibrary.core.basic.mine.MineLocationStyle
import com.sd.maplibrary.core.basic.mine.MineMethodAdv
import com.sd.maplibrary.core.basic.mine.MineNai
import com.sd.maplibrary.core.basic.mine.MinePoiSearch
import com.sd.maplibrary.core.basic.mine.MineRoutePlans
import com.sd.maplibrary.core.basic.mine.MineToggleLayers
......@@ -164,6 +165,22 @@ class MineBasic : IMapBasic {
)
}
override fun startNavi(
mapReadView: MapReadyView?,
navType: Int,
starPoint: MSLatLng,
startName: String,
endPoint: MSLatLng,
endName: String,
ways: List<WayPoi>
) {
if (navType == 1) {//用户自己实现接口
MineNai.startNavi(mapReadView)
} else if (navType == 2) {//直接到写好的页面
MineNai.startNaviDirect(starPoint, startName, endPoint, endName, ways)
}
}
companion object {
val mineBasic: MineBasic by lazy { MineBasic() }
......
......@@ -18,7 +18,7 @@ import com.sd.maplibrary.ui.MapMultiView.OnMapReadyLis
//private const val ARG_PARAM2 = "param2"
/**
*四维地图
*四维地图容器
*/
class ForeMapFragment : Fragment() {
// private var param1: String? = null
......@@ -79,7 +79,7 @@ class ForeMapFragment : Fragment() {
}
}
/****地图加载监听回调*/
/**地图加载完成监听回调*/
fun addMapRenderCallback(onMapReadyLis: OnMapReadyLis) {
this.onMapReadyLis = onMapReadyLis
}
......
......@@ -14,6 +14,9 @@ import com.amap.api.navi.model.AimLessModeCongestionInfo
import com.amap.api.navi.model.AimLessModeStat
import com.amap.api.navi.model.NaviInfo
/**
* 高德导航监听
*/
abstract class MyAMapNaviListener : AMapNaviListener {
override fun onInitNaviFailure() {
......
......@@ -14,8 +14,8 @@ import com.minedata.minenavi.navi.RouterErrorInfo
import com.minedata.minenavi.navi.SmoothNaviData
import com.minedata.minenavi.navi.TmcSections
/***
* 导航监听
/**
* 四维导航监听
*/
abstract class MyMineNaviListener : MineNaviListener {
override fun onCalculateRouteSuccess(data: RouteCollection) {
......@@ -33,7 +33,7 @@ abstract class MyMineNaviListener : MineNaviListener {
override fun onCalculateVrpSuccess(p0: List<PoiFavorite?>?) {
}
//到达目的地后回调函数
/**到达目的地后回调函数*/
override fun onArriveDestination() {
}
......@@ -94,38 +94,41 @@ abstract class MyMineNaviListener : MineNaviListener {
override fun onSimNaviEnd(data: RouteBase?) {
}
/**
* 导航结束
*/
override fun onNaviEnded() {
}
/***
/**
* 车位置发生改变
* */
*/
override fun onTracking(data: NaviSessionData) {
}
/**
* 导航或者模拟导航时平滑跟踪
* **/
*/
override fun onSmoothTracking(data: SmoothNaviData) {
}
/**
* 解析 naviProgressData 导航更新信息
* **/
*/
override fun onDataUpdated(naviProgressData: NaviProgressData) {
}
/**
* 引导文字改变
* **/
*/
override fun onTextChanged(guidanceText: GuidanceText) {
}
/**
* 导航路口剩余距离
* */
override fun onDistanceChanged(p0: Int) {
*/
override fun onDistanceChanged(distance: Int) {
}
/**
......
......@@ -2,12 +2,21 @@ package com.sd.maplibrary.intfaces
import com.minedata.minenavi.navi.GuidanceText
import com.minedata.minenavi.navi.NaviProgressData
import com.minedata.minenavi.navi.NaviSessionData
import com.minedata.minenavi.navi.RouteBase
import com.minedata.minenavi.navi.RouteDetailItem
import com.minedata.minenavi.navi.SmoothNaviData
import com.minedata.minenavi.navi.TmcSections
/**
* 四维导航监听回调
*/
interface OnNaviPresenterListener {
fun onTracking(data: NaviSessionData)
fun onSmoothTracking(data: SmoothNaviData)
fun onDataUpdated(naviProgressData: NaviProgressData)
fun onTiBarUpdated(tmcSections: TmcSections)
......@@ -16,27 +25,7 @@ interface OnNaviPresenterListener {
fun onDistanceChanged(distance: Int)
fun onRouteDetailBrowserLoaded(routeDetailItems: MutableList<RouteDetailItem>?)
fun onCalculateRouteSuccess(routeBase: RouteBase?)
fun onCalculateRouteFailed(msg: String?)
fun onArriveDestination()
fun onRerouteFailed(msg: String?)
fun onNaviBegin()
fun onNaviEnded()
fun onSimNaviBegin()
fun onSimNaviEnd()
/**
* 走过了多少路
* @param ratio
*/
fun onTracking(ratio: Float)
fun onGpsConnected()
}
\ No newline at end of file
package com.sd.maplibrary.ui
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.sd.maplibrary.R
import com.sd.maplibrary.core.MapReadyView
import com.sd.maplibrary.core.basic.mine.MineNaiParams
import com.sd.maplibrary.databinding.ActivityMineNaiDirBinding
import com.sd.maplibrary.ui.MapMultiView.OnMapReadyLis
/**
* 直接开始导航
*/
class MineNaiDirActivity : AppCompatActivity() {
private lateinit var binding: ActivityMineNaiDirBinding
private var mapReadView: MapReadyView? = null
private var mineNaiParams:MineNaiParams?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityMineNaiDirBinding.inflate(layoutInflater)
setContentView(binding.root)
/* ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}*/
mineNaiParams=intent.getParcelableExtra<MineNaiParams>("mineNaiParams")
binding.mapMultiView.addMapRenderCallback(object : OnMapReadyLis {
override fun onMapReady(mapReadyView: MapReadyView) {
this@MineNaiDirActivity.mapReadView = mapReadyView
}
})
//算路成功以后启动导航
}
}
\ No newline at end of file
package com.sd.maplibrary.ui.widget
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.widget.LinearLayout
import android.widget.RelativeLayout
import com.minedata.minenavi.navi.TmcSections
import com.sd.maplibrary.R
/***横向的汽车**/
class HorCarTmc : LinearLayout {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs, 0){
init()
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
init()
}
// private lateinit var mUtils: Utils
//绘制内边距
private var mDrawPadding = 3
//车标
private lateinit var mCarIcon: Bitmap
private lateinit var mPublicPaint: Paint
private lateinit var mDrawContentPaint: Paint
var mTmcSections: TmcSections? = null
var mTmcBarSegments: ArrayList<TmcBarSegment> = ArrayList()
private var mHalfCarIconHeight = 0f
private var mHalfCarIconWidget = 0f
//行程百分比
private var mRatio = 0.0f
private fun init() {
// mUtils = Utils.getInstance()
mDrawPadding = paddingLeft
// mCarIcon = BitmapFactory.decodeResource(getResources(), R.drawable.small_car_icon);
mCarIcon = BitmapFactory.decodeResource(resources, R.drawable.my_small_car)
initPaint()
}
private fun initPaint() {
mPublicPaint = Paint()
mDrawContentPaint = Paint()
}
fun setTmcSections(tmcSections: TmcSections) {
val width = width
val height = height
if (height < width) {
mTmcSections = tmcSections
val tempPixels = mTmcSections!!.pixels
val pixels = IntArray(tempPixels.size)
for (i in tempPixels.indices) {
pixels[i] = width * tempPixels[i] / 100
}
val states = mTmcSections!!.states
mTmcBarSegments.clear()
for (i in 0..<mTmcSections!!.length) {
val tmcBarSegment = TmcBarSegment()
tmcBarSegment.colorStates = states[i]
val left = if (i > 0) pixels[i - 1] else 0
val top = 0
val right = pixels[i]
val bottom = height
val rect = RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
tmcBarSegment.rect = rect
mTmcBarSegments.add(tmcBarSegment)
}
}
invalidate()
}
fun updateRatio(ratio: Float) {
if ((this.mRatio * 1000).toInt() == (ratio * 1000).toInt() && ratio != 0f) {
return
}
this.mRatio = ratio
invalidate()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// if (mTmcBarSegments.size == 0) {
// return
// }
val width = width
val height = height
if (height < width) {
drawCar(canvas, height, width)
}
}
private fun drawCar(canvas: Canvas, height: Int, width: Int) {
if (height < width) {
val originalCarIconWidth = mCarIcon.width
val originalCarIconHeight = mCarIcon.height
// 计算缩放比例
val scaleHeight =
Math.round((height * 10 / originalCarIconHeight).toFloat()).toFloat() / 10
val scaleWidth = scaleHeight
val matrix = Matrix()
matrix.postScale(scaleWidth, scaleHeight)
// 得到新的图片
mCarIcon = Bitmap.createBitmap(
mCarIcon,
0,
0,
originalCarIconWidth,
originalCarIconHeight,
matrix,
true
)
mHalfCarIconWidget = mCarIcon.width * 0.5f
mHalfCarIconHeight = mCarIcon.height * 0.5f
canvas.save()
canvas.translate(mHalfCarIconWidget, mHalfCarIconHeight) // 将旋转中心移动
val offsetWidth = mRatio * width * 0.99f
// int left = -mCarIcon.getWidth() - Math.round(mHalfCarIconWidget);
val left = -mCarIcon.width
canvas.drawBitmap(mCarIcon, left + offsetWidth, -mHalfCarIconWidget, null)
// mPublicPaint.reset()
// mPublicPaint.color = Color.GRAY
// val grayRectF = RectF(
// left.toFloat(),
// -mHalfCarIconHeight,
// left + offsetWidth + mCarIcon.width,
// -mHalfCarIconHeight
// )
// // canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
// canvas.drawRect(grayRectF, mPublicPaint)
// canvas.restore()
}
}
}
\ No newline at end of file
package com.sd.maplibrary.ui.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.core.content.ContextCompat;
import com.minedata.minenavi.mapdal.NativeEnv;
import com.minedata.minenavi.navi.LaneDetector;
import com.sd.maplibrary.R;
import java.io.InputStream;
import java.util.ArrayList;
@SuppressLint({"NewApi"})
public class MyLaneView extends LinearLayout implements LaneDetector.OnLaneDetectorListener {
private static final String ASSET_PREFIX = "land/";
private LaneDetector mLaneDetector = null;
private int mHeight = 0;
private LaneDetector.LaneIconId[] mLaneIconIds = null;
private Drawable mNormDraw = null;
//图片间隔
private int mIconMargin = 0;
private ArrayList<LaneDetector.OnLaneDetectorListener> mListeners = new ArrayList();
private Context context;
private AssetManager assetManager;
public MyLaneView(Context context) {
super(context);
this.init();
}
public MyLaneView(Context context, AttributeSet attrs) {
super(context, attrs);
this.init();
}
// public MyLaneView(Context context, AttributeSet attrs, int defStyle) {
// super(context, attrs);
// this.init();
// }
public void addListener(LaneDetector.OnLaneDetectorListener listener) {
this.mListeners.add(listener);
}
public void removeListener(LaneDetector.OnLaneDetectorListener listener) {
this.mListeners.remove(listener);
}
public void onLaneDetectorEvent(int event, Object data) {
switch (event) {
case 1:
this.mLaneIconIds = (LaneDetector.LaneIconId[]) data;
// this.updateCache((LaneDetector.LaneIconId[]) data);
this.layoutLanes();
case 2:
default:
for (LaneDetector.OnLaneDetectorListener onLaneDetectorListener : this.mListeners) {
onLaneDetectorListener.onLaneDetectorEvent(event, data);
}
}
}
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// this.mHeight = this.getHeight();
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
this.mHeight = this.getMeasuredHeight();
// this.mWidget = getMeasuredWidth();
}
private void init() {
setOrientation(LinearLayout.HORIZONTAL);
this.context = getContext();
assetManager = context.getAssets();
this.mLaneDetector = new LaneDetector();
this.mLaneDetector.addListener(this);
this.mNormDraw = ContextCompat.getDrawable(context, R.drawable.l2_1);
this.mIconMargin = NativeEnv.dp2px(2.0F);
this.setGravity(Gravity.CENTER_VERTICAL);
}
private void layoutLanes() {
if (mLaneIconIds.length == 0)
return;
this.removeAllViews();
this.layout();
// this.layoutTest();
}
private void layout() {
if (this.mHeight == 0) {
this.mHeight = NativeEnv.dp2px(50.0F);
}
int iconHeight = this.mHeight - this.getPaddingTop() - this.getPaddingBottom();
int iconWidth = iconHeight * this.mNormDraw.getIntrinsicWidth() / this.mNormDraw.getIntrinsicHeight();
for (int i = 0; i < this.mLaneIconIds.length; ++i) {
ImageView view = createLaneItemView(mLaneIconIds[i], iconWidth, iconHeight);
if (view != null) {
this.addView(view);
if (i != this.mLaneIconIds.length - 1) {
this.addView(this.createSepView(iconHeight));
}
}
}
}
private ImageView createLaneItemView(LaneDetector.LaneIconId iconId, int width, int height) {
ImageView view = new ImageView(context);
view.setAdjustViewBounds(true);
// view.setScaleType(ImageView.ScaleType.CENTER_CROP);
try {
InputStream istr = assetManager.open(ASSET_PREFIX + iconId.lowerX + "-" + iconId.lowerY + ".png"); // 确保文件名和扩展名正确
Drawable d = Drawable.createFromStream(istr, null);
if (d != null) {
view.setAdjustViewBounds(true);
view.setScaleType(ImageView.ScaleType.CENTER_CROP);
view.setImageDrawable(d);
LayoutParams params = new LayoutParams(width, height);
view.setLayoutParams(params);
}
} catch (Exception e) {
return null;
}
return view;
}
private void layoutTest() {
if (this.mHeight == 0) {
this.mHeight = NativeEnv.dp2px(50.0F);
}
int len = 5;
// int iconHeight = this.mHeight - this.getPaddingTop() - this.getPaddingBottom();
// int iconWidth = iconHeight * this.mNormBitmap.getIntrinsicWidth() / this.mNormBitmap.getIntrinsicHeight();
int iconHeight = this.mHeight - this.getPaddingTop() - this.getPaddingBottom();
int iconWidth = iconHeight * this.mNormDraw.getIntrinsicWidth() / this.mNormDraw.getIntrinsicHeight();
// int sepWidth = NativeEnv.dp2px(1.0F);
// int totalWidth = this.getPaddingLeft() + this.getPaddingRight() + (iconWidth + this.mIconMargin * 2) * 3 + sepWidth * (len - 1);
for (int i = 0; i < len; ++i) {
ImageView view = createLaneItemViewTest(iconWidth, iconHeight);
if (view != null) {
this.addView(view);
if (i != len - 1) {
this.addView(this.createSepView(iconHeight));
}
}
}
// RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(-2, -1);
// params.width = totalWidth;
// params.height = this.mHeight;
// this.setLayoutParams(params);
// this.setBackground(new NinePatchDrawable(this.getResources(), this.mBackgroudBitmap, this.mBackgroudBitmap.getNinePatchChunk(), new Rect(), (String) null));
}
private ImageView createLaneItemViewTest(int width, int height) {
ImageView view = new ImageView(context);
view.setAdjustViewBounds(true);
// view.setScaleType(ImageView.ScaleType.CENTER_CROP);
try {
InputStream istr = assetManager.open(ASSET_PREFIX + "2-1.png"); // 确保文件名和扩展名正确
Drawable d = Drawable.createFromStream(istr, null);
if (d != null) {
view.setImageDrawable(d);
}
LayoutParams params = new LayoutParams(width, height);
view.setLayoutParams(params);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return view;
}
/**
* 分割线
**/
private ImageView createSepView(int height) {
ImageView view = new ImageView(context);
ColorDrawable colorDrawable = new ColorDrawable(Color.parseColor("#99FFFFFF"));
view.setBackground(colorDrawable);
LayoutParams params = new LayoutParams(-2, -1);
params.width = NativeEnv.dp2px(1.0F);
params.height = height - NativeEnv.dp2px(2.0F);
params.setMargins(this.mIconMargin, 0, this.mIconMargin, 0);
view.setLayoutParams(params);
return view;
}
}
package com.sd.maplibrary.ui.widget
import android.content.Context
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import com.minedata.minenavi.navi.RouteDetailItem
import com.minedata.minenavi.navi.TurnIconModel
import com.sd.maplibrary.R
class MyTurnIconView : AppCompatImageView {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
fun setTurnIconModel(turnIconModel: TurnIconModel) {
when (turnIconModel.toDirection) {
4 -> {//左转
setImageResource(R.drawable.turn_left)
}
in 5..7 -> {//左前
setImageResource(R.drawable.turn_left_font)
}
12 -> {//右转
setImageResource(R.drawable.turn_right)
}
in 9..11 -> {//右前
setImageResource(R.drawable.turn_right_font)
}
in 1..2 -> {//左后
setImageResource(R.drawable.turn_left_back)
}
}
}
fun setTurnIconId(turnIconId: Int) {
when (turnIconId) {
TurnIconModel.TurnIconId.keepDrivingOnCurrentRoad -> {
//沿路直行
setImageResource(R.drawable.turn_zhixing)
}
TurnIconModel.TurnIconId.turnAround -> {
//掉头
setImageResource(R.drawable.turn_diaotou)
}
TurnIconModel.TurnIconId.enterRotary, TurnIconModel.TurnIconId.leaveRotary, TurnIconModel.TurnIconId.uTurnOnRotary -> {
//环岛
setImageResource(R.drawable.turn_rota)
}
TurnIconModel.TurnIconId.straightKeepLeft -> {
//左侧直行
setImageResource(R.drawable.turn_left_ver)
}
TurnIconModel.TurnIconId.straightKeepRight -> {
//右侧直行
setImageResource(R.drawable.turn_right_ver)
}
RouteDetailItem.TurnIconID.WindOverpass -> {
//盘桥立交桥
setImageResource(R.drawable.turn_38)
}
RouteDetailItem.TurnIconID.Overpass -> {
//非盘桥立交桥
setImageResource(R.drawable.turn_37)
}
}
}
}
\ No newline at end of file
package com.sd.maplibrary.ui.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.minedata.minenavi.navi.TmcSections;
import com.sd.maplibrary.R;
import com.sd.maplibrary.utils.DisplayUtil;
import java.util.ArrayList;
/**
* 导航界面路况条控件
*/
public class TmcBar extends RelativeLayout {
private final String TAG = "[TmcBar]";
private Paint mDrawContentPaint, mPublicPaint;
TmcSections mTmcSections;
ArrayList<TmcBarSegment> mTmcBarSegments = new ArrayList<>();
//车标
private Bitmap mCarIcon = null;
//绘制内边距
private int mDrawPadding = 3;
//大圆半径
private float mBigCircleRadius = 0;
//小圆半径
private float mSmallCircleRadius = 0;
//裁剪区域
Path mClipPath = null;
//行程百分比
private float mRatio = 0.0f;
//暂存的tmc绘制结果
private Bitmap mSavedTmcMap = null;
//tmc是否更新
private boolean mIsTmcUpdated = true;
//布局控件宽高
private int mWidth = -1;
private int mHeight = -1;
//CarIcon的宽高 高的半值
private boolean mIsCarIconWidthInited;
private int mCarIconHeight = 0;
private int mCarIconWidth = 0;
private float mHalfCarIconHeight = 0;
private float mHalfCarIconWidget = 0f;
//tmc上下圆弧大小
private float mTopBottomArcAngle;
// private Utils mUtils;
public TmcBar(Context context) {
this(context, null);
}
public TmcBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public TmcBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
// mUtils = Utils.getInstance();
mDrawPadding = getPaddingLeft();
// mCarIcon = BitmapFactory.decodeResource(getResources(), R.drawable.small_car_icon);
mCarIcon = BitmapFactory.decodeResource(getResources(), R.drawable.my_small_car);
initPaint();
}
private void initPaint() {
mPublicPaint = new Paint();
mDrawContentPaint = new Paint();
}
public void setTmcSections(final TmcSections tmcSections) {
int width = getWidth();
int height = getHeight();
if (height < width) {
mTmcSections = tmcSections;
int[] tempPixels = mTmcSections.pixels;
int[] pixels = new int[tempPixels.length];
for (int i = 0; i < tempPixels.length; i++) {
pixels[i] = width * tempPixels[i] / 100;
}
int[] states = mTmcSections.states;
mTmcBarSegments.clear();
for (int i = 0; i < mTmcSections.length; i++) {
TmcBarSegment tmcBarSegment = new TmcBarSegment();
tmcBarSegment.colorStates = states[i];
int left = i > 0 ? pixels[i - 1] : 0;
int top = 0;
int right = pixels[i];
int bottom = height;
RectF rect = new RectF(left, top, right, bottom);
tmcBarSegment.rect = rect;
mTmcBarSegments.add(tmcBarSegment);
}
} else {
mIsTmcUpdated = true;
if (getWidth() != mWidth || getHeight() != mHeight) {
reMeasure();
}
if (tmcSections.pixels.length == 0) {
//防止离线算路时,tmc信息不能及时获取到而引发崩溃
mTmcSections = new TmcSections(new int[]{mHeight}, new int[]{TmcSections.State.unknown});
}
mTmcSections = tmcSections;
int[] tempPixels = new int[mTmcSections.pixels.length];
//此时tmcSections.pixels为各段所占百分比
for (int i = 0; i < tmcSections.length; i++) {
tempPixels[i] = tmcSections.pixels[i] * getHeight() / 100;
}
float[] pixels = new float[tempPixels.length];
float totalPixels = (float) tempPixels[tempPixels.length - 1];
for (int i = 0; i < tempPixels.length; i++) {
pixels[i] = tempPixels[i] / totalPixels * 1;
}
int[] states = mTmcSections.states;
mTmcBarSegments.clear();
float totalHeight = height - mCarIconHeight;
for (int i = 0; i < mTmcSections.length; i++) {
TmcBarSegment tmcBarSegment = new TmcBarSegment();
tmcBarSegment.colorStates = states[i];
float left;
float top;
float right;
float bottom;
float from = i == 0 ? 0 : totalHeight * pixels[i - 1];
float lengthRate = i == 0 ? pixels[0] : pixels[i] - pixels[i - 1];
left = mDrawPadding;
top = height - lengthRate * totalHeight - mHalfCarIconHeight - from;
right = width - mDrawPadding;
bottom = top + lengthRate * totalHeight;
RectF rect = new RectF(left, top, right, bottom);
tmcBarSegment.rect = rect;
mTmcBarSegments.add(tmcBarSegment);
}
}
invalidate();
}
/**
* 设置TmcBar外部圆角弧度,不设置或者传入0都显示半圆
*/
public void setTmcBarArcAngle(int arcAngle) {
// mTopBottomArcAngle = mUtils.dp2Px(arcAngle);
mTopBottomArcAngle = DisplayUtil.INSTANCE.dp2px(arcAngle);
reMeasure();
invalidate();
}
/**
* 设置绘制内边距(单位:px)
*/
public void setDrawPadding(int drawPadding) {
mDrawPadding = drawPadding;
reMeasure();
invalidate();
}
//将背景图板绘制到bitmap中
private void drawTmcMap2Bitmap(Canvas canvas) {
mPublicPaint.reset();
mPublicPaint.setColor(Color.WHITE);
//绘制背景白框
float centerX = 0.5f * mWidth;
float topBottomArcAngle = mTopBottomArcAngle == 0 || mTopBottomArcAngle > mWidth ? centerX : mTopBottomArcAngle;
float topCircleX = centerX;
float topCircleY = mHalfCarIconHeight + mSmallCircleRadius;
float bottomCircleX = centerX;
float bottomCircleY = mHeight - (mHalfCarIconHeight + mSmallCircleRadius);
RectF topRectF = new RectF(topCircleX - mBigCircleRadius, topCircleY - mBigCircleRadius
, centerX + mBigCircleRadius, topCircleY + mBigCircleRadius);
canvas.drawRoundRect(topRectF, topBottomArcAngle, topBottomArcAngle, mPublicPaint); // 画top圆
RectF bottomRectF = new RectF(bottomCircleX - mBigCircleRadius, bottomCircleY - mSmallCircleRadius
, bottomCircleX + mBigCircleRadius, bottomCircleY + mSmallCircleRadius + mDrawPadding); // 加上margin是为了和外框有边距
canvas.drawRoundRect(bottomRectF, topBottomArcAngle, topBottomArcAngle, mPublicPaint); // 画bottom圆
RectF rectF = new RectF(0, mHalfCarIconHeight + mSmallCircleRadius, mWidth, mHeight - (mHalfCarIconHeight + mSmallCircleRadius));
canvas.drawRect(rectF, mPublicPaint);
canvas.save();
canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
for (int i = 0; i < mTmcBarSegments.size(); i++) {
TmcBarSegment tmcBarSegment = mTmcBarSegments.get(i);
canvas.drawRect(tmcBarSegment.rect, getPaint(tmcBarSegment.colorStates));
}
canvas.restore();
}
//reset mWidth and mHeight,and reset clipPath
private void reMeasure() {
mWidth = getWidth();
mHeight = getHeight();
mBigCircleRadius = 0.5f * mWidth;
mSmallCircleRadius = mBigCircleRadius - mDrawPadding;
float center = 0.5f * mWidth;
float topBottomArcAngle = mTopBottomArcAngle == 0 || mTopBottomArcAngle > mWidth ? center : mTopBottomArcAngle;
mClipPath = new Path();
Path temPath = new Path();
RectF rectTop = new RectF(0, 0, mWidth, mHalfCarIconHeight + mSmallCircleRadius);
RectF rectBottom = new RectF(0, mHeight - (mHalfCarIconHeight + mSmallCircleRadius), mWidth, mHeight);
mClipPath.addRect(rectTop, Path.Direction.CW);
mClipPath.addRect(rectBottom, Path.Direction.CW);
float topCircleX = center;
float topCircleY = mHalfCarIconHeight + mSmallCircleRadius;
float bottomCircleX = center;
float bottomCircleY = mHeight - (mHalfCarIconHeight + mSmallCircleRadius);
RectF topRectF = new RectF(topCircleX - mSmallCircleRadius, topCircleY - mSmallCircleRadius
, topCircleX + mSmallCircleRadius, topCircleY + mSmallCircleRadius);
RectF bottomRectF = new RectF(bottomCircleX - mSmallCircleRadius, bottomCircleY - mSmallCircleRadius
, bottomCircleX + mSmallCircleRadius, bottomCircleY + mSmallCircleRadius);
temPath.addRoundRect(topRectF, topBottomArcAngle, topBottomArcAngle, Path.Direction.CW);
temPath.addRoundRect(bottomRectF, topBottomArcAngle, topBottomArcAngle, Path.Direction.CW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mClipPath.op(temPath, Path.Op.DIFFERENCE);
}
}
private void reMeasure_copy() {
mWidth = getWidth();
mHeight = getHeight();
mBigCircleRadius = 0.5f * mWidth;
mSmallCircleRadius = mBigCircleRadius - mDrawPadding;
float center = 0.5f * mWidth;
float topBottomArcAngle = mTopBottomArcAngle == 0 || mTopBottomArcAngle > mWidth ? center : mTopBottomArcAngle;
mClipPath = new Path();
Path temPath = new Path();
RectF rectTop = new RectF(0, 0, mWidth, mHalfCarIconHeight + mSmallCircleRadius);
RectF rectBottom = new RectF(0, mHeight - (mHalfCarIconHeight + mSmallCircleRadius), mWidth, mHeight);
mClipPath.addRect(rectTop, Path.Direction.CW);
mClipPath.addRect(rectBottom, Path.Direction.CW);
float topCircleX = center;
float topCircleY = mHalfCarIconHeight + mSmallCircleRadius;
float bottomCircleX = center;
float bottomCircleY = mHeight - (mHalfCarIconHeight + mSmallCircleRadius);
RectF topRectF = new RectF(topCircleX - mSmallCircleRadius, topCircleY - mSmallCircleRadius
, topCircleX + mSmallCircleRadius, topCircleY + mSmallCircleRadius);
RectF bottomRectF = new RectF(bottomCircleX - mSmallCircleRadius, bottomCircleY - mSmallCircleRadius
, bottomCircleX + mSmallCircleRadius, bottomCircleY + mSmallCircleRadius);
temPath.addRoundRect(topRectF, topBottomArcAngle, topBottomArcAngle, Path.Direction.CW);
temPath.addRoundRect(bottomRectF, topBottomArcAngle, topBottomArcAngle, Path.Direction.CW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mClipPath.op(temPath, Path.Op.DIFFERENCE);
}
}
public void updateRatio(float ratio) {
if ((int) (this.mRatio * 1000) == (int) (ratio * 1000) && ratio != 0) {
return;
}
this.mRatio = ratio;
invalidate();
}
@Override
public void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
if (mTmcBarSegments.size() == 0) {
return;
}
int width = getWidth();
int height = getHeight();
if (height < width) {
for (int i = 0; i < mTmcBarSegments.size(); i++) {
TmcBarSegment tmcBarSegment = mTmcBarSegments.get(i);
canvas.drawRect(tmcBarSegment.rect, getPaint(tmcBarSegment.colorStates));
}
if (mTmcBarSegments.size() == 0) {
return;
}
// drawCar(canvas, height, width);
} else {
if (mTmcBarSegments.size() == 0) {
return;
}
drawCar(canvas, height, width);
}
}
private void drawCar(Canvas canvas, int height, int width) {
if (height < width) {
int originalCarIconWidth = mCarIcon.getWidth();
int originalCarIconHeight = mCarIcon.getHeight();
// 计算缩放比例
float scaleHeight = (float) Math.round(height * 10 / originalCarIconHeight) / 10;
float scaleWidth = scaleHeight;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
mCarIcon = Bitmap.createBitmap(mCarIcon, 0, 0, originalCarIconWidth, originalCarIconHeight, matrix, true);
mHalfCarIconWidget = mCarIcon.getWidth() * 0.5f;
mHalfCarIconHeight = mCarIcon.getHeight() * 0.5f;
canvas.save();
canvas.translate(mHalfCarIconWidget, mHalfCarIconHeight); // 将旋转中心移动
float offsetWidth = mRatio * width;
// int left = -mCarIcon.getWidth() - Math.round(mHalfCarIconWidget);
int left = -mCarIcon.getWidth();
canvas.drawBitmap(mCarIcon, left + offsetWidth, -mHalfCarIconHeight, null);
mPublicPaint.reset();
mPublicPaint.setColor(Color.GRAY);
RectF grayRectF = new RectF(left, -mHalfCarIconHeight, left + offsetWidth + mCarIcon.getWidth(), -mHalfCarIconHeight);
// canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
canvas.drawRect(grayRectF, mPublicPaint);
canvas.restore();
} else {
if (!mIsCarIconWidthInited) {
// 获得图片的宽高
int originalCarIconWidth = mCarIcon.getWidth();
int originalCarIconHeight = mCarIcon.getHeight();
// 计算缩放比例
float scaleWidth = (float) Math.round(width * 10 / originalCarIconWidth) / 10;
float scaleHeight = scaleWidth;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
mCarIcon = Bitmap.createBitmap(mCarIcon, 0, 0, originalCarIconWidth, originalCarIconHeight, matrix, true);
mCarIconHeight = mCarIcon.getHeight();
mCarIconWidth = mCarIcon.getWidth();
mHalfCarIconHeight = 0.5f * mCarIconHeight;
reMeasure();
mIsCarIconWidthInited = true;
}
if (getWidth() != mWidth || getHeight() != mHeight) {
reMeasure();
}
if (mIsTmcUpdated) {
mSavedTmcMap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
Canvas temCanvas = new Canvas(mSavedTmcMap);
drawTmcMap2Bitmap(temCanvas);
mIsTmcUpdated = false;
}
mPublicPaint.reset();
Rect src = new Rect(0, 0, mWidth, mHeight);
canvas.drawBitmap(mSavedTmcMap, src, src, mPublicPaint);
drawGray(canvas);
Rect srcIcon = new Rect(0, 0, mCarIconWidth, mCarIconHeight);
float totalHeight = mHeight - mCarIconHeight;
float from = mHeight - mHalfCarIconHeight - mRatio * totalHeight;
canvas.drawBitmap(mCarIcon, srcIcon, getLocRect(from), mPublicPaint);
}
}
private void drawGray(Canvas canvas) {
canvas.save();
mPublicPaint.reset();
mPublicPaint.setColor(Color.GRAY);
float totalHeight = mHeight - mCarIconHeight;
float from = mHeight - mHalfCarIconHeight - totalHeight * mRatio;
float to = mHeight - mHalfCarIconHeight - totalHeight * 0;
float left = mDrawPadding;
float right = mWidth - left;
RectF grayRectF = new RectF(left, from, right, to);
canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
canvas.drawRect(grayRectF, mPublicPaint);
canvas.restore();
}
private RectF getLocRect(float dot) {
float left = 0 + (float) (mWidth - mCarIconWidth) / 2f;
float right = mWidth - (float) (mWidth - mCarIconWidth) / 2f;
float top = dot - (float) mCarIconHeight / 2f;
float bottom = dot + (float) mCarIconHeight / 2f;
return new RectF(left, top, right, bottom);
}
/**
* @param state 见{@link TmcSections.State}
* @return
*/
public Paint getPaint(int state) {
mDrawContentPaint.reset();
switch (state) {
case TmcSections.State.light:
mDrawContentPaint.setColor(Color.parseColor("#43CA63"));//绿色
break;
case TmcSections.State.medium:
mDrawContentPaint.setColor(Color.parseColor("#F9B000"));//黄色
break;
case TmcSections.State.heavy:
mDrawContentPaint.setColor(Color.parseColor("#F45956"));//红
break;
case TmcSections.State.blocked:
mDrawContentPaint.setColor(Color.parseColor("#701200"));//黑色
break;
case TmcSections.State.unknown:
case TmcSections.State.none:
mDrawContentPaint.setColor(Color.parseColor("#3385FE"));//蓝色
break;
default:
mDrawContentPaint.setColor(Color.parseColor("#C3C0C0"));
break;
}
return mDrawContentPaint;
}
}
\ No newline at end of file
/*********************************************************************************************************************************
* NaviCore Corporate MIT License 0.1
* Copyright (c) 2019 GIS Core R&D Department, NavInfo Corp.
*
* Permission is hereby granted, free of charge, to any entity within the corporation(Entity) obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit Entities to whom the Software is furnished to do so, subject to the following conditions:
*
* 1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. and
* 2. The above copyright notice, this permission notice and the acknowledgments below shall be displayed in UI or web pages
* if the Software is redistributed in binary form or as web service.
*
* Acknowledgments: "This work uses NaviZeroAndroid provided by GIS Core R&D Department, NavInfo Corp."
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* You may also get a copy of the license at http://navicore.cn/license/NC_MIT_0.1
**********************************************************************************************************************************/
package com.sd.maplibrary.ui.widget;
import android.graphics.RectF;
/**
* 组成TmcBar的片段信息
*/
public class TmcBarSegment {
/**
* 见{@link com.minedata.minenavi.navi.TmcSections.State}
*/
public int colorStates;
public RectF rect;
@Override
public String toString() {
return "TmcBarSegment{" +
"colorStates=" + colorStates +
", rect=" + rect +
'}';
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment