mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-19 04:53:36 +00:00
[android] Add current speed widget
Signed-off-by: TobiPeterG <codeberg.sadness522@passmail.net>
This commit is contained in:
@@ -26,6 +26,7 @@ import app.organicmaps.sdk.util.StringUtils;
|
||||
import app.organicmaps.util.UiUtils;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.util.WindowInsetUtils;
|
||||
import app.organicmaps.widget.CurrentSpeedView;
|
||||
import app.organicmaps.widget.LanesView;
|
||||
import app.organicmaps.widget.SpeedLimitView;
|
||||
import app.organicmaps.widget.menu.NavMenu;
|
||||
@@ -51,6 +52,8 @@ public class NavigationController implements TrafficManager.TrafficCallback, Nav
|
||||
private final LanesView mLanesView;
|
||||
@NonNull
|
||||
private final SpeedLimitView mSpeedLimit;
|
||||
@NonNull
|
||||
private final CurrentSpeedView mCurrentSpeed;
|
||||
|
||||
private final MapButtonsViewModel mMapButtonsViewModel;
|
||||
|
||||
@@ -94,6 +97,7 @@ public class NavigationController implements TrafficManager.TrafficCallback, Nav
|
||||
mLanesView = topFrame.findViewById(R.id.lanes);
|
||||
|
||||
mSpeedLimit = topFrame.findViewById(R.id.nav_speed_limit);
|
||||
mCurrentSpeed = topFrame.findViewById(R.id.nav_current_speed);
|
||||
|
||||
// Show a blank view below the navbar to hide the menu content
|
||||
final View navigationBarBackground = mFrame.findViewById(R.id.nav_bottom_sheet_nav_bar);
|
||||
@@ -128,7 +132,7 @@ public class NavigationController implements TrafficManager.TrafficCallback, Nav
|
||||
|
||||
mLanesView.setLanes(info.lanes);
|
||||
|
||||
updateSpeedLimit(info);
|
||||
updateSpeedWidgets(info);
|
||||
}
|
||||
|
||||
private void updatePedestrian(@NonNull RoutingInfo info)
|
||||
@@ -136,6 +140,7 @@ public class NavigationController implements TrafficManager.TrafficCallback, Nav
|
||||
mNextTurnDistance.setText(Utils.formatDistance(mFrame.getContext(), info.distToTurn));
|
||||
|
||||
info.pedestrianTurnDirection.setTurnDrawable(mNextTurnImage);
|
||||
updateSpeedWidgets(info);
|
||||
}
|
||||
|
||||
public void updateNorth()
|
||||
@@ -261,16 +266,18 @@ public class NavigationController implements TrafficManager.TrafficCallback, Nav
|
||||
RoutingController.get().cancel();
|
||||
}
|
||||
|
||||
private void updateSpeedLimit(@NonNull final RoutingInfo info)
|
||||
private void updateSpeedWidgets(@NonNull final RoutingInfo info)
|
||||
{
|
||||
final Location location = MwmApplication.from(mFrame.getContext()).getLocationHelper().getSavedLocation();
|
||||
if (location == null)
|
||||
{
|
||||
mSpeedLimit.setSpeedLimit(0, false);
|
||||
mSpeedLimit.setSpeedLimit(-1, false);
|
||||
mCurrentSpeed.setCurrentSpeed(-1);
|
||||
return;
|
||||
}
|
||||
final int fSpeedLimit = StringUtils.nativeFormatSpeed(info.speedLimitMps);
|
||||
final boolean speedLimitExceeded = fSpeedLimit < StringUtils.nativeFormatSpeed(location.getSpeed());
|
||||
mSpeedLimit.setSpeedLimit(fSpeedLimit, speedLimitExceeded);
|
||||
mCurrentSpeed.setCurrentSpeed(location.getSpeed());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
package app.organicmaps.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public abstract class BaseSignView extends View
|
||||
{
|
||||
private float mBorderWidthRatio = 0.1f;
|
||||
protected void setBorderWidthRatio(float ratio) {
|
||||
mBorderWidthRatio = ratio;
|
||||
}
|
||||
|
||||
private float mBorderInsetRatio = 0f;
|
||||
protected void setBorderInsetRatio(float ratio) {
|
||||
mBorderInsetRatio = ratio;
|
||||
}
|
||||
|
||||
// colors
|
||||
protected int mBackgroundColor;
|
||||
protected int mBorderColor;
|
||||
protected int mAlertColor;
|
||||
protected int mTextColor;
|
||||
protected int mTextAlertColor;
|
||||
|
||||
// paints
|
||||
protected final Paint mBackgroundPaint;
|
||||
protected final Paint mBorderPaint;
|
||||
protected final Paint mTextPaint;
|
||||
|
||||
// geometry
|
||||
protected float mWidth;
|
||||
protected float mHeight;
|
||||
protected float mRadius;
|
||||
protected float mBorderWidth;
|
||||
protected float mBorderRadius;
|
||||
|
||||
public BaseSignView(Context ctx, @Nullable AttributeSet attrs)
|
||||
{
|
||||
super(ctx, attrs);
|
||||
mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mBorderPaint.setStyle(Paint.Style.STROKE);
|
||||
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mTextPaint.setTextAlign(Paint.Align.CENTER);
|
||||
mTextPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
|
||||
}
|
||||
|
||||
protected void setColors(int backgroundColor,
|
||||
int borderColor,
|
||||
int alertColor,
|
||||
int textColor,
|
||||
int textAlertColor)
|
||||
{
|
||||
mBackgroundColor = backgroundColor;
|
||||
mBorderColor = borderColor;
|
||||
mAlertColor = alertColor;
|
||||
mTextColor = textColor;
|
||||
mTextAlertColor = textAlertColor;
|
||||
|
||||
mBackgroundPaint.setColor(mBackgroundColor);
|
||||
mBorderPaint.setColor(mBorderColor);
|
||||
mTextPaint.setColor(mTextColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
float px = getPaddingLeft() + getPaddingRight();
|
||||
float py = getPaddingTop() + getPaddingBottom();
|
||||
mWidth = w - px;
|
||||
mHeight = h - py;
|
||||
mRadius = Math.min(mWidth, mHeight) / 2f;
|
||||
mBorderWidth = mRadius * mBorderWidthRatio;
|
||||
// subtract half the stroke PLUS the extra inset
|
||||
float gap = mRadius * mBorderInsetRatio;
|
||||
mBorderRadius = mRadius - (mBorderWidth / 2f) - gap;
|
||||
configureTextSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(@NonNull Canvas canvas)
|
||||
{
|
||||
super.onDraw(canvas);
|
||||
String str = getValueString();
|
||||
if (str == null) return;
|
||||
|
||||
float cx = mWidth / 2f;
|
||||
float cy = mHeight / 2f;
|
||||
|
||||
// background & border
|
||||
boolean alert = isAlert();
|
||||
mBackgroundPaint.setColor(alert ? mAlertColor : mBackgroundColor);
|
||||
canvas.drawCircle(cx, cy, mRadius, mBackgroundPaint);
|
||||
if (!alert)
|
||||
{
|
||||
mBorderPaint.setStrokeWidth(mBorderWidth);
|
||||
mBorderPaint.setColor(mBorderColor);
|
||||
canvas.drawCircle(cx, cy, mBorderRadius, mBorderPaint);
|
||||
}
|
||||
|
||||
// text
|
||||
mTextPaint.setColor(alert ? mTextAlertColor : mTextColor);
|
||||
drawValueString(canvas, cx, cy, str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(@NonNull MotionEvent e)
|
||||
{
|
||||
float cx = mWidth / 2f, cy = mHeight / 2f;
|
||||
float dx = e.getX() - cx, dy = e.getY() - cy;
|
||||
if (dx*dx + dy*dy <= mRadius*mRadius)
|
||||
{
|
||||
performClick();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performClick()
|
||||
{
|
||||
super.performClick();
|
||||
return false;
|
||||
}
|
||||
|
||||
private void drawValueString(Canvas c, float cx, float cy, String str)
|
||||
{
|
||||
Rect b = new Rect();
|
||||
mTextPaint.getTextBounds(str, 0, str.length(), b);
|
||||
float y = cy - b.exactCenterY();
|
||||
c.drawText(str, cx, y, mTextPaint);
|
||||
}
|
||||
|
||||
void configureTextSize()
|
||||
{
|
||||
String text = getValueString();
|
||||
if (text == null) return;
|
||||
float textRadius = mBorderRadius - mBorderWidth;
|
||||
float maxSz = 2f * textRadius;
|
||||
float maxSz2 = maxSz * maxSz;
|
||||
float lo = 0f, hi = maxSz, sz = maxSz;
|
||||
Rect b = new Rect();
|
||||
while (lo <= hi)
|
||||
{
|
||||
sz = (lo + hi) / 2f;
|
||||
mTextPaint.setTextSize(sz);
|
||||
mTextPaint.getTextBounds(text, 0, text.length(), b);
|
||||
float area = b.width()*b.width() + b.height()*b.height();
|
||||
if (area <= maxSz2) lo = sz + 1f;
|
||||
else hi = sz - 1f;
|
||||
}
|
||||
mTextPaint.setTextSize(Math.max(1f, sz));
|
||||
}
|
||||
|
||||
/** child must return the string to draw, or null if nothing */
|
||||
@Nullable
|
||||
protected abstract String getValueString();
|
||||
|
||||
/** child decides if this is in “alert” state */
|
||||
protected abstract boolean isAlert();
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package app.organicmaps.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.sdk.util.StringUtils;
|
||||
|
||||
public class CurrentSpeedView extends BaseSignView
|
||||
{
|
||||
private double mSpeedMps = -1.0;
|
||||
private String mSpeedStr = "--";
|
||||
|
||||
public CurrentSpeedView(Context ctx, @Nullable AttributeSet attrs)
|
||||
{
|
||||
super(ctx, attrs);
|
||||
|
||||
setBorderWidthRatio(0.1f);
|
||||
setBorderInsetRatio(0.05f);
|
||||
|
||||
try (TypedArray a = ctx.getTheme()
|
||||
.obtainStyledAttributes(attrs, R.styleable.CurrentSpeedView /* reuse same attrs or define new */ , 0, 0))
|
||||
{
|
||||
int bg = a.getColor(R.styleable.CurrentSpeedView_currentSpeedBackgroundColor, DefaultValues.BACKGROUND_COLOR);
|
||||
int bd = a.getColor(R.styleable.CurrentSpeedView_currentSpeedBorderColor, DefaultValues.BORDER_COLOR);
|
||||
int tc = a.getColor(R.styleable.CurrentSpeedView_currentSpeedTextColor, DefaultValues.TEXT_COLOR);
|
||||
setColors(bg, bd, 0, tc, 0);
|
||||
|
||||
if (isInEditMode())
|
||||
{
|
||||
mSpeedMps = a.getInt(R.styleable.CurrentSpeedView_currentSpeedEditModeCurrentSpeed, 50);
|
||||
mSpeedStr = Integer.toString((int)mSpeedMps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setCurrentSpeed(double mps)
|
||||
{
|
||||
mSpeedMps = mps;
|
||||
if (mps < 0)
|
||||
{
|
||||
mSpeedStr = "--";
|
||||
}
|
||||
else
|
||||
{
|
||||
Pair<String,String> su = StringUtils.nativeFormatSpeedAndUnits(mps);
|
||||
mSpeedStr = su.first;
|
||||
}
|
||||
requestLayout();
|
||||
configureTextSize();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getValueString()
|
||||
{
|
||||
return mSpeedStr;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAlert()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private interface DefaultValues
|
||||
{
|
||||
int BACKGROUND_COLOR = 0xFFFFFFFF;
|
||||
int BORDER_COLOR = 0xFF000000;
|
||||
int TEXT_COLOR = 0xFF000000;
|
||||
}
|
||||
}
|
||||
@@ -3,225 +3,135 @@ package app.organicmaps.widget;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.organicmaps.R;
|
||||
|
||||
public class SpeedLimitView extends View
|
||||
public class SpeedLimitView extends BaseSignView
|
||||
{
|
||||
private interface DefaultValues
|
||||
private int mSpeedLimit = -1;
|
||||
private boolean mAlert = false;
|
||||
private String mSpeedStr = "-1";
|
||||
private final int unlimitedBorderColor;
|
||||
private final int unlimitedStripeColor;
|
||||
|
||||
public SpeedLimitView(Context ctx, @Nullable AttributeSet attrs)
|
||||
{
|
||||
@ColorInt
|
||||
int BACKGROUND_COLOR = Color.WHITE;
|
||||
@ColorInt
|
||||
int BORDER_COLOR = Color.RED;
|
||||
@ColorInt
|
||||
int ALERT_COLOR = Color.RED;
|
||||
@ColorInt
|
||||
int TEXT_COLOR = Color.BLACK;
|
||||
@ColorInt
|
||||
int TEXT_ALERT_COLOR = Color.WHITE;
|
||||
super(ctx, attrs);
|
||||
|
||||
float BORDER_WIDTH_RATIO = 0.1f;
|
||||
}
|
||||
setBorderWidthRatio(0.2f);
|
||||
setBorderInsetRatio(0.05f);
|
||||
|
||||
@ColorInt
|
||||
private final int mBackgroundColor;
|
||||
|
||||
@ColorInt
|
||||
private final int mBorderColor;
|
||||
|
||||
@ColorInt
|
||||
private final int mAlertColor;
|
||||
|
||||
@ColorInt
|
||||
private final int mTextColor;
|
||||
|
||||
@ColorInt
|
||||
private final int mTextAlertColor;
|
||||
|
||||
@NonNull
|
||||
private final Paint mSignBackgroundPaint;
|
||||
@NonNull
|
||||
private final Paint mSignBorderPaint;
|
||||
@NonNull
|
||||
private final Paint mTextPaint;
|
||||
|
||||
private float mWidth;
|
||||
private float mHeight;
|
||||
private float mBackgroundRadius;
|
||||
private float mBorderRadius;
|
||||
private float mBorderWidth;
|
||||
|
||||
private int mSpeedLimit = 0;
|
||||
@NonNull
|
||||
private String mSpeedLimitStr = "0";
|
||||
private boolean mAlert = false;
|
||||
|
||||
public SpeedLimitView(Context context, @Nullable AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
|
||||
try (TypedArray data = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SpeedLimitView, 0, 0))
|
||||
try (TypedArray a = ctx.getTheme()
|
||||
.obtainStyledAttributes(attrs, R.styleable.SpeedLimitView, 0, 0))
|
||||
{
|
||||
mBackgroundColor =
|
||||
data.getColor(R.styleable.SpeedLimitView_speedLimitBackgroundColor, DefaultValues.BACKGROUND_COLOR);
|
||||
mBorderColor = data.getColor(R.styleable.SpeedLimitView_speedLimitBorderColor, DefaultValues.BORDER_COLOR);
|
||||
mAlertColor = data.getColor(R.styleable.SpeedLimitView_speedLimitAlertColor, DefaultValues.ALERT_COLOR);
|
||||
mTextColor = data.getColor(R.styleable.SpeedLimitView_speedLimitTextColor, DefaultValues.TEXT_COLOR);
|
||||
mTextAlertColor =
|
||||
data.getColor(R.styleable.SpeedLimitView_speedLimitTextAlertColor, DefaultValues.TEXT_ALERT_COLOR);
|
||||
int bg = a.getColor(R.styleable.SpeedLimitView_speedLimitBackgroundColor, DefaultValues.BACKGROUND_COLOR);
|
||||
int bd = a.getColor(R.styleable.SpeedLimitView_speedLimitBorderColor, DefaultValues.BORDER_COLOR);
|
||||
int al = a.getColor(R.styleable.SpeedLimitView_speedLimitAlertColor, DefaultValues.ALERT_COLOR);
|
||||
int tc = a.getColor(R.styleable.SpeedLimitView_speedLimitTextColor, DefaultValues.TEXT_COLOR);
|
||||
int tac = a.getColor(R.styleable.SpeedLimitView_speedLimitTextAlertColor, DefaultValues.TEXT_ALERT_COLOR);
|
||||
setColors(bg, bd, al, tc, tac);
|
||||
|
||||
unlimitedBorderColor = a.getColor(R.styleable.SpeedLimitView_speedLimitUnlimitedBorderColor, DefaultValues.UNLIMITED_BORDER_COLOR);
|
||||
unlimitedStripeColor = a.getColor(R.styleable.SpeedLimitView_speedLimitUnlimitedStripeColor, DefaultValues.UNLIMITED_STRIPE_COLOR);
|
||||
|
||||
if (isInEditMode())
|
||||
{
|
||||
mSpeedLimit = data.getInt(R.styleable.SpeedLimitView_speedLimitEditModeSpeedLimit, 60);
|
||||
mSpeedLimitStr = Integer.toString(mSpeedLimit);
|
||||
mAlert = data.getBoolean(R.styleable.SpeedLimitView_speedLimitEditModeAlert, false);
|
||||
mSpeedLimit = a.getInt(R.styleable.SpeedLimitView_speedLimitEditModeSpeedLimit, 60);
|
||||
mAlert = a.getBoolean(R.styleable.SpeedLimitView_speedLimitEditModeAlert, false);
|
||||
mSpeedStr = Integer.toString(mSpeedLimit);
|
||||
}
|
||||
}
|
||||
|
||||
mSignBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mSignBackgroundPaint.setColor(mBackgroundColor);
|
||||
|
||||
mSignBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mSignBorderPaint.setColor(mBorderColor);
|
||||
mSignBorderPaint.setStrokeWidth(mBorderWidth);
|
||||
mSignBorderPaint.setStyle(Paint.Style.STROKE);
|
||||
|
||||
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mTextPaint.setColor(mTextColor);
|
||||
mTextPaint.setTextAlign(Paint.Align.CENTER);
|
||||
mTextPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
|
||||
}
|
||||
|
||||
public void setSpeedLimit(final int speedLimit, boolean alert)
|
||||
public void setSpeedLimit(int limit, boolean alert)
|
||||
{
|
||||
final boolean speedLimitChanged = mSpeedLimit != speedLimit;
|
||||
|
||||
mSpeedLimit = speedLimit;
|
||||
mAlert = alert;
|
||||
|
||||
if (speedLimitChanged)
|
||||
if (mSpeedLimit != limit)
|
||||
{
|
||||
mSpeedLimitStr = Integer.toString(mSpeedLimit);
|
||||
configureTextSize();
|
||||
mSpeedLimit = limit;
|
||||
mSpeedStr = Integer.toString(limit);
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
mAlert = alert;
|
||||
configureTextSize();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected void onDraw(@NonNull Canvas canvas)
|
||||
protected String getValueString()
|
||||
{
|
||||
super.onDraw(canvas);
|
||||
|
||||
final boolean validSpeedLimit = mSpeedLimit > 0;
|
||||
if (!validSpeedLimit)
|
||||
return;
|
||||
|
||||
final float cx = mWidth / 2;
|
||||
final float cy = mHeight / 2;
|
||||
|
||||
drawSign(canvas, cx, cy, mAlert);
|
||||
drawText(canvas, cx, cy, mAlert);
|
||||
return (mSpeedLimit > 0 ? mSpeedStr : null);
|
||||
}
|
||||
|
||||
private void drawSign(@NonNull Canvas canvas, float cx, float cy, boolean alert)
|
||||
@Override
|
||||
protected boolean isAlert()
|
||||
{
|
||||
if (alert)
|
||||
mSignBackgroundPaint.setColor(mAlertColor);
|
||||
return mAlert;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas)
|
||||
{
|
||||
float cx = mWidth/2f, cy = mHeight/2f;
|
||||
|
||||
if (mSpeedLimit == 0)
|
||||
{
|
||||
// background
|
||||
mBackgroundPaint.setColor(mBackgroundColor);
|
||||
canvas.drawCircle(cx, cy, mRadius, mBackgroundPaint);
|
||||
|
||||
// black border
|
||||
mBorderPaint.setColor(unlimitedBorderColor);
|
||||
mBorderPaint.setStrokeWidth(mBorderWidth);
|
||||
canvas.drawCircle(cx, cy, mBorderRadius, mBorderPaint);
|
||||
|
||||
// draw 5 diagonal stripes
|
||||
drawUnlimitedStripes(canvas, cx, cy);
|
||||
}
|
||||
else
|
||||
mSignBackgroundPaint.setColor(mBackgroundColor);
|
||||
|
||||
canvas.drawCircle(cx, cy, mBackgroundRadius, mSignBackgroundPaint);
|
||||
if (!alert)
|
||||
{
|
||||
mSignBorderPaint.setStrokeWidth(mBorderWidth);
|
||||
canvas.drawCircle(cx, cy, mBorderRadius, mSignBorderPaint);
|
||||
// delegate to BaseSignView’s onDraw
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawText(@NonNull Canvas canvas, float cx, float cy, boolean alert)
|
||||
private void drawUnlimitedStripes(Canvas c, float cx, float cy)
|
||||
{
|
||||
if (alert)
|
||||
mTextPaint.setColor(mTextAlertColor);
|
||||
else
|
||||
mTextPaint.setColor(mTextColor);
|
||||
Paint stripe = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
stripe.setColor(unlimitedStripeColor);
|
||||
stripe.setStrokeWidth(mBorderWidth * 0.4f);
|
||||
|
||||
final Rect textBounds = new Rect();
|
||||
mTextPaint.getTextBounds(mSpeedLimitStr, 0, mSpeedLimitStr.length(), textBounds);
|
||||
final float textY = cy - textBounds.exactCenterY();
|
||||
canvas.drawText(mSpeedLimitStr, cx, textY, mTextPaint);
|
||||
}
|
||||
float r = mRadius * 0.8f; // shorten to 80% of full radius
|
||||
float diag = (float)(1/Math.sqrt(2));
|
||||
float dx = -diag, dy = +diag;
|
||||
float px = -dy, py = +dx; // perpendicular
|
||||
float step = r * 0.15f; // spacing
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(@NonNull MotionEvent event)
|
||||
{
|
||||
final float cx = mWidth / 2;
|
||||
final float cy = mHeight / 2;
|
||||
if (Math.pow(event.getX() - cx, 2) + Math.pow(event.getY() - cy, 2) <= Math.pow(mBackgroundRadius, 2))
|
||||
for (int i = -2; i <= 2; i++)
|
||||
{
|
||||
performClick();
|
||||
return true;
|
||||
float ox = px * step * i;
|
||||
float oy = py * step * i;
|
||||
float sx = cx + dx * r + ox;
|
||||
float sy = cy + dy * r + oy;
|
||||
float ex = cx - dx * r + ox;
|
||||
float ey = cy - dy * r + oy;
|
||||
c.drawLine(sx, sy, ex, ey, stripe);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performClick()
|
||||
|
||||
private interface DefaultValues
|
||||
{
|
||||
super.performClick();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||
{
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
final float paddingX = (float) (getPaddingLeft() + getPaddingRight());
|
||||
final float paddingY = (float) (getPaddingTop() + getPaddingBottom());
|
||||
|
||||
mWidth = (float) w - paddingX;
|
||||
mHeight = (float) h - paddingY;
|
||||
mBackgroundRadius = Math.min(mWidth, mHeight) / 2;
|
||||
mBorderWidth = mBackgroundRadius * 2 * DefaultValues.BORDER_WIDTH_RATIO;
|
||||
mBorderRadius = mBackgroundRadius - mBorderWidth / 2;
|
||||
configureTextSize();
|
||||
}
|
||||
|
||||
// Apply binary search to determine the optimal text size that fits within the circular boundary.
|
||||
private void configureTextSize()
|
||||
{
|
||||
final String text = mSpeedLimitStr;
|
||||
final float textRadius = mBorderRadius - mBorderWidth;
|
||||
final float textMaxSize = 2 * textRadius;
|
||||
final float textMaxSizeSquared = (float) Math.pow(textMaxSize, 2);
|
||||
|
||||
float lowerBound = 0;
|
||||
float upperBound = textMaxSize;
|
||||
float textSize = textMaxSize;
|
||||
final Rect textBounds = new Rect();
|
||||
|
||||
while (lowerBound <= upperBound)
|
||||
{
|
||||
textSize = (lowerBound + upperBound) / 2;
|
||||
mTextPaint.setTextSize(textSize);
|
||||
mTextPaint.getTextBounds(text, 0, text.length(), textBounds);
|
||||
|
||||
if (Math.pow(textBounds.width(), 2) + Math.pow(textBounds.height(), 2) <= textMaxSizeSquared)
|
||||
lowerBound = textSize + 1;
|
||||
else
|
||||
upperBound = textSize - 1;
|
||||
}
|
||||
|
||||
mTextPaint.setTextSize(Math.max(1, textSize));
|
||||
int BACKGROUND_COLOR = 0xFFFFFFFF;
|
||||
int BORDER_COLOR = 0xFFFF0000;
|
||||
int ALERT_COLOR = 0xFFFF0000;
|
||||
int TEXT_COLOR = 0xFF000000;
|
||||
int TEXT_ALERT_COLOR = 0xFFFFFFFF;
|
||||
int UNLIMITED_BORDER_COLOR = 0xFF000000;
|
||||
int UNLIMITED_STRIPE_COLOR = 0xFF000000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +123,24 @@
|
||||
app:lanesEditModeLanesCount="10"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<app.organicmaps.widget.CurrentSpeedView
|
||||
android:id="@+id/nav_current_speed"
|
||||
style="@style/MwmWidget.CurrentSpeed"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="@dimen/margin_half"
|
||||
app:layout_constraintStart_toEndOf="@id/nav_next_turn_container"
|
||||
app:layout_constraintTop_toBottomOf="@id/street_frame"/>
|
||||
|
||||
<app.organicmaps.widget.SpeedLimitView
|
||||
android:id="@+id/nav_speed_limit"
|
||||
style="@style/MwmWidget.SpeedLimit"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_margin="@dimen/margin_half"
|
||||
app:layout_constraintStart_toEndOf="@id/nav_next_turn_container"
|
||||
app:layout_constraintTop_toBottomOf="@id/street_frame" />
|
||||
app:layout_constraintTop_toBottomOf="@id/nav_current_speed"
|
||||
android:translationY="-21dp"
|
||||
android:translationX="-12dp"
|
||||
android:translationZ="1dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -124,13 +124,26 @@
|
||||
app:lanesEditModeLanesCount="5"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<app.organicmaps.widget.CurrentSpeedView
|
||||
android:id="@+id/nav_current_speed"
|
||||
style="@style/MwmWidget.CurrentSpeed"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="@dimen/margin_half"
|
||||
app:layout_constraintEnd_toEndOf="@id/nav_next_turn_container"
|
||||
app:layout_constraintStart_toStartOf="@id/nav_next_turn_container"
|
||||
app:layout_constraintTop_toBottomOf="@id/nav_next_turn_container"/>
|
||||
|
||||
<app.organicmaps.widget.SpeedLimitView
|
||||
android:id="@+id/nav_speed_limit"
|
||||
style="@style/MwmWidget.SpeedLimit"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_margin="@dimen/margin_half"
|
||||
app:layout_constraintEnd_toEndOf="@id/nav_next_turn_container"
|
||||
app:layout_constraintStart_toStartOf="@id/nav_next_turn_container"
|
||||
app:layout_constraintTop_toBottomOf="@id/nav_next_turn_container" />
|
||||
app:layout_constraintTop_toBottomOf="@id/nav_current_speed"
|
||||
android:translationY="-23dp"
|
||||
android:translationX="-23dp"
|
||||
android:translationZ="1dp"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<declare-styleable name="SpeedLimitView">
|
||||
<attr name="speedLimitBackgroundColor" format="color" />
|
||||
<attr name="speedLimitBorderColor" format="color" />
|
||||
<attr name="speedLimitUnlimitedBorderColor" format="color" />
|
||||
<attr name="speedLimitUnlimitedStripeColor" format="color" />
|
||||
<attr name="speedLimitAlertColor" format="color" />
|
||||
<attr name="speedLimitTextColor" format="color" />
|
||||
<attr name="speedLimitTextAlertColor" format="color" />
|
||||
@@ -11,6 +13,14 @@
|
||||
<attr name="speedLimitEditModeAlert" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="CurrentSpeedView">
|
||||
<attr name="currentSpeedBackgroundColor" format="color" />
|
||||
<attr name="currentSpeedBorderColor" format="color" />
|
||||
<attr name="currentSpeedTextColor" format="color" />
|
||||
<!-- These values are used only in edit mode -->
|
||||
<attr name="currentSpeedEditModeCurrentSpeed" format="integer" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="LanesView">
|
||||
<attr name="lanesActiveLaneTintColor" format="reference" />
|
||||
<attr name="lanesInactiveLaneTintColor" format="color" />
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
<item name="speedLimitBorderColor">@color/base_red</item>
|
||||
</style>
|
||||
|
||||
<style name="MwmWidget.CurrentSpeed">
|
||||
<item name="speedLimitBorderColor">@color/black_primary</item>
|
||||
</style>
|
||||
|
||||
<style name="MwmWidget.FrameLayout"/>
|
||||
|
||||
<style name="MwmWidget.Downloader"/>
|
||||
|
||||
Reference in New Issue
Block a user