Aligning custom view to screen bottom - android

I have created my own view. It is a semicircle. I want it to align it to the bottom of the screen. Since, I drew it using drawArc, it does not align to the bottom. I have tried the alternative of setting a circle with center's y co-ordinate co-incident with screen bottom co-ordinate. I do not wish to use it as I wish to implement some additional things to it. Here is my code for custom view.
package legacy_systems.customview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class CircleView extends View{
private Paint markerPaint;
private Paint textPaint;
private Paint circlePaint;
private int textHeight;
public CircleView(Context context)
{
super(context);
initCircleView();
}
public CircleView(Context context, AttributeSet attrs)
{
super(context, attrs);
initCircleView();
}
public CircleView(Context context, AttributeSet attrs, int defaultStyle)
{
super(context, attrs, defaultStyle);
initCircleView();
}
protected void initCircleView()
{
setFocusable(true);
circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
circlePaint.setColor(getResources().getColor(android.R.color.black));
circlePaint.setStrokeWidth(3);
circlePaint.setStyle(Paint.Style.STROKE);
markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
markerPaint.setColor(getResources().getColor(android.R.color.darker_gray));
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int measuredWidth = measure(widthMeasureSpec);
int measuredHeight = measure(heightMeasureSpec);
int d = Math.min(measuredWidth, measuredHeight);
setMeasuredDimension(d,d);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
int px, py;
px = getMeasuredWidth()/2;
py = getMeasuredHeight()/2;
int radius = Math.min(px, py);
RectF oval = new RectF();
oval.set(px-radius, py-radius, px+radius, py+radius);
canvas.drawArc(oval,180,180,false, circlePaint);
//canvas.drawCircle(px, py, radius, circlePaint);
canvas.save();
}
private int measure(int measureSpec)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if(specMode == MeasureSpec.UNSPECIFIED)
{
result = 200;
}
else
{
result = specSize;
}
return result;
}
}
I want to align the semi-circle to bottom of screen. Any ideas how I can do it ?

First of all, thanks all of you for your answers. Your answer is partially correct. Yes, with
android:layout_alignParentBottom="true"
would do the half trick. Suppose I have a circle to draw. In custom view, (0,0) represents the heightest leftmost co-ordinate of the view, not of the screen. And suppose one wants to half circle to be located at thebottom of screen just as I wanted to do, co-ordinate guessing turns out to be a problem. Here is how I actually solved it.
px = getMeasuredWidth()/2;
py = getMeasuredHeight();
canvas.drawCircle(px, py, radius, paint);
Here, px would be the centre of whole width of view, midpoint of view width and py would be the last screen y axis co-ordinate assigned to view.
Hope it helps somebody else too.

You can try to use the:
android:gravity="bottom"
or
android:layout_gravity="bottom"
property.

Make sure that the screen on which you want to put/add it is a RelativeLayout.
Do this in the layout
<legacy_systems.customview.CircleView
android:id="#+id/myview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"/>
In your onCreate() method
CircleView view = (CircleView) findViewById(R.id.myview);

Related

Draw round corners on top left top right bottom left bottom right using Path and RectF in Android

