I want to add views (in this example, ImageViews) to a grid layout programmatically. My grid is fixed to 5 columns and 7 rows (35 items in total) and I don't want to add these 35 views in my xml so I want to do it programmatically. I'm struggling to find a conversion from xml to java/kotlin code for the attributes layout_width, layout_height, layout_columnWeight and layout_rowWeight so that the layout looks exactly the same as if I have defined the views in the xml. Can someone write the code for the views' layoutparams that matches these attributes?
<GridLayout
android:id="#+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill"
android:columnCount="5"
android:rowCount="7">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
app:srcCompat="#drawable/ic_photo_camera"/>
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_columnWeight="1"
android:layout_rowWeight="1"
app:srcCompat="#drawable/ic_photo_camera"/>
... //35 times the Image view
</GridLayout>
The previous xml would give me the next layout:
I tried the next one without success (Imageviews are showing too big and not fitting all inside the grid boundaries):
for(i in 1..35) {
val view = ImageView(context)
val params = GridLayout.LayoutParams(
GridLayout.spec(GridLayout.UNDEFINED, GridLayout.FILL,1f),
GridLayout.spec(GridLayout.UNDEFINED,GridLayout.FILL,1f))
view.layoutParams = params
gridView.addView(view, 0)
}
Can you help me translate the xml into java/kotlin code? Thanks in advance
First step would be to create a view object
val image = ImageView()
image.setImageResource(resourceID)
Then you'll need to set layout attributes
val params = GridLayout.LayoutParams(x, y)
//x and y is your size, if you want something special you can do for instance LayoutParams.FILL_PARENT
You can also set size a bit later:
params.height = X
params.width = Y
Lastly you just add the view to the layout
gridView.addView(image)
Put that all inside a for loop and you're done. GridView would take care of placing the views.
Result :
Try something like this :
final int MAX_COLUMN = gridView.getColumnCount(); //5
final int MAX_ROW = gridView.getRowCount(); //7
final int itemsCount = MAX_ROW * MAX_COLUMN; //35
int row = 0, column = 0;
for (int i = 0; i < itemsCount; i++) {
ImageView view = new ImageView(this);
//Just to provide alternate colors
if (i % 2 == 0) {
view.setBackgroundColor(Color.RED);
} else {
view.setBackgroundColor(Color.GREEN);
}
GridLayout.LayoutParams params = new GridLayout.LayoutParams(GridLayout.spec(row, 1F), GridLayout.spec(column, 1F));
view.setLayoutParams(params);
gridView.addView(view);
column++;
if (column >= MAX_COLUMN) {
column = 0;
row++;
}
}
If you want specific width and height for your cells, then use :
params.width = 100; // Your width
params.height = 100; //your height
Related
I am programmatically generating a GridLayout of TextViews. I want the second and third columns (TextViews) of the GridLayout to have equal width, and when there is a lot of text in the TextViews, I want the TextViews to expand vertically downwards instead of occupying more space. I am trying to achieve this by programmatically setting the column weight of the second and third TextViews to be 1. However, when there is lot of text in the second TextView for instance, the second and third TextViews just get pushed to the side. Below is a screenshot:
However, this is what I want my application to look like:
Below is my XML code:
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:rowCount="1"
android:columnCount="3">
<!-- Difference Table -->
<LinearLayout
android:orientation="vertical"
android:id="#+id/difference_table"
android:layout_width="match_parent"
android:layout_column="0"
android:layout_row="0"
android:layout_columnWeight="1"
android:layout_height="wrap_content"></LinearLayout>
</GridLayout>
Below is my Kotlin code:
val diffLayout = findViewById<LinearLayout>(R.id.difference_table)
var diffTable: GridLayout = GridLayout(this)
// Set the dimensions of the grid
diffTable.layoutParams =
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
diffTable.columnCount = 3;
diffTable.rowCount = 1;
// Create the three columns and add them to the grid
var lineNumber: TextView = TextView(this)
lineNumber.text = "asdf"
lineNumber.setTextColor(Color.parseColor("#000000"))
lineNumber.gravity = Gravity.LEFT
var currentLine1: TextView = TextView(this)
currentLine1.setTextColor(Color.parseColor("#000000"))
currentLine1.text = "asdfasdfasdfadfasdfadfasdfasdfasdfasdfasdfasdf"
lineNumber.gravity = Gravity.LEFT
// 3. Create the TextView representing the current line in Text 2
var currentLine2: TextView = TextView(this)
currentLine2.setTextColor(Color.parseColor("#000000"))
currentLine2.text = "asdfasdfasdfadfasdfadfasdfasdfasdfasdfasdfasdf"
lineNumber.gravity = Gravity.LEFT
// TODO: ENABLE LAYOUT WEIGHT FOR API < 21
diffTable.addView(lineNumber, GridLayout.LayoutParams(
GridLayout.spec(0, GridLayout.CENTER),
GridLayout.spec(0, GridLayout.CENTER, 0.0f)));
// Add the current line in Text 1 to the table
diffTable.addView(currentLine1, GridLayout.LayoutParams(
GridLayout.spec(0, GridLayout.CENTER),
GridLayout.spec(1, GridLayout.CENTER, 1.0f)));
// Add the current line in Text 2 to the table
diffTable.addView(currentLine2, GridLayout.LayoutParams(
GridLayout.spec(0, GridLayout.CENTER),
GridLayout.spec(2, GridLayout.CENTER, 1.0f)));
1) There should be something wrong with flag on extending GridLayouts.
Your both Views inside GridLayout should have weight for vertical and horizontal axis. Try to setup this params for your first and second Views above.
final GridLayout.LayoutParams params = new GridLayout.LayoutParams(GridLayout.spec(
GridLayout.UNDEFINED,GridLayout.FILL,1f),
GridLayout.spec(GridLayout.UNDEFINED,GridLayout.FILL,1f));
2) As an alternative and simple solution, you could replace your both Views above with single LinearLayout container, which could handle weight by it's own. Something like this.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="true"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/view.line.1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<TextView]
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
<LinearLayout
android:id="#+id/view.line.2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<TextView]
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
<LinearLayout>
I modified a bit in your previous code and added the width = 0property, which may achieve the display effect you want
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// setContentView(R.layout.activity_main)
// val diffLayout = findViewById<LinearLayout>(R.id.difference_table)
// val diffTable = findViewById<GridLayout>(R.id.grid_layout);
var diffTable: GridLayout = GridLayout(this)
// Set the dimensions of the grid
diffTable.layoutParams =
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
diffTable.columnCount = 3
diffTable.rowCount = 1
// Create the three columns and add them to the grid
var lineNumber: TextView = TextView(this)
lineNumber.text = "asdf"
lineNumber.setTextColor(Color.parseColor("#000000"))
lineNumber.gravity = Gravity.LEFT
var currentLine1: TextView = TextView(this)
currentLine1.setTextColor(Color.parseColor("#000000"))
currentLine1.text = "asdfasdfasdfadfasdfadfasdfasdfasdfasdfasdfasdf"
lineNumber.gravity = Gravity.CENTER
// 3. Create the TextView representing the current line in Text 2
var currentLine2: TextView = TextView(this)
currentLine2.setTextColor(Color.parseColor("#000000"))
currentLine2.text = "asdfasdfasdfadfasdfadfasdfasdfasdfasdfasdfasdf"
lineNumber.gravity = Gravity.CENTER
var layoutParams = GridLayout.LayoutParams()
layoutParams.rowSpec = GridLayout.spec(0, GridLayout.FILL)
layoutParams.columnSpec = GridLayout.spec(0, GridLayout.FILL)
// TODO: ENABLE LAYOUT WEIGHT FOR API < 21
diffTable.addView(lineNumber, layoutParams)
var layoutParams1 = GridLayout.LayoutParams()
layoutParams1.rowSpec = GridLayout.spec(0, GridLayout.FILL)
layoutParams1.columnSpec = GridLayout.spec(1, GridLayout.FILL, 1f)
layoutParams1.width = 0
// Add the current line in Text 1 to the table
diffTable.addView(currentLine1, layoutParams1)
// Add the current line in Text 2 to the tableLEFT
var layoutParams2 = GridLayout.LayoutParams()
layoutParams2.rowSpec = GridLayout.spec(0, GridLayout.FILL)
layoutParams2.columnSpec = GridLayout.spec(2, GridLayout.FILL, 1f)
layoutParams2.width = 0
diffTable.addView(currentLine2, layoutParams2)
addContentView(diffTable, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT))
}
My suggestion is to dynamically set the column width for the views. Finally it will align each view with required amount of space.
var diffTable: GridLayout = GridLayout(this)
diffTable.setAlignmentMode(GridLayout.ALIGN_BOUNDS);
diffTable.setColumnCount(3);
diffTable.setRowCount(1);
TextView lineNumber;
for (int i = 0; facilities != null && i < facilities.size(); i++) {
lineNumber = new TextView(getContext());
lineNumber.setText(facilities.get(i));
diffTable.addView(lineNumber, i);
lineNumber.setCompoundDrawablesWithIntrinsicBounds(rightIc, 0, 0, 0);
GridLayout.LayoutParams param =new GridLayout.LayoutParams();
param.height = LayoutParams.WRAP_CONTENT;
param.width = LayoutParams.WRAP_CONTENT;
param.rightMargin = 5;
param.topMargin = 5;
param.setGravity(Gravity.CENTER);
param.columnSpec = GridLayout.spec(c);
param.rowSpec = GridLayout.spec(r);
lineNumber.setLayoutParams (param);
}
Where c stands for 'column index' and r stands for row index of GridLayout.
Note: The above code may require a bit of change if you want to insert your parameters.
I have to do some animation in my application but i have a problem with textview.
I need to animate a textview and make it compare from right corner.
this is my layout:
<RelativeLayout
android:id="#+id/ThirdPartBottomLayout"
android:layout_width="2000dp"
android:layout_height="250dp"
android:layout_alignParentBottom="true"
android:background="#color/RedTA"
android:paddingTop="20dp"
android:paddingBottom="80dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/ThirdPartText1"
android:textSize="20dp"
android:textColor="#ffffff"
android:lines="1"
android:text="#string/Onboarding_Page3_Text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center" />
<TextView
android:id="#+id/ThirdPartText2"
android:textSize="16dp"
android:textColor="#ffffff"
android:layout_below="#+id/ThirdPartText1"
android:text="#string/Onboarding_Page3_Text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center" />
</RelativeLayout>
</RelativeLayout>
and this is where I inizialize variable:
int widhtR1 = 0;
if (ThirdPartText1.Width > WidthPixel - PixelsToDp(50))
widhtR1 = WidthPixel - PixelsToDp(50);
else
widhtR1 = ThirdPartText1.Width;
lp = new RelativeLayout.LayoutParams(widhtR1,
ThirdPartText1.Height);
lp.LeftMargin = WidthPixel;
ThirdPartText1LeftMargin = (WidthPixel - widhtR1) / 2;
ThirdPartText1.LayoutParameters = lp;
int widhtR2 = 0;
if (ThirdPartText2.Width > WidthPixel - PixelsToDp(50))
widhtR2 = WidthPixel - PixelsToDp(50);
else
widhtR2 = ThirdPartText2.Width;
lp = new RelativeLayout.LayoutParams(widhtR2,
ThirdPartText2.Height);
lp.LeftMargin = WidthPixel;
lp.TopMargin = PixelsToDp(10);
lp.AddRule(LayoutRules.Below, Resource.Id.ThirdPartText1);
ThirdPartText2LeftMargin = (WidthPixel - widhtR2) / 2;
ThirdPartText2.LayoutParameters = lp;
To animate i use a ValueAnimator that move LeftMargin from WidhtPixel to the minium left margin of textview.
And I do with this code.
ThirdPartText1Animator = ValueAnimator.OfInt(1);
ThirdPartText1Animator.SetDuration(
ThirdPartText1AnimatorDuration);
ThirdPartText1Animator.SetInterpolator(new
AccelerateDecelerateInterpolator());
var lpTxt1 =
(RelativeLayout.LayoutParams)ThirdPartText1.LayoutParameters;
ThirdPartText1Animator.Update += (sender, e) =>
{
int val = (int)e.Animation.AnimatedValue;
Console.WriteLine("VAL TXT1:" + val);
lpTxt1.LeftMargin = WidthPixel - (int)((WidthPixel -
ThirdPartText1LeftMargin) * (val / 100f));
ThirdPartText1.LayoutParameters = lpTxt1;
};
ThirdPartText2Animator = ValueAnimator.OfInt(1);
ThirdPartText2Animator.SetDuration(
ThirdPartText2AnimatorDuration);
ThirdPartText2Animator.SetInterpolator(new
LinearInterpolator());
var lpTxt2 =
(RelativeLayout.LayoutParams)ThirdPartText2.LayoutParameters;
ThirdPartText2Animator.Update += (sender, e) =>
{
int val = (int)e.Animation.AnimatedValue;
Console.WriteLine("VAL TXT2:" + val);
lpTxt2.LeftMargin = WidthPixel - (int)((WidthPixel -
ThirdPartText2LeftMargin) * (val / 100f));
ThirdPartText2.LayoutParameters = lpTxt2;
};
/*** START WITH ****/
ThirdPartText1Animator.SetIntValues(0, 100);
ThirdPartText1Animator.Start();
ThirdPartText2Animator.SetIntValues(0, 100);
ThirdPartText2Animator.Start();
And here comes the problem when the animation start, text view compare from right but text will move to fit the textview dimension on screen instead of stay blocked on textview real dimension.
How could I avoid to make text move inside a textview.
Hope my information is enough and sorry for my bad english.
EDIT
WidthPixel = Resources.DisplayMetrics.WidthPixels;
AccelerateDecelerateInterpolator is an Interpolator Android.Views.Animation
Full classes
OnboardingPage.cs
OnboardingPageLayout.axml
Thanks in advance.
Matteo.
For everyone have the same problem i figured out a solution.
In a first time i use left margin to make textview compare, so when application start i set left margin to width of screen and when i need to make it appear i reduce left margin.
It seems that if you change somethings of textview it been forced to redraw everythings so also widht and height change.
To avoid this problem I create a layout and put textview inside it and use the same trick of left margin to layout instead on textview and everythings work.
Sorry for my bad english.
Hope that should be helpful for someone.
I have the following structure within a view hierarchy
ScrollView
LinearLayout (horizontal)
- RelativeLayout (X)
-LinearLayout
-CustomView
- RelativeLayout
- RelativeLayout
- RelativeLayout
- RelativeLayout
- RelativeLayout
Here is a sample of it in the xml
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:id="#+id/linLayoutWrapper"
android:layout_width="match_parent"
android:layout_height="1080dp"
android:background="#color/white">
<!--- note this include is a <RelativeLayout> -->
<include
android:id="#+id/dg_axis"
layout="#layout/day_grid_axis"></include>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#color/grayBorder"></View>
<--- start of repetitive substructure which his higlighted in screen shot -->
<RelativeLayout
android:id="#+id/sundayColumn"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="1080dp">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
</LinearLayout>
<com.mynursesstation.views.DayView
android:id="#+id/sundayDayView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="#color/grayBorder"></View>
<!--- repeat above sub structure 6 more times --->
</LinearLayout>
</ScrollView>
where the inner structure (X) is repeated for all other RelativeLayout siblings. The Linear Layout, RelativeLayouts
NOTE: (X) is shown highlighted in its unusual behavior in Red, where as its parent is the entire screen width and is delimited with the grey vertical line above it.
The RelativeLayouts would all be flush to the top of the Linear Layout if all of them were the same size (That is my experimental opinion which has yet to be proved). If one is bigger than the rest, then they by default align to the bottom. My question is, how can These children of the RelativeLayout's exceed their parent when they are defined by the parent? Could it be that I am programmatically creating views whose intrinsic heights exceed the height of their parents? What is android's official handling of this case? Does the view overflow like an HTML DOM element?
UPDATE:
On inspecting each RelativeLayout, my hypothesis that one of them exceeded 3240pixels was wrong. None of them do. Only there seems to be a top margin applied to some (Which would theoretically increase the height of its parent, being wrap_content) but it does not.
The definition of the RelativeLayout called CustomView, is a RelativeLayout within which are programmatically positioned relativelayouts. They are positioned within their parent as follows:
int pixels = (int) (height * scale + 0.5f);
pixels = (pixels + 4) / 5 * 5;
relativeLayout.setLayoutParams(new RelativeLayout.LayoutParams(
columnWidth / maxConflicts,
pixels));
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) relativeLayout.getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params.addRule(RelativeLayout.ALIGN_PARENT_START);
start = cal2.get(Calendar.HOUR_OF_DAY);
height = start > 0 ? start * 44.000000000f + (start - 1) : start * 44.00000000f;
height += cal2.get(Calendar.MINUTE) / 60.00000000000f;
pixels = (int) (height * scale + 0.5f);
if (offsetAmount != null){
params.setMargins( (columnWidth / maxConflicts) * offsetAmount, pixels, 0, 0);
} else {
params.setMargins(0, pixels, 0, 0);
}
relativeLayout.setLayoutParams(params);
However there is never a case where the top margin of the relativeLayout above plus the height of the of the relativeLayout exceeds 1080dp. I verify this dynamically by logging the height of the CustomView DayView with the following code:
columnHeight = MeasureSpec.getSize(heightMeasureSpec);
which always logs out as 3240 pixels which at a scale of 3 is exactly 1080dp.
So this eliminates the possibility that one of the DayView exceeds 1080 and that is why not all the children of the top level LinearLayout are not flush to its top. However, I still cannot comprehend what could be causing this behavior. All elements programmatically added to the DayView are alignTop to their parent and are positioned with a vertically margin which, with the height of the view being programmatically added` never exceeds 1080dp.
Notice that the red views have a mysterious mTop added even though their dynamic height is 1080dp. mTop + 1080dp > 1080dp yet there parent is 1080dp (it is wrap_content) !
Take a good look at the view which is flush. It also has the same height but has a zero mTop. I don't understand why this is or how can be possible.
enter image description here
UPDATE Saturday:
Good News! i have narrowed down the problem to a subview of a subview, which when omitted, does not cause this strange inconsistency in my layout logic / intention. The culprit is a <TextView> which is programmatically added to the two types of events which are programmatically added <RelativeLayout>s added to DayView. when both types of views have textviews added as subviews it breaks the view hierarchy. When only one is present, the views present as intended. Here is the code for programmatically laying out the calendar events the entirety of which consist of all the subviews of a DayView:
private void createEventLayout(CalendarEvent e, Integer offsetAmount, int maxConflicts) {
final float scale = getContext().getResources().getDisplayMetrics().density;
int idForMyView = e.assignmentId > 0 ? e.assignmentId : -e.conflictId;
RelativeLayout relativeLayout = new RelativeLayout(getContext());
relativeLayout.setId(idForMyView);
Calendar cal2 = Calendar.getInstance();
cal2.setTimeZone(TimeZone.getTimeZone("UTC"));
cal2.setTime(e.startDate);
Calendar cal3 = Calendar.getInstance();
cal3.setTimeZone(TimeZone.getTimeZone("UTC"));
cal3.setTime(e.endDate);
float start = cal2.get(Calendar.HOUR_OF_DAY);
start += cal2.get(Calendar.MINUTE) / 60.0000000f;
float end = cal3.get(Calendar.HOUR_OF_DAY);
end += cal3.get(Calendar.MINUTE) / 60.00000000f;
float height = (end - start) * 45.0000000f;
int pixels = (int) (height * scale + 0.5f);
pixels = (pixels + 4) / 5 * 5;
relativeLayout.setLayoutParams(new RelativeLayout.LayoutParams(
columnWidth / maxConflicts,
pixels));
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) relativeLayout.getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params.addRule(RelativeLayout.ALIGN_PARENT_START);
start = cal2.get(Calendar.HOUR_OF_DAY);
height = start > 0 ? start * 44.000000000f + (start - 1) : start * 44.00000000f;
height += cal2.get(Calendar.MINUTE) / 60.00000000000f;
pixels = (int) (height * scale + 0.5f);
if (offsetAmount != null){
params.setMargins( (columnWidth / maxConflicts) * offsetAmount, pixels, 0, 0);
} else {
params.setMargins(0, pixels, 0, 0);
}
relativeLayout.setLayoutParams(params);
if (e.assignmentId > 0){
// company name
TextView tv = new TextView(getContext());
tv.setId(idForMyView);
tv.setText(e.companyName);
LayoutParams tvParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
tvParams.setMargins(0,0,0,0);
tv.setLayoutParams(tvParams);
RelativeLayout.LayoutParams companyNameParams = (RelativeLayout.LayoutParams) tv.getLayoutParams();
tv.setTextColor(Color.parseColor("#ffffff"));
tv.setTypeface(null, Typeface.BOLD);
companyNameParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
//time of assignment / conflict
TextView tvTime = new TextView(getContext());
tvTime.setTextColor(Color.parseColor("#ffffff"));
SimpleDateFormat sdf = new SimpleDateFormat("h:mm a");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String startTime = sdf.format(e.startDate);
String endTime = sdf.format(e.endDate);
tvTime.setText(startTime + " - " + endTime);
tvTime.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
RelativeLayout.LayoutParams timeParams = (RelativeLayout.LayoutParams) tvTime.getLayoutParams();
timeParams.addRule(RelativeLayout.BELOW, idForMyView);
relativeLayout.addView(tv); // ALSO this will break if present with the other kind
relativeLayout.addView(tvTime); // this too
relativeLayout.setBackground(ContextCompat.getDrawable(getContext(), R.drawable.gradient_background_home));
relativeLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final int assignmentId = view.getId();
if (assignmentId > 0) {
Intent intent = new Intent(getContext(), AssignmentDetailActivity.class);
intent.putExtra(getContext().getString(R.string.extra_assignment_id), assignmentId);
getContext().startActivity(intent);
}
}
});
} else {
final CalendarEvent event = e;
relativeLayout.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.conflict));
if (isConflictMode && e.isAllDay == 1){
TextView tv = new TextView(getContext());
tv.setId(idForMyView);
tv.setText(ALL_DAY_TEXT);
LayoutParams tvParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
tvParams.setMargins(0,0,0,0);
tv.setLayoutParams(tvParams);
RelativeLayout.LayoutParams companyNameParams = (RelativeLayout.LayoutParams) tv.getLayoutParams();
tv.setTextColor(Color.parseColor("#ffffff"));
tv.setTypeface(null, Typeface.BOLD);
companyNameParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.calendar_small_font));
relativeLayout.addView(tv); //THIS will break the layout logic
}
}
this.addView(relativeLayout);
return;
}
I tried making sure the <TextView> is clipped by its parent by setting
tv.setGravity(Gravity.CLIP_HORIZONTAL | Gravity.CLIP_VERTICAL)
when I inspect it in the view it appears that it is clipping exactly to the bounds of the tv, yet, something seems to be exceeding the height of its parent based on the fact that when the <TextViews> are gone everything addes up, but when they are present, there seems to be too much vertical content.
So my problem was that i was assigning the same id to the <RelativeLayout> which was the particular CalendarEvent as well as to the children of this view, the <TextViews>. This created circular logic which referred to the parent and child which caused the views to not properly by aligned, I think specifically with the BELOW requirement of one of the textViews, being essentially made to be below itself. By creating a unique id with View.generateId() each time I created a <TextView> then the intended layout was made possible.
I'm stuck on a strange little problem.
The goal with this activity is to display two texts, one is the original the second the answer text. The answer text contains errors and the user has to find and mark those errors.
The solution we came up with is to split the text into its words and display each word as its own in a TextView. All these TextViews are created dynamically at runtime, because there are many different texts to display.
There are two instances, where we need a 'line break': a) the text contains a linebreak () and b) the width of the display wouldn't fit any more text.
This solution works most of the time but each text has 2-4 words, which don't fit the line width and are therefore broken up into multiple lines visually.
Here's the code:
String[] questionSplit = exercise.exerciseQuestion.split(" ");
ids = new Integer[questionSplit.length];
int displayWidth = getResources().getDisplayMetrics().widthPixels;
int currentLineWidth = 0;
Integer lastIdInRow = 0;
int counter = 0;
for(String bit : questionSplit) {
TextView tv = new TextView(this);
tv.setId(generateViewId());
ids[counter] = tv.getId();
//Exception for <br>
if(bit.equals("<br>")) {
lastIdInRow = ids[counter - 1];
currentLineWidth = 0;
} else {
tv.setText(bit);
tv.setPadding(dpToPx(3), dpToPx(3), dpToPx(2), dpToPx(2));
tv.measure(0, 0);
currentLineWidth += tv.getMeasuredWidth();
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
if(currentLineWidth <= displayWidth && counter == 0) {
// move along, nothing to see here
} else if(currentLineWidth <= displayWidth && counter != 0) {
p.addRule(RelativeLayout.RIGHT_OF, ids[counter - 1]);
} else {
lastIdInRow = ids[counter - 1];
currentLineWidth = 0;
}
if(lastIdInRow != 0 && lastIdInRow != tv.getId()) {
p.addRule(RelativeLayout.BELOW, lastIdInRow);
}
rlTextComparisonOriginal.addView(tv,p);
}
counter++;
}
To explain the layout rules of the TextViews: if the measuredWidth fits into the line, a RIGHT_OF the last id rule is added. If it would overflow, a BELOW the last id in the line rule is added.
As I mentioned earlier, for most of the text that works perfectly. But there are some words which do not fit. If I change the displayWidth to be only 80% of the display width, the error persists just the word changes, so I think it's not the specific text / word.
And here is the relevant part of the view's xml
<ScrollView
android:id="#+id/svTextComparisonDesc"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/tvTextComparisonHeaderMiddle"
android:paddingBottom="55dp"
>
<RelativeLayout
android:id="#+id/rlTextComparison"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tvTextComparisonDescription"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="#color/text_background"
android:padding="10dp"
android:text="#string/text_exercise_desription"
android:textSize="#dimen/activity_text_description_size"
android:scrollHorizontally="false"
/>
<RelativeLayout
android:id="#+id/rlTextComparisonOriginal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#color/text_background"
android:layout_below="#id/tvTextComparisonDescription"
/>
<RelativeLayout
android:id="#+id/rlTextComparisonAnswer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/rlTextComparisonOriginal"
/>
</RelativeLayout>
</ScrollView>
The last bit of information: right now the code above resides in the activity's onCreate Method. If I log the measuredWidth and displayWidth and currentWidth, the logic isn't broken, the measuredWidth fits into the line, but after rendering, it doesn't.
Any ideas what the problem actually might be? Thanks in advance!
After using the mentioned lib the code is much cleaner and looks like this:
//Exception for <br>
if(bit.equals("<br>")) {
FlowLayout.LayoutParams lp = new FlowLayout.LayoutParams(0,0);
lp.setNewLine(true);
flTextComparisonOriginal.addView(tv,lp);
} else {
tv.setText(bit);
tv.setPadding(dpToPx(3), dpToPx(3), dpToPx(2), dpToPx(2));
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
flTextComparisonOriginal.addView(tv, p);
}
In case using a library is acceptable instead of coding it yourself, you will find two projects on github under the keyword "FlowLayout". These sound like they solve the layout you need:
https://github.com/ApmeM/android-flowlayout
https://github.com/blazsolar/FlowLayout
To get width and height of the text view,
Rect bounds = new Rect();
Paint textPaint = textView.getPaint();
textPaint.getTextBounds(text,0,text.length(),bounds);
int height = bounds.height();
int width = bounds.width();
I would like to add some buttons with equal width into table layout dynamically. I've already tried everything from StackOverflow, but I cann't find a right solution.
This is my initial XML-layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#color/puzzle_background"
android:orientation="vertical"
android:layout_height="fill_parent"
android:layout_width="match_parent"
android:layout_gravity="center">
<TextView
android:text="#string/levels_label"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dip"
android:layout_marginBottom="10dip"
android:textSize="28sp" />
<TableLayout
android:id="#+id/displayLevels"
android:background="#color/puzzle_background"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical" >
</TableLayout>
</LinearLayout>
This is my code part:
int i = 0;
int j = 0;
while (i<levelNum) {
j = i + 4;
row = new TableRow(this);
TableRow.LayoutParams lp = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT);
row.setLayoutParams(lp);
row.setWeightSum(4);
while ((i<j)&&(i<levelNum)) {
Button iBtn = new Button(this);
iBtn.setGravity(Gravity.CENTER_HORIZONTAL);
iBtn.setText(Integer.toString(i + 1));
iBtn.setId(i + 1);
iBtn.setOnClickListener(btnclick);
row.addView(iBtn, 4 + i - j);
i++;
}
lTable.addView(row);
}
But every time I get 4 buttons in the row which don't really fit into the row. The right button in the row is always out of the screen.
What am I doing wrong? Please advice.
With best regards, Alex
I will propose you another way, you could get witdh of your screen by code:
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int width1 = displaymetrics.widthPixels;
and next set width of your button by this:
iBtn.getLayoutParams().width = width1;
or you could else set max width of your button by similar function.
I hope this could help.
after some try, I have solution:
First, your logic has some problem, two while loops equal to one while loop. It confused me.
Second, Button in android has default minimunWidth, so if you setWidth of button less than default value, it will set width with default value.
Third, I use gravity.CENTER is to have all buttons in CENTER.
ok, that is my explain. the following is my code:
TableLayout displayLevels = (TableLayout)findViewById(R.id.displayLevels);
final int screenWidth = dpToPx(getResources().getConfiguration().screenWidthDp);
int i = 0;
int j = 0;
int levelNum = 8;
TableRow row = new TableRow(this);
TableRow.LayoutParams lp = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT);
row.setLayoutParams(lp);
row.setGravity(Gravity.CENTER);
int width = (screenWidth - (levelNum)*4)/levelNum;//4: I don't remember name of it. It is default value.4dp or 4px... I don't remember exactly
displayLevels.addView(row);
while (i<levelNum) {
Button iBtn = new Button(this);
iBtn.setGravity(Gravity.CENTER_HORIZONTAL);
iBtn.setMinimumWidth(100);//I set 100px for minimunWidth.
iBtn.setWidth(width);
iBtn.setText(Integer.toString(i + 1));
iBtn.setId(i + 1);
//iBtn.setOnClickListener(btnclick);
row.addView(iBtn, i);
i++;
}
with:
private int dpToPx(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}