This question already has answers here:
Android - Dynamically Add Views into View
(5 answers)
Closed 10 years ago.
I want to add a view comprising of 4 buttons and a textview to a linear layout and set that newly made view to a viewflipper...Client's requirement is that i need to create the layout the programmatically and not using an xml file
See this is sample code, this might helpful for you. Instaed of LockView you can mention other views..
lockLayout = (LinearLayout) findViewById(R.id.quick_lock_layout);
private void renderLockLayout() {
lockLayout.removeAllViews();
lockLayout.invalidate();
lockLayout.setLayoutParams(new LinearLayout.LayoutParams(
lockLayoutWidth + 7, (height / 6)));
/*
* Toast.makeText(ApplicationContext.getContext(), "Num count is :" +
* _totalLocks, Toast.LENGTH_SHORT).show();
*/
Log.i(getClass().getSimpleName(), "Total :" + _totalLocks);
lockViewArray = new LockView[_totalLocks];
for (int index = 0; index < _totalLocks; index++) {
LockView lockview = (LockView) inflater.inflate(R.layout.lockview,
null);
lockview.setLayoutParams(new LayoutParams((width),
LayoutParams.WRAP_CONTENT));
lockLayout.addView(lockview);
lockViewArray[index] = lockview;
}
lockLayout.invalidate();
}
It's recommended to define UI in XMl. But for your client requirement you can do it dynamically. In android, UI in xml and at run time (.java file) are optional each other.
So use java methods to create LinearLayout and add newly created views to it. Finally you can add this LinearLayout to ViewFlipper.
Related
I'm trying to create a function that pulls together information that is currently scattered around different parts of my project.
As part of this task, I have a layout file with something like the following content... basically a set of rows, with each row having a label (TextView) and a UI element (e.g. CheckBox, Spinner or EditText) to collect information from the user:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="#style/MyLinearLayout.Section"
android:id="#+id/section_pressure" >
<TableLayout style="#style/MyTableLayout"
android:id="#+id/table_pressure" >
<TableRow style="#style/MyTableRow" >
<TextView
style="#style/MyTextView.Label.WithHelp"
android:tag="label_show"
android:text="#string/label_show" />
<CheckBox
style="#style/MyCheckBox"
android:id="#+id/pressure" />
</TableRow>
<TableRow style="#style/MyTableRow" >
<TextView
style="#style/MyTextView.Label.WithHelp"
android:tag="label_unit"
android:text="#string/label_unit" />
<Spinner
style="#style/MySpinnerStyle"
android:id="#+id/pressureUnit" />
</TableRow>
</TableLayout>
</LinearLayout>
I already have an array of all the android:id values for the UI elements, and from that I want to generate another array of the corresponding android:text labels.
e.g. from R.id.pressureUnit I want to find the associated R.string.label_unit from that TableRow, so that I have a central record of what label is used for each UI element... currently that information is scattered across lots of different layout files.
Is this possible programmatically?
From what I understand you want to find #string resource ID of a sibling view of a given view.
Assuming you have the xml file already inflated, you can do the following:
private int getSiblingStringId(#IdRes int viewId) {
View uiElement = findViewById(viewId);
ViewGroup parent = (ViewGroup) uiElement.getParent();
// iterate through the siblings
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
if (view instanceof TextView) {
String value = ((TextView) view).getText().toString();
// found
return getStringIdFromValue(value);
}
}
throw new IllegalArgumentException("no TextView sibling for " + viewId);
}
private int getStringIdFromValue(String value) {
// get all fields using reflection
Field[] fields = R.string.class.getDeclaredFields();
for (Field field : fields) {
int stringResId = getResources().getIdentifier(field.getName(), "string", getPackageName());
String s = getString(stringResId);
if (s.equals(value)) return stringResId;
}
throw new IllegalArgumentException("no matching string for " + value);
}
The above code will work inside an activity. You might need to modify it a bit for other classes. (You will need to call findViewById, getResources and getString)
Well, I would set an ID to each table row. Then, programmatically get every child view under each row by iterating over the row's children. From there, you can easily manipulate every view by simply determining which one are you at by using instanceof. But, let's assume you cannot change this, you can still be doing it but it might not be efficient.
Since I don't really know the structure of your array of ids, I just assume its an array of integers called uiIds. Then, you would have to do something like
TableLayout layout = findViewById(R.id.table_pressure);
TableRow tr = null;
View rowChild = null;
TextView tv = null;
View secondaryView = null;
int tableChildCount = layout.getChildCount();
int rowChildCount = 0;
// Since I don't really know the structure of your array of ids,
// I just assume its an array of integers called uiIds
//This will contain the corresponding text strings of every textview
List<String> textLabels = Arrays.asList(new String[uiIds.length]);
// Go over all the rows on your table
for (int i = 0; i < tableChildCount; i++) {
// I'm assuming that you only have rows as the children of your table
tr = (TableRow) layout.getChildAt(i); //This is the row
rowChildCount = tr.getChildCount();
tv = null;
secondaryView = null;
// Now go over all the children of the current row i
for (int j = 0; j < rowChildCount; j++) {
// Here I'm also assuming you only have two children on every row
rowChild = getChildAt(j);
// At this point, the view v could be any type of the ones you have
// used. Since we are interested in TextView simply do an instanceof
if ( rowChild instanceof TextView ) {
tv = (TextView) v;
} else {
// This is the other view in the row. The ones from which you alreade have its ids
// e.g. the spinner with id pressureUnit
secondaryView = rowChild; //We do not need to cast
}
}
// Now we construct the array
if (tv != null && secondaryView != null) {
// The id we just obtained is one from the ones you have already saved
// in an array called uiIds
int secondaryViewId = secondaryView.getId();
//Now, we need to find the index of this id in uiIds
for (int idx = 0; idx < uiIds.length; idx++) {
if ( uiIds[idx] == secondaryViewId ) {
//We have found a match. Then just add the text of the textview in the corresponding index of our new array
textLabels.set(idx,tv.getText().toString());
}
}
}
}
// At this point, textLabels should contain the text of the text view on every row
// such that the ith element in the array you already have corresponds to
// ith element of the array we just created.
// In other words, if uiIds[0] is equals to R.id.pressureUnit, then,
// textLabels.get(0) is equals to R.string.label_unit
I have edited the answer directly on the text editor so it might have some sintax erros. Hopefully this solves your problem or at least gives you an idea.
To get overview of your label mappings, I suggest to code more systematically, in this case to name the label just like the id.
#+id/pressure => #string/label_pressure
#+id/pressureUnit => #string/label_pressureUnit
I know this is not a direct answer to your question. However I think, if you work in this way, you don't need a central table of your mappings at all and your layouts become more readable. Android Studio makes it really easy to do this kind of changes.
I want to create the following view:
For above picture, I declared a vertical radio group in xml, and rows were added at run time. In a single radio button , i want to add two other buttons,as shown in picture,
This code is to add address (radio buttons) to radiogroup.
private void add_to_address_list() {
for (int i = 0; i < addresses_list.size(); i++) {
RadioButton rdbtn = new RadioButton(this);
Log.d("mytag", "id : " + i + "name :" + i);
addresses_list.get(i).getUser_line2());
String line1 = addresses_list.get(i).getUser_line1();
String line2 = addresses_list.get(i).getUser_line2();
String line3 = addresses_list.get(i).getGoogle_line1();
rdbtn.setId(i);
rdbtn.setText(Html.fromHtml("<font color=black size=3em>" +line1+"<br>"+line2+"<br></font>" +"<font color=grey size=3em>"+ line3+"</font><br>"));
((ViewGroup) findViewById(R.id.address_radio_group)).addView(rdbtn);
}
}
How can i add two other buttons, one is for delete the address and another is for edit address, is it possible ? or can i go with simple list view?
if i use listview to display it, is it possible to select one only. i think it may possible with check boxes. suggest any correct method. pleas help me.Thanks.
I am using the reddit API and trying to load the comment tree of a thread. My problem is that I am using a recursive function to do that. I am building a view and then adding it programmatically. And it works for small threads but when it has to load a large comment tree I get stackoverflow.So my main question is: what is a good way to load nested comments programmatically and what is the best practice to go around the stack overflow? I have debated adding a counter for comments added and when they exceed some number I might break the loop, but that still doesn't guarantee me a "stackoverflow" free program. Generally speaking how can I keep track of the stack and the heap? Also as a follow up question: my dynamic view gets destroyed on rotation and I recreate it every time. The problem with that is recreating is slow and it slows the rotation. So is there an easy way to keep/save the view on rotation and add it again (setRetainInstance(true) has no effect on the dynamic view, just on the main layout).
private void addTextTree(JSONObject j, LinearLayout layoutparent) throws JSONException {
JSONObject j2 = j.getJSONObject("data");
JSONArray j3 = j2.getJSONArray("children");
LinearLayout currentparent = layoutparent;
Log.d("ADDINGVIEW", j3.length() + "");
for (int i = 0; i < j3.length(); i++) {
JSONObject j4 = j3.getJSONObject(i);
JSONObject j5 = j4.getJSONObject("data");
addComment(j5, currentparent);
}
}
private void addComment(JSONObject j, LinearLayout parent) throws JSONException {
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
LinearLayout LLHmain = new LinearLayout(getActivity());
LinearLayout LLVsecond = new LinearLayout(getActivity());
LLHmain.setOrientation(LinearLayout.HORIZONTAL);
LLHmain.setLayoutParams(lp);
LLVsecond.setOrientation(LinearLayout.VERTICAL);
LLVsecond.setLayoutParams(lp1);
TextView author = new TextView(getActivity());
TextView content = new TextView(getActivity());
ImageView bar = new ImageView(getActivity());
bar.setBackgroundResource(R.drawable.lines);
LLHmain.addView(bar, lp1);
author.setText(" " + j.optString("author") + " " + j.optInt("score") + " points");
author.setBackgroundResource(R.drawable.border);
String temp = j.optString("body_html");
String temp1 = Html.fromHtml(temp.substring(22, temp.length() - 12)).toString();
content.setText(Html.fromHtml(temp1));
content.setAutoLinkMask(Linkify.WEB_URLS);
content.setMovementMethod(LinkMovementMethod.getInstance());
LLVsecond.addView(author, lp);
LLVsecond.addView(content, lp);
LLHmain.addView(LLVsecond, lp1);
parent.addView(LLHmain, lp);
if (!j.optString("replies").equals("")) {
JSONObject replies = j.getJSONObject("replies");
addTextTree(replies, LLVsecond);
}
}
Summed up:
What is the best way to handle loading trees of textviews and preventing stack overflow.
Keeping track of the stack and the heap
Saving dynamic view on rotation
Disclaimer: I am new to any sort of programming and by no means do I believe this is the best or only way to do it. I am open to any possible solutions regarding my problem.
I'll give the very short version of the answer (because I'm kinda busy at work) but you follow it that you'll get what you want:
The issue is that View are memory heavy objects and shouldn't be allocating that many. What you do to avoid that is using a ListView that can recycle views.
So instead of recursively create and add views you'll create a data class, for example:
public class DataItem{
String author;
String content;
}
then you build an ArrayList<DataItem> and recursively add all the items to this array. Then you use this array in an adapter in the listview.
that way you can have a thread with thousands of items without issue.
I am working on a project that will display math problems to the screen such as:
10 + 5 =
and then the user will need to guess the answer. I am doing this as more of way for me to learn how android ticks.
I have images from 0 to 9 saved in the drawable folder for each of the dpi setting I need to account. I also have the operators (+,-,*,/,=) also saved.
My questions:
How easy is this to do?
How would I go about doing the above dynamically?
Thanks
--EDIT--
The images and operators are stored as .9.png files in my drawable folder. I have string-array contain my problems that I will randomly pull from and then display them to the screen.
In the past I would do the following:
public View buildProblem()
{
LinearLayout rtnView = new LinearLayout(ctx);
rtnView.setOrientation(LinearLayout.HORIZONTAL);
rtnView.setLayoutParams(new GridLayout.LayoutParams());
// Build LeftSide
Iterator<Integer> itor = buildLeftSide();
ImageView iv;
// loop through of iterator
while(itor.hasNext())
{
iv = new ImageView(ctx);
iv.setScaleType(ImageView.ScaleType.FIT_CENTER);
iv.setImageResource(itor.next());
itor.remove();
rtnView.addView(iv);
}
// Space
rtnView.addView(space);
// Operator
rtnView.addView(plusSign);
// Build LeftSide
itor = buildRightSide();
// another loop
while(itor.hasNext())
{
iv = new ImageView(ctx);
iv.setScaleType(ImageView.ScaleType.FIT_CENTER);
iv.setImageResource(itor.next());
itor.remove();
rtnView.addView(iv);
}
// Space
rtnView.addView(space);
// Equal Sign
rtnView.addView(equalSign);
// Space
rtnView.addView(space);
// return the view
return rtnView;
}
I was thinking of using ImageViews for the numbers to be displayed to the screen which I have used in the past but not sure if that is the best way to do it.
https://github.com/barakisbrown/MathTest -- Is one attempt at doing the above but I have now started to rewrite it from scratch so which is why I am asking for help.
I am reading data from a SOAP service and then using that data to load images from the res folder locally. I am using a loop because there will always be six images being loaded. This is my code :
final TableLayout tblLay = (TableLayout)findViewById(R.id.lottotl);
final LayoutParams params = new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
for(int i=2;i<9;i++) {
final ImageView image = new ImageView(LastDraw.this);
image.setLayoutParams(trparams);
image.setMaxHeight(20);
image.setMaxWidth(20);
String imgName = "img_" + split[i].substring(split[i].indexOf("=") + 1);
int id = getResources().getIdentifier(imgName, "drawable", getPackageName());
image.setImageResource(id);
row2.setLayoutParams(params);
row2.addView(image);
}
tblLay.addView(row2);
The issue I am having is that there is a gap between the first image and the consecutive images.
It looks like this (each number representing an image):
1.........23456
I am thinking it has to do with the layout of the row in the tablelayout, I could be wrong.
Thank you
Anyone?
Figured it out ... feel kind of stupid but, I learnt something! I load a textview into the first row and then the imageviews into the second row. The textview is in the first column and its width is making the first column stretch ... THAT is why there is a gap.