I am working on a custom list view. I want to show a CheckBox at the custom view. There is no text for the CheckBox. I found it always have some spaces at the right of the CheckBox.
Here is my layout xml file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:orientation="horizontal" android:background="#fa9654"
android:paddingTop="65dp" android:paddingBottom="65dp">
<TextView android:id="#+id/bus_route_list_item_num"
android:layout_height="wrap_content" android:layout_width="0dip"
android:gravity="center" android:layout_gravity="center_vertical|center_horizontal"
android:layout_weight="0.15"></TextView>
<TextView android:id="#+id/bus_route_list_item_station"
android:layout_height="wrap_content" android:layout_width="0dip"
android:gravity="left" android:layout_gravity="center_vertical|center_horizontal"
android:layout_weight=".5"></TextView>
<TextView android:id="#+id/bus_route_list_item_fee"
android:layout_height="wrap_content" android:layout_width="0dip"
android:gravity="center" android:layout_gravity="center_vertical|center_horizontal"
android:layout_weight=".15"></TextView>
<CheckBox android:id="#+id/bus_route_list_item_reminder" android:layout_height="wrap_content"
android:layout_width="0dip" android:layout_weight=".20" android:gravity="center"
android:layout_gravity="center" android:paddingRight="0dp" android:paddingLeft="0dp"
android:paddingTop="0dp" android:paddingBottom="0dp" android:background="#0066ff"
android:text=""
/>
</LinearLayout>
The result looks like:
As you can see there are some space at the right of the checkbox. What I want is put the checkbox at the middle of the blue area.
Is it possible to remove the unwanted space? thanks
by default, the Checkbox has minWidth and minHeight value
you can set its value to 0
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="0dp"
android:minHeight="0dp" />
The result will be like that without any extra spaces
You can wrap CheckBox in LinearLayout and then use android:gravity="center" on that layout.
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="0dip"
android:layout_weight=".20"
android:background="#ff0000"
android:gravity="center">
<CheckBox android:id="#+id/bus_route_list_item_reminder"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
</LinearLayout>
As another alternative, you can use RelativeLayout. This would greatly simplify you layout and you will be able to get rid of layout_weight.
Neither of previous solutions worked for me, but I've tried applying a translation to the content and it worked pretty well, no need in additional layout hierarchy, nor implementing own views:
<CheckBox
...
android:text="#null"
android:translationX="12dp" />
Also, it keeps bounds of the element in proper place, so touch area is not shifted.
The translationX seems to work. But it causes problem if you want to support RTL layouts. Another solution would be to set the width of checkbox to a fixed length (e.g. 26dp):
<CheckBox
android:layout_width="26dp"
android:layout_height="wrap_content"
android:text="#null" />
To remove extra space at right of the image (when there is no text) extend CheckBox class and override getSuggestedMinimumWidth() method in order to return there image width. Complete solution:
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.CheckBox;
public class CheckBoxWithoutText extends CheckBox
{
private Drawable buttonDrawable;
public CheckBoxWithoutText(Context context)
{
super(context);
}
public CheckBoxWithoutText(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
protected int getSuggestedMinimumWidth()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
{
return getCompoundPaddingLeft() + getCompoundPaddingRight();
}
else
{
return buttonDrawable == null ? 0 : buttonDrawable.getIntrinsicWidth();
}
}
#Override
public void setButtonDrawable(Drawable d)
{
buttonDrawable = d;
super.setButtonDrawable(d);
}
}
I would use a relative layout here. Aligning checkbox on parent right...
Regards,
Stéphane
Related
I have a layout that animate as below
The txt_billion is shown dynamically, with android:animateLayoutChanges="true" (Layout code below).
Notice the Hundred is jumping (actually all are jumping, but the Hundred is just more obvious). How to prevent the text from jumping?
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="8dp"
android:background="#9f9"
android:text="Hundreds" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="8dp"
android:background="#f9f"
android:text="Thousands" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="8dp"
android:background="#0ff"
android:text="Millions" />
<TextView
android:id="#+id/txt_billion"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="8dp"
android:visibility="gone"
android:background="#ff0"
android:text="Billions" />
</LinearLayout>
You could get the code from https://github.com/elye/issue_horizontal_layout_animate to test out
Try to use Support Transitions instead animateLayoutChanges
First, remove android:animateLayoutChanges="true" from your XML file
After, add compile 'com.android.support:transition:25.4.0' to your app dependencies.
Then, add this line before change visibility (TransitionManager from android.support.transition package)
TransitionManager.beginDelayedTransition(parentOfAnimatedView);
For your code
public void clickMe(View view) {
TransitionManager.beginDelayedTransition((ViewGroup) billionText.getParent());
if (billionText.getVisibility() == View.GONE) {
billionText.setVisibility(View.VISIBLE);
} else {
billionText.setVisibility(View.GONE);
}
}
The problem is that animateLayoutChanges only affects subclasses of ViewGroup. TextView can't react to layout change animations, so the text jumps. There are two ways to fix it:
1) Wrap each TextView in a FrameLayout and put the weight on the FrameLayout. You'll also have to add android:animateLayoutChanges="true" to each, as well as calling getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING) on each FrameLayout. This is kind of gross layout-wise, but it will allow you to keep using the transition animations.
2) Use a ValueAnimator and animate the weight of the (dis)appearing item. The animation may be a little choppier since it needs to lay out the LinearLayout on each frame, but it should still be passable. You'd also have to solve for text reflowing on the disappearing item, maybe by animating it fading out first and then animating the weight change.
To be able to select the item (the row) AND sub items on the row, I use android:descendantFocusability="blocksDescendants". And I'm using the onItemSelectevent....
I as well use a custom background for my row.
Now the problem is, when I touch a row, the checkbox get's it's selected background as well (the blue default background, when you select a checkbox), how do I avoid this? I only want the row itself to adjust it's background to the item state, when I touch the row.
I'm using following row layout as a row in a listview in an adapter:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rlMain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#drawable/list_gradient"
android:descendantFocusability="blocksDescendants" >
<CheckBox
android:id="#+id/cbSelected"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true" />
<TextView
android:id="#+id/tvDayName"
style="#style/text_list_info_big"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/cbSelected"
android:text="Tag" />
<RelativeLayout
android:id="#+id/drag_handle"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" >
<ImageView
android:layout_width="60dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:src="#drawable/grabber" />
</RelativeLayout>
<LinearLayout
android:id="#+id/lvData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/s"
android:layout_toRightOf="#+id/tvDayName"
android:orientation="vertical" >
<TextView
android:id="#+id/tvCount"
style="#style/text_list_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:text="" />
<TextView
android:id="#+id/tvInfo"
style="#style/text_list_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:text="" />
<TextView
android:id="#+id/tvInfo2"
style="#style/text_list_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:text="" />
</LinearLayout>
</RelativeLayout>
PS: I know I could handle the onClick event of the row and the sub items in my adapter instead of using onItemClick, but I'm using the DragAndSortList view and doing it that way does not work with the drag&drop there...
I found a solution. Overriding SetPressed of the row didn't work.
Now I'm using following RelativeLayout and that's solving my problem:
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
public class UnpressableRL extends RelativeLayout
{
public UnpressableRL(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
protected void dispatchSetPressed(boolean pressed) {
// avoid handing on the event to the child views
}
}
I need to put check to the right hand top corner of my imageview. But when I do this I noticed a default margin around my checkbox. Is there a way to remove this??
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" >
<ImageView
android:id="#+id/thumbImage"
android:layout_width="100dp"
android:layout_height="132dp"
android:layout_gravity="center" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="#ff0000"
android:gravity="center" >
<CheckBox
android:id="#+id/itemCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_gravity="center"
android:button="#drawable/checkbox_background"
android:paddingLeft="0dp"
android:paddingTop="0dp" />
</LinearLayout>
</RelativeLayout>
There's now a better way of doing this:
android:minWidth="0dp"
android:minHeight="0dp"
To remove radio button default margins or padding in android
if you using xml
android:minWidth="0dp"
android:minHeight="0dp"
if using programmatically
radiobtn.setMinimumHeight(0);
radiobtn.setMinimumWidth(0);
You could use a negative margin.
android:layout_marginTop = "-5dp"
android:layout_marginRight = "-5dp"
This works for me in Constraint Layout. I hope it will work for another layout.
<androidx.appcompat.widget.AppCompatCheckBox
...
android:translationX="-5dp"
/>
If you look at the source code for the CompoundButton class that is extended by the Checkbox class at the onDraw() method, the padding depends from the gravity
#Override
protected void onDraw(Canvas canvas) {
...
final int top;
switch (verticalGravity) {
case Gravity.BOTTOM:
top = getHeight() - drawableHeight;
break;
case Gravity.CENTER_VERTICAL:
top = (getHeight() - drawableHeight) / 2;
break;
default:
top = 0;
}
...
}
So what you can do is set the xml value for the attribute gravity to
android:gravity="top|start"
But this can be used only if you don't want to use text with your checkbox, since the gravity is used to center the text.
Thanks to #VladislavShcherbakov comment, it is:
android:paddingLeft="-5dp"
android:layout_marginStart="-5dp"
android:layout_marginLeft="-5dp"
// android:translationX="-5dp"
Why to complicate with a negative padding and all. Use the simple and straight way, give padding to the FrameLayout instead tof the top most Relative layout that would do the trick. As you have only the CheckBox in the second layout there is no need to give padding for it.
Please do let me know if you face any problems or have any further doubts
I have a custom view like this
public class ButtonBar extends HorizontalScrollView
{
public View mButtonRows;
public ButtonBar(Context context, AttributeSet attrs)
{
super(context, attrs);
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mButtonRows = inflater.inflate(R.layout.toolbar, null);
// button click handling code goes here
addView(mButtonRows);
}
}
which is included in my main xml like this
<com.example.ButtonBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="#+id/pagecontent" />
and inflates an xml file like this:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ButtonsRow"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="#+id/button1"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="0.3"
android:text="button1"
/>
<Button
android:id="#+id/button2"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="0.3"
android:text="button2"
/>
<Button
android:id="#+id/button3"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_weight="0.3"
android:text="button3"
/>
</LinearLayout>
(It currently only has three buttons, but more are going to be needed in later versions, hence the HorizontalScrollView.)
Looking in hierarchyviewer, the custom view does seem to be screen wide, but the LinearLayout is only as wide as the buttons it contains (about 2/3 of the screen at the current button size), despite having the fill_parent width set; the buttons don't stretch. If I set the LinearLayout's background to #android:drawable/bottom_bar (which is a png the width of the screen), the buttons properly resize; I realise I could do the same thing by creating my own images to match, but I'd much rather do it without if possible.
What am I doing wrong?
ETA: if I change HorizontalScollView to ScrollView, it works fine. Do HSVs just not allow their children to "fill_parent"?
ETA2: Setting android:fillViewport="true" in the main xml fixed it!
Setting android:fillViewport="true" in the main xml fixed it!
If you change to this, for each of the buttons, does it work?
android:layout_width="0px"
android:layout_weight="1"
Basically I am trying to recreate the default contact screen when you click on "+" button another row of Phone number added to the list.
Right now I have an ImageView as the "+" button and a ListView to contain the list of phone numbers. The problem is that the ListView doesn't expand when I add more item into the list.
I could build the same look with LinearLayout but how can I save all those numbers that way?
Below is the layout of the item that will be inflate with custom Adapter
<?xml version="1.0" encoding="utf-8"?>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="60px"
android:stretchColumns="1"
android:background="#FFFFFFFF"
android:gravity="center_vertical">
<TableRow>
<Button
android:id="#+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:text="Home" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
>
<EditText
android:id="#+id/value"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:text=""
android:hint="Name"
android:lines="1"
android:textSize="10pt"
android:typeface="sans"
android:textColor="#FF000000"
android:gravity="left"
/>
</RelativeLayout>
<ImageView
android:id="#+id/del"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:paddingRight="14dp"
android:src="#android:drawable/ic_delete" />
</TableRow>
</TableLayout>
This is the ListView portion.
<ListView
android:id="#+id/phoneList"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#FFFFFFFF"
android:scrollbars="none" />
This is really confusing :S. Could anyone help me please?
You should use a ViewStub.
A ViewStub is an invisible, zero-sized
View that can be used to lazily
inflate layout resources at runtime.
When a ViewStub is made visible, or
when inflate() is invoked, the layout
resource is inflated.
Here you have some tutorials or you can clone the android's git repo to check how they did it.
I've built an Animation class, which animates the margin to negative values, making the item disappear.
The animation looks like this:
public class ExpandAnimation extends Animation {
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
// Calculating the new bottom margin, and setting it
mViewLayoutParams.bottomMargin = mMarginStart
+ (int) ((mMarginEnd - mMarginStart) * interpolatedTime);
// Invalidating the layout, making us seeing the changes we made
mAnimatedView.requestLayout();
}
}
}
I have an entire example app for this animation on my blog post:
http://udinic.wordpress.com/2011/09/03/expanding-listview-items/
I ended up created my own class extending LinearLayout and have its size recalculate every time item is added or removed. I'm sure the code is dirty and takes up lots of memories but it work for now.