Android centered box - android

I have this custom view that should display a centered box in the page, with different resolutions and displays.
(i removed all the code relative to the text, etc):
public class CustomView extends View {
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
Paint x = new Paint();
x.setColor(Color.BLUE);
Resources r = getResources();
//dimension of display
int displayW = r.getDisplayMetrics().widthPixels;
int displayH = r.getDisplayMetrics().heightPixels;
//
int boxW = 200;
int boxH = 300;
//actual box dimensions
float boxEffettivaW = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, boxW, r.getDisplayMetrics());
float boxEffettivaH = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, boxH, r.getDisplayMetrics());
float left = (displayW-boxEffettivaW) / 2;
float top = (displayH-boxEffettivaH) / 2;
float right = left + boxEffettivaW;
float bottom = top + boxEffettivaH;
RectF boxf = new RectF();
boxf.set(left,top,right,bottom);
canvas.drawRect(boxf, x);
}
}
My issue is that the box is not centered, because of the android application title bar, and because of the notify bar. screenshot
So, how can i center my box?
I'd need to know the size of the actual app-dedicated display area, not the global display size...

Related

Set seekbar thumb above seekbar line

In my Android app, I have to customize a seekbar and I wonder how I can set a seekbar thumb above its progress line instead of center by default?
You can check it out Discrete Seekbar
seekBar.setMin(0);
seekBar.setMax(yourArray.length);
seekBar.setOnProgressChangeListener(new DiscreteSeekBar.OnProgressChangeListener() {
int onProgressChanged =0;
#Override
public void onProgressChanged(DiscreteSeekBar seekBar, int value, boolean fromUser) {
onProgressChanged = value;
}
#Override
public void onStartTrackingTouch(DiscreteSeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(DiscreteSeekBar seekBar) {
}
});
I looked for this info in many posts and get some ideas from there and here, and created SeekBayHint, which creates text of progress above arrow:
SeekBar
MainClass:
package your_package;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import your_package.R;
public class SeekBarHint extends android.support.v7.widget.AppCompatSeekBar {
private Paint mTextPaint;
private Rect mTextBounds = new Rect();
private Bitmap mBitmapIconArrowDown;
/** for this class yPosition must be as minHeight in layoutFile for this seekBar*/
private static int sTextYPositionIndent = 20;
private float mTextSizeDecrease = 1.75f;
public static void setTextYPositionIndent(int textYPositionIndent) {
sTextYPositionIndent = textYPositionIndent;
}
public SeekBarHint(Context context) {
super(context);
mBitmapIconArrowDown = BitmapFactory.decodeResource(context.getResources(),
R.drawable.progress_seek_bar_arrow_down);
mTextPaint = new Paint();
mTextPaint.setColor(getResources().getColor(R.color.colorPrimary));
}
public SeekBarHint(Context context, AttributeSet attrs) {
super(context, attrs);
mBitmapIconArrowDown = BitmapFactory.decodeResource(context.getResources(),
R.drawable.progress_seek_bar_arrow_down);
mTextPaint = new Paint();
mTextPaint.setColor(getResources().getColor(R.color.colorPrimary));
}
public SeekBarHint(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mBitmapIconArrowDown = BitmapFactory.decodeResource(context.getResources(),
R.drawable.progress_seek_bar_arrow_down);
mTextPaint = new Paint();
mTextPaint.setColor(getResources().getColor(R.color.colorPrimary));
}
#Override
protected synchronized void onDraw(Canvas canvas) {
// first draw the regular progress bar, then custom draw our textString
super.onDraw(canvas);
// now progress position and convert to textString.
String textString = Integer.toString(getProgress()) + "%";
// now get size of seek bar.
float width = getWidth();
float height = getHeight();
// set textString size.
mTextPaint.setTextSize(height / mTextSizeDecrease);
// get size of textString.
mTextPaint.getTextBounds(textString, 0, textString.length(), mTextBounds);
// calculate where to start printing textString.
float position = (width / getMax()) * getProgress();
// get start and end points of where textString will be printed.
float textXStart = position - mTextBounds.centerX();
float textXEnd = position + mTextBounds.centerX();
// check does not start drawing text outside seek bar.
if (textXStart < 0)
textXStart = 0;
if (textXEnd > width)
textXStart -= (textXEnd - width);
// calculate y textString print position.
float yPosition = (height / 2) - mTextBounds.centerY();
canvas.drawText(textString, textXStart, yPosition - sTextYPositionIndent, mTextPaint);
// arrow draw logic
// check does not start drawing arrow outside seek bar
int seekBarAbsoluteWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int thumbPos = (getPaddingLeft() / 2) + (seekBarAbsoluteWidth * getProgress() / getMax());
// set height and width for new bitmap
int arrowHeight = Math.round(mTextBounds.height()/2f);
int arrowWidth = mTextBounds.width()/3;
Bitmap scaledBitmapIconArrowDown = Bitmap
.createScaledBitmap(mBitmapIconArrowDown, arrowWidth, arrowHeight, true);
canvas.drawBitmap(scaledBitmapIconArrowDown, thumbPos, yPosition, null);
}
}
To support different dimension use this code in OnCreateView (if seekBar used in fragment) or in OnCreate (if seekBar used in activity):
DisplayMetrics metrics = getResources().getDisplayMetrics();
int dpi = metrics.densityDpi;
if(dpi < 230){
SeekBarHint.setTextYPositionIndent(5);
} else if (dpi < 310){
SeekBarHint.setTextYPositionIndent(15);
} else if (dpi < 470){
SeekBarHint.setTextYPositionIndent(10);
}

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"

Android custom horizontal progressbar with progress dividers

I need to make a custom horizontal progressbar in Android, but it doesn't have to be continuous. It must have DIVIDERS for every progress value. For example: it must have green progress and white dividers. Please see the next image to understand what I'm looking for. Thank you.
For now I am trying to make a custom Drawable and set it to the progress bar.
public class CustomProgressDrawable extends Drawable {
private static final int DEFAULT_RECT_WIDHT = 20;
private static int DEFAULT_RECT_COLOR;
private int rectWidth;
private int rectColor;
Paint paint = new Paint();
public CustomProgressDrawable(Context context){
init(context);
}
private void init(Context context){
DEFAULT_RECT_COLOR = context.getResources().getColor(android.R.color.black);
rectColor = DEFAULT_RECT_COLOR;
rectWidth = DEFAULT_RECT_WIDHT; // Default rect width
}
#Override
public void draw(Canvas canvas) {
float parentWidth = 300;
float parentHeight = 40;
float childTop = 0;
float childBottom = parentHeight;
for (int i = rectWidth; i < parentWidth; i =+ rectWidth){
paint.setColor(rectColor);
canvas.drawRect(i - rectWidth + 10, childTop, i + 10, childBottom, paint);
}
}
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return super.onLevelChange(level);
}
}
And in my may activity I have:
CustomProgressDrawable customProgressDrawable = new CustomProgressDrawable(this);
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
progressBar.setProgressDrawable(customProgressDrawable);
progressBar.setProgress(50);

