Adding elements programmatically to FrameLayout using a for loop - android

Why when I add the elements to the FrameLayout flCatScroll only one shows and not ten are they perhaps overlapping and or why dosn't the margin increase.
myactivity.runOnUiThread(new Runnable() {
#Override
public void run() {
//Main Framelayout
FrameLayout flCatScroll = (FrameLayout) myactivity.findViewById(R.id.flCatScroll);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.TOP;
params.topMargin = 20;
for(int i = 0; i < 10; i++) {
//FrameLayout mainItemLayout = new FrameLayout(myactivity);
listFramelayouts.add(new FrameLayout(myactivity));
}
for(int i = 0; i < listFramelayouts.size(); i++) {
params.topMargin = 20 * i;
TextView itemName = new TextView(myactivity);
itemName.setText("Test" + i);
listFramelayouts.get(i).addView(itemName);
flCatScroll.addView(listFramelayouts.get(i), params);
}
}
});

Reference semantics strike again!
Because you're reusing the params object instead of creating a new one each time, They all share the same margin at the end regardless of what the margin was when you added the view. So they are, indeed, all overlapping.
Does this make sense?

dcow is right. You are reusing the same LayoutParams object for each new TextView. So at the end all of them have the same topMargin. You need to create params per each new view. You can add new function like:
private FrameLayout.LayoutParams getLayoutParamsFor(final int i) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.TOP;
params.topMargin = 20 * i;
return params;
}
and then inside your loop you call it in addView(...) call:
flCatScroll.addView(listFramelayouts.get(i), getLayoutParamsFor(i));

Related

onScrollChange() is not being called for every pixel scrolled on ScrollView

I want to add new child views after every 50 pixels of scrolling but the statement Log.d("scroll",scrollY+":"+oldScrollY); is missing some values i.e. scrollY = 149 and scrollY = 151 are there in Log but scrollY = 150 is missing. So the code doesn't run for scrollY = 150 and new child views is not added.
Although it works as it should for most of the values of scrollY but for few values of scrollY, the event is not being triggered.
How can i resolve this issue? Or is there any other way to achieve this.
public class MainActivity extends AppCompatActivity implements ScrollViewListener {
RelativeLayout parent;
TextView height;
ObservableScrollView scrollView;
int position=1;
View view1,view2;
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parent = (RelativeLayout) findViewById(R.id.parent);
scrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
LayoutInflater inflater = LayoutInflater.from(this);
view1 = inflater.inflate(R.layout.education,null, false);
view1.setId(R.id.parent+position);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.LEFT_OF,R.id.divider);
params.topMargin = 100;
params.rightMargin = 3;
parent.addView(view1, params);
position++;
final Animation leftAnimation = new TranslateAnimation(view1.getX()-50,view1.getX(),view1.getY()+100,view1.getY());
leftAnimation.setDuration(1000);
view1.setAnimation(leftAnimation);
scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View view, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
Log.d("scroll",scrollY+":"+oldScrollY);
if((scrollY-oldScrollY)>0 && scrollY%50 == 0)
{
Log.d("scroll","abcghfg");
if(position%2==0)
{
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.RIGHT_OF,R.id.divider);
// params.topMargin = (position-1)*(view1.getLayoutParams().height)+position*100;
params.topMargin = 30;
params.leftMargin = 3;
params.addRule(RelativeLayout.BELOW,parent.getChildAt(position-1).getId());
Log.d("scroll","abc");
view2 = LayoutInflater.from(MainActivity.this).inflate(R.layout.education,null,false);
view2.setId(R.id.parent+position);
Animation rightAimation = new TranslateAnimation(view2.getX()+50,view2.getX(),view2.getY()+100,view2.getY());
rightAimation.setDuration(1000);
view2.startAnimation(rightAimation);
parent.addView(view2, params);
}
else
{
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.LEFT_OF,R.id.divider);
//params.topMargin = (position-1)*(view1.getLayoutParams().height)+position*100;
params.topMargin = 30;
params.rightMargin = 3;
params.addRule(RelativeLayout.BELOW,parent.getChildAt(position-1).getId());
Log.d("scroll","def");
view2 = LayoutInflater.from(MainActivity.this).inflate(R.layout.education,null,false);
view2.setId(R.id.parent+position);
Animation animation = new TranslateAnimation(view2.getX()-50,view2.getX(),view2.getY()+100,view2.getY());
animation.setDuration(1000);
view2.startAnimation(animation);
parent.addView(view2, params);
}
position++;
}
}
});
}
}
Thanks in advance.
Android doesn't render every pixel in a scroll, because it would be bad for performance. If you scroll really slow, you will see that your callback will be called for every pixel, but if you scroll fast, it will be called just when the render triggers.
In your case, you need to check if it rendered 50 or more pixels since last time you rendered the last view.

