How to inflate a textview xml in my layout? - 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"/>

Related

Centered textview does not appear in RelativeLayout

I have a TextView, which I need to be centered horizontally and vertically inside a square. To do this, I have put it inside a RelativeLayout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#fff"
>
<TextView
android:id="#+id/centered_text_view_text"
android:layout_centerInParent="true"
android:text="test"
android:background="#00ff00"
android:textColor="#000"
android:textSize="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
I instantiate the RelativeLayout with a LayoutInflater and then call the layout method on the RelativeLayout to position it where I need it.
LayoutInflater inflater = Helpers.getInflater();
containerLayout = (RelativeLayout) inflater.inflate(R.layout.centered_text_view, null);
textView = (TextView) containerLayout.findViewById(R.id.centered_text_view_text);
... (later in the code)
containerLayout.layout(dayLeft, weekTop, dayRight, weekBottom);
My problem is that the TextView is not visible. I can see the white background for the RelativeLayout, but neither the text nor the background for the TextView.
I have also tried getting rid of the RelativeLayout and calling the layout method on the TextView. I haven't been able to get this to work, however, because the text is only horizontally, and not vertically, aligned after I set the gravity on the TextView.
First - Custom views should extend some sort of View.class. The class to extend should be whatever your root view is in your xml.
Second - You are keeping a reference to containerLayout (root view) which is redundant. This class is the root view.
Replace containerLayout with this or just removing entirely:
textView = (TextView) findViewById(R.id.centered_text_view_text);
Third - I can't say how you are inflating is wrong, but I have never done it like that.
Instead of calling layout on a containerLayout, try inflating with the inflate() method. (You get access to this when extending a sub class of View)
inflate(getContext(), R.layout.view_user_tag, this);
Notice how I am setting this as the root, and using the inflater from the view class.
Your class may look like something like this:
public static class TextInLinear extends RelativeLayout {
public TextView textView;
//region default constructers
public void TextInLinear(Context context){
this(context, null);
}
public void TextInLinear(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public void TextInLinear(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if(!isInEditMode()) init();
}
//endregion
private void init(){
inflate(getContext(), R.layout.view_user_tag, this);
textView = (TextView) this.findViewById(R.id.centered_text_view_text);
}
/* more methods. i.e. setText(), getText() or whatever */
}

How to Correctly Extend LinearLayout to Create a Custom View

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.

Custom view: how to set the root layout

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.

Alternatives to creating a Compound Control by extending a Layout

I want to create a custom Compound Control in Android that holds some logic. For the purpose of this example, let's say I want it to switch between two views when clicked.
According to the API guide, it looks like the way to do that is to create a new class that extends Layout, and do everything in there.
So I did just that:
I created a XML layout to inflate for my custom component:
.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/view1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="Hello"/>
<TextView
android:id="#+id/view2"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="World"
android:visibility="gone"/>
</RelativeLayout>
Then I created my custom Layout class, and added the logic in there:
public class MyWidget extends RelativeLayout {
public final View mView1;
public final View mView2;
public MyWidget(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout view = (RelativeLayout) inflater.inflate(R.layout.my_widget, this, true);
mView1 = view.findViewById(R.id.view1);
mView2 = view.findViewById(R.id.view2);
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
switchViews();
}
});
}
public void switchViews() {
if (mView1.getVisibility() == View.VISIBLE) {
mView1.setVisibility(View.GONE);
} else {
mView1.setVisibility(View.VISIBLE);
}
if (mView2.getVisibility() == View.VISIBLE) {
mView2.setVisibility(View.GONE);
} else {
mView2.setVisibility(View.VISIBLE);
}
}
}
And finally, I included my custom view in some layout:
.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.MyWidget
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</RelativeLayout
And that works.
I am not completely happy with that solution though, for 2 reasons:
In the constructor of MyWidget, I instantiate 2 nested RelativeLayout by calling the super() constructor, and the one that is at the root of my XML layout. For that, I know I can instead use <merge> as my XML root and that gets me rid of the extra RelativeLayout. Except that defining XML attributes, such as android:background on my <merge> tag doesn't have any effect, so I have to define it programmatically, which is not as nice.
The custom View is a subclass of RelativeLayout, and therefore expose methods it inherits from it, such as addView(), even if it doesn't make sense to add child views to it. I know I can override those methods to prevent users from doing that, but I would still find it cleaner to inherit from View.

