Confusion with findViewById() - android

I am trying to programmatically add LinearLayouts inside an existing RelativeLayout. Each LinearLayout will contain some buttons and I want to be able to toggle the visibility of each set of buttons by setting the visibility of the container LinearLayout.
// We iterate over a list and call the following to create the new
// layout assigning an index from a int counter
LinearLayout LL = new LinearLayout(MainActivity.this);
LL.setOrientation(LinearLayout.VERTICAL);
LL.setId(nextId);
LinearLayout.LayoutParams LLParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
LL.setWeightSum(6f);
LL.setLayoutParams(LLParams);
LinearLayout mll=((LinearLayout) findViewById(R.id.menuLayout));
mll.addView(LL);
My problem comes when I try to retrieve these layouts later, for instance to be able to toggle their visibility on/off. I thought I would be able to use
LinearLayout ll = (LinearLayout) findViewById(layoutIndex);
But findViewById() gives me an error when I try to supply an int, it wants a resource ID. Is there an easy way I can convert the ints that I have assigned as the Ids for these layouts to R.id.XXX ids?
Thanks,
Andy

findViewById(id) looks up elements that were included as part of the XML defining a layout.
You will probably have better luck with getChildAt(index), which returns the View at the passed index.

Yes! Find all LinearLayout in a container without using ID.
LinearLayout mll= (LinearLayout) findViewById(R.id.menuLayout);//container
for(int i=0; i<mll.getChildCount(); ++i) {
View nextChild = mll.getChildAt(i);
if (nextChild instanceof LinearLayout ) {
//TODO add your code here nextChild is a LL that you wanna find
}
}

Related

Add UI elements dynamically in android

I want to add some ui elements to my android app, a Button for example!
But I can't find a complete tutorial! I found this code after a lot of searches:
LinearLayout ll = (LinearLayout)findViewById(R.id.layout);
Button btn = new Button(this);
btn.setText("Manual Add");
btn.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
ll.addView(btn);
My first problem is first line! Can you explain it for me please? What is R.id.layout? I know R is an object for resources but I don't know what is layout!
Second problem is line 3, What is LayoutParams?
Thank you all!
You can create views using default constructors for example
Button button = new Button(context);
After that you should determine to which type of parent view you are going to attach it, and create corresponding layot params. Every parent view LayoutParams type has uniqe customize methods, for example rules of RelativeLayout.LayoutParams.
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height)
//customize params here
button.setLayoutParams(params)
Attach view to your parent view
frameLayout.addView(button)
That is it.
LinearLayout ll = (LinearLayout)findViewById(R.id.layout);// you are getting a refrence to your layout
Button btn = new Button(this); // creating a new object of button type
btn.setText("Manual Add"); //setting the button text
btn.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT)); //setting the width and height of the element
ll.addView(btn);//adding the button to your layout
R.id.layout is the name of your activity layout
It is the parent view which you are going to add your views. In your example it is a LinearLayout called layout.

how to i manage textviews inside linear layout orientation horizontal

