I have an app that queries a database and get a recordset, on the display, I need to present these data with a row that is a complex layout. Each row contains some ImageView, many TextView etc...
It's really difficult to create the row layout programmatically, is there any way to get the entire row layout (container and children of the row layout) from an xml, edit some of the properties (like the TextViews of the row layout) and add the result to a LinearLayout?
is there any way to get the entire row layout (container and childs of the row layout) from an xml
What you are looking for is how to inflate a view (LayoutInflator)
Now that you have the right term, it should be easy to find examples, inflate is popular in ListView tutorials. For an example, take a look at at getView() in this tutorial for an example:
HowTo: ListView, Adapter, getView and different list items’ layouts in one ListView
http://android.amberfog.com/?p=296
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
...
convertView = mInflater.inflate(R.layout.item1, null);
... edit some of the properties (like the TextViews of the row layout) ...
Once you inflate the view, you can search for the widgets within it, so you can manipulate it.
holder.textView = (TextView) convertView.findViewById(R.id.text);
If your view is fairly complex and/or you will often be looking for widgets within it, I want to point out the ViewHolder technique, shown in the example referenced, relevant bits below:
// Data structure to save lookups
public static class ViewHolder {
public TextView textView;
}
...
// Save lookups to widgets for this view in ViewHolder in tag
ViewHolder holder = new ViewHolder();
holder.textView = (TextView) convertView.findViewById(R.id.text);
view.setTag(holder);
...
// Grab saved widgets - no need to search tree for them via lookup again
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.textView.setText(mData.get(position));
... and add the result to a LinearLayout?
Presumably, you're already programatically adding to the LinearLayout, but if you want to see some code, here's an example that shows setting some layout parameters:
Android LinearLayout
http://developerlife.com/tutorials/?p=312
// main "enclosing" linearlayout container - mainPanel
final LinearLayout mainPanel = new LinearLayout(ctx);
{
mainPanel.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
mainPanel.setOrientation(LinearLayout.VERTICAL);
...
}
...
// top panel
LinearLayout topPanel = new LinearLayout(ctx);
{
// WEIGHT = 1f, GRAVITY = center
topPanel.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT,
1));
...
}
...
// bottom panel
LinearLayout bottomPanel = new LinearLayout(ctx);
{
LayoutUtils.Layout.WidthFill_HeightWrap.applyLinearLayoutParams(bottomPanel);
...
}
...
// add the panels
mainPanel.addView(topPanel);
mainPanel.addView(bottomPanel);
...
Lastly, you can do alot (including custom rows) with the AdapterView / Adapter paradigm, e.g. using ListView with a SimpleCursorAdapter. It may save you some code by looking into it. Some babbling about it here:
Android ListView with different layouts for each row
As a rule of thumb, whenever you create an instance of View using code, think twice.
Review LayoutInflater on how to create layout from resources. In your special case, you might also want to check ResourceCursorAdapter if you want to show multiple rows in a ListView.
What kind of table are you using? If your layout would be something like this:
<TableLayout>
<LinearLayout android:id="#+id/linearLayoutTest">
<TextView/>
<TextView ....
<ImageView ....
</LinearLayout>
<LinearLayout ....
</TableLayout>
It would be easy to access the row container through the id and then find by position the desirable child:
LinearLayout linearLayout = (LinearLayout)this.findViewById(R.id.linearLayoutTest);
TextView textView = (TextView)linearLayout.getChildAt(0);
textView.setText("New Text");
Related
I am trying to create a textview in Android for each element in a list. How can I dynamically generate a textview for each element in the list?
I have tried using a for loop to iterate through the list and create a new textview for each element, but I am having trouble implementing this. Any help would be greatly appreciated.
You will normally use a RecycleView for this, but in certain scenarios you will add list manually.
You can simply create the TextView and add the properties to it, it is important that you include the LayoutParams so that the view can be rendered.
val food = listOf("apple", "pie", "banana", "cookie")
val linearLayout = findViewById<LinearLayout>(R.id.myList)
food.forEach {
TextView(this).apply {
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
text = it
linearLayout.addView(this)
}
}
keep in mind that LayoutParams needs to be the nested class of the respective ViewGroup, so if the parent is a LinearLayout, you should use LinearLayout.LayoutParams
If it is not a TextView but a view that you defined in your own XML layout (res/layout/my_custom_row.xml) you can use binding for it:
MyCustomRowBinding.inflate(layoutInflater, containerLayout, true).apply {
nameTextView.text = item.name
}
you don't need to use viewGroup.addView() because inflater already adds the view when last parameter is true.
I have inflated one layout in my Activity now in that Activity I have some common fields for multiple times, so I have created one more layout with those common fields and included in my layout.And I got inflated all those fields.But now My problem is that While I am inserting data in those fields only first included fields gets inserted with data not the second, third, and so on... So how to get data inserted in such fields with common ids..
LayoutInflater inflater = LayoutInflater.from(getContext());
View w4FragmentRowView = inflater.inflate(R.layout.weekly_report4_row_item, null);
etWhere = (EditText)w4FragmentRowView.findViewById(R.id.et_weekly_reports_where_w4_tab);
etHowSubStd = (EditText)w4FragmentRowView.findViewById(R.id.et_weekly_reports_how_sub_std_w4_tab);
Now I have to insert data multiple times in same activity with these edit Text fields.
Say you have two views and they have common ids and you inflate them
Like shown below
now for common ids when you are doing find view by id make sure
the point to right parent
//look at item and item2 as while finding view
LinearLayout item = (LinearLayout) mLayoutInflater.inflate(
R.layout.layout1, null);
TextView skunitNameTextView = (TextView) item.findViewById(R.id.textView);
LinearLayout item2 = (LinearLayout) mLayoutInflater.inflate(
R.layout.layout1, null);
TextView skunitNameTextView2 = (TextView) item2.findViewById(R.id.textView);
i think this should solve your problem
Take example you have a layout file with name "reuse.xml" where you have only one view TextView with id "txv".
Now in your Activity you are inserting this layout file multiple times like:-
TextView tv1 = (TextView) mLayoutInflater.inflate(
R.layout.reuse, null);
tv1.setId(R.id.txv_activity_1);
TextView tv2 = (TextView) mLayoutInflater.inflate(
R.layout.reuse, null);
tv2.setId(R.id.txv_activity_2);
TextView tv3 = (TextView) mLayoutInflater.inflate(
R.layout.reuse, null);
tv3.setId(R.id.txv_activity_3);
Now you are using the same layout file but they gave different id so you can easily update any of file which one you want.
But if you are using the same layout more than 3-4 times it is recommended to use it as ListView or RecyclerView item, which also provide you better performance in case of large layout and easy to maintain.
I have a custom layout xml which i use as a template for creating items in a list dynamically. However I can't seem to change the text and color of elements within this custom layout properly before I add it to the main layout. I need to do this as each item in the list can be different.
If I have added more than one of these custom layouts to the main layout any changes I make to the TextView object always happen on the first item in the list.
My custom layout has a textview and a check box within a relative layout in a file called 'cat_panel.xml'.
My coding to produce the layout is:
LinearLayout rootEl = (LinearLayout) findViewById(R.id.pageWrapper);
LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
View vw;
vw=inflater.inflate(R.layout.cat_panel, rootEl, false);
catTitleTv = (TextView) findViewById(R.id.catPanelTitle);
catTitleTv.setText("testing 1");
rootEl.addView(vw);
//the above is then repeated
vw=inflater.inflate(R.layout.cat_panel, rootEl, false);
catTitleTv = (TextView) findViewById(R.id.catPanelTitle);
catTitleTv.setText("testing 2");
rootEl.addView(vw);
Thanks in advance
Change
catTitleTv = (TextView) findViewById(R.id.catPanelTitle);
to
catTitleTv = (TextView) vw.findViewById(R.id.catPanelTitle);
I am currently populating an Adapter on startup with views inflated from XML using
private void addView(Context context) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.deal_tile, this, null);
mViews.add(view);
}
However, I've found that storing the views in a list inside the AdapterView creates problems with controls within those views, so I want to change over to use the recycling functions in Adapter#getView(int position, View recycle, ViewGroup container).
For this reason I want to use a custom view class so I can do a sanity check (if(recycle!=null && recycle instanceof CustomView)) before I repopulate it in the adapter. However, I can't find out how you inflate a custom view class from XML. I can find out how you add an inflated view to a custom view, I can find out how you insert a custom view into an XML layout, etc, and obviously I am quite happily inflating these things directly using LayoutInflater, but I can't find an equivalent for generating the custom view itself. I want to reuse the XML I already have; consequently I don't want to program in the elements (and how they look) directly.
I used this to create my own slide gallery, i think it would help.
LinearLayout internalWrapper = new LinearLayout(getContext());
internalWrapper.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
internalWrapper.setOrientation(LinearLayout.HORIZONTAL);
addView(internalWrapper);
this.mItems = items;
LinearLayout generalLayout = new LinearLayout(this.getContext());
generalLayout = (LinearLayout) View.inflate(this.getContext(), R.layout.galleryrow, null);
// inside linear layout
LinearLayout generalLinear = (LinearLayout) generalLayout.findViewById(R.id.rowgenerallin);
// set height & width to the LINEAR
generalLinear.setLayoutParams(new LayoutParams(reference_width, reference_height));
ImageView ivl = (ImageView) generalLayout.findViewById(R.id.arrow_left);
ImageView ivr = (ImageView) generalLayout.findViewById(R.id.arrow_right);
internalWrapper.addView(generalLayout);
In my case, R.layout.gallery_row contains the two images I want to manage, nested by a LinearLayous (rowgenerllin), the internal wrapper is an empty LinearLayout declared in the main layout of your activity.
Double check the LayoutParams code or you will get a big NULL :)
Cheers!
I'm trying to implement a ListView on my app, but i'm trying to understand and learn how to achieve it without using XML files, all with java code.
I'm stuck on the inflater part, the mInflater.inflate(); function needs a resource xml file, so, i didn't understand how to continue without using XML files
I have a ArrayList of strings, and I simply need a ListView that shows a list with these strings of the Arraylist, and a delete Button on the right of the String. If the user press the Button, the item of the List get's deleted.
Each item of the ListView has two things, a TextView with the String of the ArrayList and a Button to delete it.
If someone can give me code examples i will be grateful.
Thanks
I totally agree with CommonsWare. But the part that you are stuck is the part that you have to create a row "template" for the ListView rows. The inflater is used so as to make a single View out of a complete layout.xml file. So the basic idea is that you create an xml that represents each row and then inflate it through that piece of code.
In your situation, you need to do that through code. Perhaps add a LinearLayout as a parent with orientation=vertical add some width or height properties and then add 2 TextViews so as to be a title and a subtitle with some additional properties. Then you should add them to the LinearLayout and you there you go.
Your LinearLayout is a pile of Views that are dynamically created and have the same effect as inflating all the above code through an xml file.
But I reaaaaally don't see the point in creating such a fuss over a much faster, easier, straight forwarded, better implemented and not to mention best practice...
EDIT: Somewhere inside your adapter you have: mInflater.inflate(); with the resource that you mention. As I previously said the resource determines how the "template" for each row would be. So a normal xml file that will determine a list row would be something like this:
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content" android:orientation="vertical" >
<TextView ... /> <! --some properties you want to set -->
<TextView ... /> <! --some properties you want to set -->
</LinearLayout>
This xml produces a 2 line list row for a ListView. With the layout inflater the above xml file returns a View object that contains all the bundle.
So if you want to create it from code, then the snippet would be:
LinearLayout layout = new LinearLayout(context);
//layout set some properties
TextView title = new TextView(context);
//title set some properties
TextView subtitle = new TextView(context);
//subtitle set some properties
layout.add(title);
layout.add(subtitle);
Now instead of inflating the xml to get the contents into a single View object, you have the layout variable in the code snippet that contains all the logic that was previously inflated through the xml.
If you have created a custom ListView adapter before then you should be familiar with creating a custom list row and how it works.
EDIT: sample code for the adapter of the ListView
this is the standart procedure of getView() method of the adapter by inflating a single layout:
#Override
public View getView(int position, View view, ViewGroup viewgroup) {
ViewHolder holder; //our view holder of the row
if (view == null) {
view = context.getLayoutInflater().inflate(R.layout.static_layout, null);
holder = new ViewHolder();
//set the views of the holder
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
//rest of implementation of the View
return view;
}
dynamic implementation:
#Override
public View getView(int position, View view, ViewGroup viewgroup) {
ViewHolder holder; //our view holder of the row
if (view == null) {
LinearLayout layout = new LinearLayout(context);
//layout set some properties
TextView title = new TextView(context);
//title set some properties
TextView subtitle = new TextView(context);
//subtitle set some properties
layout.add(title);
layout.add(subtitle);
//CREATING THE LAYOUT THROUGH CODE
view = layout; //INSTEAD OF INFLATING A LAYOUT FOR THE ROW I JUST BINDED IT TO THE RECENTLY CREATED LAYOUT
holder = new ViewHolder();
//bind the views of the holder to the views of the layout
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
//rest of implementation of the View
return view;
}