I want to create a composite view from a bunch of controls, by extending a LinearLayout.
I'm using an XML file to specify the inner layout of my custom control. I'm inflating the custom control from the code via LayoutInflater.
The Problem is:
If i replace the root LinearLayout element to a merge element in the XML, my whole layout fall apart. If I don't, then I only encapsulated a LinearLayout with my custom one.
The question is:
What do i have to change in the merge layout, so my view looks like how a linear layout should?
How it looks like:
With LinearLayout (this is how i want it to look like):
http://oi45.tinypic.com/2pqwby1.jpg
With merge (this is the tag i want to use):
http://i45.tinypic.com/155j4o0.png
The code:
TowerLayout.java (no problems here, just in case):
public class TowerLayout extends LinearLayout implements OnClickListener {
public TowerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.tower_layout, this, true); //this is what i want to use.
//((LinearLayout)findViewById(R.id.root)).setOnClickListener(this); //this is the current ugly workaround.
this.setClickable(true);
setOnClickListener(this);
}
#Override
public void onClick(View v) {
Toast.makeText(getContext(), "Foo", Toast.LENGTH_SHORT).show();
}
}
What i have in Tower_Layout.xml:
<?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:clickable="true"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:duplicateParentState="true">
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="TowerA"
android:textAppearance="?android:attr/textAppearanceLarge"
android:duplicateParentState="true"
android:textSize="32sp" />
<ImageView
android:id="#+id/imageView1"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.28"
android:duplicateParentState="true"
android:src="#drawable/icon" />
</LinearLayout>
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Basic information"
android:duplicateParentState="true"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_marginLeft="15dip"
android:layout_height="wrap_content"
android:duplicateParentState="true"
android:text="Lorem ipsum dolor sit amet, consectetuer adipiscing elit." />
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:duplicateParentState="true"
android:text="16m"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="100sp" />
What i want in Tower_Layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:duplicateParentState="true">
...
</LinearLayout>
...
</merge>
One more thing:
I know, the screenshots are from the eclipse designer, but believe me: they look like this on android phone as well.
You should explicitly set the android:orientation tag for your layouts(and any LinearLayout, ever). Android supposedly uses horizontal by default, but in my experience it just messes it up if it's not set, and leads to some very strange-looking layouts.
Related
I've done this before with no issue so i know my mistake is subtle.
picker_dialog_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|center_horizontal"
android:id="#+id/pickerDialog_title"
android:text="HELLO WORLD!!"/>
<NumberPicker
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/pickerDialog_title"
android:id="#+id/pickerDialog_selector"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/pickerDialog_selector"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="5"
android:id="#+id/pickerDialog_cancel"
android:gravity="center"
android:text="Cancel"/>
<Button
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="5"
android:id="#+id/pickerDialog_set"
android:gravity="center"
android:text="Set"/>
</LinearLayout>
</merge>
During the Custom Class constructor, PickerDialog(Context context, AttributeSet attrs, int defStyle) i call:
LayoutInflater.from(context).inflate(R.layout.picker_dialog_layout, this);
And in the parent XML:
<com.company.simonaddicott.controlpanel_1.PickerDialog
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/pickerDialog" />
The view itself does show, and from using layout bound tools in developer tools i can identify that the ui elements are present, or at least the boundaries are present (see below)
What am i missing from this to make there UI elements appear like they should??
My mistake was that I extended the custom view by LinearLayout, but was using RelativeLayout positioning on the picker_dialog_layout.xml.
The elements inside the layout were not showing as they had no relative parent element to be positioned against
I need to have like several listviews on a scrollview which Android doesn't allow me to do so I decided to make it manually to simply inflate some listrows on a vertical LinearLayout, but everything goes not the right way
private void fillData(final ViewGroup parent, final ArrayList<Person> array ){
for (int i=0;i<array.size();i++){
final View view = lf.inflate(R.layout.personal_listrow, parent,true);
parent.setBackgroundColor(getActivity().getResources().getColor(R.color.background_light_darker));
view.setBackgroundColor(getActivity().getResources().getColor(R.color.background_night_lighter));
TextView tvName=(TextView) view.findViewById(R.id.tvName);
TextView tvStatus=(TextView) view.findViewById(R.id.tvStatus);
TextView tvGender=(TextView) view.findViewById(R.id.tvGender);
//fill textviews with info, set the onClickListeners and so on
}
So what I get - the view.setBackgroundColor paints parent as well .
parent is a vertical LinearLayout, view is horizontal LinearLayout - it's strange that I don't paint inflated element only so please explain me why
The next thing - after I add something to array - 1st element changes and all the rest is with unchanged text. However, I walked through the code with debugger - it passes every element and sets text.
The clicklisteners works on the 1st element only..
Would you plz explain
here's vertical , parent layout - nothing special:
<LinearLayout
android:id="#+id/rodll"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
the inflateable listrow is nothing special also :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="#+id/tvStatus"
android:layout_width="0dp"
android:layout_weight=".3"
android:maxLines="1"
android:layout_height="wrap_content"
android:text="tvSt" />
<TextView
android:id="#+id/tvName"
android:layout_weight="1"
android:layout_width="0dp"
android:maxLines="1"
android:layout_height="wrap_content"
android:text="tvName" />
<TextView
android:id="#+id/tvGender"
android:layout_weight=".1"
android:layout_width="0dp"
android:maxLines="1"
android:layout_height="wrap_content"
android:text="tvGender" />
<com.andexert.library.RippleView
android:id="#+id/removeRipple"
xmlns:ripple="http://schemas.android.com/apk/res-auto"
android:layout_marginLeft="30dp"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginRight="7.5dip"
android:padding="3dp"
ripple:rv_alpha="255"
ripple:rv_zoom="true"
ripple:rv_zoomScale="0.8"
ripple:rv_type="rectangle">
<ImageView
android:id="#+id/remove_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/remove" />
</com.andexert.library.RippleView>
<com.andexert.library.RippleView
android:id="#+id/addRipple"
xmlns:ripple="http://schemas.android.com/apk/res-auto"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginRight="7.5dip"
android:padding="3dp"
ripple:rv_alpha="255"
ripple:rv_zoom="true"
ripple:rv_zoomScale="0.8"
ripple:rv_type="rectangle">
<ImageView
android:id="#+id/add_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/add" />
</com.andexert.library.RippleView>
</LinearLayout>
So. what's the problem and how to solve it?
I have a custom view that uses a layout to inflate the subviews inside of it.
When this view is created and inflated, the view hierarchy has two plus n views:
MyCustomView -> RelativeLayout -> {subview1, subview2,…}
Is there any way to eliminate the RelativeLayout node?
Related class:
class MyCustomView extends RelativeLayout {
...
public void start(Context context) {
final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.view_custom, this);
}
...
}
Related XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#232323">
<TextView
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/view_video"
android:paddingTop="#dimen/activity_vertical_margin_medium"
android:paddingBottom="#dimen/activity_vertical_margin_slim"
android:paddingRight="#dimen/activity_vertical_margin_medium"
android:gravity="left"
android:text="#string/video_title"
android:textSize="#dimen/text_size_largest"
android:textColor="#color/text_login_gray"
android:textAllCaps="true"
android:background="#232323" />
<TextView
android:id="#+id/tv_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/tv_title"
android:layout_alignLeft="#+id/tv_title"
android:paddingBottom="#dimen/activity_vertical_margin_medium"
android:paddingRight="#dimen/activity_vertical_margin_medium"
android:gravity="left"
android:text="#string/video_desc"
android:textSize="#dimen/text_size_small"
android:textColor="#color/text_very_light_gray"
android:background="#232323" />
</RelativeLayout>
The correct way to do this is with the merge tag.
This has the added benefit of removing non-sense attributes on the root node.
In some circumstances, this will create visual errors in "Preview".
At this time I am unaware of any fix for that.
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/view_video"
android:paddingTop="#dimen/activity_vertical_margin_medium"
android:paddingBottom="#dimen/activity_vertical_margin_slim"
android:paddingRight="#dimen/activity_vertical_margin_medium"
android:gravity="left"
android:text="#string/video_title"
android:textSize="#dimen/text_size_largest"
android:textColor="#color/text_login_gray"
android:textAllCaps="true"
android:background="#232323" />
<TextView
android:id="#+id/tv_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/tv_title"
android:layout_alignLeft="#+id/tv_title"
android:paddingBottom="#dimen/activity_vertical_margin_medium"
android:paddingRight="#dimen/activity_vertical_margin_medium"
android:gravity="left"
android:text="#string/video_desc"
android:textSize="#dimen/text_size_small"
android:textColor="#color/text_very_light_gray"
android:background="#232323" />
</merge>
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 have a custom ListActivity in which i have a custom ListAdapter that inflates a layout for each item in the list. In eclipse, in the visual editor the layout looks like this
This is made by the following code:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/largeFrame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:id="#+id/RelativeLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="1dp"
android:layout_marginRight="3dp"
android:layout_marginTop="5dp"
android:background="#color/mainBack"
android:orientation="vertical" >
<View
android:id="#+id/imageView1"
android:layout_width="5dp"
android:layout_height="fill_parent"
android:layout_alignParentLeft="false"
android:layout_alignParentTop="false"
android:layout_marginLeft="2dp"
android:background="#android:color/darker_gray" />
<TextView
android:id="#+id/newtimeslot_class"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="4dp"
android:layout_marginTop="10dp"
android:layout_toRightOf="#+id/imageView1"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#android:color/black" />
<View
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="2dp"
android:layout_alignRight="#+id/newtimeslot_class"
android:layout_below="#+id/newtimeslot_class"
android:layout_toRightOf="#+id/imageView1"
android:background="#android:color/darker_gray" />
<TextView
android:id="#+id/newtimeslot_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/newtimeslot_class"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#646464" />
<TextView
android:id="#+id/newtimeslot_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#+id/imageView2"
android:layout_marginRight="5dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#646464" />
<TextView
android:id="#+id/newtimeslot_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_below="#+id/newtimeslot_location"
android:layout_marginBottom="10dp"
android:layout_marginRight="5dp"
android:layout_marginTop="2dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#646464" />
</RelativeLayout>
</FrameLayout>
Unfortunately though, when i run this on an android device, the line to the left completely disappears. It instead looks like
I have just done the usual in terms on inflating it, and i only ever access the TextView objects. So i'm just wondering what could possibly be going on and if someone could help me out of this mess?
Cheers
Edit: The inflation code
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final View view = mInflater.inflate(R.layout.timeslotlayout_new, parent, false);
return view;
}
I suspect the reference #android:color/darker_gray to be the problem.
It might be that on some devices, this value does not exist ?!? (it may be under another name for instance)
Try setting the background attribute to a COLOR value (instead of an android color reference) like this #00000 which represents black (or choose another custom color like this #A9A9A9 for DarkGray ) :
android:background="#A9A9A9"
/OR/
Create an XML file for most basic colors like done HERE, in this manner you are sure that the colors will not change among devices, and most of all, that they will exist on all devices for your application.
So if you do so (see the link), you can create a color like this (the name of the XML file does not matter at all) :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="Black">#000000</color>
<color name="DarkGray">#A9A9A9</color>
</resources>
And reference it in the following way :
android:background="#color/DarkGray"
Note :
No matter if this solved your issue or not, I strongly advise you to follow this manner to be on the safe side.
Maybe you're missing to set this:
android:layout_alignParentLeft="false"
to this:
android:layout_alignParentLeft="true"
And, by the way, android:orientation="vertical" doesn't apply to a relative layout. It applies only to LinearLayout.
And to the newtimeslot_time TextView change the
android:layout_toRightOf="#+id/imageView1"
to
android:layout_toRightOf="#id/imageView1"
Hope it helps!
Cheers!