Adding more than one LinearLayout into scrollview using while loop - java

I want to add more than one LinearLayout into my ScrollView, the number of LinearLayout is base on how many data selected from the MySQL database. However, it seems can't add more than one LinearLayout into the ScrollView.
The reason is maybe this: The specified child already has a parent. You must call removeView() on the child's parent first. But I am not sure about the real reason. How can I solve this problem? Here is my coding in Android Studio:
String query = "select * from restaurant";
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
LinearLayout data_big_layout, detail_data_layout;
TextView name, type_area, price_txt;
ImageView restaurant_img;
LinearLayout.LayoutParams restaurant_img_params, data_big_params;
while(rs.next()){
data_big_layout = new LinearLayout(this);
data_big_params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
data_big_params.setMargins(0,15,0,0);
data_big_layout.setLayoutParams(data_big_params);
data_big_layout.setOrientation(LinearLayout.HORIZONTAL);
data_big_layout.setWeightSum(20);
data_big_layout.setBackgroundColor(Color.WHITE);
data_big_layout.setTag(rs.getInt(1));
detail_data_layout = new LinearLayout(this);
lparams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT,8.0f);
detail_data_layout.setLayoutParams(lparams);
detail_data_layout.setOrientation(LinearLayout.VERTICAL);
detail_data_layout.setPadding(50,0,0,0);
lparams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
name = new TextView(this);
name.setLayoutParams(lparams);
name.setText(rs.getString(2));
name.setTextSize(24);
name.setTypeface(Typeface.DEFAULT_BOLD);
type_area = new TextView(this);
type_area.setLayoutParams(lparams);
type_area.setText(rs.getString(5)+"/"+rs.getString(6));
type_area.setTextSize(18);
price_txt = new TextView(this);
price_txt.setLayoutParams(lparams);
price_txt.setText(rs.getString(7));
price_txt.setTextSize(18);
detail_data_layout.addView(name);
detail_data_layout.addView(type_area);
detail_data_layout.addView(price_txt);
data_big_layout.addView(detail_data_layout);
restaurant_img = new ImageView(this);
restaurant_img_params = new LinearLayout.LayoutParams(200,
300,12.0f);
restaurant_img.setImageResource(R.drawable.test_restaurant);
restaurant_img.setPadding(0,0,50,0);
data_big_layout.addView(restaurant_img, restaurant_img_params);
Toast.makeText(getBaseContext(),"ID: "+rs.getInt(1), Toast.LENGTH_LONG).show();
data_scroll_view.addView(data_big_layout); //Cannot add data_big_layout in the next loop
z = "Search successful";
}
isSuccess = true;
stmt.close();
rs.close();
con.close();
The code data_scroll_view.addView(data_big_layout); only can run in the first time of the while loop. I selected two rows of data but the output in programme only can show one LinearLayout. How can I solve it? Thanks all.

scroll view can only contain one child
Scroll view may have only one direct child placed within it. Google doc
therefore, inside your loop, you should gather your views into a single vertical LinearLayout then add it to the ScrollView outside of the loop.

Referring to https://developer.android.com/reference/android/widget/ScrollView
ScrollView is "A view group that allows the view hierarchy placed
within it to be scrolled. Scroll view may have only one direct child
placed within it.
To add multiple views within the scroll view, make the direct child you add a view group, for example LinearLayout, and place additional views within that LinearLayout".
So instead of trying to add LinearLayouts to the ScrollView, put one LinearLayout as the ScrollView's child and add any views/layouts to that LinearLayout.

Related

Cannot add a RelativeLayout to a RelativeLayout programmatically

