I wish I could implement in Android what I show in this screenshot:
The number inside the circle there is no problem for me (simply make some accounts). But I do not know how to put the circle or as putting the marker.
I mean, it's like a speedometer. Then I want depending on the numerical value, the marker is in the position of the circle that matches the numerical value (the value is moved in a range of 0-100, so that the minimum value of the marker in the circle will be 0 or 100, obviously).
I'm a bit stuck with this, any help would be welcome. Thank you.
i created a circleView for you..just give a try...
CircleView.java
package com.example.err2;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class Circle extends View {
int radius, number, fontSize = 80;
Paint myPaint;
public void setRadius(int radius) {
this.radius = radius;
}
public void setNumber(int number) {
this.number = number;
}
private void init() {
Log.d("init", "start");
myPaint = new Paint();
myPaint.setColor(Color.RED);
}
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.save();
// Drawing main crcle
canvas.drawCircle(getWidth() / 2,
getHeight() / 2,
radius, myPaint);
myPaint.setColor(Color.WHITE);
canvas.drawCircle(getWidth() / 2,
getHeight() / 2,
radius - 10, myPaint);
// end of main circle
// drawing text-number
myPaint.setColor(Color.BLACK);
myPaint.setTextSize(fontSize);
myPaint.setTextAlign(Align.CENTER);
myPaint.setFakeBoldText(true);
canvas.drawText(number + "",
getWidth() / 2,
getHeight() / 2 + fontSize / 3, myPaint);
// end of drwaing text
// drawing point on circle boundry
// findPointLocation();
double deg = number * 3.6f;
double radians = Math.toRadians(deg);
int px = (int) Math.abs(radius * Math.sin(radians));
int py = (int) Math.abs(radius * Math.cos(radians));
if (number <= 25) {
px = -px;
} else if (number <= 50) {
px = -px;
py = -py;
} else if (number <= 75) {
py = -py;
}
// end od find point
myPaint.setColor(Color.GREEN);
canvas.drawCircle(getWidth() / 2 + px, getHeight() / 2 + py, 15,
myPaint);
// end of drawing point
canvas.restore();
}
}
below given the mainactivity code
MainActivity.java
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Circle circle=(Circle)findViewById(R.id.circle1);
circle.setRadius(100);
circle.setNumber(90);
}
}
given below xml code
XML
<com.example.err2.Circle
android:id="#+id/circle1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="73dp"
android:background="#778888" />
Related
I want to create custom sliders or seekbars in android (just as in the gif, slider on the bottom and right), could you provide me with any relevant process how to achieve this.
After searching for several days I have finally got enough resources to address the problem statement.
For staters go through the following resources:
1) https://guides.codepath.com/android/Basic-Painting-with-Views
2) https://guides.codepath.com/android/Progress-Bar-Custom-View
3) https://developer.android.com/guide/topics/ui/custom-components
Basics Steps -
Extend an existing View class or subclass with your own class.
Override some of the methods from the superclass. The superclass methods to override start with 'on', for example, onDraw(), onMeasure(), and onKeyDown(). This is similar to the on... events in Activity or ListActivity that you override for lifecycle and other functionality hooks.
Use your new extension class. Once completed, your new extension class can be used in place of the view upon which it was based.
Below is the code that demonstrate a working Clock in canvas -
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.Calendar;
/**
* Created by moonis
* on 23/06/18.
*/
public class CustomClock extends View {
private int height, width = 0;
private int padding = 0;
private int fontSize = 0;
int numeralSpacing = 0;
private int handTruncation, hourHandTruncation = 0;
private int radius = 0;
private Paint paint;
private boolean isInit;
private int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
private Rect rect = new Rect();
public CustomClock(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
setFocusable(true);
setFocusableInTouchMode(true);
}
private void initClock() {
height = getHeight();
width = getWidth();
padding = numeralSpacing + 50;
fontSize = (int) DeviceDimensionHelper.convertDpToPixel(13, getContext());
int min = Math.min(height, width);
radius = min / 2 - padding;
handTruncation = min / 20;
hourHandTruncation = min / 7;
paint = new Paint();
isInit = false;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isInit) {
initClock();
}
canvas.drawColor(Color.BLACK);
drawCircle(canvas);
drawCentre(canvas);
drawNumeral(canvas);
drawHands(canvas);
postInvalidateDelayed(500);
}
private void drawCircle(Canvas canvas) {
paint.reset();
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(width / 2, height / 2, radius + padding - 10, paint);
}
private void drawCentre(Canvas canvas) {
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(width / 2, height / 2, 12, paint);
}
private void drawNumeral(Canvas canvas) {
paint.setTextSize(fontSize);
for (int number : numbers) {
String tmp = String.valueOf(number);
paint.getTextBounds(tmp, 0, tmp.length(), rect);
double angle = Math.PI / 6 * (number - 3);
int x = (int) (width / 2 + Math.cos(angle) * radius - rect.width() / 2);
int y = (int) (height / 2 + Math.sin(angle) * radius - rect.height() / 2);
canvas.drawText(tmp, x, y, paint);
}
}
private void drawHands(Canvas canvas) {
Calendar c = Calendar.getInstance();
float hour = c.get(Calendar.HOUR_OF_DAY);
hour = hour > 12 ? hour - 12 : hour;
drawHand(canvas, (hour + c.get(Calendar.MINUTE) / 60) * 5f, true);
drawHand(canvas, c.get(Calendar.MINUTE), false);
drawHand(canvas, c.get(Calendar.SECOND), false);
}
private void drawHand(Canvas canvas, double loc, boolean isHour) {
double angle = Math.PI * loc / 30 - Math.PI / 2;
int handRadius = isHour ? radius - handTruncation - hourHandTruncation : radius - handTruncation;
canvas.drawLine(width / 2, height / 2, (float) (width / 2 + Math.cos(angle) * handRadius), (float) (height / 2 + Math.sin(angle) * handRadius), paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//code to move clock hands on screen gestures
break;
case MotionEvent.ACTION_MOVE:
//code to move clock hands on screen gestures
break;
default:
return false;
}
//redraw view
postInvalidate();
return true;
}
}
Finally this library can be used to achieve the desired output -
https://github.com/moldedbits/android-dial-picker
have a look at this Wheelview Library to achieve the bottom wheel
and this for your vertical ruler
to scale your image horizontally and vertically, probably you might have to go with some sort of custom solution, Vector images would be a suitable fit.
Also refer this
Hope this helps you.
Is there any way to draw polygonal shapes on Android xml layouts?
or is any helper class as library to draw them?
I am using enhanced version of this Class
See working sample on GitHub (https://github.com/hiteshsahu/Benzene)
Drawable Class
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
/**
* Originally Created by AnderWeb (Gustavo Claramunt) on 7/10/14.
*/
public class PolygonalDrwable extends Drawable {
private int numberOfSides = 3;
private Path polygon = new Path();
private Path temporal = new Path();
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public PolygonalDrwable(int color, int sides) {
paint.setColor(color);
polygon.setFillType(Path.FillType.EVEN_ODD);
this.numberOfSides = sides;
}
#Override
public void draw(Canvas canvas) {
canvas.drawPath(polygon, paint);
}
#Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
#Override
public int getOpacity() {
return paint.getAlpha();
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
computeHex(bounds);
invalidateSelf();
}
public void computeHex(Rect bounds) {
final int width = bounds.width();
final int height = bounds.height();
final int size = Math.min(width, height);
final int centerX = bounds.left + (width / 2);
final int centerY = bounds.top + (height / 2);
polygon.reset();
polygon.addPath(createHexagon(size, centerX, centerY));
polygon.addPath(createHexagon((int) (size * .8f), centerX, centerY));
}
private Path createHexagon(int size, int centerX, int centerY) {
final float section = (float) (2.0 * Math.PI / numberOfSides);
int radius = size / 2;
Path polygonPath = temporal;
polygonPath.reset();
polygonPath.moveTo((centerX + radius * (float)Math.cos(0)), (centerY + radius
* (float)Math.sin(0)));
for (int i = 1; i < numberOfSides; i++) {
polygonPath.lineTo((centerX + radius * (float)Math.cos(section * i)),
(centerY + radius * (float)Math.sin(section * i)));
}
polygonPath.close();
return polygonPath;
}
}
Set drawable to any Imageview like this
//Triangle
((ImageView) findViewById(R.id.triangle))
.setBackgroundDrawable(new PolygonalDrwable(Color.GREEN, 3));
//Square
((ImageView) findViewById(R.id.square))
.setBackgroundDrawable(new PolygonalDrwable(Color.MAGENTA, 4));
//Pentagon
((ImageView) findViewById(R.id.pentagon))
.setBackgroundDrawable(new PolygonalDrwable(Color.LTGRAY, 5));
//Hexagon
((ImageView) findViewById(R.id.hex))
.setBackgroundDrawable(new PolygonalDrwable(Color.RED, 6));
//Heptagon
((ImageView) findViewById(R.id.hept))
.setBackgroundDrawable(new PolygonalDrwable(Color.MAGENTA, 7));
//Octagon
((ImageView) findViewById(R.id.oct))
.setBackgroundDrawable(new PolygonalDrwable(Color.YELLOW, 8));
You can create custom drawable and shapes as drawable resources.
Right click on the "drawable" folder in Android Studio and select New->Drawable Resource File.
Here is a decent tutorial for shapes and strokes to get started.
Here is some example shapes ready to use.
Here is documentation for some more complex things you can do with drawables.
I created my own TextView by extending the TextView class in order to improve its display. I created various Paint and stuff to add a kind of margin. Then text has to be displayed right after the margin. If I set
android:layout_width="fill_parent"
the display is ok and my line is fully filled with a white background (as defined in my layout).
BUT if I set
android:layout_width="wrap_content"
the display goes wrong and the end of the text of my TextView is cropped. I guess this is due to the fact that I made a Translate in the onDraw method of my TextView but I don't know how to fix it.
Please note that I need the set wrap_content because I want to add another TextBox right after, and a LinearLayout around both, but for the moment the other TextBox erase a part of the content of the first one.
The code of my new TextBox is the following one :
package com.flo.ui;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.TextView;
import com.flo.musicalnotes.R;
public class NoteItemTextView extends TextView {
// Properties
private Paint marginPaint;
private Paint linePaint;
private Paint circlePaint;
private int paperColor;
private float margin;
private float marginEnd;
private float textStart;
// Initialization
public NoteItemTextView(Context context) {
super(context);
this.Init(context);
}
public NoteItemTextView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.Init(context);
}
private void Init(Context context)
{
// Resources retrieval
Resources myResources = getResources();
// Brush definition
this.marginPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.marginPaint.setColor(myResources.getColor(R.color.marginColor));
this.marginPaint.setStrokeWidth((float) 1.8);
this.linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.linePaint.setColor(myResources.getColor(R.color.underlineColor));
this.circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.circlePaint.setColor(myResources.getColor(R.color.marginColor));
this.circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
// various resources
this.paperColor = myResources.getColor(R.color.bgColor);
this.margin = myResources.getDimension(R.dimen.marginSize);
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int ot = getResources().getConfiguration().orientation;
switch(ot)
{
case Configuration.ORIENTATION_LANDSCAPE:
this.marginEnd = this.margin + metrics.widthPixels / 100;
this.textStart = this.marginEnd + metrics.widthPixels / 100;
case Configuration.ORIENTATION_PORTRAIT:
this.marginEnd = this.margin + metrics.heightPixels / 100;
this.textStart = this.marginEnd + metrics.heightPixels / 100;
default:
this.marginEnd = this.margin + 5;
this.textStart = this.marginEnd + 10;
}
}
//#Override
protected void onDraw(Canvas canvas) {
// paper color
canvas.drawColor(this.paperColor);
// lines drawing
canvas.drawLine(0, getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight(), this.linePaint);
// marge drawing
canvas.drawLine(this.margin, 0, this.margin, getMeasuredHeight(), this.marginPaint);
canvas.drawLine(this.marginEnd, 0, this.marginEnd, getMeasuredHeight(), this.marginPaint);
double x = (this.textStart + this.marginEnd) / 1.8;
float y1 = getMeasuredHeight() / 3;
float y2 = getMeasuredHeight() * 2 / 3;
float radius = (float) 2.5;
canvas.drawCircle((float) x, y1, radius, this.circlePaint);
canvas.drawCircle((float) x, y2, radius, this.circlePaint);
canvas.save();
canvas.translate(this.textStart, 0);
super.onDraw(canvas);
canvas.restore();
}
}
Thanks for your help !
Try to add this code to your custom textview class
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = getMeasuredHeight();
int width = getMeasuredWidth();
Log.e(getClass().getSimpleName() , String.format("height x %s ::: width x %s ",height , width));
float density = getResources().getDisplayMetrics().density;
//Extra space after last letter.
float px = 2 * density;
int adjustedWidth = (int) (width + textStart + px);
setMeasuredDimension(adjustedWidth, height);
}
add this to your textview
android:paddingRight="25dp"
I have to design a triangle and display some text inside it with an angle of 45, below that I have to put a text view outside the boundaries of the triangle to display some other text. It is like a banner. However when I use a relative layout and put a triangular background, it still acts as a rectangle, obscuring my Text view. Below is the code I use:
<RelativeLayout
android:id="#+id/relative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="#drawable/image_sticker" >
<com.example.AngledTextView
android:id="#+id/textViewx"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:rotation="52"
android:textColor="#FFFFFF" />
</RelativeLayout>
My AngledTextView Class:
public class AngledTextView extends TextView {
private int mWidth;
private int mHeight;
public AngledTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
/*Paint textPaint = new Paint();
int xPos = (canvas.getWidth() / 2);
int yPos = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2)) ;
canvas.rotate(45, xPos,yPos); */
super.onDraw(canvas);
canvas.restore();
}
}
Problem:
Any hints or links to suggested tutorials will be highly appreciated :)
i've done similar stuff recently. Here are some tips i've used:
Create customView class.
Init at least one Paint (semitransparent, fill) and one Path on your init method. It should be called from constructors.
On your onDraw method customize path. For example:
mPath = new Path();
mPath.moveTo(.0f, this.getHeight());
mPath.lineTo(this.getWidth(), this.getHeight());
mPath.lineTo(this.getWidth(),0.25f*this.getHeight());
mPath.lineTo(.0f, .0f);
mPath.lineTo(.0f, this.getHeight());
This will make a Path similar to a trapezoid. Just customize your points to make a triangle. Then call
canvas.clipPath(mPath);
canvas.drawPath(mPath,mPaint);
With these points, you will draw your triangle. You could pass a String to your init method and call drawText before drawing the path:
canvas.drawText(str, xTit, yTit, mPaintTit);
I hope this will help =)
In your regular textview use rotate animation like.
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:rotation="45"
android:text="#string/hello_world" />
Your implementation could inherit from Drawable and implement getTransparentRegion()
Next, use this drawable as background on a view that is drawn on top of your TextView (probably by having both as childs inside a FrameView)
i have some link for crate triangle background as below
link1
link2
link3
i hope it helpful for you
Before you do any drawing, you must initialize and load the shapes you plan to draw. Unless the structure (the original coordinates) of the shapes you use in your program change during the course of execution, you should initialize them in the onSurfaceCreated() method of your renderer for memory and processing efficiency.
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
...
// initialize a triangle
mTriangle = new Triangle();
// initialize a square
mSquare = new Square();
}
Example
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.LinearLayout;
public class Slice extends LinearLayout {
final static String TAG = "Slice";
Paint mPaint;
Path mPath;
public enum Direction {
NORTH, SOUTH, EAST, WEST;
}
public Slice(Context context) {
super(context);
Create(context);
}
public Slice(Context context, AttributeSet attrs) {
super(context, attrs);
Create(context);
}
private void Create(Context context) {
Log.i(TAG, "Creating ...");
mPaint = new Paint();
mPaint.setStyle(Style.FILL);
mPaint.setColor(Color.RED);
Point point = new Point();
point.x = 80;
point.y = 80;
mPath = Calculate(point, 70, Direction.SOUTH);
}
#Override
protected void onDraw(Canvas canvas) {
Log.i(TAG, "Drawing ...");
canvas.drawPath(mPath, mPaint);
}
private Path Calculate(Point p1, int width, Direction direction) {
Log.i(TAG, "Calculating ...");
Point p2 = null, p3 = null;
if (direction == Direction.NORTH) {
p2 = new Point(p1.x + width, p1.y);
p3 = new Point(p1.x + (width / 2), p1.y - width);
} else if (direction == Direction.SOUTH) {
p2 = new Point(p1.x + width, p1.y);
p3 = new Point(p1.x + (width / 2), p1.y + width);
} else if (direction == Direction.EAST) {
p2 = new Point(p1.x, p1.y + width);
p3 = new Point(p1.x - width, p1.y + (width / 2));
} else if (direction == Direction.WEST) {
p2 = new Point(p1.x, p1.y + width);
p3 = new Point(p1.x + width, p1.y + (width / 2));
}
Path path = new Path();
path.moveTo(p1.x, p1.y);
path.lineTo(p2.x, p2.y);
path.lineTo(p3.x, p3.y);
return path;
}
}
I use the following class to create a rotatable dialog and everything is ok.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;
public class RotateLinearLayout extends LinearLayout {
private Matrix mForward = new Matrix();
private Matrix mReverse = new Matrix();
private float[] mTemp = new float[2];
private float degree = 0;
public RotateLinearLayout(Context context) {
super(context);
}
public RotateLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void dispatchDraw(Canvas canvas) {
if (degree == 0) {
super.dispatchDraw(canvas);
return;
}
canvas.rotate(degree, getWidth() / 2, getHeight() / 2);
mForward = canvas.getMatrix();
mForward.invert(mReverse);
canvas.save();
canvas.setMatrix(mForward); // This is the matrix we need to use for
// proper positioning of touch events
super.dispatchDraw(canvas);
canvas.restore();
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (degree == 0) {
return super.dispatchTouchEvent(event);
}
final float[] temp = mTemp;
temp[0] = event.getX();
temp[1] = event.getY();
mReverse.mapPoints(temp);
event.setLocation(temp[0], temp[1]);
return super.dispatchTouchEvent(event);
}
public void rotate() {
if (degree == 0) {
degree = 180;
} else {
degree = 0;
}
}
}
I have an ImageView on left side of this dialog which is equipped with an animation. When the dialog is not rotated ImageView animates correctly. When I rotate my dialog, ImageView must animate on right side of dialog but it changes the screen pixels of previously placed ImageView in an ugly state. I mean after rotation the position of ImageView changes correctly but the position of its animation remains unchanged.
How can I set the new position of ImageView's animation?
I just added the line invalidate(); and everything was corrected:
#Override
protected void dispatchDraw(Canvas canvas) {
if (degree == 0) {
super.dispatchDraw(canvas);
return;
}
canvas.rotate(degree, getWidth() / 2, getHeight() / 2);
mForward = canvas.getMatrix();
mForward.invert(mReverse);
canvas.save();
canvas.setMatrix(mForward); // This is the matrix we need to use for
// proper positioning of touch events
super.dispatchDraw(canvas);
canvas.restore();
// is needed
invalidate();
}