Add dots to TextView like in the receipt - java

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.

Related

Marque Text Starting and Stopping [duplicate]

I have LinearLayout and inside 2 TextView both have marquee and when I update text in first then second TextView restarts marquee.
<LinearLayout
android:id="#+id/panel"
android:layout_width="320dp"
android:layout_height="match_parent"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="#+id/first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="bottom|center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true" />
<TextView
android:id="#+id/second"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="top|center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
/>
</LinearLayout>
I found that if for R.id.first and R.id.second i set layout_width="320dp" the effect don't occurs.
But I want to set android:layout_width="match_parent" there is some workaround?
I found similar problem but without solution:
Android, RelativeLayout restarts Marquee-TextView when changing ImageView in same RelativeLayout
I had a similar problem and the solution IS to set fixed size for the Textview.
So why not do it progammatically? In my case, it solved the problem. Here is my solution in details :
The layout is a bit complex with a lot of changing values. Here is the interesting part :
layout.xml :
<!-- The height and visibility values change programatically -->
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="30dp"
android:layout_alignParentBottom="true"
android:visibility="gone" >
<FrameLayout>
...
// some code
...
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="fill_parent" />
<!-- My scrolling textview. see below. -->
<!-- The size will be set when -->
<!-- the layout will be draw, -->
<!-- after the Activity.onCreate(). -->
<!-- I removed ALL THE UNECESSARY (I mean -->
<!-- scrollHorizontally, focusable and focusableInTouchMode. -->
<!-- You don't need it !!!!) -->
<fr.cmoatoto.android.widget.ScrollingTextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever" />
<ImageView
...
// some code
... />
</LinearLayout>
</RelativeLayout>
The ScrollingTextView has been defined in this answer
Here it is again :
ScrollingTextView.java :
public class ScrollingTextView extends TextView {
public ScrollingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ScrollingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollingTextView(Context context) {
super(context);
}
#Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if(focused)
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
#Override
public void onWindowFocusChanged(boolean focused) {
if(focused)
super.onWindowFocusChanged(focused);
}
#Override
public boolean isFocused() {
return true;
}
}
And finally the Activity. As I said before, You need to set fixed width and height so we will do it programmatically with a listener in the onCreate() :
MyActivity.java :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
TextView textView = ((TextView) findViewById(R.id.home_trafic_text));
textView.setText(getString(R.string.loading));
textView.setEnabled(true); // Thanks to Romain Guy
textView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
LayoutParams params = v.getLayoutParams();
params.width = right - left;
params.height = bottom - top;
params.weight = 0;
v.removeOnLayoutChangeListener(this);
v.setLayoutParams(params);
}
});
}
Be careful if you need to change orientation or things like that but it works pretty well for me !
----EDIT FOR PRE-API-11---
Because OnLayoutChangeListener exists only from Api v11, there is a workaround (It works but I think it is less good) :
Remove the OnLayoutChangeListener from your activity :
MyActivity.java :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
TextView textView = ((TextView) findViewById(R.id.home_trafic_text));
textView.setText(getString(R.string.loading));
textView.setEnabled(true); // Thanks to Romain Guy
}
and add a onSizeChanged in your ScrollingTextView :
ScrollingTextView.java :
public class ScrollingTextView extends TextView {
...
// Same code as before
...
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
LayoutParams params = (LayoutParams) getLayoutParams();
params.width = w;
params.height = h;
params.weight = 0;
setLayoutParams(params);
}
}
I hope it helps !
You should prevent putting both marquee in the same ViewGroup. In your case, you can wrap each marquee TextView with a LinearLayout (this won't work if using RelativeLayout).
just a simple Fix..:) no need to worry much...just fix width of textview as some 800dp or too higher width. it will solve reset issue

How to make the height match the relative width?

