Achieving Clickable views with both Parent and Child - android

I have a Relativelayout that is clickable. I have an element inside it (an ImageButton) that I also want to be clickable.
The layout was clickable just fine until I added the ImageButton; now only that is clickable.
I have tried all combinations of focusable and focusableInTouchMode = true and false in both elements (I tried only in xml layout). How can I make them BOTH clickable?
My code; note this is inside a ListView and each row has this; there is a non-clickable LinearLayout surrounding this:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/row_selector"
android:duplicateParentState="true"
android:paddingBottom="10dp" >
// several TextViews edited out
<ImageButton
android:id="#+id/ibMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="#color/row_overflow_state"
android:contentDescription="menu"
android:src="#drawable/ic_action_overflow" />
</RelativeLayout>

Use this to your parent
android:addStatesFromChildren="true"
if used this then don't use the following otherwise you will get stuck overflow exception
what about setting this to your child
android:duplicateParentState="true"

I had faced the same problem. I had a rectangular view which had to receive clicks for some other functionality, as well as an ImageView inside the rectangle, had to receive clicks for some other functionality.
Used Relative Layout for this purpose where Relative Layout was clickable=true and having the property
android:descendantFocusability="afterDescendants"
which means that the layout will receive focus only if none of its descendants want.
So parent, as well as the child, was clickable for two different functionalities.

Set android:descendantsFocusability="blocksDescendants" on the
RelativeLayout.

Related

How to let click events to go through child views and reach its parent (and change background)