By making a custom ImageView and override the onDraw method with the following will make the ImageView to have rounded corners. Reference
#Override
protected void onDraw(Canvas canvas) {
float radius = getContext().getResources().getDimension(R.dimen.round_corner_radius);
Path path = new Path();
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
path.addRoundRect(rect, radius, radius, Path.Direction.CW);
canvas.clipPath(path);
super.onDraw(canvas);
}
How can I selectively make the round corners instead of making all four corners round. For example, only making the top left and top right corners round and leave the bottom corners intact. Here is a solution to do to through Bitmap. I am looking for doing it in this onDraw method and only using Path and RectF.
There is a Path#addRoundRect() overload that takes a float array of eight values wherein we can specify the x- and y-radius for each of the four corners. These values are in [x, y] pairs, starting at the top-left corner, and going clockwise around the rest. For those corners we want rounded, we set both values of the pair to the radius value, and leave them at zero for those we don't.
As an illustrative example, a simple method that will return a Path that can be used in your snippet:
private Path getPath(float radius, boolean topLeft, boolean topRight,
boolean bottomRight, boolean bottomLeft) {
final Path path = new Path();
final float[] radii = new float[8];
if (topLeft) {
radii[0] = radius;
radii[1] = radius;
}
if (topRight) {
radii[2] = radius;
radii[3] = radius;
}
if (bottomRight) {
radii[4] = radius;
radii[5] = radius;
}
if (bottomLeft) {
radii[6] = radius;
radii[7] = radius;
}
path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()),
radii, Path.Direction.CW);
return path;
}
Per your example description, rounding the top-left and top-right corners:
#Override
protected void onDraw(Canvas canvas) {
float radius = getContext().getResources().getDimension(R.dimen.round_corner_radius);
Path path = getPath(radius, true, true, false, false);
canvas.clipPath(path);
super.onDraw(canvas);
}
As always, I would recommend keeping the onDraw() method as tight as possible, moving anything that doesn't absolutely have to be there elsewhere. The resource value for the radius, for instance, could be retrieved in the constructor, and kept in a field. Furthermore, the Path could be constructed only when necessary; i.e., when the View's size changes, or when the radius or chosen corners change.
Since I put together a simple custom ImageView to test this, I'll include it here, as it demonstrates the above points. This custom View also offers XML attributes that allow the corner radius and the rounded corners to be set in your layout.
public class RoundishImageView extends ImageView {
public static final int CORNER_NONE = 0;
public static final int CORNER_TOP_LEFT = 1;
public static final int CORNER_TOP_RIGHT = 2;
public static final int CORNER_BOTTOM_RIGHT = 4;
public static final int CORNER_BOTTOM_LEFT = 8;
public static final int CORNER_ALL = 15;
private static final int[] CORNERS = {CORNER_TOP_LEFT,
CORNER_TOP_RIGHT,
CORNER_BOTTOM_RIGHT,
CORNER_BOTTOM_LEFT};
private final Path path = new Path();
private int cornerRadius;
private int roundedCorners;
public RoundishImageView(Context context) {
this(context, null);
}
public RoundishImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundishImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundishImageView);
cornerRadius = a.getDimensionPixelSize(R.styleable.RoundishImageView_cornerRadius, 0);
roundedCorners = a.getInt(R.styleable.RoundishImageView_roundedCorners, CORNER_NONE);
a.recycle();
}
public void setCornerRadius(int radius) {
if (cornerRadius != radius) {
cornerRadius = radius;
setPath();
invalidate();
}
}
public int getCornerRadius() {
return cornerRadius;
}
public void setRoundedCorners(int corners) {
if (roundedCorners != corners) {
roundedCorners = corners;
setPath();
invalidate();
}
}
public boolean isCornerRounded(int corner) {
return (roundedCorners & corner) == corner;
}
#Override
protected void onDraw(Canvas canvas) {
if (!path.isEmpty()) {
canvas.clipPath(path);
}
super.onDraw(canvas);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setPath();
}
private void setPath() {
path.rewind();
if (cornerRadius >= 1f && roundedCorners != CORNER_NONE) {
final float[] radii = new float[8];
for (int i = 0; i < 4; i++) {
if (isCornerRounded(CORNERS[i])) {
radii[2 * i] = cornerRadius;
radii[2 * i + 1] = cornerRadius;
}
}
path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()),
radii, Path.Direction.CW);
}
}
}
For the XML attributes to work, the following needs to be in your <resources>, which you can do by putting this file in your project's res/values/ folder, or adding to the one that might already be there.
attrs.xml
<resources>
<declare-styleable name="RoundishImageView">
<attr name="cornerRadius" format="dimension" />
<attr name="roundedCorners">
<flag name="topLeft" value="1" />
<flag name="topRight" value="2" />
<flag name="bottomRight" value="4" />
<flag name="bottomLeft" value="8" />
<flag name="all" value="15" />
</attr>
</declare-styleable>
</resources>
The cornerRadius is a dimension attribute, and should be specified as a dp or px value. The roundedCorners is a flag attribute, and multiple corners can be chosen using the pipe character, |. For example:
<com.mycompany.myapp.RoundishImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/riv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:src="#drawable/magritte"
app:cornerRadius="#dimen/round_corner_radius"
app:roundedCorners="topLeft|topRight" />
I also spent a half-day to solve the problem; the key point here is how to use mPath.arcTo make a corner. The basic knowledge is E direction is 0 degree, then the second param means which degree start; the third param means how many degrees to show.
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
public class RectangleConerView extends View {
private Path mPath;
private Paint mPaint;
private PathMeasure mPathMeasure;
private float mAnimatorValue;
private Path mDst;
private float mLength;
private float left = 300;
private float top = 200;
private float width = 800;
private float height = 300;
private float checkWidth = 100;
private float checkHeight = 60;
private float cornerRadius = 30;
public RectangleConerView(Context context) {
super(context);
}
public RectangleConerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public RectangleConerView(Context context, AttributeSet attrs)
{
super(context, attrs);
mPathMeasure = new PathMeasure();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPath = new Path();
mPath.moveTo(left + width, top + checkHeight/2);
//bottom-right
mPath.lineTo(left + width, top + height - cornerRadius);
mPath.arcTo(new RectF(left + width-cornerRadius, top + height - cornerRadius, left + width, top + height), 0, 90); //start degree is E direct, then CW 90 degree, which is the bottom-right corner.
//bottom-left
mPath.lineTo(left + cornerRadius, top + height);
mPath.arcTo(new RectF(left, top + height - cornerRadius, left + cornerRadius, top + height), 90, 90);//start degree is the S, then CW 90 degree, which is the bottom-left corner.
//top-left
mPath.lineTo(left, top + cornerRadius);
mPath.arcTo(new RectF(left, top, left + cornerRadius, top + cornerRadius), 180, 90);//start degree W
//top-right
mPath.lineTo(left + width - checkWidth/2, top);
mPathMeasure.setPath(mPath, false);
mLength = mPathMeasure.getLength();
mDst = new Path();
final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mAnimatorValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator.setDuration(1000);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.start();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mDst.reset();
// 硬件加速的BUG
mDst.lineTo(0,0);
float stop = mLength * mAnimatorValue;
mPathMeasure.getSegment(0, stop, mDst, true);
canvas.drawPath(mDst, mPaint);
}
}

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);
}

