I am using the following layout and want to add textviews one below another dynamically(depending on the data I want to display)
main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/contain"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</LinearLayout>
</ScrollView>
So I tried this
public class Feeds extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent=getIntent();
Bundle b=intent.getExtras();
String s= b.getString("datapack");
Log.w("String",s);
String data[]=s.split("#");
String temp="";
LinearLayout l=(LinearLayout)findViewById(R.id.contain);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
(LayoutParams.WRAP_CONTENT), (LayoutParams.WRAP_CONTENT));
RelativeLayout relative = new RelativeLayout(getApplicationContext());
relative.setLayoutParams(lp);
for(int i=1;i<data.length;i++)
{Log.w("i data",data[i]);
temp=temp + data[i] + ",";
Log.w("tag",temp);
if(i%5==0)
{Log.w("data",temp);
TextView tv = new TextView(getApplicationContext());
tv.setLayoutParams(lp);
tv.setId(i);
tv.setText(temp);
relative.addView(tv, lp);
temp=null;
}
}
l.addView(relative);
}
}
I am using Scrollview for the first time so that is crating a bit of problem but the main problem is that the textviews in the relative layout overlap one another.How can I specify the gap between each view??
If you're adding views into a RelativeLayout you have to set where the view will be placed, different than LinearLayout that you only need to add the views inside there.
Trye to change to this
LinearLayout layout= new LinearLayout (getApplicationContext());
layout.setLayoutParams(lp);
And here you go a little tip. Do not do this
if(i%5==0)
{Log.w("data",temp);
try to do this
if(i%5==0){
Log.w("data",temp);
it's better to read and understand
I don't see where you are defining the positions for each textview, ie layout_below, layout_toLeftOf... If no positions are defined the relative layout stacks each view in the upper left corner.
Addition
It seems digulino and I agree. I would like to add that you should be able to get the layout scheme you want with only a RelativeLayout inside a ScrollView, maybe a HorizontalScrollView too if you want horizontal scrolling with fling gesture support.
Related
In my Project , I have 80 TextViews.
I should set their text from 1 to 80 once project runs , and they dont need to be changed in future.
Except TxtViews , I have some other things in my Layout, the TextViews are under ImagesViews. actually I have 80 imagesViews and under them are 80 TextViews. I want to set text of textViews from 1 to 80 dynamically.
I know I can do it in my layout.xml ,
but its really time consuming.
is there any way to do that by code?
for example with a for cycle or something like that?
Create a ViewGroup suitable for your needs in the layout, for example:
<LinearLayout
android:id="#+id/linear_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
Then you create you TextView instances programatically, and add them to the LinearLayout, like this:
LinearLayout layout = (LinearLayout)findViewById(R.id.linear_layout);
for(int i = 0; i < 80; i++) {
TextView textView = new TextView(getContext());
textView.setText("text" + i);
layout.addView(textView);
}
Optionally, you can add tags or whatever to locate them again. Alternatively just iterate over the layouts subviews.
If you know that 80 Textview fixed then you should take listview for that.
Listview Benefit
Memory management automatically
Listview manage indexing
If they share the same layout, except for the text, and could be displayed as a list, you could use an ArrayAdapter and pass the values from code.
http://www.mkyong.com/android/android-listview-example/
Checkout the below example,
public class MainActivity extends Activity {
LinearLayout linearLayout ;
ScrollView scrollView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scrollView = (HorizontalScrollView) findViewById(R.id.scrollViewActivityMain);
}
private void populateTextViews() {
linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
//add all textViews here
for(int i=0; i < 80; i++){
TextView myTextView = new TextView(this);
myTextView.setText("My TextView "+i);
myTextView.setGravity(Gravity.CENTER);
linearLayout.addView(myTextView);
}
scrollView.addView(linearLayout);
}
}
Don't forget to put that scrollView in your xml.
Let me know if it works for you...
If your TextViews are declared on the xml, wrap them on another view so you can reference it on the java code later, then simply use a for.
Something like:
View view = findViewById(R.id.your_wrapper);
for(int i=0; i<((ViewGroup)view).getChildCount(); i++) {
View nChild = ((ViewGroup)view).getChildAt(i);
TextView tv = (TextView) nChild;
tv.setText(String.valueOf(i + 1));
}
If not, you can simply create them dynamically inside your java code, and append them to a layout like LinearLayout.
Example:
xml
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/linear"
/>
Java code
LinearLayout ll = (LinearLayout) findViewById(R.id.linear);
for (int i = 1; i <= 80; i++) {
TextView tv = new TextView(this); // Assuming you're inside an Activity.
int count = ll.getChildCount();
tv.setText(String.valueOf(i));
ll.addView(tv, count, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
}
EDIT: But truly, you should use RecyclerView or ListView for that if your values are not going to change.
You can read more about RecyclerView here, and on ListView here.
Second edit: From what you're saying on your comments, you REALLY should be using ListView instead of your current design. The solutions above and from the other answers won't work at all for your problem.
I have been attempting to programmatically add buttons based on a list of values.
PROBLEM: Only one button is produced, rather than a series. This button contains the information of the last value in the array.
I gather an array of values aptly named 'values', I then use a for loop to add the buttons.
Here is the code of my loop to add buttons:
public void updateButtons(List<String> values, View rootView) {
//Find relative layout
RelativeLayout rl = (RelativeLayout) rootView.findViewById(R.id.RelativeLayoutManage);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(50, 10, 50, 10);
for (String mTrip : values) {
//New button
Button Postbtn = new Button(mContext);
//Style
Postbtn.setBackgroundResource(R.drawable.buttonshape);
Postbtn.setTextColor(getResources().getColor(R.color.DarkGreen));
Postbtn.setTextSize(25);
//set text
Postbtn.setText(mTrip.toString());
//set id
Postbtn.setId(i);
int id_ = Postbtn.getId();
//Add to view
rl.addView(Postbtn, params);
Postbtn = ((Button) rootView.findViewById(id_));
//Add listener
Postbtn.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
Log.v("TripNumber", Integer.toString(i));
//TODO: Change Fragment
}
});
i++;
}
}
And my corresponding layout file if needed:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="#+id/RelativeLayoutManage"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
</RelativeLayout>
Seems that they might be overlapping each other. You need to use a LinearLayout
<LinearLayout android:id="#+id/RelativeLayoutManage"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
/>
You are adding Button to RelativeLayout. In your current code all your buttons are present but one above other. You should make one below/above other to make all buttons visible. Else use a LinearLayout
I solved the problem by positioning each button as it is added to the layout. Simply using:
params.addRule(RelativeLayout.BELOW, Postbtn.getId() - 1);
Postbtn.setLayoutParams(params);
I'm having a difficulty adding buttons dynamically to a ScrollView. The code below is adding the buttons BUT there is no scroller.
If I'm putting the buttons directly in the XML (not dynamically) it's working and I can scroll down/up.
My view:
<ScrollView android:id="#+id/ScrollView01"
android:layout_width="264dp"
android:layout_height="match_parent"
android:fillViewport="true"
>
<LinearLayout
android:id="#+id/buttons"
android:layout_width="264dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:scrollbars="vertical"
>
** HERE THE BUTTONS SHOULD BE ADDED DYNAMICALLY **
</LinearLayout>
</ScrollView>
The code which adding buttons:
// create new button
final Button newbutton = new Button(this);
// set background color
newbutton.setBackgroundColor(Color.GRAY);
// set width and height
newbutton.setWidth(50);
newbutton.setHeight(20);
// set position
newbutton.setY(((float)numOfButton*20)+20);
newbutton.setX(100);
// set text
newbutton.setText(Integer.toString(numOfButton));
// create patameter
final LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
//set listener
android.view.View.OnClickListener buttonListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
// make all the DrawView invisible
for(View view : comments){
view.setVisibility(View.INVISIBLE);
}
// set the chosen comment visible
comments.get(numOfButton).setVisibility(View.VISIBLE);
boardsHandler.setCurrenBoard(numOfButton);
}};
newbutton.setOnClickListener(buttonListener);
// creating a thread to add button
buttons.post(new Runnable() {
#Override
public void run() {
buttons.addView(newbutton, p);
}
});
Is it something with the LinearLayout.LayoutParams p ?
Thanks!
Try following code
first do
LinearLayout myContainer = findViewById(R.id.layoutId);
When you set parameters for a view, they need to correspond to the parent view for your widget.
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.FILL_PARENT);
finally add button as you are doing.
try and tell if it works
Setting X and Y position will not work. The LinearLayout layouts it's children vertically or horizontally, only taking their width/height into account.
Besides this -- have you tried calling buttons.invalidate() after buttons.addView(...). This should refresh the layout and should show your newbutton.
This is a rather old post but I found it quickly when doing research on that kind of problem. So I'll post am answer anyway, maybe it'll be of help to anyone..
I had a similar problem with a relative layout to which buttons were added dynamically. I found a workaround in defining the layout's size manually when adding the buttons. For your case, adding the line
buttons.getLayoutParams().height = numOfButton*20+40;
after
buttons.addView(newbutton, p);
might help, though it's probably not the best solution.
I thought my mistake was using the RelativeLayout at all, but since you appear to have the same problem...
Ever thought of using a table layout?
I want to nest a TableLayout inside a RelativeLayout and later dynamically edit the TableLayout in my Java Code.
My XML-File looks like this:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_load_date"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoadDateActivity" >
<!-- few buttons and textviews -->
<TableLayout
android:id="#+id/activity_load_date_table_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/button" >
</TableLayout>
</RelativeLayout>
Java Code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_load_date);
//Do something with my Buttons and TextViews(this works fine)
tblLayout = (TableLayout) findViewById(R.id.activity_load_date_table_layout);
}
#Override
public void onClick(View v) {
if (v.getId() == R.id.button_calc) {
for (int i = 0; i < listOfEntries.size(); i++) {
Entry temp = listOfEntries.get(i);
if (temp.getDate().getTime() >= startDate.getTime()
&& temp.getDate().getTime() <= endDate.getTime()) {
TableRow tr = new TableRow(this);
TextView comm = new TextView(this);
comm.setText(listOfEntries.get(i).getComment());
TextView val = new TextView(this);
val.setText(String.valueOf(listOfEntries.get(i).getValue()));
LayoutParams params = new LayoutParams(0,
LayoutParams.WRAP_CONTENT, 1f);
tr.setLayoutParams(params);
tr.addView(comm);
tr.addView(val);
tblLayout.addView(tr);
}
}
tblLayout.invalidate(); //Shouldn't this redraw the entire TableLayout and therefore adding my TableRows? This is not working.
}
}
Through various tests with TextViews and Toasts I have gathered that the tblLayout should be filled and the TableRows are added to the Layout, the only thing that is not working is the "repainting" of my Layout. How do I achieve that?
Edit:
Apparently the thing that made this not work was actually the LayoutParams given to the TableRow, once I commented those out I atleast got it printed to the screen. They are however not where I expect them to be.
I expected them to be below the buttons, instead they are in the top left corner on top of the buttons. This leads me to believe that the TableLayout is actually the same size as the RelativeLayout but is layered above the RelativeLayout. The error should therefor lie in my XML-File. What height do I need to give my TableLayout to make this work the way I expect?
Edit2:
I needed to add the android:layout_below attribute to my TableLayout, works as a charm now!
You need to call the method "requestLayout()"
Call this when something has changed which has invalidated the layout of this view. This will schedule a layout pass of the view tree.
Im posting from my phone so please excuse stupid typos and formatting issues.
I have an activity which lists saved games that the player can load.
I created a simple layout xml file which defines a ScrollView. On load, I grab all the saved games and programatically add a view for each saved game to a vertically oriented LinearLayout child of the ScrollView.
The view for each game consists of a Horizontally oriented LinearLayout which in turn contains a Button and a vertically oriented LinearLayout. That LinearLayout in turn contains some TextViews and ImageViews (and one more LinearLayout which I'm ommitting here for the sake of clarity).
The hierarchy looks something like this (some details omitted).
ScrollView
LinearLayout - vertical
Each saved game:
LinearLayout - horizontal
Button - load game
LinearLayout - vertical
TextView - game name
TextView - date string
My problem:
I would like the top of the button and the "game name" texview to be vertically aligned but the TextView (or maybe it's LinearLayout parent) has some rogue padding on top that I can't get rid of. See screenshot for details.
LoadSaved class:
Note: mScrollView is badly named. It refers to the ScrollView's child LinearLayout.
public class LoadSaved extends Activity {
public LinearLayout mScrollView;
private MinerDb mDb;
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.loadsaved);
mDb = new MinerDb(this);
mScrollView = (LinearLayout) findViewById(R.id.load_scroll_view);
Bundle[] savedGames = mDb.getSavedGames();
for (int i = 0; i < savedGames.length; i++) {
Bundle game = savedGames[i];
final int gameId = game.getInt("gameId");
String name = game.getString("name");
String date = game.getString("date");
Bundle player = game.getBundle("player");
int playerMoney = player.getInt("money");
int playerHealth = player.getInt("health");
LinearLayout gameContainer = new LinearLayout(getApplicationContext());
gameContainer.setPadding(5, 5, 5, 5);
gameContainer.setGravity(Gravity.TOP);
gameContainer.setOrientation(LinearLayout.HORIZONTAL);
gameContainer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
Button loadButton = new Button(getApplicationContext());
loadButton.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
loadButton.setText("Load");
LinearLayout gameInfo = new LinearLayout(getApplicationContext());
gameInfo.setOrientation(LinearLayout.VERTICAL);
gameInfo.setPadding(10,0,10,10);
gameInfo.setGravity(Gravity.TOP);
gameInfo.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
TextView nameView = new TextView(getApplicationContext());
nameView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
nameView.setGravity(Gravity.TOP);
nameView.setText(name);
TextView dateView = new TextView(getApplicationContext());
dateView.setPadding(5,0,0,0);
dateView.setGravity(Gravity.TOP);
dateView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
dateView.setText(date);
LinearLayout playerView = new LinearLayout(getApplicationContext());
playerView.setOrientation(LinearLayout.HORIZONTAL);
playerView.setPadding(5,0,0,0);
playerView.setGravity(Gravity.TOP);
playerView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
TextView playerMoneyView = new TextView(getApplicationContext());
playerMoneyView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
playerMoneyView.setPadding(0,0,10,0);
playerMoneyView.setTextColor(Color.GREEN);
playerMoneyView.setText("$" + playerMoney);
TextView playerHealthView = new TextView(getApplicationContext());
playerHealthView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
playerHealthView.setPadding(0,0,10,0);
playerHealthView.setTextColor(Color.RED);
playerHealthView.setText(playerHealth + "%");
playerView.addView(playerMoneyView);
playerView.addView(playerHealthView);
gameInfo.addView(nameView);
gameInfo.addView(dateView);
gameInfo.addView(playerView);
gameContainer.addView(loadButton);
gameContainer.addView(gameInfo);
mScrollView.addView(gameContainer);
loadButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Log.e("LoadSaved", "LoadSaved::onCreate: Clicking: " + gameId);
Intent loadGameIntent = new Intent(LoadSaved.this, Miner.class);
loadGameIntent.putExtra("load_game", gameId);
startActivity(loadGameIntent);
finish();
}
});
}
}
}
loadsaved.xml
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/load_scroll_view" />
</ScrollView>
</LinearLayout>
If you want any kind of alignment, why don't you use a RelativeLayout? That's basically designed to align one view with another. android:layout_alignTop sounds like something you want.
(And, of course, verify that the padding values are the same in all controls, but I'm sure you did that.)
Why don't you try using a ListView for that kind of gui.
You will still need to define a row xml.
+1 to the answers suggesting ListView and RelativeLayout. For this type of situation you probably want a ListView with an item layout using RelativeLayout. (ListView will scale much better if there are many items, and if this is for a list of saved games it seems like this could grow quite a bit.) For this type of UI it's recommended to have the whole row/list item clickable rather than use a small Load button, but that's a design issue and ultimately up to you.
Don't use getApplicationContext for creating your views. Activity is a Context, just pass this in your case.
By default LinearLayouts try to align child views by their text baseline if present. Note that the bottom of your button's Load text aligns perfectly with the CURRENT_GAME text in your screenshot. Try gameContainer.setBaselineAligned(false).
Normally your gameInfo layout would only report the baseline of one of its children if you set a baselineAlignedChildIndex, but it looks like this behavior changed between cupcake and eclair when creating LinearLayouts programmatically. (Link to the commit that changed it in AOSP here.)