I am trying to create CardView type objects which will enable users to input their working hours for each day. I first did them in plain xml, which worked flawlessly, but not once I had to make some small changes and that meant modifying the code in 8 places.
I managed to understand how to create the cardviews programmatically ( I am using an enum type class in order to hold id's and names for the elements from the cardviews. The problem is, the result doesn't work as it should.
I can't manage to make the elements( CheckBox, TextView, SpinnerStart, SpinnerEnd) to be in the right place.
_checkBox should be aligned to the start of _relativeLayoutInCard, _TVDayLabel after it, then _spinnerEnd aligned to the end of the relatie layout and _spinnerStart at the beginning of spinnerEnd
The problem seems to be at the _layoutParamsOtherViews
private void createCards() {
/* get each day from enum and make the card
* with the necessary elements
*/
DaysOfWeek _previousDay = DaysOfWeek.MONDAY;
RelativeLayout _rootRelativeLayout = mActivity.findViewById(R.id.act_SWHours_RL_RootCV);
for (DaysOfWeek _day : DaysOfWeek.values()) {
Log.d("Stop", _day.geteDisplayName());
CardView _cardview = new CardView(mActivity, null, R.style.CardViewSWHours);
RelativeLayout.LayoutParams _layoutParamsCV = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
);
/* for Checkbox, Textviews and spinners inside CV */
RelativeLayout.LayoutParams _layoutParamsOtherViews = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
RelativeLayout _relativeLayoutInCard = new RelativeLayout(mActivity, null, R.style.RelativeLayoutInCVSWHours);
_relativeLayoutInCard.setLayoutParams(_layoutParamsCV);
if(_day.geteDisplayName().equals("Monday") || _day.geteDisplayName().equals("All week days")) {
Log.d("Stop", "It gets here");
_layoutParamsCV.addRule(RelativeLayout.BELOW, R.id.act_SWHours_CB_DiffHours);
}
else {
_layoutParamsCV.addRule(RelativeLayout.BELOW, _previousDay.getCardViewId());
}
if(_day.geteDisplayName().equals("Saturday")) {
_layoutParamsCV.addRule(RelativeLayout.BELOW, DaysOfWeek.ALLDAYS.getCardViewId());
}
_layoutParamsCV.setMargins(64, 9, 64, 9);
_cardview.setRadius(32);
_cardview.setCardElevation(6);
_cardview.setId(_day.getCardViewId());
_cardview.setLayoutParams(_layoutParamsCV);
_rootRelativeLayout.addView(_cardview);
_cardview.addView(_relativeLayoutInCard);
CheckBox _checkBox = new CheckBox(mActivity);
_checkBox.setId(_day.geteCheckBoxID());
_checkBox.setText(R.string.act_SWHours_CB_FreeDay);
_relativeLayoutInCard.addView(_checkBox, _layoutParamsOtherViews);
_layoutParamsOtherViews.addRule(RelativeLayout.ALIGN_PARENT_START);
_checkBox.setLayoutParams(_layoutParamsOtherViews);
_layoutParamsOtherViews.removeRule(RelativeLayout.ALIGN_PARENT_START);
TextView _TVDayLabel = new TextView(mActivity);
_TVDayLabel.setText(_day.geteDisplayName());
_relativeLayoutInCard.addView(_TVDayLabel, _layoutParamsOtherViews);
_layoutParamsOtherViews.addRule(RelativeLayout.END_OF, _day.geteCheckBoxID());
_TVDayLabel.setLayoutParams(_layoutParamsOtherViews);
_layoutParamsOtherViews.removeRule(RelativeLayout.END_OF);
Spinner _spinnerEnd = new Spinner(mActivity);
_spinnerEnd.setId(_day.geteSpinnerEndID());
_relativeLayoutInCard.addView(_spinnerEnd, _layoutParamsOtherViews);
_layoutParamsOtherViews.addRule(RelativeLayout.ALIGN_PARENT_END);
_spinnerEnd.setLayoutParams(_layoutParamsOtherViews);
_layoutParamsOtherViews.removeRule(RelativeLayout.ALIGN_PARENT_END);
Spinner _spinnerStart = new Spinner(mActivity);
_spinnerStart.setId(_day.geteSpinnerStartID());
_relativeLayoutInCard.addView(_spinnerStart, _layoutParamsOtherViews);
_layoutParamsOtherViews.addRule(RelativeLayout.START_OF, _day.geteSpinnerEndID());
_spinnerStart.setLayoutParams(_layoutParamsOtherViews);
_previousDay = _day;
}
}
Apparently, the problem was that I used the same LayoutParams object at all views( even though I removed the rules before assigning it to the next one).
In order for this to work, just other LayoutParams objects for each view and that shall do the work.
/* for Checkbox, Textviews and spinners inside CV */
RelativeLayout.LayoutParams _layoutParamsCB = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
RelativeLayout.LayoutParams _layoutParamsTV = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
RelativeLayout.LayoutParams _layoutParamsSPS = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
RelativeLayout.LayoutParams _layoutParamsSPE = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
...
TextView _TVDayLabel = new TextView(mActivity);
_TVDayLabel.setText(_day.geteDisplayName());
_relativeLayoutInCard.addView(_TVDayLabel, _layoutParamsTV);
_layoutParamsTV.addRule(RelativeLayout.END_OF, _day.geteCheckBoxID());
_TVDayLabel.setLayoutParams(_layoutParamsTV);
Related
For my activity, we were tasked with creating the views entirely programmatically (not allowed to use XML).
I created what I want the layout to look like in XML.
but I'm having trouble getting my contentEditText and the gravities to correctly set the, up as I've done in the XML file.
This is what I have for my view.
public class NoteGridLayout extends GridLayout {
public NoteGridLayout(final Context context, EditText titleEditText, Spinner spinner, EditText contentEditText, Button backButton) {
super(context);
setColumnCount(2);
GridLayout.Spec colSpec, rowSpec;
colSpec = GridLayout.spec(0, 1, 1);
rowSpec = GridLayout.spec(0, 0, 0);
GridLayout.LayoutParams titleParams = new GridLayout.LayoutParams(rowSpec, colSpec);
colSpec = GridLayout.spec(1,1,1);
rowSpec = GridLayout.spec(0,0,0);
GridLayout.LayoutParams spinnerParams = new GridLayout.LayoutParams(rowSpec, colSpec);
colSpec = GridLayout.spec(0,2,1);
rowSpec = GridLayout.spec(1,1,1);
GridLayout.LayoutParams contentParams = new GridLayout.LayoutParams(rowSpec, colSpec);
colSpec = GridLayout.spec(0,2,1);
rowSpec = GridLayout.spec(2,1,0);
GridLayout.LayoutParams buttonParams = new GridLayout.LayoutParams(rowSpec, colSpec);
titleParams.width = 0;
titleParams.height = LayoutParams.WRAP_CONTENT;
spinnerParams.width = 0;
spinnerParams.height = LayoutParams.WRAP_CONTENT;
contentParams.width = 0;
contentParams.height = 0;
buttonParams.width = LayoutParams.MATCH_PARENT;
buttonParams.height = LayoutParams.WRAP_CONTENT;
contentParams.setGravity(Gravity.TOP);
titleEditText.setLayoutParams(titleParams);
spinner.setLayoutParams(spinnerParams);
contentEditText.setLayoutParams(contentParams);
backButton.setLayoutParams(buttonParams);
addView(titleEditText);
addView(spinner);
addView(contentEditText);
addView(backButton);
}
}
The two main problems I'm having are:
1. The titleEditText is not appearing to span an entire column, rather, the spinner is taking up the whole two columns.
2. The contentEditText gravity is not able to be set, placing the text at the top of the box.
What do I need to do to fix these two problems?
For layout_gravity following is a code snippet,
LinearLayout.LayoutParams params = new
LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
params.weight = 1.0f;
params.gravity = Gravity.CENTER;
yourView.setLayoutParams(params);
For Gravity use following line,
yourLayout.setGravity(Gravity.CENTER)
I'm trying to make a Scheduling app, and in doing so have made a Schedule screen with TextViews and Views that represent the time slots that an activity can correspond to.
However I'm having a hard time getting a generated TextView (which will represent the activity on the Schedule) to line up correctly with the View associated with the Activity's start time.
For example in this case I make a TextView with text = "CSI2120", and attempt to line it up with line (which is a View) above the "13:00" TextView here. However I am missing something as the advice from these links as I can't get them to work.
Can I set “android:layout_below” at runtime, programmatically?
Android How to change layout_below to TextView programmatically (See Second Way in the Answer)
The TextView is in the default location on the top-right, not where I want it to be. What should be doing instead of what the links advise?
Here is my full method. timeSlots is an array of R.id.view[####] ints and Schedule is the Activity the method is in:
public void displayDailyActivities(int[] timeSlots){
String[] todaysActivities = {"CSI2120", "01", "14", "2017", "0300", "0400"};
// Make the associated TextView(s)
for(int i=0; i < todaysActivities.length; i=i+6){
int startTime = Integer.valueOf(todaysActivities[i+4]);
int startTimeHour = startTime / 100;
int startTimeMin = startTime % 100;
// Make the TextView and add it to the Schedule
// Code I got from links
TextView newActivity = new TextView(Schedule.this);
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
LinearLayout.LayoutParams linearParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
// Make the activity, grabbing the corresponding timeslot (View) from the timeSlots array
newActivity.setText(todaysActivities[i]);
// In this case ( timeSlots[startTimeHour + 1] ) returns ( R.id.view0300 )
// which is the View (line) on the Schedule directly above to the "03:00" TextView
relativeParams.addRule(RelativeLayout.BELOW, timeSlots[startTimeHour + 1]);
newActivity.setLayoutParams(relativeParams);
linearParams.setMargins(0, startTimeMin-3, 0, 0);
newActivity.setLayoutParams(linearParams);
// Add to the screen
RelativeLayout schedule = (RelativeLayout) findViewById(R.id.scheduleView);
schedule.addView(newActivity);
// Make sure we're not going out of bounds
if(i + 6 > todaysActivities.length){
i = todaysActivities.length;
}
else{
}
}
}
EDIT: The code that I've found from other similar questions, specifically, that doesn't work for me are the lines:
TextView newActivity = new TextView(Schedule.this);
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
LinearLayout.LayoutParams linearParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
...
relativeParams.addRule(RelativeLayout.BELOW, timeSlots[startTimeHour + 1]);
newActivity.setLayoutParams(relativeParams);
linearParams.setMargins(0, startTimeMin-3, 0, 0);
newActivity.setLayoutParams(linearParams);
you are overriding the relativeParams with the linearParams. set margins to relativeParms variable iteself and then setLayoutParams to newActivity like below:
relativeParams.addRule(RelativeLayout.BELOW, timeSlots[startTimeHour + 1]);
relativeParams.setMargins(0, startTimeMin-3, 0, 0);
newActivity.setLayoutParams(relativeParams);
// Add to the screen
RelativeLayout schedule = (RelativeLayout) findViewById(R.id.scheduleView);
schedule.addView(newActivity);
This can solve your problem
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.setMargins(10,10,10,10);
TextView textView = (TextView) findViewById(R.id.textView);
textView.setLayoutParams(params);
I have found a couple ways to do this, but my issue is that my code has to be a LinearLayout with a horizontal orientation. So what happens is the dynamically created TextViews go off the screen.
The code I have is below:
mProductAttrLayout.setOrientation(LinearLayout.HORIZONTAL);
mProductAttrLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
for (ProductAttribute productAttribute : aProductAttributes) {
String name = productAttribute.getName();
TextView attr = new TextView(getContext());
attr.setText(name);
attr.setPadding(8, 8, 8, 8);
attr.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
attr.setTextColor(getResources().getColor(R.color.black));
mProductAttrLayout.addView(attr);
for (int i = 0; i < productAttribute.getValues().size(); i++) {
TextView value = new TextView(getContext());
value.setText(productAttribute.getValues().get(i));
value.setTextColor(getResources().getColor(R.color.black));
value.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
value.setPadding(8, 8, 8, 8);
mProductAttrLayout.addView(value);
}
}
What I currently have is:
| name: value, value, value, val--|
what I need is something like:
name: value, value(unknown number of values)
but I need it to go the the next line in the screen if it's too wide like below:
| name: value, value, value,---|
| value, value, value. ------------|
Hope you can understand what I need?
LinearLayout is the wrong choice here.
You could either write your own layout or use existing work.
What you probably want is usually called a FlowLayout, like this.
Custom layouts can be used like any other Layout. E.g. you can add views with layout.addView. Noramlly the only difference in use is reflected in the custom layoutParams.
Create a flow layout in OnCreate:-
muscle_gp_tag_flow_layout = new FlowLayout(mContext);
//add the flow layout to your main layout
Call the method first time and whenever you want to refresh the view:-
public void createShowSpannableStringMuscleGroup(List<MuscleGroup> muscleGroups) {
// clears the flowlayout views
muscle_gp_tag_flow_layout.removeAllViews();
for (int countGroup = 0; countGroup < muscleGroups.size(); countGroup++) {
MuscleGroup group = muscleGroups.get(countGroup);
if (group.getName() != null && group.getName().length() > 0) {
// inflating the textview views in flow layout
TextView textView=new textView(context);
//set color, background for textview
textView.setText(group.getName().toString());
// adding views to flowlayout muscle group
muscle_gp_tag_flow_layout.addView(mView);
}
}
You have to go with Creating a Customized LinearLayout class. Refer the link for some sample ideas.
How can I add a TextView to a LinearLayout dynamically in Android?
you can use SpannableStringBuilder and TextAppearanceSpan. Example code:
List<String> manyStrings = Arrays.asList(new String[]{"name", "value", "value", "value"});
TextView textView = (TextView) view.findViewById(R.id.textView);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
for (int i = 0; i < manyStrings.size(); i++) {
String text;
if (i == 0) {
text = manyStrings.get(i) + ": ";
} else if (i == manyStrings.size() - 1) {
text = manyStrings.get(i);
} else {
text = manyStrings.get(i) + ", ";
}
if (i == 0) {
spannableStringBuilder.append(text);
spannableStringBuilder.setSpan(new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_DeviceDefault_Large), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
int oldLength = spannableStringBuilder.length();
spannableStringBuilder.append(text);
spannableStringBuilder.setSpan(new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_DeviceDefault_Small), oldLength, spannableStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
textView.setText(spannableStringBuilder);
Read more about SpannableStringBuilder and TextAppearanceSpan:
http://developer.android.com/reference/android/text/SpannableStringBuilder.html
http://developer.android.com/reference/android/text/style/TextAppearanceSpan.html
I know this is an old question I asked long ago but they (Google) have given us a solution to this problem using FlexboxLayout with the flexWrap="wrap" attribute.
This is for anyone else that finds this question with the same problem.
Example in XML:
<com.google.android.flexbox.FlexboxLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flexWrap="wrap" />
For more info you can visit the github repo here FlexboxLayout Repo
It works like this:
Can read more over here:
Build flexible layouts with FlexboxLayout
I am adding some table rows to a tableLayout dynamically and adding an onClickListener to each row- but when I removeAllViews, for some reason it gets rid of the listener too....
Here is my code for adding the data:
private void addTickerToTable(String ticker, String last, String chg, String pchg, String time){
rowId++;
int theColor=Color.WHITE;
int rowColor=0;
float theSize=13f;
lp = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT);
row= new TableRow(this);
row.setPadding(0, 5, 0, 5);
if(rowOdd==0){row.setBackgroundColor(Color.parseColor("#343434"));rowColor=Color.parseColor("#343434");}
if(rowOdd==1){row.setBackgroundColor(Color.BLACK);rowOdd=-1;rowColor=Color.BLACK;}
rowOdd++;
row.setLayoutParams(lp);
tv0 = new TextView(this);
tv0.setTextColor(Color.parseColor("#3A54A7"));
tv0.setTextSize(theSize);
tv1 = new TextView(this);
tv1.setTextColor(theColor);
tv1.setTextSize(theSize);
tv2 = new TextView(this);
tv2.setTextSize(theSize);
tv3 = new TextView(this);
tv3.setTextSize(theSize);
tv0.setText(ticker);
tv0.setLayoutParams(params);
row.addView(tv0);
tv1.setText(last);
tv1.setLayoutParams(params);
row.addView(tv1);
tv2.setText(chg);
tv2.setLayoutParams(params);
row.addView(tv2);
tv3.setText(pchg);
tv3.setLayoutParams(params);
row.addView(tv3);
ll.addView(row,rowCount);
row.setId(rowId);
row.setOnClickListener(this);
row.setOnLongClickListener(this);
row.startAnimation(anim2);
rowCount++;
}
Then I have a separate method that simply resets the data-
ll.removeAllViews();
rowCount=0;
rowOdd=0;
rowId=0;
It runs perfect the first time- everything is clickable etc...but as soon as you refresh or run the reset code, all of a sudden the onClickListeners don't work...
Nevermind- looks like I wasn't resetting my clicked variable- Oops!
I try to add dinamically some TextViews in Java. I assume that when I want to use setText() method, I should earlier connect my Java's TextView object with XML's TextView - I use setId().
At the end, I got NullPointerException in the line where I use setId().
My code:
TextView[] tvQuestion = new TextView[numberOfQuestions];
TextView[] tvAnswer1 = new TextView[numberOfQuestions];
TextView[] tvAnswer2 = new TextView[numberOfQuestions];
TextView[] tvAnswer3 = new TextView[numberOfQuestions];
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
for (int i = 0; i < numberOfQuestions; i++) {
tvQuestion[i].setId(View.generateViewId()); // NullPointerException!
tvAnswer1[i].setId(View.generateViewId());
tvAnswer2[i].setId(View.generateViewId());
tvAnswer3[i].setId(View.generateViewId());
tvQuestion[i].setLayoutParams(params);
tvAnswer1[i].setLayoutParams(params);
tvAnswer2[i].setLayoutParams(params);
tvAnswer3[i].setLayoutParams(params);
tvQuestion[i].setText(question[i]);
tvAnswer1[i].setText(option1[i]);
tvAnswer2[i].setText(option2[i]);
tvAnswer3[i].setText(option3[i]);
layAll.addView(tvQuestion[i]);
layAll.addView(tvAnswer1[i]);
layAll.addView(tvAnswer2[i]);
layAll.addView(tvAnswer3[i]);
}
EDIT:
Solution: Philipp Jahoda's post.
You just created an Array for the TextViews. The TextViews inside the Array are null as long as they are not initialized.
So you need to call
tvQuestion[i] = new TextView(Context);
tvAnswer[i] = new TextView(Context);
// and so on ...
// and then later
tvQuestion[i].setId(View.generateViewId());
// and so on ...
before setting the ID and other stuff.