Drawing custom shapes

i want to show a custom marker in google maps and marker's color is subjected to change dynamically when some specific events happen.So i was wondering which is the best way to draw shape like a map marker
I have created a custom view that will draw shape like default marker.
Here is the code :
public class CustomView extends View {
private Paint paint;
private RectF oval;
private Path fillPath;
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#Override
protected void onDraw(Canvas canvas) {
oval.bottom = getHeight();
oval.left = 0;
oval.right = getWidth();
oval.top = 0;
// canvas.drawRect(oval, paint);
canvas.drawArc(oval, 0, -180, true, paint);
fillPath.moveTo(0, getHeight() / 2); // Your origin point
fillPath.lineTo(getWidth(), getHeight() / 2); // First point
// Repeat above line for all points on your line graph
fillPath.lineTo(getWidth() / 2, getHeight()); // Final point
fillPath.lineTo(0, getHeight() / 2); // Same origin point
canvas.drawPath(fillPath, paint);
}
private void init() {
android.view.ViewGroup.LayoutParams params = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
setLayoutParams(params);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
oval = new RectF();
fillPath = new Path();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
setMeasuredDimension(width, height);
Log.e("H" + width, "W" + height);
}
}
Hope this might help you.
#sijeesh: Yes.You can set Custom Marker (Image Should be Small) .
Markers indicate single locations on the map. You can customize your markers by changing the default color, or replacing the marker icon with a custom image.
First import the following class:
import com.google.android.gms.maps.model.MarkerOptions;
Now you can set Custom marker this way
MarkerOptions custommarker = new MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.your_custom_icon));
For more info Please Have a look Android Custom marker with ImageView
My Advise
Please follow Official documentations.I hope it will helps you .
https://developers.google.com/maps/documentation/android-api/marker
If you only need to change color of marker, you'd better make marker icon as a simple image and just change its tinting color when required.
Bitmap original = BitmapFactory.decodeResource(getResources(), R.drawable.ic_brush_black_24dp);
Bitmap colored = Bitmap.createBitmap(original.getWidth(), original.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(colored);
canvas.drawBitmap(original, 0, 0, null);
canvas.drawColor(Color.RED, PorterDuff.Mode.SRC_ATOP);
marker.setIcon(BitmapDescriptorFactory.fromBitmap(colored));

How to add pagelines to a EditText in android?

Is it possible to show pagelines in a EditText?
I mean these lines:
Let's say my EditText is 500 by 500 pixels in size. I want those lines to be visible across that 500 by 500 square.
Is there a build in way to do this? I already tried Google but I couldn't find an answer.
I guess my other option is to dynamically create a graphic based on the textheight and linespacing, such an ugly work-around.
The notepad application sample from the android dev site shows you how to do this.
http://developer.android.com/resources/samples/NotePad/index.html
Looks like this (scroll down for code):
Most of the relevant code is in this file. Pay attention to the LinedEditText inner class. It is defined within the activity. It draws the lines required.
Inside the activity onCreate() method, setContentView(R.id.note_editor) is set as the view, it is defined like here
Snippet extracted from here. Update: Code modified by #Pieter888 to draw lines on the entire EditText control.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.EditText;
public class LinedEditText extends EditText
{
private Rect mRect;
private Paint mPaint;
public LinedEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(0xFF000000);
}
/**
* This is called to draw the LinedEditText object
* #param canvas The canvas on which the background is drawn.
*/
#Override
protected void onDraw(Canvas canvas)
{
int height = canvas.getHeight();
int curHeight = 0;
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);
for (curHeight = baseline + 1; curHeight < height;
curHeight += getLineHeight())
{
canvas.drawLine(r.left, curHeight, r.right, curHeight, paint);
}
super.onDraw(canvas);
}
}
#gideon's answer above works well but has an issue when you enter more text in the edittext because more lines are not drawn accordingly. To solve this, I wrote an override for onMeasure() and called invalidate(). and more lines will be drawn when text increases.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
invalidate();
}
The code now is:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.EditText;
public class LinedEditText extends EditText
{
private Rect mRect;
private Paint mPaint;
public LinedEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(0xFF000000);
}
/**
* This is called to draw the LinedEditText object
* #param canvas The canvas on which the background is drawn.
*/
#Override
protected void onDraw(Canvas canvas)
{
int height = canvas.getHeight();
int curHeight = 0;
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);
for (curHeight = baseline + 1; curHeight < height;
curHeight += getLineHeight())
{
canvas.drawLine(r.left, curHeight, r.right, curHeight, paint);
}
super.onDraw(canvas);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
invalidate();
}
}
#gideon's code works but more lines not be drawn
you must just change canvas.getHeight() to getHeight() as following below:
public class LinedEditText extends EditText
{
private Rect mRect;
private Paint mPaint;
public LinedEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(ResourcesCompat.getColor(getResources(), R.color.blue,null));
}
#Override
protected void onDraw(Canvas canvas)
{
int height = getHeight();
int curHeight = 0;
Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);
for (curHeight = baseline + 1; curHeight < height;
curHeight += getLineHeight())
{
canvas.drawLine(r.left, curHeight, r.right, curHeight, paint);
}
super.onDraw(canvas);
}

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