how to draw a circle on center of any device in android - android

I want to draw a circle or any object on center of any device.but i am unable to get center of device in all device accurately.i am able to work on some device but on max its not drawing accurately.please help..thanks in advance.I am also posting my piece of code here as well
package com.app.maxcircle;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
public class CircleWithMaxRadiusActivity extends Activity {
/** Called when the activity is first created. */
float pixelCenterX, pixelCenterY;
DrawCanvasCircle pcc;
LinearLayout ll;
private Canvas canvas;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
ll = (LinearLayout) findViewById(R.id.ll);
float centerx = width / 2;
float centery = height / 2;
pixelCenterX = convertDpToPixel(centerx, this);
pixelCenterY = convertDpToPixel(centery, this);
System.out.println("px..." + pixelCenterX);
System.out.println("py..." + pixelCenterY);
pcc = new DrawCanvasCircle(this);
Bitmap result = Bitmap.createBitmap(25, 25, Bitmap.Config.ARGB_8888);
canvas = new Canvas(result);
pcc.draw(canvas);
pcc.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
ll.addView(pcc);
}
public static float convertDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return px;
}
/**
* This method converts device specific pixels to device independent pixels.
*
* #param px
* A value in px (pixels) unit. Which we need to convert into db
* #param context
* Context to get resources and device specific display metrics
* #return A float value to represent db equivalent to px value
*/
public static float convertPixelsToDp(float px, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float dp = px / (metrics.densityDpi / 160f);
return dp;
}
class DrawCanvasCircle extends View {
public DrawCanvasCircle(Context mContext) {
super(mContext);
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
p.setColor(Color.WHITE);
DashPathEffect dashPath = new DashPathEffect(new float[] { 5, 5, 2,
2 }, (float) 1.0);
p.setPathEffect(dashPath);
p.setStyle(Style.STROKE);
for (int i = 0; i < 25; i++) {
canvas.drawCircle(pixelCenterX, pixelCenterY, pixelCenterY - 20
* i, p);
}
invalidate();
}
}
}

ok here is the link for you to get the status bar and title bar size.
after that, you need to substract them with :
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight() - statusHeight - titleHeight ;
ll = (LinearLayout) findViewById(R.id.ll);
float centerx = width / 2;
float centery = height / 2;
// you don't actually need to convert to Dp though, but if that is what you want then do it.
pixelCenterX = convertPixelToDp(centerx, this);
pixelCenterY = convertPixelToDp(centery, this);
good luck.

Try this
public class TestSO extends Activity {
/** Called when the activity is first created. */
float pixelCenterX, pixelCenterY;
DrawCanvasCircle pcc;
LinearLayout ll;
private Canvas canvas;
private float centerX, centerY;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
ll = (LinearLayout) findViewById(R.id.ll);
pixelCenterX = convertPixelsToDp(width, this) / 2;
pixelCenterY = convertPixelsToDp(height, this) / 2;
centerX = convertDpToPixel(pixelCenterX, this);
centerY = convertDpToPixel(pixelCenterY, this);
System.out.println("px..." + pixelCenterX);
System.out.println("py..." + pixelCenterY);
pcc = new DrawCanvasCircle(this);
Bitmap result = Bitmap.createBitmap(25, 25, Bitmap.Config.ARGB_8888);
canvas = new Canvas(result);
pcc.draw(canvas);
pcc.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
ll.addView(pcc);
}
public static float convertDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return px;
}
/**
* This method converts device specific pixels to device independent pixels.
*
* #param px
* A value in px (pixels) unit. Which we need to convert into db
* #param context
* Context to get resources and device specific display metrics
* #return A float value to represent db equivalent to px value
*/
public static float convertPixelsToDp(float px, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float dp = px / (metrics.densityDpi / 160f);
return dp;
}
class DrawCanvasCircle extends View {
public DrawCanvasCircle(Context mContext) {
super(mContext);
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
p.setColor(Color.WHITE);
DashPathEffect dashPath = new DashPathEffect(new float[] { 5, 5, 2,
2 }, (float) 1.0);
p.setPathEffect(dashPath);
p.setStyle(Style.STROKE);
for (int i = 0; i < 25; i++) {
canvas.drawCircle(centerX, centerY, pixelCenterY - 20
* i, p);
}
invalidate();
}
}
}

