LinearLayout selector doesn't cover the whole View's children - android

The following is my XML code, I need to make a selector for the LinearLayout, but when I tap on the child TextView it doesn't show the selector backgroud as tapping other areas of the LinearLayout!
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:descendantFocusability="blocksDescendants"
android:background="?android:attr/selectableItemBackground">
<ImageView android:paddingLeft="35dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/chart"/>
<TextView android:paddingLeft="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="#+id/tv_title" />
<ImageView android:paddingRight="15dp"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/ic_star_border_black_48dp"
android:id="#+id/iv_bookmark" />
</LinearLayout>

Try this:
<TextView android:paddingLeft="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="#+id/tv_title"
android:clickable="false"
android:focusable="false" />
I think the reason for the error is because descendantFocusability is only for focusing state. It does not affect touch events. Since the TextView is still clickable it can still consume the touch event, and thus keep the parent from consuming the click.
Edit:
Try setting android:descendantFocusability to beforeDescendants instead of blocksDescendants.
Edit 2:
Changing the parent to android:addStatesFromChildren="true" and removing the clickable and focusable from the child TextView seemed to do the trick. This works because according to the ViewGroup android docs:
addStatesFromChildren: Sets whether this ViewGroup's drawable states also include its children's drawable states.
So when the child will set its state it also sets its parents state.

Try setting android:focusable and android:focusableInTouchMode to false in your TextView.

Related

getLayoutParams for LinearLayout under ScrollView not working

I have a LinearLayout and I controlled the height of this layout using getLayoutParams previously and it was working beautifully. Now I want the layout to be scrollable so I placed it under a ScrollView. Now for some reason the getLayoutParams stopped working. I seem to have come to a dead end trying to resolve this. Please help.
Here is my code
if(subHistories.getLayoutParams().height==0)
(subHistories.getLayoutParams()).height=ViewGroup.LayoutParams.WRAP_CONTENT;
else
(subHistories.getLayoutParams()).height=0;
Here subHistories is the layout object I want to control the height for. I want it to switch it's height from zero to wrap_content on every onClick event
And here is the relevant xml code:
...<ScrollView
android:id="#+id/left"
android:layout_width="200dp"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_below="#id/head"
android:animateLayoutChanges="true">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/historyBut"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="#5261a5"
android:paddingBottom="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingTop="5dp"
android:text="Historical Places"
android:textAllCaps="false"
android:textSize="20sp"
android:typeface="normal" />
<!-- historical places category -->
<LinearLayout
android:id="#+id/histories"
android:layout_marginLeft="10dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:animateLayoutChanges="true" >...
After touching layout params, call requestLayout() for the changes to take effect.
For hiding/showing a layout, consider using setVisibility() with GONE and VISIBLE instead.

Android - Background reset after show/hide views with animation

I am showing and hiding views on a particular actions using some animation, I used LayoutTransition and it seems to work fine except one thing, while the animation is going, the background of some TextViews changes and reset to the default white background!!
Following is the code I am using to apply animation after hide/show.
mRightTransitioner = new LayoutTransition();
mRightTransitioner.setDuration(1000);
vg_rightContainer.setLayoutTransition(mRightTransitioner);
Edited: even without animation i tried, same problem, the background resets once view's position changes
Edited: here how i declared the views in the XML
<LinearLayout
android:id="#+id/ll_req_reasonwrapper"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:baselineAligned="false"
android:gravity="right"
android:orientation="horizontal"
android:visibility="gone" >
<EditText
android:id="#+id/et_req_reasons"
android:layout_width="400dp"
android:layout_height="match_parent"
android:background="#drawable/comments_textbox"
android:gravity="right|center_vertical"
android:inputType="text"
android:paddingRight="8dp" />
<TextView
android:layout_width="100dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="#string/str_req_preasons" />
</LinearLayout>
<LinearLayout
android:id="#+id/ll_req_timewrapper"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:baselineAligned="false"
android:gravity="right"
android:orientation="horizontal"
android:visibility="gone" >
<LinearLayout
android:id="#+id/ll_req_endtimewrapper"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
<TextView
android:id="#+id/ftv_req_endtime"
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="#drawable/comments_textbox"
android:freezesText="true"
android:gravity="right|center_vertical"
android:inputType="numberDecimal"
android:paddingRight="8dp" />
<TextView
android:layout_width="100dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="#string/str_req_endtime" />
</LinearLayout>
<LinearLayout
android:id="#+id/ll_req_starttimewrapper"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="50dp" >
<TextView
android:id="#+id/ftv_req_starttime"
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="#drawable/comments_textbox"
android:freezesText="true"
android:gravity="right|center_vertical"
android:inputType="numberDecimal"
android:paddingRight="8dp" />
<TextView
android:layout_width="100dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="#string/str_req_starttime" />
</LinearLayout>
</LinearLayout>
for instance: if i hide 'll_req_reasonwrapper', then the LinearLayout 'll_req_timewrapper' moves up, then the backgrounds of the textViews like 'ftv_req_starttime' becomes white!!
Please help.
Edited Answer:
if your are using linear layout then if the child is not being displayed, it is not going to be laid out and not going to be the part of the measurements ( as it looks like ). I recommend to use the RelativeLayout.
You can try
android:background="#null"
for your buttons. if your are using some custom class for button then add
.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
for this specific views.
Need more code. The fact that disabling the LayoutTransition does not solve your issue, means that the animation is not the issue.
How do you reinstantiate child views or populate your view. Are you removing views with setVisibility(View.GONE) and then setting them back with setVisibility(View.VISIBLE)
OR
Are you removing childAt(i) and then dynamically adding custom views
I'm sorry I couldnt add a comment since I dont have the reputation for that but I think I am able to answer your question if you post more code.

