Only the first of three custom views draws properly - android

I have a custom ScoreView that consists of two lines of text (a name and a score). Behind that text, I am drawing a bar representing the score.
I have a fragment that contains three such ScoreViews. When I update the ScoreViews with a new name or score, everything works fine. However, if I update the rectangle behind them, only the first rectangle is redrawn.
The end result is something like this:
All three ScoreViews should have a gray bar behind the text.
To prevent the possibility of my fill color attribute causing this, I am statically setting the bar's color in the ScoreView.
ScoreView snippet:
public class ScoreView extends View {
public void setFillPercent(float percent) {
mFillPercent = percent;
mFillRect = new Rect(getLeft(), getTop(), getLeft() + Math.round(mFillPercent*getWidth()), getBottom());
invalidate();
requestLayout();
}
#Override
protected void onSizeChanged (int w, int h, int oldw, int oldh) {
mFillRect = new Rect(getLeft(), getTop(), getLeft() + Math.round(mFillPercent*w), getBottom());
mTextXPos = getLeft() + 20; // TODO dp?
mNameTextYPos = h/2 - (int)mNameTextSize;
mScoreTextYPos = h/2 + (int)mScoreTextSize;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(mFillRect, mFillPaint);
canvas.drawText(mName, mTextXPos, mNameTextYPos, mNameTextPaint);
canvas.drawText(String.valueOf(mScore), mTextXPos, mScoreTextYPos, mScoreTextPaint);
}
}
In my fragment, I call:
oneScoreView.setFillPercent(.5f);
twoScoreView.setFillPercent(.5f);
threeScoreView.setFillPercent(.5f);
I set a breakpoint in onDraw() and I can see that it is being called, and that mFillRect has the correct size and position. It simply doesn't get displayed.
I also discovered that if I rearrange the three ScoreViews, it is always the first ScoreView that updates properly.

I am not sure, but mFillRect = new Rect(getLeft(), getTop(), getLeft() it means you set offset left and top of the view, but then you use this rectangle to draw inside the same view. I think it's just out of view's canvas area, that's why you cannot see it. I might be wrong though.

Related

Change a SeekBar position inside its container

Whenever extending the class, the bar will be drawn in the vertical center of its container. I need to place text above the bar and increasing the height (I am setting an arbitrary height on the view) causes a bunch of blank space beneath the bar. I've been googling for quite some time now but all I find is regarding the thumb mostly, and I need to draw the bar on the bottom of its container.
This is what I'm trying to achieve as a single view (notice how the bar's position in not centered):
The only "useful" code I could find was this:
Window window = ((Activity) getContext()).getWindow();
window.setGravity(Gravity.BOTTOM);
WindowManager.LayoutParams wmlp = window.getAttributes();
wmlp.y = getHeight() / 4;
window.setAttributes(wmlp);
But it has no effect whatsoever.
My custom class, nothing out of the ordinary:
public class RateSeekbar extends AppCompatSeekBar {
private Paint lettersPaint;
private Paint numberPaint;
// constructors and call to init()
private void init() {
lettersPaint = new Paint();
numberPaint = new Paint();
... // style the two different paints
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
... // get a couple of strings from resources and measure them
int middleHor = getWidth() / 2;
canvas.drawText(text1, getPaddingLeft(), 40, lettersPaint);
canvas.drawText(text2, getWidth() - text2Size - getPaddingRight(), 40, lettersPaint);
canvas.drawText(String.valueOf(getProgress()), middleHor - (text3Size / 2), 50, numberPaint);
}
}
Any ideas?

onDraw method not drawing everything I put in to it

