I'm developing for Android API v11. There is a large RelativeLayout area (like a canvas) that should be filled with a number of buttons, programmatically. Each button represents a video, and I've extended the android.widget.Button class with my VideoViewButton.
Here's what I'm doing now in the main activity:
private void addButtonForVideo(int videoId) {
Log.d(TAG, "Adding button for video " + videoId);
VideoButtonView button = new VideoButtonView(this, videoId);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.layout_napping);
layout.addView(button, params);
mVideoButtons.add(button);
}
Here, mVideoButtons just contains all buttons so I can reference them later.
The buttons themselves are however placed at the top left of the RelativeLayout, one over the other. What I need to do is place each button to the right of the previous one, so they fill up the screen.
I've tried this, where I check if the video ID is not 0 (meaning, a button already exists). I then get the ID of the previously placed button and say that I want the next button to be placed right of that previous one:
private void addButtonForVideo(int videoId) {
Log.d(TAG, "Adding button for video " + videoId);
VideoButtonView button = new VideoButtonView(this, videoId);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.layout_napping);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
// align to right of previous button
if (videoId != 0) {
VideoButtonView previousButton = mVideoButtons.get(videoId - 1);
params.addRule(RelativeLayout.RIGHT_OF, previousButton.getId());
}
layout.addView(button, params);
mVideoButtons.add(button);
}
However, it's not working — the buttons are still placed on top of each other. How can I get them to show next to the previous one instead?
You need to call setId with the videoId in the constructor of the VideoButtonView for this to work.
Make sure that setId contains a positive number, so for example if videoIds start with 0, use:
public VideoButtonView(Context context, int videoId) {
super(context);
this.setId(videoId + 1);
// other code to set layout
}
I suggest not using the Relative Layout for placing object programmatically. Use Linear Layouts instead and organize the content using LinearLayout.LayoutParams
To do this with LinearLayout, just make sure you set the orientation to HORIZONTAL
private void addButtonForVideo(int videoId) {
Log.d(TAG, "Adding button for video " + videoId);
VideoButtonView button = new VideoButtonView(this, videoId);
LinearLayout layout = (LinearLayout) findViewById(R.id.layout_napping);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCHPARENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
);
LinearLayout buttonWrapper = new LinearLayout();
buttonWrapper.setLayoutParams(params);
buttonWrapper.setOrientation(LinearLayout.HORIZONTAL);
// align to right of previous button
if (videoId != 0) {
VideoButtonView previousButton = mVideoButtons.get(videoId - 1);
}
buttonWrapper.addView(button);
layout.addView(buttonWrapper);
mVideoButtons.add(button);
}
Just remember to place the first button in the ButtonWrapper before placing the second in there.
With a linear layout, the next child will either appear below, or next to the previous child depending on the direction and the orientation given for the layout. here, each button will sit next to each other and the wrapper will extend the full length of the layout it sits in.
Best of luck!
Related
There are some Textview,I need to add them in RelativeLayout dynamically. How can I add them without overlap with previous ? thx :D
public class CusRelativeLayout extends RelativeLayout {
private String TAG = "CusRelativeLayout";
...
public void add(String s){
final int childCount = getChildCount();
final TextView tv = new TextView(context);
tv.setText(s);
tv.setTextColor(getResources().getColor(R.color.black));
LayoutParams params = (LayoutParams) generateDefaultLayoutParams();
int[] xy = getRandomXY();
if(childCount == 0){
//no view
params.setMargins(xy[0],xy[1],0,0);
}else{
//what shoud I do???
}
addView(tv,params);
}
...
}
It looks like this:
result
when I add the first tag, I just need to get random X and Y,and new a textview.I use the method setMargins(x,y,0,0) to adding in the RelativeLayout.
But when I add the second tag , I can use getTop(),getLeft(),getHeight(),getiWidth() to getting the previous position and range.And use getRandomXY() to getting random X and Y for the second.But I can't get the range of the second to determine whether the second overlaps with the first
I tried to do this
final TextView tv = new TextView(context);
tv.setText(s);
tv.setTextColor(getResources().getColor(R.color.black));
tv.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT));
tv.post(new Runnable() {
#Override
public void run() {
Log.e(TAG,"height:" + tv.getHeight());
Log.e(TAG,"width:" + tv.getWidth());
}
});
but the value is 0
If I just determine by X and Y , It will be this case.determine by X and Y
I just want to get the range of the new tag before adding to the RelativeLayout ,so I can determine whether it will overlap with the previous.
if I can determine all the tag position before add in Relativelayout?(I know the exact number of tag)
RelativeLayout is made to allow views to overlap each other. You could use a LinearLayout.
If you for some reason need to stick to RelativeLayout, then you have to place your new View with some layout parameters relative to previously added children
params.addRule(RelativeLayout.BELOW, R.id.below_id);
instead of R.id.below_id you could use your own ids that you have set on other children
Take a look here
Programatically add view one below other in relative layout
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.
I have a piece of code which I use to create a new LinearLayout. Within the layout I wish to add a TextView which contains both a label and a value. Then next to it on the right I want to display the button. I want the button to be located toward the end of the screen, without stretching the button. I am happy with the button width and height as WARP_CONTENT.
How can I achieve this in code? I have barely any XML so using XML is not an option. I am trying to make the app as dynamic as possible, so I decided to steer clear of XML.
Please see the code below:
// Build a button
final Button addButton = new Button(task.getParent());
addButton.setText("Add New");
addButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
// Open a file picker here to let the user pick a file
}
});
// Build a new layout to hold all the elements
LinearLayout verticalLayout = new LinearLayout(task.getParent());
verticalLayout.setOrientation(LinearLayout.HORIZONTAL);
verticalLayout.addView(sizeTextView);
verticalLayout.addView(addButton);
Thank you guys in advance.
Try this: Add Space (View) between TextView & Button.
// View space = new View(parent_context);
View space = new View(task.getParent());
// Width:0dp, Height:1 & Weight: 1.0
LinearLayout.LayoutParams spaceLP = new LinearLayout.LayoutParams(0, 1, 1.0f);
space.setLayoutParams(spaceLP);
verticalLayout.addView(sizeTextView);
verticalLayout.addView(space);
verticalLayout.addView(addButton);
Add textview with size and gravity,like this:
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
params.setLayoutDirection(Gravity.RIGHT|Gravity.CENTER_VERTICAL);
verticalLayout.addView(sizeTextView,params);
To achieve this you should use Relative layout and RelativeLayout.LayoutParams. By using LayoutParams you can set the rule to align your views as per your requirements.
for example
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)button.getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
params.addRule(RelativeLayout.LEFT_OF, R.id.id_to_be_left_of);
button.setLayoutParams(params);
I'm trying to set up a layout at runtime that alternates from having a button on the left side of the screen on then the right side. I have an arrayList of button strings and it iterates through, creating a button for each and then applying some styling. Almost all the styling works, except that the margins I'm using to push them to the side of the screen aren't alternating correctly. I'm trying to make the margin push either from the left or the right, but it seems like the buttons are staying within only one column.
Here's the code first of all:
LayoutParams noteStyle = new LayoutParams((int) getResources().getDimension(R.dimen.sticky_note_height),
(int) getResources().getDimension(R.dimen.sticky_note_width));
int margin = (int) getResources().getDimension(R.dimen.margin_huge);
layout = (LinearLayout) findViewById(R.id.note_layout);
int i = 0;
for (String note : notes){
Button btnTag;
if (i % 2 == 0){
btnTag = (Button) getLayoutInflater().inflate(R.layout.sticky_note_right, null);
noteStyle.setMargins(margin,0,0,0);
} else {
btnTag = (Button) getLayoutInflater().inflate(R.layout.sticky_note_left, null);
noteStyle.setMargins(0,0,margin,0);
}
btnTag.setLayoutParams(noteStyle);
btnTag.setText(note);
btnTag.setId(i);
layout.addView(btnTag);
((Button) findViewById(i)).setOnClickListener(this);
i++;
}
And here's a screenshot of how it comes out:
For some reason unknown to me, reusing the LayoutParams can cause goofy results. Instantiating them each time they are needed can help resolve this.
This means putting them inside the for loop, in this situation
for (String note : notes) {
LayoutParams noteStyle = new LayoutParams((int) getResources().getDimension(R.dimen.sticky_note_height),
(int) getResources().getDimension(R.dimen.sticky_note_width));
I'm trying to create Buttons in LinearLayout dynamically, and I want to add those in vertical and horizontal way.
At first, add a button A in the layout, and if there's enough space between button A and screen edge, add button B to the right of button A (horizontally). Otherwise, add button B below button A (vertically).
My current layout :
<LinearLayout
android:id="#+id/btn_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
in class :
LinearLayout btnLayout = (LinearLayout) findViewById(R.id.btn_layout);
btnLayout.removeAllViewsInLayout();
for(Tag tag : tagList.getChildTags()) {
Button button = new Button(this);
button.setId(tag.getId());
button.setText(tag.getName());
btnLayout.addView(button);
}
In this case, if I set orientation as horizontal, then some of buttons are not showing (cut-off by screen), and if I set as vertical, it looks pretty bad.
Is there any way to solve this problem? Thanks everyone in advance!
You can achieve this but not in a trivial way. I'll explain how I do something similar (in my case, I add TextViews) to TableRows, if they fit.
With this approach you'll have to use a TableLayout and add TableRows to it with your Buttons. So you might replace your "#+id/btn_layout" LinearLayout to be a TableLayout instead.
Firstly, to get the screen's width, use something like this:
final Display display = getWindowManager().getDefaultDisplay();
final Point size = new Point();
display.getSize(size);
final WindowManager.LayoutParams params = getWindow().getAttributes();
// Your screen's width will be stored within your params.width value
You'll use this to know if the current Button still fits the screen's width within the current TableRow or it has to be added to a new one. So now, use something like this to create your buttons:
int currentRowsWidth = 0;
TableLayout tl = (TableLayout) findViewById(R.id.my_table_layout);
TableRow currentRow = new TableRow();
for (Tag tag : tagList.getChildTags()) {
Button button = new Button(this);
button.setId(tag.getId());
button.setText(tag.getName());
// There's where you check whether it still fits the current `TableRow` or not
if (currentRowsWidth + button.getWidth() < params.width) {
currentRowsWidth += button.getWidth();
currentRow.addView(button);
}
else {
// It doesn't fit, add the currentRow to the table and start a new one
tl.add(currentRow);
currentRow = new TableRow();
currentRow.addView(button);
currentRowsWidth = button.getWidth();
}
}
It might happen that once you get out of the loop there are still Buttons to add in the currentView, simply test it:
if (currentRow.getChildCound() > 0)
tl.add(currentRow);
I'm writing this from head, so some things might not compile at first time, but I hope you get the idea.