Related

How to create custom UI components like responsive seekbar?

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.

Getting the touchdown to move a Rect object

I am trying to get this paddle_user to move vertically on when the screen is touched. But the paddle isn't moving. I've double checked the onTouch Code but i'm still no closer to finding out what I am doing wrong.
package com.nblsoft.pong;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;
public class PongLogic extends View implements View.OnTouchListener {
//set screen constrains in dip
Configuration configuration = this.getResources().getConfiguration();
int dpHeight = configuration.screenHeightDp; //The current height of the available screen space, in dp units, corresponding to screen height resource qualifier.
int dpWidth = configuration.screenWidthDp; //The current width of the available screen space, in dp units, corresponding to screen width resource qualifier.
//int smallestScreenWidthDp = configuration.smallestScreenWidthDp; //The smallest screen size an application will see in normal operation, corresponding to smallest screen width resource qualifier.
//DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
//float dpHeight = displayMetrics.heightPixels / displayMetrics.density;
//float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
private int dptopixel(int DESIRED_DP_VALUE){
final float scale = getResources().getDisplayMetrics().density;
return (int)((DESIRED_DP_VALUE) * scale + 0.5f);
}
private int pixeltodp(int DESIRED_PIXEL_VALUE){
final float scale = getResources().getDisplayMetrics().density;
return (int) ((DESIRED_PIXEL_VALUE) - 0.5f / scale);
}
//set paddle size, speed, position vector
int paddle_pos_x = 4 * (dptopixel(dpWidth)/100); //3 for 320x480, 10 for 1080x1920 etc.
int paddle_width = (dptopixel(dpWidth)/10); //
int paddle_pos_y = (dptopixel(dpHeight)/10); //48 for 320x480, 190 for 1080x1920 etc.
int paddle_height = (dptopixel(dpHeight)/100) + 3; //the paddle is 100% of the total height of phone.
int user_paddle_pos_x = 4 * (dptopixel(dpWidth)/100) ;
int user_paddle_pos_y = dptopixel(dpHeight) - ((dptopixel(dpHeight)/10) + (dptopixel(dpHeight)/100) + 3) ;
//User Paddle
public Rect paddle_user = new Rect(user_paddle_pos_x,
user_paddle_pos_y,
user_paddle_pos_x + paddle_width,
user_paddle_pos_y + paddle_height);
//AI paddle
Rect paddle_AI = new Rect(paddle_pos_x,
paddle_pos_y,
paddle_pos_x + paddle_width,
paddle_pos_y + paddle_height);
//set ball position vector, Velocity vector, acceleration
//Override onDraw method
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Paint mytext = new Paint();
mytext.setColor(Color.WHITE);
// Draw Middle point
canvas.drawRect(0, ((dptopixel(dpHeight)) / 2), (dptopixel(dpWidth)), (((dptopixel(dpHeight)) / 2) + 2), mytext);
canvas.drawRect(paddle_user,mytext);
canvas.drawRect(paddle_AI, mytext);
//Practise Methods
//canvas.drawText(Integer.toString(dptopixel(dpHeight)),300,300,mytext);
//canvas.drawText(Integer.toString(dptopixel(dpWidth)), 400, 400, mytext);
//canvas.drawText(Integer.toString(dpHeight),500,500,mytext);
//canvas.drawText(Integer.toString(dpWidth),600,600,mytext);
//canvas.drawText("Fuck", 700, 700, mytext);
//canvas.drawRect(0,0,dptopixel(dpWidth),dptopixel(dpHeight),mytext);
}
//Override Touch method
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
paddle_user.offsetTo(10,0);
}
return true; //Event Handled
}
public PongLogic(Context context) {
super(context);
setBackgroundColor(Color.BLACK); //to set background
this.setFocusableInTouchMode(true); //to enable touch mode
this.setOnTouchListener(this);
}
}
You have to implement the OnTouchListener interface and do this.setOnTouchListener(this).
Edit:
public class CustomClass extends View implements View.OnTouchListener{}
then in your constructor you add this.setOnTouchListener(this);
Edit2:
Ok so I forgot to tell you but when you does some modification for exemple with you rect you have to call the draw method and to do that properly you call invalidate. So in your ontouch method add invalidate().
here is the code that I did if you wan to check (I just cut your code to have a easier exemple):
public class PongLogic extends View implements View.OnTouchListener {
//set ball position vector, Velocity vector, acceleration
Rect paddle_user = new Rect(0, 100, 100, 200);
public PongLogic(Context context, AttributeSet attrs) {
super(context, attrs);
this.setOnTouchListener(this);
setBackgroundColor(Color.BLACK); //to set background
this.setFocusableInTouchMode(true);
}
//Override onDraw method
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Paint mytext = new Paint();
mytext.setColor(Color.WHITE);
mytext.setStyle(Paint.Style.STROKE);
mytext.setStrokeWidth(2);
canvas.drawRect(paddle_user, mytext);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
paddle_user.offsetTo(0,0);
invalidate();
return false;
}
}
So what you missed was basically the invalidate() method. So what you did in the begging was not wrong with the first OnTouch method but better to do with the interface if you make a custom view.