Android GridLayout only shows last child

I am new to Android Development. I have been working with using a GridLayout to display Dynamically inserted ImageViews.
My issue is located in "onFocusWindowChanged" but I pasted my onCreate where I do my assignments of the images.
private List<Behavior> behaviors = null;
private static int NUM_OF_COLUMNS = 2;
private List<ImageView> images;
private GridLayout grid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_behaviors);
XMLPullParserHandler parser = new XMLPullParserHandler();
try {
behaviors = parser.parse(getAssets().open("catagories.xml"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
grid = (GridLayout) findViewById(R.id.behaviorGrid);
images = new ArrayList<ImageView>();
grid.setColumnCount(NUM_OF_COLUMNS);
grid.setRowCount(behaviors.size() / NUM_OF_COLUMNS);
for (Behavior behavior : behaviors)
images.add(this.getImageViewFromName(behavior.getName()));
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
View view = (View) findViewById(R.id.scrollView);
int width = (int) (view.getWidth() * .45);
Log.i("ViewWidth", Integer.toString(width));
GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
lp.height = width;
lp.width = width;
int childCount = images.size();
ImageView image;
for (int i = 0; i < childCount-1; i++) {
image = images.get(i);
image.setLayoutParams(lp);
grid.addView(image);
}
}
In my (short) previous experience, using
grid.add(View);
worked fine, but now I am only seeing the last child display only. Looking through the debugger I can see that the gridview is being populated with more than just the last element, as well as the last imageview.
Thank you for your help
you should create a GridLayout.LayoutParams for each ImageView:
for (int i = 0; i < childCount-1; i++) {
GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
lp.height = width;
lp.width = width;
......
}
GridLayout.LayoutParams contains location information, e.g [column:2, row:3]. In your code, all ImageViews are set the same GridLayout.LayoutParams, so they are located in the same cell(overlapping each other).
When use LinearLayout.LayoutParams instead, there is no location information in it. GridLayout will create a new GridLayout.LayoutParams for each child view, so all ImageViews use their own different GridLayout.LayoutParams and location.
Wish this help. You can read the GridLayout.java and ViewGroup.java for more details.
So I solved my issue, although I'm not sure how-
GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
changed to...
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(x,y);
made it work just as I wanted it. But I'm not sure why- If anyone could explain, please do :)

Re-Adding views to a fragment on onResume returns an IllegalStateException

I'm developing an Android 3.1 Tablet application with fragments.
I've seen that only two fragments are on memory at the same time. When I show a third one, first one calls onDestroyView.
I add EditText to fragment's view programmatically. Those EditText don't show again after fragment's view recreation on onResume method.
I use those EditText to let users add data to a form and I store a reference in firstTable HashMap. I will use that HashMap to retrieve user's values.
Here I create those EditText programmatically:
private LinearLayout createNewFirstTableRow(long articleId)
{
LinearLayout layout = new LinearLayout(mActivity);
LayoutParams parentParams = new LayoutParams(LayoutParams.MATCH_PARENT, 40);
parentParams.weight = 1;
layout.setLayoutParams(parentParams);
if (firstTable == null)
firstTable = new HashMap<Long, ArrayList<EditText>>();
ArrayList<EditText> fields = new ArrayList<EditText>(7);
LayoutParams params = new LayoutParams(0, 40);
params.weight = 0.125f;
TextView textView = new TextView(mActivity);
textView.setLayoutParams(params);
textView.setText(new Long(articleId).toString());
layout.addView(textView);
for (int i = 0; i < 7; i++)
{
EditText edit = new EditText(mActivity);
edit.setLayoutParams(params);
edit.setInputType(InputType.TYPE_CLASS_NUMBER);
fields.add(i, edit);
layout.addView(edit);
}
firstTable.put(new Long(articleId), fields);
return layout;
}
firstTable variable is a global variable: private HashMap<Long, ArrayList<EditText>> firstTable;.
To add my EditText I do the following on onResume:
#Override
public void onResume()
{
Log.v("QuantityFragment", "onResume: " + firstTableRowIndex);
if ((firstTable != null) && (secondTable != null))
{
firstTableRowIndex = FIRST_TABLE_ROW_INDEX;
secondTableRowIndex = SECOND_TABLE_ROW_INDEX;
LinearLayout table = (LinearLayout)view.findViewById(R.id.quantityTable);
for (int index = 0; index < firstTable.size(); index++)
{
Long articleId = articleIds.get(index);
table.addView(resumeTable(articleId, secondTable.get(articleId)), secondTableRowIndex);
table.addView(resumeTable(articleId, firstTable.get(articleId)), firstTableRowIndex);
firstTableRowIndex++;
secondTableRowIndex++;
}
}
super.onResume();
}
private LinearLayout resumeTable(Long articleId, ArrayList<EditText> fields)
{
LinearLayout layout = new LinearLayout(mActivity);
LayoutParams parentParams = new LayoutParams(LayoutParams.MATCH_PARENT, 40);
parentParams.weight = 1;
layout.setLayoutParams(parentParams);
LayoutParams params = new LayoutParams(0, 40);
params.weight = 0.125f;
TextView textView = new TextView(mActivity);
textView.setLayoutParams(params);
textView.setText(new Long(articleId).toString());
layout.addView(textView);
for (int index = 0; index < fields.size(); index++)
{
layout.addView(fields.get(index));
}
return layout;
}
But, here layout.addView(textView); I get an exception:
IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Is there another way to re-add those EditText?
UPDATE:
I have solved my problem changing resumeTable:
private LinearLayout resumeTable(Long articleId, ArrayList<EditText> fields)
{
LinearLayout layout = new LinearLayout(mActivity);
LayoutParams parentParams = new LayoutParams(LayoutParams.MATCH_PARENT, 40);
parentParams.weight = 1;
layout.setLayoutParams(parentParams);
LayoutParams params = new LayoutParams(0, 40);
params.weight = 0.125f;
TextView textView = new TextView(mActivity);
textView.setLayoutParams(params);
textView.setText(new Long(articleId).toString());
layout.addView(textView);
for (int index = 0; index < fields.size(); index++)
{
LinearLayout parent = (LinearLayout)fields.get(index).getParent();
parent.removeView(fields.get(index));
layout.addView(fields.get(index));
}
return layout;
}
This is the important part:
for (int index = 0; index < fields.size(); index++)
{
LinearLayout parent = (LinearLayout)fields.get(index).getParent();
parent.removeView(fields.get(index));
layout.addView(fields.get(index));
}
The question is open, if you have a better solution, please, let me know.
That exception is thrown because you store references to Views(the EditText) that were added to the layout and then later you're again re-adding those Views to a newly constructed parent.
Regarding a solution, I don't know why you decided to store references to those EditTexts. The only data that I see worth storing from those EditTexts is the text entered by the user, in which case you should store that text instead of that particular EditText .Your method would be:
//...
if (firstTable == null) {
// your HashMap now stores text instead of an EditText
firstTable = new HashMap<Long, ArrayList<String>>();// store only the text from the EditText
}
ArrayList<String> fields = new ArrayList<String>(7);
LayoutParams params = new LayoutParams(0, 40);
params.weight = 0.125f;
TextView textView = new TextView(mActivity);
textView.setLayoutParams(params);
textView.setText(new Long(articleId).toString());
layout.addView(textView);
for (int i = 0; i < 7; i++) {
EditText edit = new EditText(mActivity);
edit.setLayoutParams(params);
edit.setInputType(InputType.TYPE_CLASS_NUMBER);
fields.add(i, ""); // the EditText are empty at first
layout.addView(edit);
}
firstTable.put(new Long(articleId), fields);
Then when is time to restore the EditTexts:
private LinearLayout resumeTable(Long articleId, ArrayList<String> fields) {
LinearLayout layout = new LinearLayout(mActivity);
LayoutParams parentParams = new LayoutParams(LayoutParams.MATCH_PARENT, 40);
parentParams.weight = 1;
layout.setLayoutParams(parentParams);
LayoutParams params = new LayoutParams(0, 40);
params.weight = 0.125f;
TextView textView = new TextView(mActivity);
textView.setLayoutParams(params);
textView.setText(new Long(articleId).toString());
layout.addView(textView);
for (int index = 0; index < fields.size(); index++) {
// create new EditTexts
EditText edit = new EditText(mActivity);
edit.setLayoutParams(params);
edit.setInputType(InputType.TYPE_CLASS_NUMBER);
edit.setText(fields.get(index)); // get the text coresponding to this particular EditText
layout.addView(edit);
}
return layout;
}
Of course when the user enters something in the EditTexts you should store it in the firstTable variable at the right position.
I think problen is due to adding the element of fields twice
ArrayList<EditText> fields = new ArrayList<EditText>(7);
1 - in createNewFirstTableRow
for (int i = 0; i < 7; i++)
{
EditText edit = new EditText(mActivity);
edit.setLayoutParams(params);
edit.setInputType(InputType.TYPE_CLASS_NUMBER);
fields.add(i, edit);//<-----------
layout.addView(edit);//<----------- added in layout
}
2- onResume()->resumeTable
for (int index = 0; index < fields.size(); index++)
{
layout.addView(fields.get(index));//<----------------
}
when fields element alreay added on the screen you can't add that twice.......

Add Buttons dynamically depending on screen width

I'm trying to add buttons dynamically depending on screen width.
i.e. if I get 6 buttons then I need to position them accordingly, so that the buttons appear at the center with equal spacings on left parent and right parent.
Here is the piece of code which I'm trying but no result:
private void btmBarBtns(int position) {
RelativeLayout rlLayout;
RelativeLayout.LayoutParams layoutParams;
int leftMargin = scrWidth/pageCount;
CommonMethods.getSystemOutput("Left Margin::::"+leftMargin);
for (int i = 0; i < pageCount; i ++ ) {
rlLayout = (RelativeLayout) findViewById(R.id.ivBottomBar);
layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
layoutParams.leftMargin = leftMargin;
ib = new ImageButton(this);
ib.setId(i);
ib.setLayoutParams(layoutParams);
ib.setBackgroundResource(R.drawable.white_circle_32x32);
rlLayout.addView(ib);
leftMargin = leftMargin + 70;
if (ib.getId() == position) {
ib.setBackgroundResource(R.drawable.black_circle_32x32);
}
}
}
In the above code I have a Relative layout with height 25dp and width fill_parent. I am able to add the buttons but they are not positioned at the center.
If all you want to is center those ImageButtons with equal space left and right then you could simple wrap them in a LinearLayout and then center that LinearLayout in the parent RelativeLayout:
RelativeLayout rlLayout = (RelativeLayout) findViewById(R.id.parent);
LinearLayout container = new LinearLayout(this);
for (int i = 0; i < 5; i++) {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
ImageButton ib = new ImageButton(this);
ib.setId(i);
ib.setLayoutParams(layoutParams);
ib.setBackgroundResource(R.drawable.ic_launcher);
container.addView(ib);
if (ib.getId() == position) {
ib.setBackgroundResource(R.drawable.black_circle_32x32);
}
}
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL,
RelativeLayout.TRUE);
rlLayout.addView(container, layoutParams);
If you want to write more code just to do the above then you could modify your current layout and add this element as an anchor:
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerHorizontal="true"
android:id="#+id/anchor" />
and then in code position the ImageButtons to the left and right of this anchor View:
int anchorId = R.id.anchor;
int btnsNr = 6; // this is the number of Buttons
RelativeLayout rlLayout = (RelativeLayout) findViewById(R.id.parent);
if (btnsNr % 2 != 0) {
anchorId = 1000;
btnsNr--;
ImageButton imgb = new ImageButton(this);
imgb.setImageResource(R.drawable.shop_open);
imgb.setId(anchorId);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
rlp.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
rlLayout.addView(imgb, rlp);
}
int whichPart = 1;
while (whichPart >= 0) {
int previousId = anchorId;
for (int i = 0; i < (btnsNr / 2); i++) {
RelativeLayout.LayoutParams tmp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
if (whichPart == 1) {
tmp.addRule(RelativeLayout.LEFT_OF, previousId);
} else {
tmp.addRule(RelativeLayout.RIGHT_OF, previousId);
}
ImageButton imgb = new ImageButton(this);
previousId += whichPart == 1 ? -1 : 1;
imgb.setId(previousId);
imgb.setImageResource(R.drawable.shop_open);
rlLayout.addView(imgb, tmp);
}
whichPart--;
}
If you want to calculate the number of ImageButtons that fit the screen(and center them horizontally) you should have mentioned.

Dynamic TextView in Relative layout

I am triying to use dynamic layout for comment part of my project but when i settext of textview dynamicly the output only appears in top of the screen. And it puts the output over the other outputs
RelativeLayout ll=(RelativeLayout) findViewById(R.id.rl);
for(int i = 0; i < 20; i++) {
TextView cb = new TextView(this);
cb.setText("YORUMLAR"+yorum[0]+i);
cb.setTextSize(30);
ll.addView(cb);
}
So how can i put the output on the bottom of the screen linearly.
You should use LinearLayout to automatically add one TextView after another.
Assuming you can't live without RelativeLayout, you'll need to dynamically generate ids for all TextView you create in order to put one view under another. Here is example:
public class HelloWorld extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
RelativeLayout layout = (RelativeLayout)findViewById(R.id.layout);
Random rnd = new Random();
int prevTextViewId = 0;
for(int i = 0; i < 10; i++)
{
final TextView textView = new TextView(this);
textView.setText("Text "+i);
textView.setTextColor(rnd.nextInt() | 0xff000000);
int curTextViewId = prevTextViewId + 1;
textView.setId(curTextViewId);
final RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, prevTextViewId);
textView.setLayoutParams(params);
prevTextViewId = curTextViewId;
layout.addView(textView, params);
}
}
}
You've to provide the location of your newly added view. As #Adinia said, with no position, it will be aligned to the top by default. So you can use the following code to do it with RelativeLayout;
RelativeLayout containerLayout = (RelativeLayout) findViewById(R.id.container);
for (int i = 0; i < 20; i++) {
TextView dynaText = new TextView(this);
dynaText.setText("Some text " + i);
dynaText.setTextSize(30);
// Set the location of your textView.
dynaText.setPadding(0, (i * 30), 0, 0);
containerLayout.addView(dynaText);
}
If you want to show multiple textviews one after the other, then you should go with LinearLayout.
You may also add Dynamic textview to relative layout. Here with i have attached some code this may help you.
RelativeLayout ll=(RelativeLayout) findViewById(R.id.rl);
for(int i = 0; i < 20; i++)
{
TextView cb = new TextView(this);
cb.setText("YORUMLAR"+yorum[0]+i);
cb.setTextSize(30);
cb.setId(2000+i);
RelativeLayout.LayoutParams TextViewLayoutParams = new RelativeLayout.LayoutParams(100,100);
if (i != 0 )DispViewLayoutParams.addRule(RelativeLayout.BELOW, 2000 - (i-1));
ll.addView(cb,TextViewLayoutParams);
}

Categories

Resources