Scale text over image in custom imageview

I have written a custom imageview to show a credit card. To create the credit card I have a base image and I have setters to set the PAN, Card holder, expiry. This text needs to be drawn on top of the base card image. My problem is maintaining the position and size of the text so that it will always look correct no matter the changing size of the base image. The only thing I can rely on is the aspect ratio of the image being the same as a normal credit card.
My custom ImageView
public class CardView extends ImageView {
private String mPan = "4321 0123 4567 8910";
private String mExpiry = "01/16";
private String mCardholder = "MR JOHN SMITH";
private float mPanTextSize = 22;
private float mOtherTextSize = 14;
private Paint mPanPaint = new Paint();
private Paint mCardholderPaint = new Paint();
public CardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initCardView();
}
public CardView(Context context, AttributeSet attrs) {
super(context, attrs);
initCardView();
}
public CardView(Context context) {
super(context);
initCardView();
}
private final void initCardView() {
mPanPaint.setColor(0xFFFFFFFF);
mPanPaint.setShadowLayer(1, 1, 1, 0xAA000000);
mPanPaint.setAntiAlias(true);
mPanPaint.setTextSize(mPanTextSize * getResources().getDisplayMetrics().scaledDensity);
mPanPaint.setTypeface(Typeface.MONOSPACE);
mCardholderPaint.setColor(0xFFFFFFFF);
mCardholderPaint.setShadowLayer(1, 1, 1, 0xAA000000);
mCardholderPaint.setAntiAlias(true);
mCardholderPaint.setTextSize(mOtherTextSize * getResources().getDisplayMetrics().scaledDensity);
mCardholderPaint.setTypeface(Typeface.MONOSPACE);
setPadding(0,0,0,0);
//setAdjustViewBounds(true);
setScaleType(ImageView.ScaleType.CENTER_INSIDE);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float panLength = mPanPaint.measureText(mPan);
float x = (getWidth() - panLength)/2;
float y = -mPanPaint.ascent() + (getHeight() * 0.46f);
canvas.drawText(mPan, x, y, mPanPaint);
x = (getWidth() - panLength)/1.5f;
y = y - mCardholderPaint.ascent();
canvas.drawText(mExpiry, x, y, mCardholderPaint);
y = y - mCardholderPaint.ascent();
canvas.drawText(mCardholder, x, y, mCardholderPaint);
//super.onDraw(canvas);
}
public void setPan(String pan) {
mPan = pan;
invalidate();
}
public String getPan() {
return mPan;
}
public void setExpiry(String expiry) {
mExpiry = expiry;
invalidate();
}
public String getExpiry() {
return mExpiry;
}
public void setCardholder(String cardholder) {
mCardholder = cardholder;
invalidate();
}
public String getCardholder() {
return mCardholder;
}
}
So sometimes this looks ok but as you get to 10 inch screens the text is way too small, right in the center of the image (imagine looking at a credit card but the number only takes up the space of the middle 8 digits), and as you get to small screens the text is too big, going right up to the image sides or past them.
Any solutions? Any explanation why?
You need to make the text sizes dependent on the size of your image.
try to experiment with different values for yourPanFactor and yourCardholderFactor until you get the desired result
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
final int height = bottom-top;
mPanPaint.setTextSize(height*yourPanFactor);
mCardholderPaint.setTextSize(height*yourCardholderFactor);
}
}
I managed to make this work in this lines of code
if (imageView.getWidth() <= resource.getWidth()) {
ratio = (float) resource.getWidth() / (float) imageView.getWidth();
} else {
ratio = (float) imageView.getWidth() / (float) resource.getWidth();
}
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(editText.getTextSize() * ratio);
Note that the editText has the default text size which is 14 sp.
I hope it help you. and correct me if am wrong

Categories

Resources