So I'm trying to add a RelativeLayout to a RelativeLayout however, when I run my app, it's an IllegalStateException that shows this error: The specified child already has a parent. You must call removeView() on the child's parent first. I'm sure you guys have seen this before. My question is how do I properly nest two relative layouts together?
Here is the code snippet that produces the exception:
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
RelativeLayout newFrame = new RelativeLayout(vidRipperService.getBaseContext());
newFrame.setLayoutParams(layoutParams);
// configure image view constraints...
// have the frame be right in the center of the layout.
ImageView editedFrame = new ImageView(vidRipperService.getBaseContext());
// Note: when doing padding the height and the width must be a multiple of two. A nice example is 70+30 = 100/2 = 50, but 80+30 = 110/2 = 55 <- not a multiple of two. Keep this in mind.
editedFrame.setId(View.generateViewId());
editedFrame.setPadding(30,30,30,0); // padding of 30 around the whole view.
editedFrame.setImageBitmap(frame); // set the frame to be that of the actual background.
RelativeLayout.LayoutParams frameLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
frameLayoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL); // place frames in center of the view.
editedFrame.setLayoutParams(frameLayoutParams);
newFrame.addView(breakingNewsLayout); // add the breaking news layout to this view!
newFrame.addView(editedFrame);
The problem is specifically triggered from the second to last line newFrame.addView(breakingNewsLayout) That line triggers the exception. The breakingNewsLayout is another relative layout that I would like to add to newFrame. I would appreciate any knowledge on how to get this to work. I never ran into a problem when nesting layouts before, but for some reason, this is really not playing nice.
Here is the code that creates the breakingNewsLayout:
private void createBreakingNewsLayout()
{
breakingNewsLayout = new RelativeLayout(vidRipperService.getBaseContext()); // create the new breaking new layout.
breakingNewsLayout.setElevation(5);
breakingNewsLayout.setPadding(0,0,0,15);
breakingNewsLayout.setBackgroundColor(ContextCompat.getColor(vidRipperService, R.color.transparent)); // ensure that the background is transparent.
// MATCH_PARENT for both width and height so that banner is shown on the frame for the video.
RelativeLayout.LayoutParams breakingNewsParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
breakingNewsParams.setMargins(0,50,0,0); // todo: ensure that the margin is 50dp not pixels!
breakingNewsParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
breakingNewsLayout.setLayoutParams(breakingNewsParams); // set the layout params for the breaking news layout.
// set all of the text view attributes.
TextView liveBannerText = getLiveBannerText();
TextView breakingNewsTime = getBreakingNewsTime();
TextView breakingNewsHeadline = getBreakingNewsHeadline(breakingNewsTime.getId()); // headline goes about the breaking news time.
TextView breakingNewsBanner = getBreakingNewsBanner(breakingNewsHeadline.getId()); // banner goes above the breaking news headline
TextView viddyWatermarkText = getViddyWatermarkText(breakingNewsHeadline.getId()); // viddy watermark goes above the breaking news headline.
TextView breakingNewsDescription = getBreakingNewsDescription(breakingNewsTime.getId()); // breaking news description goes to the end of the breaking news time
// Add all of the views for the breaking news layout.
breakingNewsLayout.addView(liveBannerText);
breakingNewsLayout.addView(breakingNewsBanner);
breakingNewsLayout.addView(viddyWatermarkText);
breakingNewsLayout.addView(breakingNewsHeadline);
breakingNewsLayout.addView(breakingNewsTime);
breakingNewsLayout.addView(breakingNewsDescription);
}
maybe you should remove breakingNewsLayout before you add it:
((ViewGroup) breakingNewsLayout.getParent()).removeView(breakingNewsLayout);
I figured it out! After extensive researching and testing the reason I was getting this issue was because I was attempting to reuse the breakingNewsLayout when creating a new frame. I have x amount of frames and I needed to generate the breakingNewsLayout every single time I wanted to apply the layout to the frame. Since I was trying to reuse the layout that I have already added, the layout already has a parent and thus the exception above was called.
Apologies for the question and any lack of details.

Runtime added View does not know it's location

