I am trying to create a custom view (which extends RelativeLayout), which wraps a lot of other views.
I would like to create that child-views in a xml layout file. Now I wonder how I could inflate that layout and use it in my custom view. Something like this would be great (inside my custom view):
RelativeLayout rootLayout = (RelativeLayout) inflater.inflate(my xml file)
this.setContenView(rootLayout);
Unfortunatelly this is only possible in activities. Is there something similar for views?
EDIT:
I don't want to use View.addView(rootLayout) cause that adds another view hierachy, which is not needed.
You could try to use the <merge> tag as the root element in your layout and inflate it in your custom RelativeLayout with this as the parent and attachToRoot set to true. You do not have to call addView then.
Here is a similar example with a LinearLayout (bottom of page), should work with RelativeLayout too.
Use the below
View v =getLayoutInflater().inflate(R.layout.mylayout,null);
// inflate mylayout.xml with other views
CustomRelativeLayout cs = new CustomRelativeLayout(this);
// CustomRelativeLayout is a class that extends RelativeLayout
cs.addView(v); // add the view to relative layout
setContentView(cs); // set the custom relative layout to activity
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_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="111dp"
android:text="TextView" />
</RelativeLayout>
SView
public class SView extends RelativeLayout {
Paint p,paint;
public SView(Context context) {
super(context);
TextView tv = new TextView(context);
tv.setText("hello");
this.addView(tv);
}
}
In MainActivtiy
View v =getLayoutInflater().inflate(R.layout.mylayout,null);
SView cs = new SView(this);
cs.addView(v);
setContentView(cs);
Snap
Edit:
If you wish to inflate in CustomRelative layout
In the constructor
LayoutInflater inflater = LayoutInflater.from(context);
View v =inflater.inflate(R.layout.mylayout,null);
TextView tv = new TextView(context);
tv.setText("hello");
this.addView(tv);
this.addView(v);
Within your view you can get layout inflater from the context, inflate children and add them to this (sub-class of RelativeLayout)
final LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View child = inflater.inflate(R.layout.custom_layout, this, false);
// Then add child to this (subclass of RelativeLayout)
this.addView(child);
Edit:
The code above shows how to inflate children inside a custom view.
This link shows how to insert the custom view itself into XML layout.
Related
I have a TextView inside this layout inflater which i want to customize. What can be the easy way other than implementing getView()
private ViewGroup buildHeader() {
LayoutInflater infalter = getLayoutInflater();
ViewGroup header = (ViewGroup) infalter.inflate(R.layout.listitem_header, getListView(), false);
//TEXT VIEW SET COLOR
header.setEnabled(false);
return(header);
}
What inflater does is inflate the layout you specified to the view hierarchy.
In other words the inflater builds the objects (views) located in the layout specified, so they can be then used.
Once that is done you can find the views located in that layout with findViewById and manipulate them.
So if you have a layout that consists of:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="myTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
You can get and use your TextView like this:
TextView textView = (TextView) header.findViewById(R.id.myTextView);
textView.setText("Something"):
textView.setColor(Color.RED);
I have some "card", which is a simple LinearLayout with a TextView inside
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="#+id/card_label_txt"
android:layout_width="wrap_content"
android:text="label" />
</LinearLayout>
then I have my Main Fragment with a vertical LinearLayout.. and in this main fragment I add this "cards" to the main layout:
# main fragment layout
View view = inflater.inflate(R.layout.main_activity, null);
LinearLayout ll = (LinearLayout) view
.findViewById(R.id.main_activity_ll);
# get card
View card = inflater.inflate(R.layout.card, null);
# add to fragment layout
ll.addView(card);
this works very good AND my card fills the whole width of fragment layout. Actually what I am expecting.
Now I created a separate Class for my Card:
Class Card extends LinearLayout{
public Card(Context context) {
super(context);
View view = LayoutInflater.from(getContext()).inflate(
R.layout.card, null);
this.addView(view);
}
}
And, then if I add my card to the main fragment layout in the way:
# main fragment layout
View view = inflater.inflate(R.layout.main_activity, null);
LinearLayout ll = (LinearLayout) view
.findViewById(R.id.main_activity_ll);
# add new Card to fragment layout
ll.addView(new Card(getActivity());
then it is added BUT the width of the card is no more filled, but wraped to the textview.
Could someone please explain me why I get different width sizes by this two method of adding same layouts?
Solution here is changed Card class that solves this issue:
public Card(Context context) {
super(context);
LayoutInflater.from(getContext()).inflate(
R.layout.card, this);
}
}
That isn't the correct way to implement a custom View class. In your implementation of the Card class, you're actually creating an additional LinearLayout that is not needed.
First, implement your Card class that extends LinearLayout. Then, reference it in your XML layout like such:
<com.mypackagename.Card xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/card_label_txt"
android:layout_width="wrap_content"
android:text="label" />
</com.mypackagename.Card>
Here's a good tutorial on creating custom views in android.
I have created a custom textview class and i am trying to inflate it in my main xml. Here is my code :-
public class CustomTextView extends TextView{
public CustomTextView(Context context) {
super(context);
LayoutInflater li = LayoutInflater.from(context);
TextView view = (TextView) li.inflate(R.layout.customtextview,null);
view.setBackgroundColor(Color.RED);
}
}
customtextview.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:text="sgfiughbjkh"
android:id="#+id/customtext"
android:layout_height="match_parent" >
</TextView>
and in my main activity xml, i have only one linear layout :-
LinearLayout main = (LinearLayout)findViewById(R.id.mainView);
CustomTextView cus = new CustomTextView(this);
main.addView(cus);
I know if i extend it to linear layout instead of textview and add a lienarlayout as parent and in it that textview, it works.
But the problem is that i want to inflate an xml with only a textview and inflate it and the above code is not working.
Please suggest
How do inflate a xml containing only one textview using layout inflator ?
// inflate text view
TextView textView = (TextView) getLayoutInflater().inflate(R.layout.customtextview, null);
// add it to your view
// in your condition, we will add it to Linear Layout
LinearLayout main = (LinearLayout)findViewById(R.id.mainView);
main.addView(textView);
It's old and 2 years later, I ran into the same issue.
You cannot extend from a View and inflate from a layout. The view needs to be wrapped by a ViewGroup . Read Understanding Android's LayoutInflater.inflate()
I came up with 2 solutions , either :
1. in your class CustomTextView , you set programmatically all the properties . Don't inflate anything. Good luck with conversion from resources dimen.xml
2. In your Activity , inflate the Textview
LinearLayout main = (LinearLayout)findViewById(R.id.mainView);
TextView textView = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.customtextview, null);
// you might need as well to set the layout params again
// LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
// textView.setLayoutParams(params);
main.addView(textView);
A bit late but maybe it will help people.
first and like Pratik goyal said you need to declare your CustomTextView and not a TextView
<com.example.CustomTextView
android:id="#+id/customTextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Then in your CustomTextView class you need to had those lines (Constructor):
public FontFitTextView(final Context context) {
super(context);
}
public FontFitTextView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
And last (correct me if i'm wrong people), but you can't inflate a customView into a TextView.
TextView textView = (TextView) getLayoutInflater().inflate(R.layout.customtextview, null);
rather you need to put your R.layout.customTextView into a customTextView
CustomTextView customTxtView = (CustomTextView) getLayoutInflater().inflate(R.layout.customlayout, null);
And now that i'm writing this down i don't think it's possible to inflate only a TextView. If you want to inflate R.layout.customlayout you need to have at least a layout (Linear,Relative etc...) that wrap your customTextView
Something like this
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.yourpakagename.CustomTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/textView"
android:layout_centerInParent="true"
android:includeFontPadding="false"
android:text="13" />
</RelativeLayout>
You can find all of your custom created views under heading "Custom & Library Views" in the Graphical interface of Eclipse.
If your CustomTextView is in the package "com.example" than you can define your custom component as :
<com.example.CustomTextView
android:id="#+id/customTextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
I've a View declared in the XML file, and I want to define it by code, but when I establish it nothing is shown. Can you help me?
This is my XML file:
[...]
<View
android:id="#+id/marco_container"
style="#style/wrapFull"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
[...]
And I define it by this way:
setContentView(R.layout.marco);
View view = (View) findViewById(R.id.marco_container);
view.inflate(getApplicationContext(), R.layout.prueba, null);
I tried to declare it by this way too:
view = View.inflate(getApplicationContext(), R.layout.prueba, null);
This is prueba.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:text="Prueba" style="#style/wrapContent"
android:layout_gravity="center"/>
</FrameLayout>
It's not a View view. It's your custom View, just create a custom view that extends FrameLayout and inside the constructor inflate your view.
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER...);
View view = inflater.inflate(getApplicationContext(), R.layout.prueba, this);
and inside your main xml put :
<com.my.path.CustomView
android:id="#+id/marco_container"
style="#style/wrapFull"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
And in your class :
setContentView(R.layout.marco);
CustomView view = (CustomView) findViewById(R.id.marco_container);
You need to do it this way:
View view2 = view.inflate(this, R.layout.prueba, null);
((ViewGroup)view).addView(view2);
Of course view must be some kind of ViewGroup (RelativeLayout, LinearLayout, etc.)
setContentView(R.layout.marco);
LinearLayout li = (LinearLayout) findViewById(R.id.marco_container);
View view = getLayoutInflater().inflate(R.layout.prueba, li, false);
li.addView(view);
I have a layout for a view -
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="0px"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/items_header"
style="#style/Home.ListHeader" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/items_none"
android:visibility="gone"
style="#style/TextBlock"
android:paddingLeft="6px" />
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/items_list" />
</LinearLayout>
What I want to do, is in my main activity with a layout like this
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="0px"
android:id="#+id/item_wrapper">
</LinearLayout>
I want to loop through my data model and inject multiple views consisting of the first layout into the main layout. I know I can do this by building the controls completely within the code, but I was wondering if there was a way to dynamically build the views so that I can continue using a layout instead of putting everything in code.
Use the LayoutInflater to create a view based on your layout template, and then inject it into the view where you need it.
LayoutInflater vi = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = vi.inflate(R.layout.your_layout, null);
// fill in any details dynamically here
TextView textView = (TextView) v.findViewById(R.id.a_text_view);
textView.setText("your text");
// insert into main view
ViewGroup insertPoint = (ViewGroup) findViewById(R.id.insert_point);
insertPoint.addView(v, 0, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
You may have to adjust the index where you want to insert the view.
Additionally, set the LayoutParams according to how you would like it to fit in the parent view. e.g. with FILL_PARENT, or MATCH_PARENT, etc.
See the LayoutInflater class.
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup parent = (ViewGroup)findViewById(R.id.where_you_want_to_insert);
inflater.inflate(R.layout.the_child_view, parent);
It looks like what you really want a ListView with a custom adapter to inflate the specified layout. Using an ArrayAdapter and the method notifyDataSetChanged() you have full control of the Views generation and rendering.
Take a look at these tutorials
http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/
http://developerlife.com/tutorials/?p=327
http://www.androidguys.com/2008/07/14/fancy-listviews-part-one/
To make #Mark Fisher's answer more clear, the inserted view being inflated should be a xml file under layout folder but without a layout (ViewGroup) like LinearLayout etc. inside. My example:
res/layout/my_view.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/i_am_id"
android:text="my name"
android:textSize="17sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
Then, the insertion point should be a layout like LinearLayout:
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/aaa"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/insert_point"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
</RelativeLayout>
Then the code should be
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shopping_cart);
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.my_view, null);
ViewGroup main = (ViewGroup) findViewById(R.id.insert_point);
main.addView(view, 0);
}
The reason I post this very similar answer is that when I tried to implement Mark's solution, I got stuck on what xml file should I use for insert_point and the child view. I used layout in the child view firstly and it was totally not working, which took me several hours to figure out. So hope my exploration can save others' time.
// Parent layout
LinearLayout parentLayout = (LinearLayout)findViewById(R.id.layout);
// Layout inflater
LayoutInflater layoutInflater = getLayoutInflater();
View view;
for (int i = 1; i < 101; i++){
// Add the text layout to the parent layout
view = layoutInflater.inflate(R.layout.text_layout, parentLayout, false);
// In order to get the view we have to use the new view with text_layout in it
TextView textView = (TextView)view.findViewById(R.id.text);
textView.setText("Row " + i);
// Add the text view to the parent layout
parentLayout.addView(textView);
}