Centering the contents of a view inside a LinearLayout

Here's the layout (below). I'm trying to reposition the location of the checkbox; move it to the right of the view. android:gravity and android:layout_gravity seem to have no effect. Any explanation? This LinearLayout is a child of a Relative Layout.
<LinearLayout
android:id="#+id/deviceLinear"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_below="#id/view1" >
<ImageView
android:contentDescription="#string/devices_icon"
android:id="#+id/devices_img"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="0.15"
android:layout_gravity="center"
android:src="#drawable/hardware_phone" />
<TextView
android:id="#+id/devices"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.43"
android:text="#string/devices"
android:textSize="20sp" />
<CheckBox
android:id="#+id/check_devices"
android:button="#drawable/custom_checkbox"
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="0.42"
android:onClick="onCheckboxClicked" />
</LinearLayout>
I assume that you want the CheckBox to be on the right side of the LinearLayout. Since you have given it a layout_weight it will always take up some fixed percentage of the width regardless of its size as you can see by that blue bounding box.
Try wrapping the checkbox in another LinearLayout that has android:orientation='horizontal'. Give the 0.42 weight to the wrapping LinearLayout and then set the LinearLayout's android:gravity to be right. That should keep your spacing while moving the checkbox to the far right.
Something like this:
<LinearLayout
android:orientation="horizontal"
android:layout_width="0dp"
android:layout_weight="0.42"
android:layout_height="wrap_content"
android:gravity="right" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
You might also want to consider a RelativeLayout which enables you to position Views based on where other views are.
You are giving layout_weight="0.42" to your checkbox, that means that it will be measured with a width based on the LinearLayout's width. By this approach you will never manage to put it on the right.
The best way to achieve your goal is to use a RelativeLayout. Here is my list item layout with a checkbox on the right. Sorry about the merge tag but it is merged inside a RelativeLayout with
android:layout_width="match_parent"
android:layout_height="wrap_content"
attributes
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView android:id="#+id/imgChannelIcon"
android:layout_alignParentLeft="true"
style="?muListItemImage60x60" />
<CheckBox android:id="#+id/chkIsChecked"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_alignTop="#+id/imgChannelIcon"
android:layout_alignParentRight="true"
android:layout_alignBottom="#+id/imgChannelIcon"
android:layout_marginLeft="#dimen/list_item_checkbox_margin_left"
android:layout_marginRight="#dimen/list_item_checkbox_margin_right"
android:layout_marginTop="#dimen/list_item_checkbox_margin_top"
android:layout_marginBottom="#dimen/list_item_checkbox_margin_bottom"
android:focusable="false"
android:focusableInTouchMode="false" />
<TextView android:id="#+id/lblChannelTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/imgChannelIcon"
android:layout_alignTop="#+id/imgChannelIcon"
android:layout_toLeftOf="#+id/chkIsChecked"
android:layout_alignWithParentIfMissing="true"
android:includeFontPadding="false"
android:textStyle="bold"
android:text="#string/channel_item_dummy_title"
style="?muListItemTextBig" />
<TextView android:id="#+id/lblChannelSubtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/imgChannelIcon"
android:layout_below="#+id/lblChannelTitle"
android:layout_toLeftOf="#+id/chkIsChecked"
android:layout_alignWithParentIfMissing="true"
android:includeFontPadding="false"
android:textStyle="normal"
android:text="#string/channel_item_dummy_subtitle"
style="?muListItemTextNormal" />
<TextView android:id="#+id/lblChannelCategory"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_toRightOf="#+id/imgChannelIcon"
android:layout_below="#+id/lblChannelSubtitle"
android:layout_alignBottom="#+id/imgChannelIcon"
android:layout_toLeftOf="#+id/chkIsChecked"
android:layout_alignWithParentIfMissing="true"
android:includeFontPadding="false"
android:paddingLeft="3dp"
android:gravity="center_vertical|left"
android:textStyle="italic"
android:text="#string/channel_item_dummy_category"
style="?muListItemTextNormal_Inverse" />
<TextView android:id="#+id/lblChannelUpdate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_below="#+id/imgChannelIcon"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:includeFontPadding="false"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:textStyle="italic"
android:text="#string/channel_item_dummy_update"
style="?muListItemTextTiny" />
</merge>
As you can see I first place an image with layout_alignParentLeft="true" then the checkbox with layout_alignParentRight="true" and finally I arrange the other components based on those two. From your image I can see that you can use your devices_img as the left component (but you will have to give it a fixed height and maybe some margins in order to became the Layout's height) and your check box as your right.
Keep in mind that in a RelativeLayout with wrap_content as height you cannot use the AlignParentBottom attribute.
Hope this helps...

Difficulty understanding layout_alignWithParentIfMissing

I don't understand the meaning of layout_alignWithParentIfMissing for the TextView attribute.
I read the following documentation:
android:layout_alignWithParentIfMissing
If set to true, the parent will be used as the anchor when the anchor cannot be be found for layout_toLeftOf, layout_toRightOf, etc.
Must be a boolean value, either true or false.
Please explain to me.
This apply only when using RelativeLayout.
If You set element to be toLeftOf some other element it means it will be on the left of this element.
But if this element will be missing, because You delete it for example it will be align to parent.
Take this example
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="102dp"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignWithParentIfMissing="true"
android:layout_alignBottom="#+id/textView1"
android:layout_toRightOf="#+id/textView1"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
See what happens If You delete textView1 but don't touch textView2.
It will go to the bottom, on left(not right because it is inside of parent)
Android will position element relative to parent instead of element it should be because it is missing.
If it is false parameters relating to missing elements will be ignored.
Another sample. I have just used.
<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="wrap_content"
android:padding="6dip" >
<Button
android:id="#+id/streamOverflow"
android:layout_width="50dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:background="#drawable/ic_action_overflow"
android:focusable="false" />
<TextView
android:id="#+id/delete_time"
style="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Disappears "
android:layout_toLeftOf="#id/streamOverflow"
android:layout_alignWithParentIfMissing="true"
/>
</RelativeLayout>
if "streamOverflow" is missing, "delete_time" textview behaves like having android:layout_alignParentRight="true" property.
In Relative Layouts, the position of a View can be specified relative to another View.
The tags layout_toLeftOf and layout_toRightOf position the view relative to an 'anchor' view object. When this anchor View is missing, the tag alignWithParentIfMissing, will align your view with the parent view.

How to make child views get "onpress" event from root view?

I'm used to the fact that items of listview without any problem (even with complicated layout) handle onpress events (some actions that makes it pressed and unpressed). But now I want the same from LinearLayout - if you press anyway on layout, all descendants should get onpress events.
This is the part of my fragment layout, which should be highlighted onpress event.
<LinearLayout
android:id="#+id/ll_about_fragment_feedback"
android:gravity="center_vertical"
android:layout_height="54dp"
android:background="#drawable/about_item_bkg"
android:layout_width="match_parent">
<ImageView
android:layout_height="wrap_content"
android:background="#drawable/about_item_feedback_icon"
android:layout_width="wrap_content"
android:layout_marginLeft="11dp"/>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="#string/about_fragment_feedback"
android:layout_marginLeft="14dp"
android:textSize="16dp"
android:textColor="#drawable/about_item_textcolor"/>
</LinearLayout>
Background of root layout changes onpress, but textcolor of descendants don't. Looks like they don't get event from root.
So, can you help?
UPDATE: LinearLayout ll_about_fragment_feedback has bound OnClickListener and there is everything fine with selecrors
If you want a Selector to apply to all views under your LinearLayout then you just need to add android:duplicateParentState="true" to all of the child views.
<LinearLayout
android:id="#+id/ll_about_fragment_feedback"
android:layout_width="match_parent"
android:layout_height="54dp"
android:background="#drawable/about_item_bkg"
android:gravity="center_vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="11dp"
android:background="#drawable/about_item_feedback_icon"
android:duplicateParentState="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="14dp"
android:duplicateParentState="true"
android:text="#string/about_fragment_feedback"
android:textColor="#drawable/about_item_textcolor"
android:textSize="16dp" />
</LinearLayout>
Just bind your onClickListener to root object of your layout (ll_about_fragment_feedback) and that's it.

Categories

Resources