I am adding a View to a RelativeLayout at runtime, which is working fine, but now I would like to display a TextView just to left of this View but I am unable to retrieve the Top or Left of this View in order to calculate the TextView's position.
The code I have is
private void displayGuitar() {
for (GuitarString guitarString: guitar.getGuitarStrings()) {
GuitarStringView guitarStringView = new GuitarStringView(context, attributeSet, guitarString);
this.addView(guitarStringView);
// Add Note name
TextView noteNameView = new TextView(context);
RelativeLayout.LayoutParams noteParams =
new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
noteParams.addRule(LEFT_OF, guitarStringView.getId());
Log.w("string top", String.valueOf(guitarStringView.getTop()));
Log.w("string left", String.valueOf(guitarStringView.getLeft()));
noteParams.setMargins(0, 0, 2, 0);
noteNameView.setLayoutParams(noteParams);
noteNameView.setText(guitarString.getTunedNote().getNoteName(0));
this.addView(noteNameView);
}
}
This results in the TextViews all appearing on top of each other (in the correct X position) but I can't set the Top margin as both of the Log statements return 0. How can I determine what the Top position of the GuitarStringView is?
EDIT
Following advice from laalto I have now generated ID for the guitarStringView and confirmed it's being assigned. However, if I use LEFT_OF, RIGHT_OF etc the TextViews are not displayed, but if I use ALIGN_PARENT_RIGHT they're displayed fine? Code is now as follows
private void displayGuitar() {
for (GuitarString guitarString: guitar.getGuitarStrings()) {
GuitarStringView guitarStringView = new GuitarStringView(context, attributeSet, guitarString);
int viewId = guitarStringView.generateViewId();
guitarStringView.setId(viewId);
this.addView(guitarStringView);
// Add Note name
TextView noteNameView = new TextView(context);
RelativeLayout.LayoutParams noteParams =
new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
noteParams.addRule(RelativeLayout.LEFT_OF, viewId);
noteNameView.setLayoutParams(noteParams);
noteNameView.setText(guitarString.getTunedNote().getNoteName(0));
this.addView(noteNameView);
}
}
EDIT 2
The accepted fix didn't work at first as I hadn't override the onMeasure() of my GuitarStringView which according to the documentation defaults to 100x100.
First, your guitarStringView doesn't have an id and getId() will return -1, that is, NO_ID. The LEFT_OF rule therefore doesn't work as it doesn't refer to any actual id. To fix that, just set some id to the view.
Second, the view has not been measured nor laid out yet so that's why size and position come out as zeros.
using addRule with any of LEFT_OF, RIGHT_OF or BELOW the TextView is no longer displayed at all
Possibly the string view is already taking up all horizontal space. Add another constraint such as ALIGN_PARENT_LEFT to make the text view left edge align with parent relative layout's left edge.
You said "at runtime", which means you're potentially invoking this method in onCreate, or onResume. These methods should start behaving as expected in onWindowFocusChanged(boolean).
See this other question:
getRight, getLeft, getTop returning zero

Move view dynamically in relativelayout

I am doing an pageindex, and the current page should be highlighted with a arrow image (imageview).
The index is a RelativeLayout with 25 textviews added to it:
for (int i = 0; i < 25; i++) {
TextView tv = new TextView(this);
tv.setText(Integer.toString(i+1));
tv.setGravity(Gravity.CENTER);
int id = 2000+i;
tv.setId(id);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.FILL_PARENT);
if(i==0)
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
else
params.addRule(RelativeLayout.RIGHT_OF, prevViewId);
prevViewId = id;
rl.addView(tv,params);
}
And when the page changes I do something like this:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_BOTTOM, 2000+i);
params.addRule(RelativeLayout.ALIGN_RIGHT, 2000+i);
params.addRule(RelativeLayout.ALIGN_LEFT, 2000+i);
arrowImageView.setLayoutParams(params);
rl.requestLayout();
rl.invalidate();
Everything looks correct, I can place the arrow at arbitrary page at "start up", but the arrow wont move when page is changed. I have debuged and verified that the code is run and everything looks correct, but still the arrow is stuck in the first position. If I force delete and add a new imageview instead of updating the LayoutParams the arrow will disappear totally.
I have the same problem.. I also want to move my views around at run-time inside a reference layout. So if anyone ca help that would be awesome.
What i believe is happening above is that the arrow IS having its location changed, however it doesn't get updated to the screen. Correct me if I'm wrong, please, this is just my guess as I am too having the same problem.
-edit-
After some messing around I've found what works for me is to remove first then add.
rl.removeView(tv);
rl.addView(tv,params);
-edit-
also, u can save the params for the moving view into a unique variable so that way all ude have to do is change the margins...
for example: instead of params, have it be its own name "arrowParams"
then to move it ude just need: arrowParams.leftMargin = 2000+i; and so on...

