I have to dynamically build views and I have used GridLayout as the parent layout to populate 2 views in a row. The code works perfectly fine in the platforms below Nougat. But in nougat version, the views are not populated.
Here is the code section below
private void populateAnswer(List<Answer> answerList, LinearLayout parent) {
GridLayout gridLayout = new GridLayout(context);
gridLayout.setBackgroundColor(getResources().getColor(android.R.color.holo_green_light));
gridLayout.setAlignmentMode(GridLayout.ALIGN_MARGINS);
GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
gridLayout.setLayoutParams(layoutParams);
gridLayout.setColumnCount(2);
Answer temp;
RadioGroup radioGroup = new RadioGroup(context);
if (answerList != null) {
for (int i = 0; i < answerList.size(); i++) {
temp = answerList.get(i);
if (temp.getaType().equals(RADIO_BUTTON)) {
RadioButton radioButton = new RadioButton(context);
radioButton.setTextColor(getResources().getColor(R.color.colorPrimary));
radioButton.setHighlightColor(getResources().getColor(R.color.colorPrimary));
GridLayout.LayoutParams rbLayoutParams = new GridLayout.LayoutParams();
rbLayoutParams.setGravity(Gravity.CENTER);
rbLayoutParams.height = GridLayout.LayoutParams.WRAP_CONTENT;
rbLayoutParams.width = GridLayout.LayoutParams.MATCH_PARENT;
radioButton.setLayoutParams(rbLayoutParams);
radioButton.setText(temp.getaDesc());
radioGroup.addView(radioButton);
} else if (temp.getaType().equals(CHECK_BOX)) {
CheckBox checkBox = new CheckBox(context);
checkBox.setTextColor(getResources().getColor(R.color.colorPrimary));
checkBox.setHighlightColor(getResources().getColor(R.color.colorPrimary));
checkBox.setText(temp.getaDesc());
gridLayout.addView(checkBox);
} else if (temp.getaType().equals(FREE_TEXT)) {
EditText editText = new EditText(context);
editText.setHint(temp.getaDesc());
editText.setHintTextColor(getResources().getColor(android.R.color.darker_gray));
gridLayout.addView(editText);
}
}
}
if (radioGroup.getChildCount() > 0) {
gridLayout.addView(radioGroup);
}
parent.addView(gridLayout);
}
I have attached the screenshots for different devices.
Using:
GridLayout.LayoutParams layoutParams = new ViewGroup.LayoutParams();
instead of:
GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
Related
Is there any way to align the text of radio button to the top like below programmatically.
i used the below code for creating radio group
final RadioButton[] rb = new RadioButton[5];
RadioGroup rg = new RadioGroup(getActivity()); //create the RadioGroup
rg.setOrientation(RadioGroup.VERTICAL);//or RadioGroup.VERTICAL
rg.setLayoutParams(radioparams);
for (int i = 0; i < 5; i++) {
rb[i] = new RadioButton(getActivity());
rb[i].setText("Radiobtn " + i);
rb[i].setId(i + 100);
rg.addView(rb[i]);
}
layout.addView(rg);
but i get the text to the right side of each button.
final RadioButton[] rb = new RadioButton[5];
RadioGroup rg = new RadioGroup(getActivity()); //create the RadioGroup
rg.setOrientation(RadioGroup.VERTICAL);//or RadioGroup.VERTICAL
rg.setLayoutParams(radioparams);
for (int i = 0; i < 5; i++) {
rb[i] = new RadioButton(getActivity());
rb[i].setText("Radiobtn " + i);
rb[i].setId(i + 100);
rb[i].setButtonDrawable(null);
TypedArray a = getTheme().obtainStyledAttributes(R.style.AppTheme, new int[] {android.R.attr.listChoiceIndicatorSingle});
int attributeResourceId = a.getResourceId(0, 0);
Drawable drawable = getResources().getDrawable(attributeResourceId);
rb[i].setCompoundDrawablesWithIntrinsicBounds(null, null, null, drawable);
rb[i].setGravity(Gravity.CENTER | Gravity.BOTTOM);
rg.addView(rb[i]);
}
layout.addView(rg);
Try this way you can do a trick
make your layout like this
<LinearLayout
android:id="#+id/lnrView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:orientation="horizontal">
</LinearLayout>
than add programatically RadioButton like this
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
LinearLayout layout = new LinearLayout(MainActivity.this);
layout.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
LinearLayout layout2 = new LinearLayout(MainActivity.this);
layout2.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams lp2 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
final ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
final TextView textView = new TextView(MainActivity.this);
int id = 0;
textView.setId(id);
textView.setTextSize(14);
textView.setTextColor(Color.rgb(0, 0, 0));
textView.setMaxEms(2);
textView.setText("NIlu");
layout2.addView(textView);
RadioButton radioButton = new RadioButton(MainActivity.this);
layout2.addView(radioButton);
layout.setLayoutParams(lp);
lnrView.addView(layout2);
}
});
I have a simple GridLayout which contains two textviews and two editexts on each row. The Gui is like this
I want both editexts to fill the entire free space from the gridLayout.
The gridLayout and the editexts are added programatically with the following code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
ScrollView indexDefRootView = (ScrollView) rootView.findViewById(R.id.scrollViewContainer2);
GridLayout gridLayout = new GridLayout(getActivity());
gridLayout.setColumnCount(4);
gridLayout.setRowCount(20);
int tmpIndex = 0;
// Drawable drawable = getResources().getDrawable(R.drawable.backtextcom);
for (int i = 1; i < 20; i++) {
if (true) {
TextView tv = new TextView(getActivity());
tv.setPadding(60, 0, 10, 30);
Spec row = GridLayout.spec(tmpIndex);
Spec col = GridLayout.spec(0);
tv.setText("Left Text " +(i-1));
GridLayout.LayoutParams first = new GridLayout.LayoutParams(row, col);
gridLayout.addView(tv, first);
EditText editText1 = new EditText(getActivity());
//editText1.setBackground(drawable);
editText1.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
GridLayout.LayoutParams param = new GridLayout.LayoutParams();
param.height = ViewGroup.LayoutParams.WRAP_CONTENT;
param.width = GridLayout.LayoutParams.WRAP_CONTENT;
param.rowSpec = GridLayout.spec(tmpIndex);
param.columnSpec = GridLayout.spec(1);
editText1.setLayoutParams(param);
gridLayout.addView(editText1);
TextView tv1 = new TextView(getActivity());
tv1.setText("Right Text View "+i);
tv1.setPadding(60, 0, 10, 30);
row = GridLayout.spec(tmpIndex);
col = GridLayout.spec(2);
first = new GridLayout.LayoutParams(row, col);
gridLayout.addView(tv1, first);
EditText editText2 = new EditText(getActivity());
//editText2.setBackground(drawable);
editText2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
param = new GridLayout.LayoutParams();
param.height = ViewGroup.LayoutParams.WRAP_CONTENT;
param.width = GridLayout.LayoutParams.WRAP_CONTENT;
param.rowSpec = GridLayout.spec(tmpIndex);
param.columnSpec = GridLayout.spec(3);
editText2.setLayoutParams(param);
gridLayout.addView(editText2);
tmpIndex++;
i=i+2;
}
}
indexDefRootView.addView(gridLayout);
return rootView;
}
Any feedback will be appreciated.
Try these in your code
Change Width To match_parent in your code
param.width = GridLayout.LayoutParams.MATCH_PARENT;
Using XML is better way. Avoid Creating View unless Required
I have a method that adds a textview dynamically in a linearLayout everytime I click on a button, it works good in this case, but in some other cases i wanted to call it progmmatically without clicking on a button but it doesn't work.BUT when I click on the button again, the textviews appear.
This method is contained in a fragment by the way.
Here is my code :
private void add_part() {
int width = bar.getWidth();
int child_count = ((ViewGroup) bar).getChildCount();
if (child_count == 0) {
minus_btn.setEnabled(true);
LayoutParams lparams = new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
TextView part = new TextView(getActivity());
part.setLayoutParams(lparams);
part.setGravity(Gravity.CENTER);
bar.addView(part);
} else if (child_count == 1) {
minus_btn.setEnabled(true);
View nextChild = ((ViewGroup) bar).getChildAt(0);
LayoutParams newparams = new LayoutParams(width / 2,
LayoutParams.FILL_PARENT);
nextChild.setLayoutParams(newparams);
LayoutParams lparams = new LayoutParams(width / 2,
LayoutParams.FILL_PARENT);
TextView part = new TextView(getActivity());
part.setLayoutParams(lparams);
bar.addView(part);
} else if (child_count > 1 && child_count < 10) {
minus_btn.setEnabled(true);
for (int i = 0; i < child_count; ++i) {
View nextChild = ((ViewGroup) bar).getChildAt(i);
LayoutParams newparams = new LayoutParams(width
/ (child_count + 1), LayoutParams.FILL_PARENT);
nextChild.setLayoutParams(newparams);
}
LayoutParams lparams = new LayoutParams(width / (child_count + 1),
LayoutParams.FILL_PARENT);
TextView part = new TextView(getActivity());
part.setLayoutParams(lparams);
bar.addView(part);
}
}
and I called it this ways :
add_part();
or
plus_btn.performClick();
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.......
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.