I have to create a stack of images programmatically (because they have to be dynamic).
I want to stack ImageViews like this:
I've tried this, but the images all land up on top of each other:
for(int i=0; i<limit; i++){
dynamicButtons[i] = new ImageView(contextSosFragment);
int offsetLeft = 15 * i;
int offsetTop = 15 * i;
layoutParamsDynamicButton.setMargins(offsetLeft, offsetTop, 0, 0);
dynamicButtons[i].setAdjustViewBounds(true);
dynamicButtons[i].setScaleType(ScaleType.FIT_CENTER);
dynamicButtons[i].setImageResource(R.drawable.img_badge_dynamic_loading);
dynamicButtons[i].setTag(id);
containerDynamicButtons.addView(dynamicButtons[i], layoutParamsDynamicButton);
}
I've even removed the android:gravity="center" from my xml layout file.
I've also tried to add the layout params on the ImageView after setting the margins (dynamicButtons[i].setLayoutParams(layoutParamsDynamicButton);), but I read that that this might not take effect, because the layout params are for the parent and not the child of the container to which I add the ImageViews, that's why I tried to use addView(view, layoutParams).
How can I position the ImageViews like this, programmatically?
SOLUTION:
The solution was that I had to create a new layout params instance for each image - just like Devunwired suggested. However, I also found that I had to change the LinearLayout.LayoutParams to be RelativeLayout.LayoutParams. Only then did the change take effect.
The final for loop looks like this:
for(int i=0; i<limit; i++){
RelativeLayout.LayoutParams layoutParamsDynamicButton = new RelativeLayout.LayoutParams(width, height);
layoutParamsDynamicButton.bottomMargin = (int) getActivity().getResources().getDimension(R.dimen.margin_badges);
int offsetLeft = AppConstants.dynamic_button_offset_multiplier * i;
int offsetTop = AppConstants.dynamic_button_offset_multiplier * i;
layoutParamsDynamicButton.setMargins(offsetLeft, offsetTop, 0, 0);
Log.d(TAG, "offset = "+offsetLeft);
dynamicButtons[i] = new ImageView(contextSosFragment);
dynamicButtons[i].setAdjustViewBounds(true);
dynamicButtons[i].setScaleType(ScaleType.FIT_CENTER);
dynamicButtons[i].setImageResource(R.drawable.img_badge_dynamic_loading);
dynamicButtons[i].setTag(id);
containerDynamicButtons.addView(dynamicButtons[i], layoutParamsDynamicButton);
}
Each view needs its own LayoutParams object. It looks like your code just updates the same LayoutParams instance each time and passes it to addView(). If this is the case, all your views are pointing to the same params when it comes time to do layout...and their margins will all be the last value set.
As a performance optimization, if you are just placing several static images on top of each other, you could achieve the same effect (including the offsets) with a LayerDrawable (docs link) inside a single ImageView. This is the object created by <layer-list> in XML, but since you need to dynamically set the offset you could create one in code as well. Fewer views typically leads to cleaner UI.
Related
I am trying to add many button into Relativelayout or Linearlayout,
Layout
<Relativelayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
>
</Relativelayout>
then in the class
_ll_layout = (RelativeLayout) findViewById(R.id.container);
I only know how add the button dynamically with code.
JSONArray jsonArray = new JSONArray(tmp.getString("productos"));
Button bt[] = new Button[jsonArray.length()]; // size of product
for (int i = 0; i < jsonArray.length(); i ++){
int padding_40dp = (int) (40 * scale + 0.5f);
int margin_10dp = (int) (10 * scale + 0.5f);
int padding_90dp = (int) (90 * scale + 0.5f);
LinearLayout.LayoutParams params = new Relativelayout.LayoutParams(padding_90dp, padding_40dp);
params.setMargins(margin_10dp, 0 , 0, 0);
bt[i] = new Button(DetalleServicioActivity.this);
bt[i].setText(jsonArray.getJSONObject(i).getString("nombre"));
bt[i].setTag(new TagInfo(jsonArray.getJSONObject(i).getString("id_producto")));
bt[i].setTextColor(Color.parseColor("#FFFFFF"));
bt[i].setBackgroundColor(Color.parseColor("#D8D8D8"));
bt[i].setEnabled(false);
bt[i].setId(Integer.parseInt(jsonArray.getJSONObject(i).getString("id_producto")));
bt[i].setLayoutParams(params);
_ll_layout.addView(bt[i]);
}
but the result is
One on another one, but I need something like this:
Edit
If I use LinearLayout with orientation horizontal and gravity center, this happend
Instead of using Relative Layout or Linear Layout I would rather suggest you to create custom flow layout.Custom flow layout will adjust child views accordingly in rows, and will jump the button in new row according to screen width.
Please have a look here : Flow layout example
Happy Coding :)
Instead of RelativeLayout, make use of LinearLayout with orientation as horizontal and add the button in them at run time
As per your design requirement, make sure you have two linear layouts here.
you can use griedlayout for solved your problem
I'm trying to make a dynamic grid layout, it being API 10+ is the part that's been making it slow going. I tried to make it wrap automatically.. but in the end found it easier just to try to force it into a grid pattern using coordinates. This script was working by itself when I did the positioning at time of creation, but now I am trying to loop through each item as a sort. So if one item is deleted, they all float back into a grid without a hole in the middle.
Problem is, it seems the layout parameters are only applying to the last object.
Here's some base variables and onCreate setup:
int screenWidth;
int screenHeight;
int distStep = 130;
int leftPad = 20;
int numCols;
int baseID = 0;
android.util.DisplayMetrics metrics = this.getResources().getDisplayMetrics();
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
numCols = (int) (screenWidth - leftPad) / distStep;
int scrRemain = screenWidth - ((numCols * distStep) + leftPad);
distStep += (int) scrRemain / numCols;
Then on to the main function for adding:
public void addObjToLayout() {
RelativeLayout relLay = (RelativeLayout) this.findViewById(R.id.mainWindow);
for(int i = 1; i <= currQuantity; i++){
TextView tv=new TextView(this);
tv.setTextSize(40);
tv.setId(baseID + i);
tv.setPadding(24, 4, 24, 4);
tv.setBackgroundColor(0x110000FF);
tv.setText(String.valueOf(baseID + i)); //Val for debugging
tv.setTextColor(0xFFFFFFFF);
relLay.addView(tv);
}
baseID += currQuantity;
sortLayout();
}
Then the sorting:
public void sortLayout() {
int leftNum = 20;
int topNum = 0;
for(int i = 1; i <= baseID; i++){
TextView tv= (TextView) this.findViewById(baseID);
MarginLayoutParams mp = new MarginLayoutParams(tv.getLayoutParams());
mp.setMargins(leftNum, topNum, 0, 0);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(mp);
tv.setLayoutParams(lp);
leftNum += distStep;
if(leftNum >= distStep * numCols){
leftNum = leftPad;
topNum += distStep;
}
}
}
What I am getting is all the textViews pile up in the top left corner, except the last one which is positioned exactly where it should be. So it seems in my head, the params object isn't applying until the loop ends or something.. but logically I don't see why.
As I said, this worked when I set the params at the get go, problem is mass updating them all at once. I am pretty new to android, so I hope I'm not just doing something stupid.
Thanks for your time
Margin means it will set a gap between the previous view and current view.
When you add view1, view2 and view3 to grid layout and if you remove view2 at some point of time, then the margin for view3 is set according to view1. So, it won't leave empty space in place of view2. Instead of removing view2 at run time, set the background for view2 as null and set the text as empty as below.
textView.setBackground(null);
textView.setText("");
So that the view is still available but looks as deleted.
Started looking into GridView using an extended baseAdapter. Looks promising:
For more (see #2):
http://www.mkyong.com/android/android-gridview-example/
I was wondering how I could "randomly" place an array of Buttons in a RelativeLayout?
Is it possible to space the buttons around the entire view?
Thanks for your help! I tried using setX() and setY() but they are float numbers and I'm unsure how they place the buttons in proportion to the size of the screen.
You can add layout margins to your buttons. As margins will be interpreted not relative to each other but to the frame, it will in fact position your buttons.
To set the margins you have to set the view's layout params:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
Random random = new Random();
params.leftMargin = random.nextInt(100);
params.topMargin = random.nextInt(100);
button.setLayoutParams(params);
However this may cause your buttons to overlap, or be outside the Activity, so it's best not to use entirely random values for positions but to perform checks for overlapping and set random ranges according to the device resolution and button size.
To get device display size:
Display display= activity.getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int Height = display.getHeight();
instead do something like this first create a button array and find the respective id...
LayoutParams lp = new LinearLayout.LayoutParams(widthOfButtons,LayoutParams.WRAP_CONTENT);
Button[] buttons;
for(int i=0; i<4; i++) { //suppose you have four buttons
{
String buttonID = "button" + (i+1);
int resID = getResources().getIdentifier(buttonID, "id", getPackageName());
buttons[i] = ((Button) findViewById(resID));
buttons[i].setHeight(yourvalue);
buttons[i].setWidth(yourvalue);
buttons[i].setLayoutParams(lp);
}
hope it works for your
I am programatically adding ImageView elements into a horizontal Linear Layout. Then I set the scaleX and scaleY properties to "2" on one of the ImageView resources. The image gets scaled properly, but it doesn't move the other ImageView elements, instead of that it overlaps them. I don't like the image to overlap with other images. How can I fix that? Here's my code:
int resources[] = {R.drawable.desert, R.drawable.koala, R.drawable.jellyfish,
R.drawable.lighthouse, R.drawable.desert};
for(int i=0; i<5; i++) {
ImageView logo = new ImageView(this);
logo.setLayoutParams(new LinearLayout.LayoutParams(100, 75));
logo.setImageResource(resources[i]);
logosContainer.addView(logo);
}
ImageView middleImage = (ImageView) logosContainer.getChildAt(2);
middleImage.setScaleX(middleImage.getScaleX() * 2);
middleImage.setScaleY(middleImage.getScaleY() * 2);
The result from the code looks like this:
http://imageshack.us/a/img15/2811/scaleal.jpg
You can clearly see that the scaled image overlaps with the other images.
Your ImageViews are already measured and placed in the container when you leave the loop. You would have to refresh your layout to make this work, which is tricky and often leads into "removing all views and adding them again". So why don't you just do the "scaling" in the loop?
for(int i=0; i<5; i++) {
ImageView logo = new ImageView(this);
if(i==middleImageIndex){
logo.setLayoutParams(new LinearLayout.LayoutParams(100*2, 75*2,1));
} else {
logo.setLayoutParams(new LinearLayout.LayoutParams(100, 75,1));
}
logo.setImageResource(resources[i]);
logosContainer.addView(logo);
}
The last parameter (100,75, 1) is the weight of the view, which makes sure that each ImageView is equally important and doesn't get overlapped.
Another note: setScale requires API level 11 or higher, which could cut a lot of users out there
Right now, I'm struggling to accomplish something as simple as adding margin space between my child ImageViews within a custom LinearLayout (modified RadioGroup that is designed to take in a custom ImageView that implements Checkable, didn't override onMesarue). Long story short, these images are of a fixed dimension (60x60dip), and since they are dynamic (from the web), I had to add them dynamically like so:
for(int i = 0; i < num; i++){
ImageViewRadioButton childImage = new ImageViewRadioButton(mContext);
float imagehWidthHeight = getResources().getDimension(R.dimen.image_width_and_height);
LinearLayout.LayoutParams imageParams = new LinearLayout.LayoutParams((int) imageWidthHeight, (int) imageWidthHeight);
int imageSpacing = Utils.dipsToPixels(10, mContext);
int innerPadding = Utils.dipsToPixels(5, mContext);
imageParams.leftMargin = imageSpacing;
imageParams.rightMargin = imageSpacing;
childImage.setAdjustViewBounds(true);
childImage.setLayoutParams(imageParams);
childImage.setBackgroundDrawable(getResources().getDrawable(R.drawable.blue_pressed));
childImage.setPadding(innerPadding, innerPadding, innerPadding, innerPadding);
childImage.setClickable(true);
//other non-image properties...
imageContainer.addView(childImage);
}
The only thing that does work is the padding, which it spaces it out properly. However, I am not seeing any space between the padding of each child (margins). Am I doing this correctly, or is there a better way of doing it short of overriding onMeasure to factor in each child's margins?
You had create imageParams but you are not using that parameters in your code instead of imageParams you are using swatchParams parameter. And you had not put a code of swatchParams parameter.