canvas.drawText with pixel perfect text on a canvas

THIS IS NOT ABOUT AntiAlias, Please read the question before answering thank you.
ADDING BOUNTY TO--> android convert text width (in pixels) to percent of screen width/height
Quality info --> https://stackoverflow.com/a/1016941/1815624
I am getting inconsistent results when trying to draw text on a canvas. Please help, thank you.
I want the text to consume the same amount of scaled space on all devices
I do not care about ANTI_ALIAS and have added the paint.setFlags(Paint.ANTI_ALIAS_FLAG); but the problem is the same...
On 1 screen the text consumes half the width, on another only a 1/3 and even one that uses the full width.
I want them all to use equal amounts of screen real estate.
For Example
1600X900 7inch tablet Kitkat physical:
1920.1080 5.2 kitkat physical
1600x900 20in Lollipop emulated
1280x720 4.7inch
These have been created using the guide at http://www.gkproggy.com/2013/01/draw-text-on-canvas-with-font-size.html
where as that tutorial is showing consistent results
To be thorough here is the source:
public class MainActivity extends Activity
{
Paint paint;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
paint = new Paint();
View test = new TestView(this);
setContentView(test);
}
public class TestView extends View
{
public TestView(Context context)
{
super(context);
setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
public float pixelsToSp(Context context, float px) {
float scaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
return px/scaledDensity;
}
public float spToPixels(float sp) {
Context context = getContext();
float scaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
return scaledDensity*sp;
}
#Override
protected void onDraw(Canvas canvas)
{
int size = getResources().getDimensionPixelSize(R.dimen.sp20);
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
Log.v("intSize", Integer.toString(size));
Log.v("intSize", Integer.toString(px));
Log.v("intSize", Float.toString(spToPixels(20f)));
if(true) {
Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/Ultra.ttf");
paint.setTypeface(myTypeface);
}
paint.setColor(Color.BLACK);
paint.setTextSize(size);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
canvas.drawText("HELLOOOOOOOOOOOOOO!", 0, size, paint);
super.onDraw(canvas);
}
}
}
I have tried suggestion from
https://stackoverflow.com/a/5369766/1815624
Looking into this
https://stackoverflow.com/a/21895626/1815624
https://stackoverflow.com/a/14753968/1815624
https://stackoverflow.com/a/21895626/1815624 <-- trying now
Resources used:
https://stackoverflow.com/a/4847027/1815624
https://stackoverflow.com/a/21895626/1815624
Got to get screen width, some reference of text size to screen ratio, and calculate. so the results are:
and
notice the second HELLOOOOOOOOOOOOOOOOO!
public class MainActivity extends Activity
{
Paint paint;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
paint = new Paint();
View test = new TestView(this);
setContentView(test);
}
public class TestView extends View
{
public TestView(Context context)
{
super(context);
setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
public float pixelsToSp(float px) {
Context context = getContext();
float scaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
return px/scaledDensity;
}
public float spToPixels(float sp) {
Context context = getContext();
float scaledDensity = context.getResources().getDisplayMetrics().scaledDensity;
return scaledDensity*sp;
}
#Override
protected void onDraw(Canvas canvas)
{
int size = getResources().getDimensionPixelSize(R.dimen.sp20);
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
Log.v("intSize", Integer.toString(size));
Log.v("intSize", Integer.toString(px));
Log.v("intSize", Float.toString(spToPixels(20f)));
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
Log.v("intSize hm", Integer.toString(metrics.heightPixels));
Log.v("intSize wm", Integer.toString(metrics.widthPixels));
if(true) {
Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/Ultra.ttf");
paint.setTypeface(myTypeface);
}
paint.setColor(Color.BLACK);
paint.setTextSize(size);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
canvas.drawText("HELLOOOOOOOOOOOOOO!", 0, size, paint);
setTextSizeForWidth(paint, metrics.widthPixels * 0.5f, "HELLOOOOOOOOOOOOOO!");
canvas.drawText("HELLOOOOOOOOOOOOOO!", 0, size*3, paint);
super.onDraw(canvas);
}
/**
* Sets the text size for a Paint object so a given string of text will be a
* given width.
*
* #param paint
* the Paint to set the text size for
* #param desiredWidth
* the desired width
* #param text
* the text that should be that width
*/
private void setTextSizeForWidth(Paint paint, float desiredWidth,
String text) {
// Pick a reasonably large value for the test. Larger values produce
// more accurate results, but may cause problems with hardware
// acceleration. But there are workarounds for that, too; refer to
// https://stackoverflow.com/questions/6253528/font-size-too-large-to-fit-in-cache
final float testTextSize = 48f;
// Get the bounds of the text, using our testTextSize.
paint.setTextSize(testTextSize);
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
// Calculate the desired size as a proportion of our testTextSize.
float desiredTextSize = testTextSize * desiredWidth / bounds.width();
// Set the paint for that size.
paint.setTextSize(desiredTextSize);
}
}
}
please note if you not extending Activity use
DisplayMetrics metrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(metrics);
instead of
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