so I got this xml code:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal"
android:layout_weight="1">
<ImageView
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_weight="1"
android:background="#drawable/profilbildfrau"
android:id="#+id/bild0"
>
</ImageView>
<ImageView
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_weight="1"
android:background="#drawable/profilbildfrau"
android:id="#+id/bild1">
</ImageView>
<ImageView
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_weight="1"
android:background="#drawable/profilbildfrau"
android:id="#+id/bild2">
</ImageView>
</LinearLayout> (...)
And this is my JavaCode:
ImageView beispiel;
ImageView[] profilbilder = new ImageView[21];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hauptmenue);
beispiel = (ImageView)findViewById(R.id.bild0);
int weite = beispiel.getWidth();
profilbilder[0] = (ImageView)findViewById(R.id.bild0);
profilbilder[1] = (ImageView)findViewById(R.id.bild1);
profilbilder[2] = (ImageView)findViewById(R.id.bild2);
profilbilder[3] = (ImageView)findViewById(R.id.bild3);
profilbilder[4] = (ImageView)findViewById(R.id.bild4);
profilbilder[5] = (ImageView)findViewById(R.id.bild5);
profilbilder[6] = (ImageView)findViewById(R.id.bild6);
profilbilder[7] = (ImageView)findViewById(R.id.bild7);
profilbilder[8] = (ImageView)findViewById(R.id.bild8);
profilbilder[9] = (ImageView)findViewById(R.id.bild9);
profilbilder[10] = (ImageView)findViewById(R.id.bild10);
profilbilder[11] = (ImageView)findViewById(R.id.bild11);
profilbilder[12] = (ImageView)findViewById(R.id.bild12);
profilbilder[13] = (ImageView)findViewById(R.id.bild13);
profilbilder[14] = (ImageView)findViewById(R.id.bild14);
profilbilder[15] = (ImageView)findViewById(R.id.bild15);
profilbilder[16] = (ImageView)findViewById(R.id.bild16);
profilbilder[17] = (ImageView)findViewById(R.id.bild17);
profilbilder[18] = (ImageView)findViewById(R.id.bild18);
profilbilder[19] = (ImageView)findViewById(R.id.bild19);
profilbilder[20] = (ImageView)findViewById(R.id.bild20);
for(int i = 0; i < 20; i++){
profilbilder[i].setMaxHeight(weite);
//ImageView bild = profilbilder[i];
//bild.getLayoutParams().height = weite;
profilbilder[i].setMinimumHeight(weite);
profilbilder[i].requestLayout();
}
}
My goal is to get the width of one of the pictures after it has its correct width fitting the screen and then set the height of each picture to the width of the picture. Tried some code, this one is my recent one, but the height won't match the width. What am I missing here?
Thank you in advance,
Julian
In onCreate the view is not sized yet and normally the width will return 0. Add OnGlobalLayoutListener to the view and get the height and width of the ImageView inside onGlobalLayout. Then you can set a new LayoutParams to every ImageView :
beispiel.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
beispiel.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
beispiel.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
int width = beispiel.getWidth();
for(int i = 0; i <= 20; i++){
// make the height and width of each ImageView equal to width of beispiel
profilbilder[i].setLayoutParams(new LinearLayout.LayoutParams(width, width));
}
}
});

Android: Extending CardView which content can be expanded