Code :
LinearLayout linearLayout2;
final JSONArray answer=jsonObject1.getJSONArray("answer");
//Here get Answer from question
((ViewGroup) findViewById(R.id.linearLayout2)).removeView(linearLayout2); //Here remove preselected radiobuttons
linearLayout2 = new LinearLayout(TestActivity2.this); //Here create new viewgroup when user click next and previous
linearLayout2.setOrientation(LinearLayout.HORIZONTAL);
linearLayout2.setGravity(Gravity.FILL_HORIZONTAL);
indexAns=new String[answer.length()];
for(int j=0;j<answer.length();j++)
{
final JSONObject jsonObject2 = answer.getJSONObject(j);
final String answer_ans=jsonObject2.getString("answer_ans"); //get answer from loop
answer_id=jsonObject2.getString("answer_id");
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
//Here create radio buttons depending on answer loop
final TextView textBtn = new TextView(TestActivity2.this);
textBtn.setId(Integer.parseInt(answer_id));
textBtn.setLayoutParams(params);
textBtn.setAllCaps(true);
textBtn.setTextSize(12);
textBtn.setPadding(5,5,5,5);
textBtn.setGravity(Gravity.LEFT | Gravity.CENTER |Gravity.RIGHT);
textBtn.setTextColor(Color.parseColor("#000000"));
indexAns[j]=answer_id;
You may want to post your layout xml files. Looks like you are manipulating the layout programatically, which, in most cases in unnecessary. You can accomplish the same goal via xml layout files.
Also, you can save a lot of time using styles for formatting.
Check out the following layout documentation
https://developer.android.com/guide/topics/ui/declaring-layout.html
Check out the TextView documentation:
https://developer.android.com/reference/android/widget/TextView.html

How to set position of view while using addView

I'm adding multiple Views by code into Layout. I need each new View to be above previous one(top of the parent layout).
EDIT: To be more accurate I'll describe what the app module should does. User start with clean screen and one button at the bottom of the screen. The button adds a View at the top of the screen. Next clicks should add next views above previous ones to make the newest View be on the top of a container. The app saves state and on restart user see views in the same order.
Call the following method from Button's onClick Event.
private final int LAYOUT_TOP_INDEX = 0;
private void addViewOnTop(View view){
if(layout != null && view !=null)
layout.addView(view, LAYOUT_TOP_INDEX);
}
where 'layout' is your Layout (e.g., LinearLayout) to which the View is to be added.
Would really need more information from you to give a more accurate answer, but if you're saying what i think you are then you can just add these views to a LinearLayout with orientation set to vertical.
And assuming you're iterating through a list to dynamically add views, instead of incrementing from 0, increment down from the size of the list.
for(int i = size; i >= 0; i--){
linearLayout.add(new TextView(Context));
}
View positions inside ViewGroups are defined by the LayoutParams
How does this happen? Views pass their LayoutParams to their parent ViewGroups
//100% programatic approach with simple LayoutParams
LinearLayout myLinearLayout = new LinearLayout(this);
//if the **parent** of the new linear layout is a FrameLayout
FrameLayout.LayoutParams layoutParams =
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
//or if you have the XML file you don't have to worry about this
//myLinearLayout = (LinearLayout)findViewById(R.id.my_simple_linear_layout);
//you could have a LinkedList<TextView>
LinkedList<TextView> textViewList = new LinkedList<>();
//assuming the order is the correct order to be displayed
Iterator<TextView> descendingIterator = textViewList.descendingIterator();
while(descendingIterator.hasNext())
{
//just add each TextView programatically to the ViewGroup
TextView tView = descendingIterator.next();
myLinearLayout.addView(tView);
}
Just like we defined LayoutParams for the LinearLayout we could also define LayoutParams for the TextView
IMPORTANT: when setting LayoutParams you need to be sure they fit the VIEWGROUP, that is the parent of the View being added
private TextView textViewFactory(String myText) {
TextView tView = new TextView(getBaseContext());
//controling the position relatively to the PARENT
//because you are adding the textview to a LINEAR LAYOUT
LinearLayout.LayoutParams paramsExample =
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f);
tView.setLayoutParams(paramsExample);
//configuring the insides of the textview
//you can also do all kinds of stuff programatically
tView.setGravity(Gravity.CENTER_HORIZONTAL);
tView.setPadding(10, 10, 10, 10);
tView.setTypeface(Typeface.DEFAULT_BOLD);// (null, Typeface.BOLD_ITALIC);
tView.setTypeface(Typeface.SANS_SERIF);
tView.setTypeface(null, Typeface.ITALIC);
tView.setTypeface(Typeface.defaultFromStyle(R.style.AppTheme));
tView.setId(R.id.aux_info);
tView.setText(myText);
//.........all kinds of stuff really
return tView;
}
If you mean adding a view programmatically so that the new one is added above the previous one, instead of below it, then I suggest this:
Maintain an ArrayList with the items you want to turn into views
Put them into a ListView
When you want to add a new view that must appear at the top of the list, insert it as the first element of your ArrayList and recreate the ListView from it.