Issue on TextView width when creating my own TextView

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"

Using Canvas to draw rectangles to fit in a specified width screen

Using the code given below we can retrieve the height and the width of a particular screen size :
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
float dpHeight = displayMetrics.heightPixels / displayMetrics.density;
float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
I want to draw rectangles in a row as shown in the image. I have chosen default values for the rectangle width to be 100(in the drawRect() I have passed the difference between the right and left point to be 100, so that each rectangle is wide by 100). Each rectangle contains digits as shown in the picture. Now if the number of digits is small, the rectangles and the digits are rendered fine. But if the number of digits is large, the rectangles go outside the screen. For such a case I calculate the total width that the rectangles(including padding, commas, etc) will take, and compare it to the screen width. I am having issues with the code as the width that I get is in DP and the width that I calculate is not. How do I change the calculation of the total width covered by the rectangles, so that if this width is more than the width of the screen, I can reduce the dimensions of the rectangles, to render the rectangles within the scree.
Also, I want to render the rectangles "Centrally Aligned". How do I achieve that.
Given below is the image :
The code for the class is as follows :
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.StaticLayout;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
public class CounterWidget extends View {
private int DIGIT_SIZE = 120;
private int TEXT_SIZE = 75;
private int PADDING_LEFT=20;
private int PADDING_RIGHT=20;
private int RECT_HEIGHT=135;
private int RECT_WIDTH=100;
private int PADDING_BETWEEN_RECTS=10;
private int PADDING_BETWEEN_RECTANGLE_DIGIT_HORIZONTAL=12;
private int PADDING_BETWEEN_RECTANGLE_DIGIT_VERTICAL=25;
private int number = 1200000, rectColor, numColor, counter, noOfCommas, totalPadding;
private int digits[] = new int[15];
private Paint widgetPaint, numberPaint, textPaint, commaPaint;
private String defaultText;
public CounterWidget(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CounterWidget, 0, 0);
try {
rectColor = a.getInteger(R.styleable.CounterWidget_rectColor, 0);
numColor = a.getInteger(R.styleable.CounterWidget_numberColor, 1);
defaultText=a.getString(R.styleable.CounterWidget_defaultText);
} finally {
a.recycle();
}
init();
}
private void init() {
// Paint object for the rectangles.
widgetPaint = new Paint();
widgetPaint.setStyle(Paint.Style.FILL);
widgetPaint.setAntiAlias(true);
widgetPaint.setColor(rectColor);
// Paint object for the number.
numberPaint = new Paint();
numberPaint.setAntiAlias(true);
numberPaint.setColor(numColor);
numberPaint.setTextSize(DIGIT_SIZE);
// Paint object for the comma.
commaPaint = new Paint();
commaPaint.setAntiAlias(true);
commaPaint.setColor(rectColor);
commaPaint.setTextSize(DIGIT_SIZE);
//Calculation for the total number of digits.
int i = 0;
while (number > 0) {
digits[i] = number % 10;
number = number / 10;
i++;
}
counter = i - 1;
}
private void getNoOfCommas()
{
int a = counter+1;
if(a>0&&a<=3)
noOfCommas=0;
else if(a>3&&a<=6)
noOfCommas=1;
else if(a>6&&a<=9)
noOfCommas=2;
else if(a>9&&a<=12)
noOfCommas=3;
else
noOfCommas=4;
}
#Override
protected void onDraw(Canvas canvas) {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
float dpHeight = displayMetrics.heightPixels / displayMetrics.density;
float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
float pix = dpToPx(getContext(),(int) dpWidth);
checkForWidth(pix);
// The text passed in the layout.
// Starting point for the rendering of the counter.
Rect rect = new Rect(20, 20, (20+RECT_WIDTH), (20+RECT_HEIGHT)); // Calculation of the starting point.
// Origin for rendering of the digit inside the rectangle.
int xx = rect.left + PADDING_BETWEEN_RECTANGLE_DIGIT_HORIZONTAL;
int yy = (rect.bottom - PADDING_BETWEEN_RECTANGLE_DIGIT_VERTICAL);
// Origin for rendering the first comma.
int xxx,yyy = (rect.bottom +10);
for (int i = counter,j=0; i >= 0; i--,j++) {
// Drawing the rectangle and using rectangle as reference, drawing the digit.
drawColoredDigit(canvas, rect, String.valueOf(digits[i]),xx,yy);
// Updating the reference values for the rectangle.
rect.left += (PADDING_BETWEEN_RECTS + RECT_WIDTH);
rect.right += (PADDING_BETWEEN_RECTS + RECT_WIDTH);
// Updating the reference values for the digits inside the rectangle.
xx = (rect.left+ PADDING_BETWEEN_RECTANGLE_DIGIT_HORIZONTAL);
xxx = (rect.left - PADDING_BETWEEN_RECTS/2);
if(((counter-j)%3==0)&&(counter!=j))
{
canvas.drawText(",",xxx,yyy,commaPaint);
rect.left += (2*PADDING_BETWEEN_RECTS);
rect.right += (2*PADDING_BETWEEN_RECTS);
xx = (rect.left + PADDING_BETWEEN_RECTANGLE_DIGIT_HORIZONTAL);
}
}
}
private void drawColoredDigit(Canvas canvas, Rect rect, String digit, int xx, int yy) {
canvas.drawRect(rect, widgetPaint);
canvas.drawText(digit, xx, yy, numberPaint);
}
public static int dpToPx(Context context, int dp) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
int px = Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
return px;
}
public static float convertPixelsToDp(float px, Context context){
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float dp = px / (metrics.densityDpi / 160f);
return dp;
}
private void checkForWidth(float width)
{
getNoOfCommas();
totalPadding=(PADDING_BETWEEN_RECTS*(counter-1))+(noOfCommas*20)+PADDING_LEFT+PADDING_RIGHT;
int x = ((counter+1)*RECT_WIDTH)+totalPadding;
if( width<(x)) {
DIGIT_SIZE /= 3;
TEXT_SIZE /= 3;
RECT_HEIGHT-=30;
RECT_WIDTH-=30;
PADDING_BETWEEN_RECTANGLE_DIGIT_VERTICAL/=2;
PADDING_BETWEEN_RECTANGLE_DIGIT_HORIZONTAL/=2;
}
else {
Continue using the same dimensions.
}
}
public int convertToDp(int input)
{
float scale = getResources().getDisplayMetrics().density;
return (int) (input * scale + 0.5f);
}}
In the above code, I was trying to shrink the rectangles and the text within the rectangles.

Categories

Resources