well, im a begginer in android and i need to use maps on the device more specifically (polylines) i need to do something like this.
this is a web app i did to track down bus routes and bus-stops on my city , and i've been asked to do the same thing in android! ive been checking the maps api for android and did not found anything similar to polyline in JS api , is there a way to achieve this?
i have no problem adding simple overlays i've been checking the basic tutorials in android developer site, but i dont know how to draw the polyline.
There no such API in Android Google Maps API. You can only first list the actual GeoPoints of the route that you want to draw and then draw the points and lines on a Overlay object. There's just no easy way to do that.
A more easy way to do that is get your points and extend the ImageView that will display your image to draw the points, than you just need to pass the points that you want to draw .
In my project I did this:
public class ImageDraw extends ImageView{
private Paint mPaint = new Paint();
List<Point> pts = new ArrayList<Point>() ;
public ImageDraw(Context context) {
super(context);
}
//used to send the location of the points to draw on the screen
//must be called before every redraw to update the points on the screen
public void SetPointsToDraw(List<Point> pts)
{
this.pts = pts;
}
public ImageDraw(Context context, AttributeSet attrs)
{
super(context,attrs);
}
public ImageDraw(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
#Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Paint paintColor = mPaint;
paintColor.setColor(Color.YELLOW);
paintColor.setStrokeWidth(3);
if(pts.size() > 0)
{
canvas.drawCircle(pts.get(0).x, pts.get(0).y, 7, paintColor);
}
if (pts.size() > 1)
{
for (int i = 1 ; i < pts.size(); i++) {
paintColor.setColor(Color.YELLOW);
canvas.drawCircle(pts.get(i).x, pts.get(i).y, 7, paintColor);
paintColor.setColor(Color.RED);
canvas.drawLine(pts.get(i-1).x, pts.get(i-1).y, pts.get(i).x, pts.get(i).y, paintColor);
}
}
}
}
When you extends the Imageview and create the layout with xml don`t forget to put the entire package of you new widget like:
com.Myapp.MyImageView
FvZ's answer works but is not the native way, there are polylines on the map, a simple example
https://stackoverflow.com/a/21877742/618419
Also take a look at the Android Documentation, they have many simple and well put-together examples:
http://developer.android.com/reference/com/google/android/gms/maps/model/Polyline.html
Related
I a using MpAndroidChart library. I need to implement a design where I need to color the area between two limit lines. I have attached an image for reference. I have tried multiple ways but I have failed to achieve it. I am using this library for the first time. Can anyone help me about how this could be achieved.
As you can see the green shade behind the line graph. Which is the limit. I need to get that green shade
Thanks in advance,
Anudeep Reddy.
I don't think that there is a direct way to achieve this, but this workaround should help you:
LimitLine ll = new LimitLine(lowerLimit, "Systolic range");
ll.setLineColor(Color.GREEN);
ll.setLineWidth(upperLimit - lowerLimit);
ll.setTextColor(Color.WHITE);
ll.setTextSize(12f);
chart.getAxisLeft().setDrawLimitLinesBehindData(true);
The important thing here is the method setDrawLimitLinesBehindData(true).
As always, all the information is available in the documentation.
I had the same problem but reached a different workaround without having to subclass the LineChart. Using canvas to draw the rectangle works, but you have to translate your charts coordinates to the canvas coordinates. You cannot use a single limit line as there is a limit to the width of the line. The workaround I used was to simply loop through limit lines to create a rectangle within my range.
float increment = (rangeHigh - rangeLow) / 20;
float metricLine = rangeLow;
for(int i = 0; i < 20; i++) {
LimitLine llRange = new LimitLine(metricLine, "");
llRange.setLineColor(Color.parseColor("#b5eb45"));
llRange.setLineWidth(10f);
leftAxis.addLimitLine(llRange);
metricLine = metricLine + increment;
}
As this is still an issue I throw in my two cents.
I tried the solution of #HouseOfHufflepuff but I got the error message that I use too much limit lines in the plot. It seems to work anyway but I guess the performance is not optimal.
So I implemented a subclass for drawing zones in the background. Maybe it's helpful for someone:
public class TargetZoneCombinedChart extends CombinedChart {
protected Paint mYAxisSafeZonePaint;
private List<TargetZone> mTargetZones;
public TargetZoneCombinedChart(Context context) {
super(context);
}
public TargetZoneCombinedChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TargetZoneCombinedChart(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void init() {
super.init();
mYAxisSafeZonePaint = new Paint();
mYAxisSafeZonePaint.setStyle(Paint.Style.FILL);
// mGridBackgroundPaint.setColor(Color.rgb(240, 240, 240));
mTargetZones = new ArrayList<>();
}
#Override
protected void onDraw(Canvas canvas) {
for (TargetZone targetZone : mTargetZones) {
// prepare coordinates
float[] pts = new float[4];
pts[1] = targetZone.lowerLimit;
pts[3] = targetZone.upperLimit;
mLeftAxisTransformer.pointValuesToPixel(pts);
// draw
mYAxisSafeZonePaint.setColor(targetZone.color);
canvas.drawRect(mViewPortHandler.contentLeft(), pts[1], mViewPortHandler.contentRight(),
pts[3], mYAxisSafeZonePaint);
}
super.onDraw(canvas);
}
public void addTargetZone(TargetZone targetZone){
mTargetZones.add(targetZone);
}
public List<TargetZone> getTargetZones(){
return mTargetZones;
}
public void clearTargetZones(){
mTargetZones = new ArrayList<>();
}
public static class TargetZone {
public final int color;
public final float lowerLimit;
public final float upperLimit;
public TargetZone(int color, float lowerLimit, float upperLimit) {
this.color = color;
this.lowerLimit = lowerLimit;
this.upperLimit = upperLimit;
}
}
}
To add a zone you just need to add a target zone object:
float rangeHigh = 180f;
float rangeLow = 80f;
chart.addTargetZone(new TargetZoneCombinedChart.TargetZone( Color.parseColor("#33b5eb45"),rangeLow,rangeHigh));
whereby the ranges are y values of the left axis.
This can be done by sub-classing the chart class (e.g. LineChart) and then overriding the onDraw() method. In the overridden onDraw() you can draw the rectangle(s) you need directly onto the canvas and then call super.onDraw() to complete the rendering of the chart.
There is an example of how to do this on the MP Android Github (see below). I followed the code in the example and it worked well for me.
https://github.com/PhilJay/MPAndroidChart/issues/485
I'm looking to replicate the following within my application:
As you can see, its basically a button which increases/decreases the value of the text view contained within it. This button will have three visual states -> unpressed, decrease and increase (as seen in the image above, the user taps the increase arrows and the button appears pressed in on that side)
Here are my 3 button states currently:
As you can see, the problem I have is being able to correctly skew/rotate the text view so it looks visually correct and appears slanted along with the button when its being increased or decreased.
I have tried two different approaches so far:
Create a custom text view class which overrides the onDraw() method to skew the canvas:
#Override
public void onDraw(Canvas canvas) {
canvas.save();
canvas.skew(0.2f, 0f);
super.onDraw(canvas);
canvas.restore();
}
Integrate the Rotate3dAnimation class (source here) and used many different variations to get the desired result such as:
Rotate3dAnimation skew = new Rotate3dAnimation(
30, 0, centerX, centerY, 0, false);
txtAmount.startAnimation(skew);
Unfortunately, I'm not quite getting the exact result that mirrors the first image above. I'm getting confused with setting values with the Z-axis, skew, rotate etc.
I'd greatly appreciate any help from anyone who has experience with this stuff. Thanks in advance
Well I even tried and I came up with something like this:
public class DemoActivity extends TextView {
Context context;
String firstText = "$120.00";
public DemoActivity(Context context)
{
super(context);
this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setText(firstText);
setTextSize(30);
canvas.skew(1.0f, 0.3f); //you need to change values over here
Rotate3dAnimation skew = new Rotate3dAnimation(
-20, 30,200, 200, 0, false); //here too
startAnimation(skew);
}
}
I got an output as:
I guess changing the values by trial and error can solve your problem.
Hope it helps.
Thanks to Parth Doshi answer. His answer need a little tweaking to run which I'm sharing here to save someone else time.
First create a class in src folder and write all of three constructors.
public class TextViewDemo extends TextView {
Context context;
String text = "TESTING 3DX TOOLS";
public TextViewDemo(Context context) {
super(context);
this.context = context;
}
public TextViewDemo(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public TextViewDemo(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
setText(text);
setTextSize(30);
canvas.skew(0.5f, 1.0f); // you need to change values over here
Rotate3dAnimation skew = new Rotate3dAnimation(-50, 30, 0, 0, 0,
false); // here too
startAnimation(skew);
}
}
In you res/layout/my_layout.xml file you can add a tag of your custom made TextView.
<com.yourpackage.name.TextViewDemo
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="Hello World"
<!-- All parameters and value shall remain same -->
/>
Like any other view, you can create an instance of TextViewDemo in your onCreate() method
TextViewDemo txtDemo = (TextViewDemo) findViewById(R.id.name);
Regards
I have an EditText, which generally shows parallel to the screen X-axis. I want to show it obliquely (around 45 degree to horizontal axis). Is it possible to do this in Android. Please guide me in a direction so that I can try for it.
After getting the two links in the answer by pawelzeiba, I proceed a little bit in solving this, but stuck again so I put another question on this. here is the link.
As Gunnar Karisson said, there is a setRotation() method in View class introduced in Android 3.0, but I cannot use it as my application should work fro Android 2.1 version.
So please help me to solve this.
EditText is an indirect subclass of View which has a rotation field you can set with setRotation(float):
myEditText.setRotation(45.0f).
After a long R & D, I succeed to solve this by creating my own custom edittext, which works perfectly as per my requirement.
public class CustomEditText extends EditText {
private Animation rotateAnim;
public CustomEditText(Context context) {
super(context);
}
public CustomEditText(Context context, AttributeSet attrs){
super(context, attrs);
}
private void createAnim(Canvas canvas) {
rotateAnim = new RotateAnimation(0, -45, 250, 50);
rotateAnim.setRepeatCount(Animation.INFINITE);
startAnimation(rotateAnim);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// creates the animation the first time
if (rotateAnim == null) {
createAnim(canvas);
}
}
}
You can rotate view, examples:
Vertical (rotated) label in Android
Is it possible to write vertically in a textview in android?
But I'm not sure how it will look with EditText during edition.
If the setRotation() method isn't available to the API level you are working with, then your best bet would be to create your own subclass of View and implement a setRotation() method.
I want to be able to mirror my app so it can be viewed in the windshield of a vehicle.
My XML has several nested LinearLayouts, TextViews and ImageViews. Currently I'm transforming each one and although it is mirrored, the structure of the elements is not (what was at the top is now at the bottom).
I've been looking for days and so far have tried a couple of approaches that have failed.
An animation that uses a matrix to flip on the X axis kind of works, except that it either reverts back or it stays and doesn't update, which is no good for interacting with the app.
I just tried to create a custom LinearLayout extending the parent one, hoping that I could apply a Matrix in its onDraw() method but that gives me a blank screen (I had to set setWillNotDraw(false); to hit the onDraw()).
Well eventually I found a solution that works well for me (so far it's caused no issues for users).
My solution was to override dispatchDraw to scale the canvas in my custom LinearLayout. Then I just needed to flip the touch events by overriding dispatchTouchEvent:
public class CustomContainer extends LinearLayout {
public CustomContainer(Context context) {
super(context);
this.setWillNotDraw(false);
}
public CustomContainer(Context context, AttributeSet attrs) {
super(context, attrs);
this.setWillNotDraw(false);
}
public CustomContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setWillNotDraw(false);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
// Flip the view canvas
if (MyHUDActivity.mHUDMode) canvas.scale(1,-1, getWidth(), getHeight()/2f);
super.dispatchDraw(canvas);
canvas.restore();
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
// If in HUD mode then flip the touch zones
if (MyHUDActivity.mHUDMode) event.setLocation(event.getX(), getHeight()-event.getY());
return super.dispatchTouchEvent(event);
}
}
You can use the new Animation api to deal with reverting back after the horizontal flip.
OK, Brief recap, Was asked to create an app for work that records data specific data and display it to the screen when finished. So it would function like so.
press start > press stop > display results.
However, I have just been told by the IT director of my company that he wants to display information in needle graphs (g-force, average speed, top speed) and also wants a flashy way of displaying the others (time taken, distance traveled)
My initial idea is this:
create a needle gauge like this, but on a smaller scale and have the digit value display below or beside the graph and to just display the distance traveled and time taken displayed as alarm clock style digits. This would all run down the left hand side of the screen in a thin column and then hava a map displaying the starting location and end location with the route taken for the journey
basically I would like it to look like this (sorry for the crudeness of the drawing)
Something along these lines would be perfect!
I think I could work out the map business and the digits for the time and distance readouts but I have never done any really fancy UI stuff.
How would I get started making the needle gauge?
I was thinking of trying a horizontal bar gauge forst maybe? Incase I cant get the needle gauge to work.
Also, I only have a til tuesday! :S
invision the following very basic idea:
We have our Custom View with a background image which is the gauge without the needle!
So we first implement this using a class that extends View
public class ourGauge extends View {
private Bitmap bgImage = null;
public ourGauge(Context context, Bitmap bgImage) {
super(context);
this.bgImage = bgImage;
}
public ourGauge(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bgImage, 0, 0, null);
}
}
Now lets add a needle
public class ourGauge extends View {
private Bitmap bgImage = null;
private int indicator;
Paint paint = new Paint();
public ourGauge(Context context, Bitmap bgImage) {
super(context);
this.bgImage = bgImage;
}
public ourGauge(Context context) {
super(context);
}
public void setIndicator(int indicator){
this.indicator = indicator;
invalidate();
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bgImage, 0, 0, null);
//you could set color based on indicator (speed or sth)
paint.setColor(Color.BLACK);
canvas.drawLine(0, 0, 20, 20, paint);
//you have to find the formula to get from where to where the line should drawn
}
}
To make it better
Don't draw the needle using drawLine but rather make it a shape
with dimensions
To create dynamic labels for speeds, you should draw them too
etc