Adding views dynamically in a for loop results in haphazard positioning - Android

I am adding views dynamically to a relative layout (let's say container) in a for loop. There is some thing strange I am noticing. When adding rows one below the other in a relative layout in a for loop, I see that the first time a few of the views are overlapping. But when I lock and unlock the screen, I can see that the views are placed correctly.
Should I be aware of something when adding views dynamically to a relative layout?
Edit
I have found a solution as to how to get rid of this (please check my answer). But I would be more than glad to accept an answer that analyses this problem and tells me why this happens.
I have simplified to code and the comments should give a good idea as to what I am doing.
int prev_id=ID_OF_THE_ELEMENT_ABOVE;
/*Empty RelativeView with width and height as MATCH_PARENT and WRAP_CONTENT respectively*/
RelativeLayout container=(RelativeLayout) findViewById(R.id.container);
while(ThereIsData){
/*GET THE DATA HERE THAT HAS TO BE ASSIGNED TO EACH TEXTVIEW*/
...
/* ADD TEXTVIEW #1 below prev_id/
...
...
/*ADD TEXTVIEW #2 (WITH BASELINE OF TEXTVIEW#
...
...
/*TEXTVIEW #3 (BELOW TEXTVIEW#1)*/
...
...
/*TEXTVIEW #4 (BELOW TEXTVIEW#2)*/
...
...
/*ASSIGN THE ID OF TEXTVIEW#3 TO prev_id SO THAT
IN THE NEXT ITERATION TEXTVIEW#1 CAN USE prev_id
*/
prev_id=ID(TEXTVIEW#2);
/*ADD TEXTVIEWS CREATED IN THIS ITERATION*/
container.addView(TEXTVIEW#1);
container.addView(TEXTVIEW#2);
container.addView(TEXTVIEW#3);
container.addView(TEXTVIEW#4);
}
It is due to the fact that you are having a RelativeLayout with height as WRAP_CONTENT, and adding a view doesn't refresh the whole container at that time.. so as you answered you can add a line to measure the dimensions explicitly or invalidate the view to recreate it completely.
In any case LinearLayout would be better to opt-for as it will automatically arrange the children in horizontal or vertical manner and you can even add the new view in any place other than last position and it will automatically be updated..
I used to struggle against common issues a year ago, when I was working on a library for dynamically creating layouts from XML files (as Android does not support this). So when you dynamically add views to a RelativeLayout you have to take in mind a few things:
Create the container View (in this case the RelativeLayout)
Create all views without assigning any layout parameters.
Add all child views to the container.
Iterate over the container's children and populate each child's layout parameters. This is needed because when the relational constraints are applied an Excpetion is thrown if the relative View is missing (was not previously added to the container).
This is an example code taken from the project I used to work on. Take in mind that it is just a single part so it contains references to classes that are not defined in the Android API. I am sure it will give you the basic idea of dynamically creating RelativeLayot:
private void setChildren(RelativeLayout layout, T widget,
InflaterContext inflaterContext, Context context,
Factory<Widget, View> factory) {
List<Widget> children = widget.getChildren();
if (Utils.isEmpty(children))) {
return;
}
// 1. create all children
for (Widget child : children) {
View view = factory.create(inflaterContext, context, child);
layout.addView(view);
}
// 2. Set layout parameters. This is done all children are created
// because there are relations between children.
for (Widget child : children) {
try {
View view = ViewIdManager.getInstance().findViewByName(layout, child.getId());
if (view != null) {
populateLayoutParmas(child, view);
}
} catch (IndexNotFoundException e) {
Log.e(LOG_TAG, "Cannot find a related view for " + child.getId(), e);
}
}
}
I have not yet found the answer to why this is happening. But I have found a solution. After adding each row in the loop, call container.measure(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);
This seems to solve the problem. But I really think that container.addView() should also be calling measure().
/*ADD TEXTVIEWS CREATED IN THIS ITERATION*/
container.addView(TEXTVIEW#1);
container.addView(TEXTVIEW#2);
container.addView(TEXTVIEW#3);
container.addView(TEXTVIEW#4);
//---------------------------------------------------------------------
container.measure(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);
//Declare globally
LinearLayout[] layout;
ImageView[] imageView1;
ImageView[] imageView2;
ImageView[] imageView3;
// Initialize your layout. It would be RelativeLayout too. Just reference to it.
LinearLayout ll = (LinearLayout) findViewById(R.id.mylinear);
// set listview row size as your demand
layout = new LinearLayout[200];
imageView1 = new ImageView[200];
imageView2 = new ImageView[200];
imageView3 = new ImageView[200];
for (int i = 0; i < 200; i++) {
layout[i] = new LinearLayout(this);
layout[i].setBackgroundResource(R.drawable.book_shelf);
// layout[i].setLayoutParams(new
// LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.FILL_PARENT,
// 120));
layout[i].setLayoutParams(new LinearLayout.LayoutParams(
android.widget.LinearLayout.LayoutParams.FILL_PARENT, 220));
imageView1[i] = new ImageView(this);
imageView2[i] = new ImageView(this);
imageView3[i] = new ImageView(this);
imageView1[i].setLayoutParams(new LinearLayout.LayoutParams(0, 200,
0.33f));
imageView1[i].setPadding(0, 20, 0, 0);
imageView1[i].setImageResource(R.drawable.bibid_one_bankim);
imageView2[i].setLayoutParams(new LinearLayout.LayoutParams(0, 200,
0.33f));
imageView2[i].setPadding(0, 20, 0, 0);
imageView2[i].setImageResource(R.drawable.bibid_two_bankim);
imageView3[i].setLayoutParams(new LinearLayout.LayoutParams(0, 200,
0.33f));
imageView3[i].setImageResource(R.drawable.dena_pawna);
imageView3[i].setPadding(0, 20, 0, 0);
layout[i].setId(i);
layout[i].setClickable(true);
final int j = i;
layout[i].addView(imageView1[i]);
layout[i].addView(imageView2[i]);
layout[i].addView(imageView3[i]);
ll.addView(layout[i]);
}
}
Try adding your views in vertical Linear Layout.
Following link might help you
http://www.myandroidsolutions.com/2012/06/19/android-layoutinflater-turorial/
Inflate your layout in for loop.

How to create Scrollview programmatically?

I have one table "TABLE_SUBJECT" which contain a number of subjects. I need to create
one horizontal scroll view with Subject.
How do I create a ScrollView with database items programmatically? If I enter 1o subject then it will be appear in scroll view as a button. Is it possible?
you may create it as below:
ScrollView scroll = new ScrollView(context);
scroll.setBackgroundColor(android.R.color.transparent);
scroll.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
scroll.addView(yourTableView);
if you have many elements first you need to wrap-up and add in the Scroll view; for example i need a many text view inside of scrollview, so you need to create ScrollView->LinearLayout->Many textview
ScrollView scrollView = new ScrollView(context);
scrollView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
TextView textView = new TextView(context);
textView.setText("my text");
LinearLayout linearLayout = new LinearLayout(context);
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setGravity(Gravity.RIGHT);
linearLayout.addView(textView);
scrollView.addView(linearLayout);
this may help you.
HorizontalScrollView hsrll = (HorizontalScrollView)findViewById(R.id.hrsll);
b = new Button(this);
for (int i = 0; i < 5; i++) {
b.setWidth(LayoutParams.WRAP_CONTENT);
b.setHeight(LayoutParams.WRAP_CONTENT);
b.setText("b"+i);
b.setId(100+i);
hsrll.addView(b);
}
instead of for loop just modify the code as your need(no of records in db). but this the code for creating buttons in dynamically.
I was doing it like this:
Create xml with LinearLayout inside the ScrollView
Create xml as item in ScrollView
In activity set main content as xml with ScrollView
Loop through all table elements with adding new View to LinearLayout form main view
For me works fine.
In Kotlin you can use the below code
val scroll = ScrollView(context)
scroll.setBackgroundColor(R.color.transparent)
scroll.layoutParams = LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT
)
scroll.addView(yourTableView)

Categories

Resources