Set an XML file as a custom View?

I have a custom Table Row that I am in the process of making. I want to use an XML file to define what a single row looks like. I would like to have a class extend TableRow and define itself to be the file as defined in the XML. The XML file might look like:
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dp"
android:text="#string/loading"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:text="#string/loading"
android:textAppearance="?android:attr/textAppearanceLarge" />
</TableRow>
And the code might look like:
public class SpecialTableRow extends TableRow {
public SpecialTableRow (Context context) {
}
}
Is there something that I can put into the constructor to have the class assume it is the tableRow in it's entirety? Alternatively, is there another structure which would work better? The best that I've figured out is this:
TableRow tr=(TableRow) LayoutInflater.from(context).inflate(R.layout.text_pair,null);
TextView mFieldName=(TextView) tr.findViewById(R.id.label);
TextView mValue=(TextView) tr.findViewById(R.id.data);
tr.removeAllViewsInLayout();
addView(mFieldName);
addView(mValue);
But this removes the layout parameters from the XML. Anything better out there?
Take a look at the tutorial on creating custom views. You will want to subclass TableRow and add the additional views you want to display. Then, you can use your new view directly in your XML layouts and additionally create any custom attributes you might want. I've included an example which creates a custom TableRow named TextPairRow, inflates a layout with two TextViews to show within the TableRow and adds showLabel and showData custom attributes which show/hide the two TextViews. Finally, I've included how you would use your new view directly in your XML layouts.
class TextPairRow extends TableRow {
private TextView label, data;
public TextPairRow (Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.TextPairRow, 0, 0);
try {
showLabel = a.getBoolean(R.styleable.TextPairRow_showLabel, false);
showData = a.getBoolean(R.styleable.TextPairRow_showData, false);
} finally {
a.recycle();
}
initViews();
}
private void initViews(){
// Here you can inflate whatever you want to be in your
// view or add views programatically.
// In this example, we'll just assume you have a basic XML
// layout which defines a LinearLayout with two TextViews.
LinearLayout mLayout = (LinearLayout)
LayoutInflater.from(getContext()).inflate(R.layout.textview_layout, this);
label = (TextView) mLayout.findViewById(R.id.label);
data = (TextView) mLayout.findViewById(R.id.data);
if(showLabel)
label.setVisibility(View.VISIBLE);
else
label.setVisibility(View.GONE); // can also use View.INVISIBLE
// depending on your needs
if(showData){
data.setVisibility(View.VISIBLE);
else
data.setVisibility(View.GONE); // can also use View.INVISIBLE
// depending on your needs
}
}
This is where you define your custom XML attributes (locate or create this file: res/values/attrs.xml)
<resources>
<declare-styleable name="TextPairRow">
<attr name="showText" format="boolean" />
<attr name="showLabel" format="boolean" />
</declare-styleable>
</resources>
Finally, to use your new view directly in your XML layouts:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto">
<com.thefull.packageforyourview.TextPairRow
android:orientation="horizontal"
custom:showData="true"
custom:showLabel="true" />
</LinearLayout>
Note that you might need to use xmlns:custom="http://schemas.android.com/apk/res/com.thefull.packageforyourview" depending on if your custom view will be in a library project. Regardless, either this or what's in the example will work.
The real trick to doing this is actually quite simple. Use the second parameter of the inflate method. In fact, the best thing to do is this:
LayoutInflater.from(context).inflate(R.layout.text_pair,this);
This will inflate the R.layout.text_pair into this, effectively using the entire row. No need to add the view manually, Android takes care of it for you.
The only thing I can think of is to use a static method instead of constructor. For example:
public static void newInstance (Context context) {
this = context.getLayoutInflater().inflate(R.layout.text_pair, null, null);
}
Then don't use constructor for initializing an object, call this method.

Categories

Resources