The whole thing looks like this:
+---------+---------+
| Mon | 10:00AM |
+---------+---------+
It's a LinearLayout with two TextViews. I want click events to go through 'Mon' part and change background of the LinearLayout on click. '10:00AM' still needs to accept separate click events.
The XML:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:background="#drawable/button_filled_white"
android:clickable="true"
>
<TextView android:text="MON"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:clickable="false"
android:enabled="false"
android:focusable="false"
/>
<TextView android:text="10:00AM"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="#+id/txtTime"
/>
</LinearLayout>
To let click events to go thorough 'MON' TextView, I tried setting clickable, focusable and enabled to false in a various combination but still, the background of LinearLayout doesn't change.
If I remove child TextViews, the LinearLayout is clickable and I can see the background changing its color when clicked:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:background="#drawable/button_filled_white"
android:clickable="true"
/>
I'm aware of ViewGroup.onInterceptTouchEvent() but I'm looking for a XML way since handling ViewGroup.onInterceptTouchEvent() requires situation specific and view id specific implementations.
you can try to set
android:focusable="false"
to your 'Mon' child view
Sorry to answer my own question, but to help people with same problem, I will give more details.
The root cause was NestedScrollView.
I actually composited the LinearLayout inside NestedScrollView and that prevented clickable & focusable = false to work correctly. Setting to true actually works as expected (changing background & etc). But setting to false works only half as expected - ignores click, but doesn't pass click events to parent.
So if anyone is having same problem, take a look at your parent(or parent's parent) container. If it's scrollable container, you will have more challenges.

TextView changes size because of margin

When I use Android:margin to position textView half-outside it's parent, it acts weirdly: changes it's own size and text is moving inside textView box. How do I prevent it?
On image: left textView has cropped text at the end, and I don't want that.
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="16dp"
android:clipChildren="false">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="none"
android:singleLine="true"
android:textColor="#FFFFFF"
android:textSize="22.5dp"
android:layout_marginRight="200dp"
tools:text="0 TEXT VIEWVIEW"
tools:textColor="#000000" />
<...>
</FrameLayout>
FrameLayout always overlaps its Children. For effective placing widgets I suggest to use,
LinearLayout with layout_weight
arrange widgets relative to another widget by using RelativeLayout
You have two problems here:
You are using a FrameLayout. This means that when you keep increasing the margin of child, the view is gonna move out of the parent. Why? Because that's how FrameLayout is designed. Read documentation here: http://developer.android.com/reference/android/widget/FrameLayout.html
FrameLayout is designed to block out an area on the screen to display a single item. Generally, FrameLayout should be used to hold a single child view, because it can be difficult to organize child views in a way that's scalable to different screen sizes without the children overlapping each other.
So instead you could use RelativeLayout or LinearLayout.
The second problem you have is android:singleLine="true". This means that as the text increases in length, it will still be shown in a single line and hence the text will be clipped. So set this to false, or just remove this attribute.
android:singleLine="false"
i think you need to change the line:
android:singleLine="true"
to false.

OnClick Listener not working for buttons which exists in a linearlayout for which the alignParentBottom is true

I am having an activity and want to create a like button at the end of the layout, So I created a layout file and in a LinearLayout I have set it's layout_alignParentBottom property to true and created button for Likes in it. Now I am including this layout file in some other layout file but when I am applying onClickListener to the button, it does nothing.
When I remove this layout_alignParentBottom from the LinearLayout properties, then OnclickListener start working.
Can you please help me here to resolve this issue?
Some other widget might be coming in its way. if there is something above that button, it wont take clickListener.
For Ex. if there is a list in that layout too,
<Button
android:layout_alignParentBottom="true"
android:layout_marginLeft="#dimen/viewSpace1"
android:layout_marginRight="#dimen/viewSpace1"
android:layout_marginBottom="#dimen/viewSpace1"
android:layout_width="fill_parent"
android:layout_height="#dimen/headerHeight_small"
android:id="#+id/btnShare"
style="#style/ButtonLogin"
android:text="Next" />
<ListView
android:layout_above="#id/btnShare"
android:id="#+id/list"
android:layout_below="#id/layoutHeader"
android:layout_marginLeft="#dimen/viewSpace3"
android:layout_marginRight="#dimen/viewSpace3"
android:layout_marginBottom="#dimen/viewSpace3"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />
so your share button stays safe for clickability.
I have kept the list above btnShare. Just for my safety if it overlaps the button.If there is still problem, post your code so exact problem can be pin pointed.

Android layout overlap buttons on top of eachother (same center)

So the initial layout consists of a large circular "parent" button and multiple circular "child" buttons that are centered behind the parent button. So all the child buttons share the same center as the parent button. The reason for this layout is so during runtime, I can move the child buttons in and out of the parent button using translateX and translateY.
However, I'm stuck on the initial layout. How can I center the child buttons to the center of the parent button without hardcoding any child attributes?
Make the views the same size and add padding to the children so they get reduced. If the views are all in the same position the layout will look as you wish. Anyways, you can always change the properties in code.
I solved this myself using a container RelativeLayout as an anchor, with the parent button and all child buttons given android:layout_centerInParent. Then, to solve the issue of the child buttons disappearing when leaving the container, I gave the container android:clipChildren(false) and also set clipChildren to false on all of its ancestors as well.
Note that the container has to be bigger than all of its child elements, or all the child elements will be clipped to the same dimensions, even when they move outside of the container! To solve this, I gave the container a width and height of wrap_content.
Thus, all my child buttons were centered in the parent button no matter where I positioned the parent, and the child buttons were free to move around as well.
EDIT
A major flaw in this is that buttons can't recieve touch events if they are outside of their parent. To fix this, you can either use event coordinates or make the parent container big enough to always encompass the child elements (maybe twice the screen width/height?)
Here is the code:
res/layout/listfragment.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false" >
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:onClick="onButterflyMenuClicked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginBottom="20sp"
android:layout_marginRight="15sp"
android:clipChildren="false" >
<Button
android:id="#+id/btn_north_1"
style="#style/PeekabooButton"
android:text="1st"
android:translationY="-65sp" />
<Button
android:id="#+id/btn_north_2"
style="#style/PeekabooButton"
android:text="2nd"
android:translationY="-115sp" />
<Button
android:id="#+id/kingbutton"
android:layout_width="65sp"
android:layout_height="65sp"
android:layout_centerInParent="true"
android:gravity="center_vertical|center_horizontal"
android:textSize="16sp"
android:text="KING" />
</RelativeLayout>
</FrameLayout>
res/values/styles.xml
<style name="PeekabooButton">
<item name="android:layout_width">45sp</item>
<item name="android:layout_height">45sp</item>
<item name="android:layout_centerInParent">true</item>
<item name="android:textSize">10sp</item>
</style>
Use android:gravity="center" on all views after putting them all inside a FrameLayout (possibly nesting the FrameLayout inside another layout). You can then offset each Button's position in its parent by changing the layout_margin* values. Or you could translate the parent FrameLayout that holds all the Buttons however you wish.
To make the button circular, change your button's android:background value to point to a custom selector.

Which of layout should i use?

I'm confused. I want to show the map and on below of map show 5 buttons. I use RelativeLayout, but the program just show Product button. Why? I'm confused which layout i use (Linear,Relative,Frame or absolute )!! Please help me. and How can i correct this code?
location.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/frame"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.maps.MapView
android:id="#+id/mapView"
android:apiKey="0cPRv243zM1_S3ydsNg8MJP9_6BfCp642jOhPvQ"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/background"
android:layout_gravity="bottom"
android:orientation="horizontal" >
<Button
android:id="#+id/button_home"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="#drawable/home_icon"
android:text="#string/button_home"
android:textColor="#color/text_home" />
<Button
android:id="#+id/button_product"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="#drawable/product_icon"
android:onClick="Product"
android:text="#string/button_product"
android:textColor="#color/text_product" />
</LinearLayout>
</LinearLayout>
To answer your specific problem: Instead of saying that the home button is to the left of the product button, you should say that the product button is to the right of the home button. When a RelativeLayout is inflated, the layout is parsed in a linear way so if view A it positioned relative to view B, view B must come first.
<Button
android:id="#+id/button_home"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="#drawable/home_icon"
android:text="#string/button_home"
android:textColor="#color/text_home"/>
<Button
android:id="#+id/button_product"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/button_home"
android:drawableTop="#drawable/product_icon"
android:onClick="Product"
android:text="#string/button_product"
android:textColor="#color/text_product" />
Add this to the product button and delete the layout_toLeftOf from the home button.
android:layout_toRightOf="#id/button_home"
You can use gravity and alignment to position the home button and then have the other four buttons following it, each one positioned to the right of the one before it.
Good luck
RelativeLayout by default places these 2 buttons together, so you can just see the latter.
And the line
android:layout_toLeftOf="#+id/button_product"
is wrong. #+id creates an id, use #id in such cases.
I would recommend LinearLayout for the situation. Place these buttons in it, and adjust them with some margin.
LinearLayout : LinearLayout is used when we need to arrange the
widgets/views in a horizontal or vertical manner.
The direction of arrangement can be set to horizontal or vertical,
by default it is being horizontal.
TableLayout : If the Layout's widgets/views need to be arranged
in the form of rows and columns, we use this layout object.
This is similar to html tables. The cells can span columns.
The TableLayout do not display its border. We can be made to
shrink and stretch by setting the respective properties of the columns,
"TableRow" is another helper widget which should be used in conjunction
with the TableLayout.
RelativeLayout : Here the position of each of the widgets/view is
in relative/dependent to each other. For example, when a layout is needed
such that it has a text view just to the left of an Edit Textbox, and a button
just below the EditText. The relation between the views are taken care in
one iteration, hence if view B’s position is dependent on view A’s position,
view A must come first in the layout.
FrameLayout : This is a very simply layout which is used to hold a section
of the screen blank, for displaying an item or group of items at run time. All the
elements added in the framelayout will be added to the top left of the screen.
AbsoluteLayout : When there is a need is to specify exact x and y co-ordinate
position of the view, then AbsoluteLayout need to be used. This layout is
difficult to maintain.

Categories

Resources