I extended the android CardView to a Expandable version of it, with a header title and an icon which can be rotated.
CODE
This file(view_cardview_header.xml) contains the header of the ExpandableCardView, it should be the first child and not collapsed.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textAppearance="#style/TextAppearance.AppCompat.Title" />
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true" />
</RelativeLayout>
</LinearLayout>
The attrs.xml file with custom xml parameters
<resources>
<declare-styleable name="ExpandableCardView">
<attr name="expanded" format="boolean" />
<attr name="headerTitle" format="string" />
<attr name="headerIcon" format="integer" />
</declare-styleable>
</resources>
The ExpandableCardView.java class
public class ExpandableCardView extends CardView {
private static final float ROTATION_NORMAL = 0.0f;
private static final float ROTATION_ROTATED = 180f;
private static final float PIVOT_VALUE = 0.5f;
private static final long ROTATE_DURATION = 200;
private boolean isExpanded;
public ExpandableCardView(Context context) {
this(context, null);
}
public ExpandableCardView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ExpandableCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ExpandableCardView, 0, 0);
String titleText = a.getString(R.styleable.ExpandableCardView_headerTitle);
final Drawable drawable = a.getDrawable(R.styleable.ExpandableCardView_headerIcon);
a.recycle();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.view_cardview_header, this, true);
final LinearLayout parent = (LinearLayout) getChildAt(0);
final RelativeLayout header = (RelativeLayout) parent.getChildAt(0);
final TextView titleTextView = (TextView) header.getChildAt(0);
titleTextView.setText(titleText);
final ImageView toggle = (ImageView) header.getChildAt(1);
if(drawable != null) {
toggle.setImageDrawable(drawable);
}
header.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
setExpanded(toggle, !isExpanded);
onExpansionToggled(toggle);
}
});
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if(getChildAt(0) == null || getChildAt(0).equals(child)) {
super.addView(child, index, params);
} else {
((LinearLayout) getChildAt(0)).addView(child);
}
}
private void setExpanded(ImageView toggle, boolean expanded) {
isExpanded = expanded;
final LinearLayout parent = (LinearLayout) getChildAt(0);
final int childCount = parent.getChildCount();
if(expanded) {
toggle.setRotation(ROTATION_ROTATED);
for(int i = childCount - 1; i > 0; i--) {
parent.getChildAt(i).setVisibility(VISIBLE);
}
} else {
toggle.setRotation(ROTATION_NORMAL);
for(int i = 1; i < childCount; i++) {
parent.getChildAt(i).setVisibility(GONE);
}
}
}
private void onExpansionToggled(ImageView toggle) {
RotateAnimation rotateAnimation = new RotateAnimation(ROTATION_ROTATED, ROTATION_NORMAL,
RotateAnimation.RELATIVE_TO_SELF, PIVOT_VALUE, RotateAnimation.RELATIVE_TO_SELF,
PIVOT_VALUE);
rotateAnimation.setDuration(ROTATE_DURATION);
rotateAnimation.setFillAfter(true);
toggle.startAnimation(rotateAnimation);
}
}
Fragment Layout for testing the new CardView(fragment_test.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.tecdroid.views.ExpandableCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/card_margin"
android:layout_marginBottom="#dimen/card_margin"
android:layout_marginLeft="#dimen/card_margin"
android:layout_marginRight="#dimen/card_margin"
app:headerTitle="TITLE"
app:headerIcon="#mipmap/ic_action_expand">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="First inner child"/>
</com.tecdroid.views.ExpandableCardView>
</LinearLayout>
Result on Emulator
PROBLEM
As you can see on the image, the first inner child(TextView), is not placed under the Relative Layout(Header).
First i thought i have to override the onMeasure(int widthMeasureSpec, int heightMeasureSpec) method, but the ExpandableCardView extends indirect the ViewGroup, where the onMeasure(int widthMeasureSpec, int heightMeasureSpec) method does it all for me.
Maybe someone figure out what i have forgot, or did wrong.
UPDATE
Problem solved, see changes.
CardView extends FrameLayout, your header and first child are just unrelated child views. To have a spatial relation between children you need to use a LinearLayout or RelativeLayout with align-* parameters.
why not make a compound view with your cardview and a layout of your choice that contains the child view?

Inflating Vertical Linear Layout in Horizontal LinearLayout return width and height 0

I'm trying to inflate 5 vertical LinearLayout in one custom horizontal LinearLayout.
First I covert the xml to a View using the LayoutInflater. Then I add the vertical layouts to the horizontal one.
The problem is that in onMeasure, I try to set the width and the height of the children vertical LinearLayout but then, when I ask for getWidth and getHeight it always return 0.
I really don't understand this behaviour.
Can you please help me. Thank you so much.
XML of the vertical LinearLayout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#000000" >
<Button
android:id="#+id/button1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="Button"
android:layout_weight="1" />
<com.vuric.nativesampler.customviews.BandSeekBar
android:id="#+id/bandSeek"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="8"
android:layout_gravity="center"/>
<Button
android:id="#+id/button2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Button" />
</LinearLayout>
Class of the container horizontal LinearLayout:
public class EqualizerCustomLayout extends LinearLayout {
private static final int MARGIN = 4;
private Context context;
public EqualizerCustomLayout(Context context) {
super(context);
this.context = context;
init();
}
public EqualizerCustomLayout(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init();
}
public EqualizerCustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
private void init() {
setOrientation(LinearLayout.HORIZONTAL);
setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
//getNumberOfBands is 5
for (int i = 0; i < CustomApplicationClass.get().getNumberOfBands(); ++i) {
LinearLayout linearLayout = (LinearLayout) inflate(context,
R.layout.slot_band_layout, null);
addView(linearLayout);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.v("jajaja", "onMeasure children are " + getChildCount());
int width = (CustomApplicationClass.get().getScreenSize().x / 100 * 45)
+ MARGIN * 2;
int height = (CustomApplicationClass.get().getScreenSize().x / 100 * 45)
+ MARGIN * 2;
LayoutParams params = new LinearLayout.LayoutParams(width / 5, width);
for (int i = 0; i < getChildCount(); ++i) {
LinearLayout layout = (LinearLayout) getChildAt(i);
layout.setLayoutParams(new LinearLayout.LayoutParams(width
/ getChildCount(), height));
Log.v("jajaja",
"view" + i + " , w: " + layout.getWidth() + " , h: "
+ layout.getHeight()); // always return 0 for both width and height
}
setMeasuredDimension(width, height);
}
}
You have to wait until the view is actually drawn. There is a workaround that can be found here.

setMinimumHeight() on LinearLayout isn't working (in subclass)

I have a subclass of a liner layout (referenced from XML custom type) The minimum height I've tried to set just isn't working nor is setting the layout. I need to do this programatically...
Why isn't setMinimumHeight() working?
NB: The complexity of the code can be ignored, the value it is setting is 70
public class SummaryDynamicSpacer extends LinearLayout {
private static final String TAG = "mymeter-DynamicSpacer";
int dpWidth = 0;
int dpHeight = 0;
public SummaryDynamicSpacer(Context context) {
super(context);
init(context);
}
public SummaryDynamicSpacer(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
DisplayMetrics metrics = new DisplayMetrics();
((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(metrics);
//Set dpWidth, this is the key metric we use for scaling.
float density = getResources().getDisplayMetrics().density;
float dpWidth = metrics.widthPixels / density;
float dpHeight = metrics.heightPixels / density;
this.dpWidth = (int)dpWidth;
this.dpHeight = (int)dpHeight;
Log.d(TAG, "zyxHeightDP: "+metrics.heightPixels / density);
int id = this.getId();
int increment = 10;
int adjustment = getValueForLargeDevice(increment);
if(id == R.id.betweenAddressAndTopBox) {
doBetweenAddressAndTopBox(context, adjustment);
} else if(id == R.id.betweenTopAndAddress) {
doBetweenTopAndAddress(context, adjustment);
}
Log.d(TAG, "SettingHeight: "+adjustment);
this.setBackgroundColor(Color.BLUE);
}
private void doBetweenAddressAndTopBox(Context context, int adjustment) {
this.setMinimumHeight(adjustment);
}
private void doBetweenTopAndAddress(Context context, int adjustment) {
this.setMinimumHeight(adjustment);
}
private int getValueForLargeDevice(double increment) {
int largeDeviceAdjustment = 0;
if(dpHeight > 750) {
int difference = (int)dpHeight - 750;
int interval = 25;
int iterations = (difference / interval) > 12 ? 12 : (difference / interval);
int increasePerInterval = 0;
for(int i=0; i < iterations; i++) {
largeDeviceAdjustment += increment;
}
return largeDeviceAdjustment;
} else {
return 1;
}
}
}
I think your code is fine. Your layout likely has an issue. Did you set the layout as follows?
<com.example.dynamicspacerlayout.SummaryDynamicSpacer
android:id="#+id/betweenAddressAndTopBox"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
See this also does minHeight do anything?
GalaxyNexus Screen Shot running your code
Nexus7 Screen Shot
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Top Text">
<requestFocus />
</EditText>
<com.example.dynamicspacerlayout.SummaryDynamicSpacer
android:id="#+id/betweenAddressAndTopBox"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="#android:color/white"
/>
</com.example.dynamicspacerlayout.SummaryDynamicSpacer>
<EditText
android:id="#+id/editText2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Bottom Text"
/>
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
int minimumHeight = findViewById(R.id.betweenAddressAndTopBox).getHeight();
TextView text = (TextView) findViewById(R.id.textView1);
text.setText("Height: " + minimumHeight);
// text.setVisibility(minimumHeight > 1 ? View.VISIBLE : View.GONE);
}
}, 1000);
}
}
Hope that Helps!

Categories