I have created a custom view class to use in a project I'm working on. To put is simply, I'm displaying an image, then adding images on top of the original image (currently by clicking on the image, but that's not final).
I have these 2 methods in my custom view:
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
for (Drawable d : drawableList)
{
d.draw(canvas);
}
}
public void AddPoint(float x, float y)
{
Drawable tempDrawable = pin;
tempDrawable.setBounds((int)x, (int)y, (int)x + 50, (int)y + 50);
drawableList.add(tempDrawable);
invalidate();
}
The AddPoint() method is called in an OnTouchListener and is passes the coordinates of the touch event.
The way it currently works is it displays the main image, but will only display the most recent images where I clicked, previous ones just disappear.
Does anybody know what I am doing wrong here?
I've figured out what I was doing wrong.
The line of code:
Drawable tempDrawable = pin;
I changed to:
Drawable tempDrawable = mainRes.getDrawable(R.drawable.pin);
I got mainRes from the init(Context context) method I wrote in the custom View class.

Change View size to match content

I have a class Token which extends View. I override the onDraw method to draw two rects. After that i want to change the size of the Token object to match the size of the rects. For testing i added an onClickListener which should print out "Test"
layout = (RelativeLayout) findViewById(R.id.layout);
Paint p = new Paint();
Token a = new Token(0,0, Token.ONE, p, this);
layout.addView(a);
a.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("test");
}
});
The Token class:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
tSize = canvas.getWidth()/Activity.SIZE;
paint.setColor(Color.BLACK);
r.set(0, 0, tSize, tSize);
canvas.drawRect(r, paint);
r.set(tSize, 0, 2 * tSize, tSize);
canvas.drawRect(r, paint);
}
So far so good. The problem is that it is always printing out "Test", no matter where i press on the screen. I figured that is because the View, which holds this two rects is the the size of the whole screen.
So i tried LayoutParams:
setLayoutParams(new RelativeLayout.LayoutParams(tSize*2, tSize);
This results in the rects not showing up at all(i think they got to small). I tried some other numbers:
setLayoutParams(new RelativeLayout.LayoutParams(600, 600);
This is working. The rects show up and the Listener only works in a 600x600 field. The only Problem is the rects are smaller than i want them to be. My guess is that their size is relative to the size of the view they are in.
How would i achive that my View is exactly (tSize*2, tSize) with the rects filling it out?
you may override onMeasure method to change the GameTokenView's size.

How to programmatically check If string is not to wide to fit onto the screen in Android

I have a custom ListView. inside a custom ListView, I have a TextView & it's look like this
Now, my question is
1) is there any way to check If names is not to wide to fit onto the screen in Android ? I mean I don't want two lines. Like here Wachler is on 2nd line. So, how do I check if all names are wide to fit onto the screen in one line.
//1)
layout_width = yourLayout.getWidth(); //in order to measure the width of the ListView rows container
To find text size:
//2)
Paint paint = new Paint();
Rect bounds = new Rect();
int text_height = 0;
int text_width = 0;
paint.setTypeface(Typeface.DEFAULT);// your preference here
paint.setTextSize(25);// have this the same as your text size
String text = "Some random text";
paint.getTextBounds(text, 0, text.length(), bounds);
text_height = bounds.height();
text_width = bounds.width();
//3)
if(text_width < layout_width){
//..do your magic
}
Source
you can set your custom listview layout's TextView property as android:ellipsize="end" and also set the android:singleLine="true" in your TextView.
The TextView will use an ellipsize when it can not expand to show all of its text. The attribute ellipsized sets the position of the three dots if it is necessary.
I've solved this issue by checking how many lines does the TextView have after onSizeChanged finish, since only then you will have the real value of the number of lines.
First create an interface (you can define it on your desired Fragment/Activity)
public interface OnCustomTextViewSizeChangedListener {
public void SizeChanged(int size);
}
Then create your custom TextView, Override onSizeChanged and create a function to define your listener.
public class CustomTextView extends TextView {
private OnCustomTextViewSizeChangedListener sizeChangeListener;
...
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
super.onSizeChanged(w, h, oldw, oldh);
if(this.sizeChangeListener != null){
this.sizeChangeListener.SizeChanged(getLineCount());
}
}
public void setSizeChangeListener( OnCustomTextViewSizeChangedListener listener){
this.sizeChangeListener = listener;
}
}
Then just create your listener on your Fragment/Activity, define it for your desired TextView and your good to go!
OnCustomTextViewSizeChangedListener textViewSizeChanged = new OnCustomTextViewSizeChangedListener() {
#Override
public void SizeChanged(int size) {
if(size == 2){
//Do your stuff here, like changing text size
}
}
}
PS: don't forget to change your layout to use your CustomTextView
Hope it helps!
If you want your text view display in one line then do this-
textView.setMaxLines(1);
but Remember it cuts out the text which not fit in textview
I suppose you have a TextView displaying the text?
You can check if a textviews text is trimmed by calculating the width of TextView and also calculate the width of text which will be displayed in the textview:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
isMarqueed("I am fine here. How r u", textView.getWidth(), textView);
isMarqueed("I am fine", textView.getWidth(), textView);
}
private boolean isMarqueed(String text, int textWidth, TextView tv) {
Paint testPaint = new Paint();
testPaint.set(tv.getPaint());
boolean isMarquee = true;
if (textWidth > 0) {
int availableWidth = (int) (textWidth - tv.getPaddingLeft() - tv.getPaddingRight()-testPaint.measureText(text));
System.out.println("...available width..."+availableWidth);
isMarquee = false;
}
return isMarquee;
}
Taken from here: How to check if a TextView String has been trimmed (marquee)?
Since you're using a TextView you can use it's method getLineCount() to determine how many lines this TextView expands over. But be careful when using this method, you must be sure that the view has been drawn before invoking this method. See documentation for more information.