"Distribute weights evenly" in code

I have one little problem...Here is my code..Is there a way to "distribute weights evenly" for those buttons what I made.. I tried to button[i].setWidth().. but when I turn around my phone it looks ugly.. so Is there away to distribute buttons width auto?
ViewGroup row1 = (ViewGroup)findViewById(R.id.TableRow02);
ViewGroup row2 = (ViewGroup)findViewById(R.id.TableRow04);
ViewGroup row3 = (ViewGroup)findViewById(R.id.TableRow06);
ViewGroup row4 = (ViewGroup)findViewById(R.id.TableRow08);
ViewGroup row5 = (ViewGroup)findViewById(R.id.TableRow10);
Button button[] = new Button[36];
for(int i=1;i<36;i++)
{
button[i] = new Button(this);
if(i==32||i==33||i==34||i==35){button[i].setVisibility(-1);}
button[i].setText("700€");
button[i].setTextSize(10);
button[i].setWidth(20);
// Insert buttons in rows
if(i<8){row1.addView(button[i]);}
else if(i<15){row2.addView(button[i]);}
else if(i<22){row3.addView(button[i]);}
else if(i<29){row4.addView(button[i]);}
else if(i<36){row5.addView(button[i]);}
}
Tactically, put the buttons in a LinearLayout and set android:layout_weight="1" for each of them.
Strategically, design a decent UI, one that does not involve a row of 36 buttons.
As CommonsWare said, instead of setting the width, you should consider to set the weight parameter of the buttons in order to achieve a flexible layout.
If you want to achieve this programmatically (i.e. in code and not in the XML layout), you can use the button's setLayoutParams method. I haven't tested it, but something like this should work:
// outside of loop
LayoutParams p = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT,
1.0
);
....
// enter loop
....
button[i].setLayoutParams(p);
In this example, 1.0 represents the weight. The other two parameters represent layout_width and layout_height parameter.
But seriously, I can't imagine that a layout with 36 buttons is very user friendly :-)

Android Development: How To Get All EditText Children of a ViewGroup?

Basically, I have a LinearLayout that holds a random amount of horizontal LinearLayouts, and in each of the horizontal LinearLayouts there's a TextView and an EditText. I want to be able to get the value of each EditText children of the master LinearLayout.
Sorry if it's confusing, I'm no good at explaining things!
Could I just set the same ID for each of the EditTexts then use findViewById, or would that only return the first instance of an EditText?
Thanks,
Alex.
LinearLayout ll = //Your Layout this can be any Linear or Relative layout
//in which you added your spinners at runtime ;
int count = ll.getChildCount();
for(int i =0;i<count;i++)
{
View v = ll.getChildAt(i);
if(v instanceof Spinner)
{
// you got the spinner
EditText s = (EditText) v;
Log.i("Item selected",s.getText().toString());
}
}
findViewById returns only the first view with the given id. You're going to have to traverse the view hierarchy yourself, at least until you get down to each horizontal linear layout. You'll find the methods ViewGroup.getChildCount() and ViewGroup.getChildAt(int) useful for this.
You would need to call findViewById on each of the LinearLayouts. If you do this, you can set the same ID for each EditText.

Categories