I have a custom component which is overriding the onLayout method as follows:
#Override
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
int[] location = new int[2];
this.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
int w = this.getWidth();
int h = y+(8*CELL_HEIGHT);
updateMonthName();
initCells();
CELL_MARGIN_LEFT = 0;
CELL_MARGIN_TOP = monthNameBounds.height();
CELL_WIDTH = w / 7;
setFrame(x, y, x+w, h);
super.onLayout(true, x, y, w, h);
}
However, when using this component in a linearlayout as follows:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:padding="10dp"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="TextView above"
android:textSize="15sp"
/>
<com.project.calenderview.CalendarView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="TextView below"
android:textSize="15sp"
/>
</LinearLayout>
The layout is rendered such that the textview "TextView above" is first, "TextView below" is second and then my component which is expected to be in the middle between both.
Edit:
Here's also the onDraw:
#Override
protected void onDraw(Canvas canvas) {
// draw background
super.onDraw(canvas);
//Draw month name
canvas.drawText(monthName, (this.getWidth() / 2) - (monthNameBounds.width() / 2), monthNameBounds.height() + 10, monthNamePaint);
//Draw arrows
monthLeft.draw(canvas);
monthRight.draw(canvas);
// draw cells
for(Cell[] week : mCells) {
for(Cell day : week) {
if(day == null) continue;
day.draw(canvas);
}
}
}
What is it that am doing wrong here?
Thanks
the onLayout methods is passing int left, int top, int right, int bottom indicating where your view is supposed to draw, but apparently you're completely ignoring it. You muse use those values to layout it properly.
edit:
if you're not extending a ViewGroup you shouldn't be overriding onLayout(bool, int, int, int, int)
from the docs View.onLayout:
Called from layout when this view should assign a size and position to
each of its children. Derived classes with children should override
this method and call layout on each of their children.
Derived classes with children should override this method and call layout on each of their children
The issue you're having on the final result is in some other part of your code.
Related
I'm building a simple custom view, it's just a basic rectangular container at the moment cause I'm having some issues with the ConstraintLayout.
The main layout setup. The textView is constrained to the parent while the Wire view is constrained to the parent and the top to the bottom of the textView
In the onMeasure method I'm trying to make my view's height to match vertical constraint. What I mean is that I want my view's height to fill the space between the two vertical constraints.
Can't find any code about it online, anyone knows how to do it?
In order to match a constraint you need to set the width/height in zero, this way the view will take the space that the constraint declares for example:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/mytv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text view"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:text="Your wire view"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/mytv" />
</androidx.constraintlayout.widget.ConstraintLayout>
Look at the "wire" view i set the height and 0 and then it takes all the space defined by their constraints.
This is in addition to Nestor Perez's solution above but I will concentrate on the Kotlin code for onMeasure() for resolving the height and width.
First we declare width and height variables and set them to 0.
class CustomRectangle #JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {
//width and height variables
private var widthSize = 0
private var heightSize = 0
//PAINT OBJECT
private val paint = Paint().apply {
style = Paint.Style.FILL
}
......}
Inside on measure we use resolveSizeAndState() method to calculate the 2 dimens. We then set the height and width as shown below.
//ON_MEASURE
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val minWidth: Int = paddingLeft + paddingRight + suggestedMinimumWidth
val w: Int = resolveSizeAndState(minWidth, widthMeasureSpec, 1)
val h: Int = resolveSizeAndState(MeasureSpec.getSize(w), heightMeasureSpec, 0)
widthSize = w
heightSize = h
setMeasuredDimension(w, h)
}
Then onDraw() we draw the Custom Rectangle using the resolved height and width.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.color = Color.Whatever_Color
canvas.drawRect(0f, 0f, widthSize.toFloat(), heightSize.toFloat(), paint)
}
Then as Nestor Perez has explained above we set the width and height to 0dp.
<com.custombutton
android:id="#+id/custom_button"
android:layout_width="0dp"
android:layout_height="0dp" ..../>
Cheers
I have to set progressDrawable for AppCompatSeekBar programmatically but it leads to changing the SeekBar's progressDrawable height after I set it for the second time and further. You can see what I mean below:
What should I do to change this behavior? I already set minHeight and maxHeight to 12dp as it was suggested in another answer.
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatSeekBar
android:id="#+id/seek_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:maxHeight="12dp"
android:minHeight="12dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:progress="50"
android:splitTrack="false"
android:thumb="#drawable/my_thumb" />
<Button
android:id="#+id/change_seek_bar_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:text="Change seek bar" />
</FrameLayout>
my_thumb.xml:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="23dp"
android:height="23dp"
android:viewportWidth="23"
android:viewportHeight="23">
<path
android:fillColor="#B7BDC2"
android:pathData="M11.5,20L11.5,20A9.5,9.5 0,0 1,2 10.5L2,10.5A9.5,9.5 0,0 1,11.5 1L11.5,1A9.5,9.5 0,0 1,21 10.5L21,10.5A9.5,9.5 0,0 1,11.5 20z" />
</vector>
MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.change_seek_bar_button);
SeekBar seekBar = findViewById(R.id.seek_bar);
// sets it the right way
setProgressDrawable(seekBar);
// on button click it sets progressDrawable with wrong height
button.setOnClickListener((view) -> setProgressDrawable(seekBar));
}
private void setProgressDrawable(SeekBar seekBar) {
GradientDrawable progressDrawable = new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,
new int[]{0xFF000000, generateRandomColor()}
);
seekBar.setProgressDrawable(progressDrawable);
}
private int generateRandomColor() {
Random random = new Random();
return Color.argb(255, random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
}
Most probably the problem is in ProgressBar.updateDrawableBounds(int w, int h). When it calls mProgressDrawable.setBounds(0, 0, right, bottom), it doesn't really take into account that progressDrawable might not be equal to the height of the whole View. But initially this function is called when width and height are 0's and I guess that's why it works for the first time.
The problem is kind of clear, so the most obvious solution is to change bounds after setting new progressDrawable:
button.setOnClickListener((view) -> {
setProgressDrawable(seekBar);
// converting 12 dp to pixels
int desiredHeight = (int) (12 * Resources.getSystem().getDisplayMetrics().density);
Rect bounds = seekBar.getProgressDrawable().copyBounds();
int actualTop = (int) Math.round((bounds.bottom - bounds.top) / 2.0 - desiredHeight / 2.0);
seekBar.getProgressDrawable().setBounds(bounds.left, actualTop, bounds.right, actualTop + desiredHeight);
});
And it actually solves the problem.
When I scroll within my Android scrollview, it scrolls down as it should.
But I'd like the image within the imageview to anchor to the centre. So you always see the face of the person in the image as you scrolling up.
So far I have not been able to accomplish this
A similar effect is created in the image below:
Stockguy image:
My code so far (which so far doesn't accomplish this):
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fillViewport="true"
android:scrollbars="none"
android:background="#FAFAFA"
android:id="#+id/cScrollview"
>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="1100dp"
tools:context=".MainActivity"
android:id="#+id/CRLayout">
<ImageView
android:layout_gravity="center"
android:adjustViewBounds="true"
android:layout_width="601dp"
android:layout_height="250dp"
android:paddingTop="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:scaleType="centerCrop"
android:id="#+id/contactPic"
android:src="#drawable/stockguy"/>
....
</RelativeLayout>
</ScrollView>
To achieve parallax effect like on image you posted try following code. It is a very simple way.
Layout:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/rlWrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/ivContactPhoto"
android:layout_width="match_parent"
android:layout_height="#dimen/contact_photo_height"
android:scaleType="centerCrop"
android:src="#drawable/stockguy" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="#dimen/contact_photo_height"
android:layout_marginTop="250dp">
<!-- Other Views -->
</LinearLayout>
</RelativeLayout>
</ScrollView>
LinearLayout's top margin is equal to the ImageViews's height.
Listening scroll position of the ScrollView and changing position of ImageView:
#Override
protected void onCreate(Bundle savedInstanceState) {
<...>
mScrollView = (ScrollView) findViewById(R.id.scrollView);
mPhotoIV = (ImageView) findViewById(R.id.ivContactPhoto);
mWrapperRL = (RelativeLayout) findViewById(R.id.rlWrapper);
mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ScrollPositionObserver());
<...>
}
private class ScrollPositionObserver implements ViewTreeObserver.OnScrollChangedListener {
private int mImageViewHeight;
public ScrollPositionObserver() {
mImageViewHeight = getResources().getDimensionPixelSize(R.dimen.contact_photo_height);
}
#Override
public void onScrollChanged() {
int scrollY = Math.min(Math.max(mScrollView.getScrollY(), 0), mImageViewHeight);
// changing position of ImageView
mPhotoIV.setTranslationY(scrollY / 2);
// alpha you can set to ActionBar background
float alpha = scrollY / (float) mImageViewHeight;
}
}
Hope it will help.
I'd take a different approach with that.
Try building your layout based on the following snippet:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:background="#00FF00"
android:scaleType="centerCrop"
android:layout_height="200dp"/>
<FrameLayout
android:id="#+id/content"
android:layout_below="#+id/image"
android:background="#FF0000"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
Using the GestureDetector.SimpleOnGestureListeneryou can detect when the user scrolls on the content layout and update the image size and alpha accordingly to get the effect you describe.
I would implement this using a scroll callback on the ScrollView, this doesn't exist by default but is easy to create yourself by extending ScrollView:
public class UpdatingScrollView extends ScrollView {
private OnScrollChangedListener mScrollChangedListener;
public interface OnScrollChangedListener {
public void onScrollChanged(int x, int y, int oldx, int oldy);
}
public UpdatingScrollView(Context context) {
super(context);
}
public UpdatingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public UpdatingScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setOnScrollChangedListener(OnScrollChangedListener listener) {
mScrollChangedListener = listener;
}
#Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (mScrollChangedListener != null) mScrollChangedListener.onScrollChanged(x, y, oldx, oldy);
}
}
So replace ScrollView in your layout with com.your.package.UpdatingScrollView.
In your Fragment/Activity where the UpdatingScrollView is defined you set the scroll listener and update the bottom margin of the image based on the scroll offset. For every 2 pixels the ScrollView has scrolled you'll want to update the bottom margin by -1 pixel which will make the image move up the screen at half the rate of the rest of the content.
So something like this:
scrollView.setOnScrollChangedListener(new OnScrollChangedListener() {
#Override
public void onScrollChanged(int x, int y, int oldx, int oldy) {
// I think y will be negative when scrolled
if(y >= -image.getHeight()) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) image.getLayoutParams();
lp.setMargins(0, 0, 0, y / 2);
image.setLayoutParams(lp);
}
}
});
For a ListView, I want to give the individual ListView elements some kind of progress indicator - so to speak, I need a list of progress bars.
However, each of the listview elements have some text overlay in the form of a TextView that should not be affected by the progress bar at all.
I think pictures can tell more than words in this case, so here is pretty much what I want:
I know I can add "sublayouts" to the individual LinearLayouts and change the weight programmatically, which looks somewhat like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:id="#leftSide"
android:background="#color/green"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.8" >
</LinearLayout>
<LinearLayout
android:id="#rightSide"
android:background="#color/red"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="0.2" >
</LinearLayout>
</LinearLayout>
and then programmatically change the weight for both sides (completed and uncompleted):
float weightLeft = 0.8f;
float weightRight = 1f-weightLeft;
android.widget.LinearLayout.LayoutParams paramsLeft = new android.widget.LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, weightLeft);
LinearLayout left = (LinearLayout) findViewById(R.id.leftside);
left.setLayoutParams(paramsLeft);
android.widget.LinearLayout.LayoutParams paramsRight = new android.widget.LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, weightRight);
LinearLayout right = (LinearLayout) findViewById(R.id.rightside);
left.setLayoutParams(paramsRight);
But - the question now is, how do I make the textviews sit on the parent linear layout and ignore the children LinearLayouts ?
I can also imagine there is a way to just split up the distribution of the background parts using drawables, but I have no clue how to do that, especially not programmatically.
Any help is appreciated!
try this custom Drawable, mFraction is [0..1]:
public class FractionDrawable extends Drawable {
private Paint mPaint;
private float mFraction;
public FractionDrawable(float fraction) {
mPaint = new Paint();
setFraction(fraction);
}
public void setFraction(float fraction) {
mFraction = fraction;
invalidateSelf();
}
#Override
public void draw(Canvas canvas) {
Rect b = getBounds();
mPaint.setColor(0xff00aa00);
float x = b.width() * mFraction;
canvas.drawRect(0, 0, x, b.height(), mPaint);
mPaint.setColor(0xffaa0000);
canvas.drawRect(x, 0, b.width(), b.height(), mPaint);
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
I want to implement something like a product list in the receipt:
Beer ......................................... 20
Milk .......................................... 10
Cookies with jam ..................... 15
Smartphone 10GB 3GHz
1GB RAM NFC 10MPx
camera .................................. 400
Description:
Check info (Beer, Milk) I think it shoud be a TextView, which I need to fill with dots.
Money (20, 10) is another TextView which shoud be aligned to the right of ViewGroup.
Any ideas how to do this? Maybe I need inherited from TextView and override onDraw() or something?
Many thank for advices!!!
You should create THREE TextViews for each row, layed out one next to another:
TextView With product name (e.g. 'beer')
TextView with dots
TextView with number (e.g. '20')
Then put one product in one row. The Row should be relative layout where:
TextView no. 1 is aligned to left edge, with width set to wrap content
TextView no. 3 is aligneg to right edge, with width set to wrap content
TextView no. 2 is toLeftOf TV no. 3 and toRightOf TV no.1 and it should be filled with big amount of dots in XML file. this will never be changed.
This will work, since the TV no.2 will have width that will shrink and will always be fitted between product name and the price. believe me :)
I have the solution. Maybe it will help someone.
File check_info_item.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<RelativeLayout android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/txt_fake_value"
android:textSize="18dp"
android:textColor="#android:color/transparent"
android:layout_alignParentRight="true"/>
<example.com.CheckInfoTextView android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="#+id/txt_fake_info"
android:textSize="18dp"
android:textColor="#android:color/transparent"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#id/txt_fake_value"/>
<TextView android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/txt_check_info_value"
android:text=""
android:textSize="18dp"
android:textColor="#000"
android:layout_alignParentRight="true"
android:layout_alignBottom="#id/txt_fake_info"/>
<example.com.CheckInfoTextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textSize="18dp"
android:textColor="#000"
android:id="#+id/txt_check_info"
android:text=""
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#id/txt_check_info_value"/>
</RelativeLayout>
</LinearLayout>
Code to fill the info fields (in the Activity):
View row = getLayoutInflater().inflate(R.layout.check_info_item, null);
//Fake fields needed to align base fields in the xml file
TextView txtFakeValue = (TextView) row.findViewById(R.id.txt_fake_value);
txtFakeValue.setText(String.valueOf(pair.second));
TextView txtFake = (TextView) row.findViewById(R.id.txt_fake_info);
txtFake.setText(pair.first);
TextView txtValue = (TextView) row.findViewById(R.id.txt_check_info_value);
txtValue.setText(String.valueOf(pair.second));
TextView txtTitle = (TextView) row.findViewById(R.id.txt_check_info);
txtTitle.setText(pair.first);
And the CheckInfoTextView:
public class CheckInfoTextView extends TextView {
public CheckInfoTextView(Context context) {
super(context);
}
public CheckInfoTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CheckInfoTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if(!hasWindowFocus) return;
int requiredDots = getRequiredDotsNumber();
if(requiredDots == 0) {
String text = getText().toString();
StringBuilder result = new StringBuilder();
result.append(text.substring(0, text.lastIndexOf(' ')));
result.append("\n");
result.append(text.substring(text.lastIndexOf(' ') + 1));
setText(result.toString());
requiredDots = getRequiredDotsNumber();
}
String dots = "";
for (int i = 0; i < requiredDots; ++i) {
dots += " .";
}
setText(getText() + dots);
}
private int getRequiredDotsNumber() {
final int width = getWidth();
final int lastLineWidth = (int) getLayout().getLineWidth(getLineCount() - 1);
final int availableWidthForDots = width - lastLineWidth;
final int widthOfOneDot = getWidthOfOneDot();
final int widthOfTwoDotsWithSpace = getWidthOfTwoDotsWithSpace();
final int widthOfSpace = widthOfTwoDotsWithSpace - (widthOfOneDot * 2);
final int widthOfDotWithSpace = widthOfSpace + widthOfOneDot;
int numberOfDots = availableWidthForDots / widthOfDotWithSpace;
return numberOfDots;
}
private int getWidthOfTwoDotsWithSpace() {
return getStringWidth(". .");
}
private int getWidthOfOneDot() {
return getStringWidth(".");
}
private int getStringWidth(String text) {
Rect dotBounds = new Rect();
getPaint().getTextBounds(text,0,text.length(),dotBounds);
return dotBounds.width();
}
}
I've changed Serg_'s CheckinfoTextView class so that it both works in the eclipse layout editor, but also adds spaces if possible, to put the page number as close to the right side as possible. I've also changed a bit how it is used.
To accomplish:
Milk...................23
Chocolate cookies......24
set the text to 'Milk 23' and 'Chocolate cookies 24' respectively
The number of spaces is rounded to nearest rather than rounded down, so it's better to put the number a little bit over to the right rather than too much to the left
public class DotAutofillTextView extends TextView {
private int availableWidthForDots;
private int widthOfSpace;
private int widthOfDotWithSpace;
public DotAutofillTextView(Context context) {
super(context);
}
public DotAutofillTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DotAutofillTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int width = getWidth() - getPaddingLeft() - getPaddingRight();
int lastLineWidth = (int) getLayout().getLineWidth(getLineCount() - 1);
availableWidthForDots = width - lastLineWidth;
int widthOfOneDot = getWidthOfOneDot();
int widthOfTwoDotsWithSpace = getWidthOfTwoDotsWithSpace();
widthOfSpace = widthOfTwoDotsWithSpace - (widthOfOneDot * 2);
widthOfDotWithSpace = widthOfSpace + widthOfOneDot;
int requiredDots = getRequiredDotsNumber();
if (requiredDots != 0) {
int spaces = getRequiredSpacesNumber(requiredDots);
StringBuilder result = new StringBuilder();
String text = getText().toString();
result.append(text.substring(0, text.lastIndexOf(' ')));
setText(result.toString());
StringBuilder dots = new StringBuilder();
for (int i = 0; i < requiredDots; ++i) {
dots.append(" .");
}
for (int i = 0; i < spaces; ++i) {
dots.append(" ");
}
result.append(dots.toString());
result.append(text.substring(text.lastIndexOf(' ') + 1));
setText(result.toString());
}
super.onLayout(changed, left, top, right, bottom);
}
private int getRequiredSpacesNumber(int requiredDots) {
float remain = (1f * availableWidthForDots) % (1f * widthOfDotWithSpace);
return (int) ((remain / widthOfSpace) + 0.5f);
}
private int getRequiredDotsNumber() {
if (getLayout() == null) {
return 1;
}
int numberOfDots = availableWidthForDots / widthOfDotWithSpace;
return numberOfDots;
}
private int getWidthOfTwoDotsWithSpace() {
return getStringWidth(". .");
}
private int getWidthOfOneDot() {
return getStringWidth(".");
}
private int getStringWidth(String text) {
Rect dotBounds = new Rect();
getPaint().getTextBounds(text, 0, text.length(), dotBounds);
return dotBounds.width();
}
}
If '.'(dots) is your basic requirement then you can try like this..
My suggestion, Use only I TextView to fit in Beer...10 (hitch)
try like this..
int label_len = 10;//Edit as per your requirement
String MoneyValue = "20";
TextView tv = (TextView)findViewById(your id);
tv.setText("Beer");
if(tv.getText().length() < label_len){
for(int i = tv.getText().length(); i < label_len; i++){
tv.setText(tv.getText()+".");
}
}
tv.setText(tv.getText() + MoneyValue);
This is a sample with hardcoded value, you can try to add dynamically...
Hope this helps...
Use a relative layout:
TextView View TextView
The first set the width to wrap content, and below the text view of the previous row.
The second view, set to to right of first text view, and use a background drawable with dots that repeat horizontally. Set the width to match parent.
The last view, set to right of middle view and width to wrap content and aligned to right of parent.
I've had the same problem and found this solution using ConstraintLayout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="#+id/item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Phone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
/>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="...................................................................................................."
android:maxLines="1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="#id/item"
app:layout_constraintRight_toLeftOf="#id/price"/>
<TextView
android:id="#+id/price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:text="100"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
You can achieve this by using layout.xml only.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:![enter image description here][2]layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="1">
<TextView android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.9"
android:text="Milk.................................................................................................................................." />
<TextView android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="0.1"
android:text="20" />
</LinearLayout>
</LinearLayout>
This solution will work for all the device with different resolutions.