How to mark a given Latitude and Longtitude into still image map

#Dan S, gave the below statement in this post -> display a still image map
Then using a second ImageView (for the indicator) draw it on top and
move it to the correct place on the screen and make sure the
background in this View is transparent as well as the background of
your indicator
How can I create the second ImageView for my indicator? It should be transparent imageview as well as the indicator image.
UPDATE:
I am asking here on how to overlap my image map ImageView and transparent indicator ImageView in order to mark the current location.
An ImageView is transparent by default.
Your indicator image resource should have a transparent background (e.g. transparent .PNG image).
Just set the ImageView's imageResource or backgroundResource to the PNG file.
So your code for creating your ImageView will be something like this:
ImageView myImageView = new ImageView(context);
myImageView.setBackgroundColor(0x0); // not needed - it's the default
myImageView.setImageResource(R.drawable.indicator_icon);
but again, this's the default and you still have to make sure your image's background is transparent otherwise the ImageView's background won't matter.
UPDATE: following #eros update of the question, here's an updated answer:
There are two options, i can think of, to achieve positioning of one imageview on top of the other:
use the LayoutParams and set the margins to the position the indicator imageview
draw the indicator imageview on top of the map bmp's canvas
personally i like the first option better because future changes won't force you to repaint the indicator.
here's a class demonstrating option (1):
public class MyMapView extends RelativeLayout {
private ImageView mBackImageView;
private ImageView mIndicatorImageView;
public MyMapView(Context context) {
super(context);
mBackImageView = new ImageView(context);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
mBackImageView.setImageResource(R.drawable.image1);
mBackImageView.setScaleType(ImageView.ScaleType.FIT_XY);
addView(mBackImageView, params);
mIndicatorImageView = new ImageView(context);
RelativeLayout.LayoutParams indParams = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mIndicatorImageView.setImageResource(R.drawable.image2);
addView(mIndicatorImageView, indParams);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
centerIndicatorPosition();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerIndicatorPosition();
}
// #eros: this's the part you want. this method just centers the indicator view
// but if you have the relative position like you say, use it for the margins
private void centerIndicatorPosition() {
int xPos = (getMeasuredWidth() - mIndicatorImageView.getMeasuredWidth()) / 2;
int yPos = (getMeasuredHeight() - mIndicatorImageView.getMeasuredHeight()) / 2;
((RelativeLayout.LayoutParams)mIndicatorImageView.getLayoutParams())
.setMargins(xPos, yPos, 0, 0);
}
}

Categories

Resources