Android: Nested Linearlayouts will not display a grid of buttons, Matching parent - java

I have an app under construction. In one of the sub-menus I have a need for generic display of buttons, and therefor I want to make an activity that can display the given number of needed buttons.
I have succesfully made this happen, programmatically, but I want the total grid of buttons to fill up the entire parent they are placed in, which happens to be 3/4 of a landscape screen. The number of buttons varies from 16-38.!
I have also succesfully made this happen with other grids of buttons, in xml, with weight values, and match_parent values of entries.
When I assign buttons or rows the match_parent value programatically, it occupies the entire parent layout, not sharing it like i expect it to do, even though they have the same weight value of 1.0f
The relevant code follows below. I would like to post images as well, but I have not the reputation to do so.
`LinearLayout layout = (LinearLayout) findViewById(R.id.linear_custom_draw);
layout.setOrientation(LinearLayout.VERTICAL);
int columns = Math.min(6, 4+category); //sets number of buttons per row to 4-6
for (int i = 0; i < 4+category; i++) {
LinearLayout row = new LinearLayout(this);
row.setLayoutParams(new android.view.ViewGroup.LayoutParams(android.view.WindowManager.LayoutParams.MATCH_PARENT,
android.view.WindowManager.LayoutParams.MATCH_PARENT));
//the line above is the line that fills up the entirety of the linearlayout, even though there are more entries, unlike my xml-defined attempts.
row.setOrientation(LinearLayout.HORIZONTAL);
row.setWeightSum(1.0f);
if(i%2 == 0){
row.setBackgroundColor(getResources().getColor(R.color.listview_red_backgr_color));
}
for (int j = 0; j < columns; j++) {
int index = (i*columns)+j;
if(formations.size() > index){
Button btnTag = new Button(this);
btnTag.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
btnTag.setText(formations.get(index).getName());
btnTag.setTextColor(getResources().getColor(R.color.black_overlay));
btnTag.setId(formations.get(index).getId());
row.addView(btnTag);
}
}
layout.addView(row);`

Try to use TableLayout. Each Row will enforce the entire elements to match the parent with the same wights. You can control number of Buttons into each Row programatically with counter. Loop for end of Counter adding your buttons then add new Table Row
TableLayout tbl=new TableLayout(context);//create table
TableRow tr=new TableRow(context);//create table row
tr.addView(view);//add your button instead of the view
tbl.addView(tr);//add the row into the Table
In the XML file
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/keypad"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:stretchColumns="*">
<TableRow>
<Button android:id="#+id/keypad_1" android:text="#string/_1"></Button>
<Button android:id="#+id/keypad_2" android:text="#string/_2"></Button>
<Button android:id="#+id/keypad_3" android:text="#string/_3"></Button>
</TableRow>
</TableLayout>

Related

How can I programmatically generate textviews inside layout

I need to generate TextView inside a layout from a random, API generated, ArrayList. I cant seem to find a way in which they appear in one line, like a String, one after the other and also shift below once the line has reached the max layout width limit. I want each TextView to be sperate as I want to click them.
Would like to achieve something like this...
This is the current code but the line stops and I don't know how to shift it below. Currently I am using a relative layout as the base layout but it is not necessary.
for (int i = 0; i < abc.size(); i++) {
titleText = new TextView(this);
titleText.setId(i);
titleText.setText(abc.get(i));
relativeLayout.addView(titleText, i);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(10, 10, 10, 10);
layoutParams.addRule(RelativeLayout.RIGHT_OF, titleText.getId() - 1);
titleText.setLayoutParams(layoutParams);
titleText.setTextColor(getResources().getColor(R.color.teal_700));
tvArray.add(titleText);
}
Example
In your xml
<LinearLayout
android:id="#+id/my_ll"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
</LinearLayout>
And write code in yourjava.class
LinearLayout my_ll = (LinearLayout) findViewById(R.id.my_ll);
for(int i=0;i<your_number_of_textviews;i++)
{
TextView text = new TextView(this);
text.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
text.setText(""+i);
my_ll.addView(text);
}
I think this solution would have solved it. First before the loop retrieve somewhere the width of the screen by using -
Point screenSizePoint = new Point();
// this gives you the furthest point from 0,0 e.g. 1440x3168
getWindowManager().getDefaultDisplay().getSize(screenSizePoint);
int sum = 0;
Then you retrieve your abc list somewhere.
And then you always compute the width of the current TextView by using this
titleText.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int width = titleText.getMeasuredWidth();
sum += width;
if (sum >= screenSizePoint.x) {
// shift to next line
}
and sum it up with the width of text views placed before and if the width is bigger than the screen width you just begin on another line.

How to set random TextView's position inside linear layout?

I have a linearlayout on xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rootlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
And I add dynamic 100 textviews inside it by code below:
llayout = (LinearLayout) findViewById(R.id.rootlayout);
for (int i = 0; i < 100; i++) {
TextView tv = new TextView(this);
tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
int randomInt = new Random().nextInt(100) +1 ;
tv.setText(""+randomInt);
llayout.addView(tv);
}
The result is 100 textviews added and display vertically. This is not as my expect. I want these textviews display with random position inside the layout look like the image below:
How to do it? Thank you!
LinearLayout is for layouting its children linearly (as the name suggests).
As there is no RandomLayout, you can use a RelativeLayout with random left and top layout margins, or an AbsoluteLayout and set random x and y.
Edit: Avoid overlapping texts
Random positions can of course lead to overlapping and it would be up to you to adjust the positions or ignore positions too similar to previous ones. Or you might actually compare the bounding boxes (left, top, width, height) of the view you're about to add to all other views in the container and if there is any overlapping, find another place for it.
You can use tv.setX(position) and tv.setY(position) for show view on specific position

TableLayout - Remove space between columns

I'm having a problem with the TableLayout.
First, take a look at the screenshot:
As you can see, there is a pretty big space in the middle of the TableLayout.
I don't know how to reduce the space in the middle, so that the TableRows will have more Width to cover.
And also, I want to reduce the space between a TableRow and the one below it.
I'm adding the views to the TableLayout programmatically.
Also, I've already set the 'layout_weight' of the content of the TableRow to 1f:
TableRow tr = (TableRow) new TableRow(mTableLayout.getContext());
TableRow.LayoutParams params = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT);
NormalCard card = new NormalCard();
card.setLayoutParams(new TableRow.LayoutParams(0, 740, 1f));
tr.addView(card);
mTableLayout.addView(tr, params);
XML declaration of the TableLayout:
<TableLayout
android:id="#+id/tableLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:shrinkColumns="*"
android:stretchColumns="*"
android:dividerPadding="0dp"
android:showDividers="none"
android:divider="#null">
</TableLayout>
How do I reduce the space in the middle of the TableLayout.
And also, How to reduce the space between a TableRow and the one below it.
Thank you upfront.
Please specify your table layout xml file you have just shown images.
try this if it works
android:shrinkColumns="*"
android:stretchColumns="*"
in your TableLayout tag.
okay try to set padding as 0 to your table row if no of column in each row is same then specify table width as wrap_content.
Have a try with this:
params.setMargins(0, 0, 0, 0);

How to Use ClickableSpans in a TextView and still be able to scroll horizontally?

I have some code which uses a textview with a linkmovementmethod so that individual words can be clicked.
However, what I really need is a scrollingmovementmethod. When I do that, the individual spanned segments are no longer clickable.
Unfortunately this means it uses a vertical scroll, even though horizontal scroll ( android:scrollHorizontally="true") is specified.
I'm trying to figure out how to retain the ability to catch onClick on the individual span words, and still allow it to be vertically scrollable.
Can someone provide advice on how to get the best of both worlds?
String page = getPage();
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(page, BufferType.SPANNABLE);
Spannable ssPage = (Spannable) textView.getText();
Integer[] indices = getSpaceIndices(textView.getText().toString(), ' ');
int start = 0;
int end = 0;
// to cater last/only word loop will run equal to the length of indices.length
for (int i = 0; i <= indices.length; i++) {
ClickableSpan clickSpan = new ClickableSpan() {
#Override
public void onClick(View widget) {
TextView tv = (TextView) widget;
String s = tv
.getText()
.subSequence(tv.getSelectionStart(),
tv.getSelectionEnd()).toString();
Log.d("called", s);
Speak (s);
//textView.scrollBy(tv.getWidth(), tv.getHeight());
}
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
};
// to cater last/only word
end = (i < indices.length ? indices[i] : ssPage.length());
ssPage.setSpan(clickSpan, start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = end + 1;
}
Layout:
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:alpha="245"
android:ellipsize="end"
android:gravity="top"
android:paddingBottom="15dip"
android:scrollHorizontally="true"
android:scrollbars="horizontal"
android:text="#string/hello_world"
android:textColorLink="#android:color/black"
android:textSize="20dip"
tools:context=".ReadActivity" />
LinkMovementMethod already "traverses links in the text buffer and scrolls if necessary." so you can use it if you want both clickable links and scrollable views.
Then you have to adjust the textview's layout like this:
android:maxLines="3"
android:scrollbars="vertical"
By setting maxLines, the excess lines after it, will exceed the height, thus resulting in a scrollable textview.

Android - ScrollView with TextView auto scrolling

I have a TextView within a ScrollView, which currently scrolls to the bottom of the TextView.
The TextView is filled dynamically constantly updating (the TextView is essentially acting as an actions console).
However, the problem I am having is that when the dynamic text is added to the ScrollView, the user can scroll past the text into black space, which is increasing everytime more content is added to the TextView.
I have tried various different apporaches however none of these gave the right outcome. I cannot use maxLines or define height of the layouts as I need this to be dynamic for the various screen sizes, which the number of lines visible constantly changing.
I had also orginally done this progromatically, however this was crashing at random time and therefore would like to keep it in my layout (better usabilty), example code below:
final int scrollAmount = update.getLayout().getLineTop(update.getLineCount()) - update.getHeight();
if(scrollAmount > 0)
{
update.scrollTo(0, scrollAmount);
}
The code below is my current layout xml being used to automatically scroll my TextView to the bottom as content is added:
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/spacer2"
android:layout_below="#+id/spacer1"
android:fillViewport="true" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/battle_details"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="12dp"
android:layout_gravity="bottom" />
</LinearLayout>
</ScrollView>
EDIT - This is the code I am using to add text to my TextView:
private void CreateConsoleString()
{
TextView update = (TextView)findViewById(R.id.battle_details);
String ConsoleString = "";
// BattleConsole is an ArrayList<String>
for(int i = 0; i < BattleConsole.size(); i++)
{
ConsoleString += BattleConsole.get(i) + "\n";
}
update.setText(ConsoleString);
}
EDIT 2 - I add content to the BattleConsole like this:
BattleConsole.add("Some console text was added");
CreateConsoleString();
To sum up my only issue is the ScrollView and/or TextView is adding blank space to the bottom rather than stop the user from scrolling at the last line of text. Any help or guidence as to where I am going wrong would be much appreciated.
It looks like that when you call
BattleConsole.get(i)
it sometimes returns an empty String so you are just basically adding new lines to your TextView.
You can do this for example:
StringBuilder consoleString = new StringBuilder();
// I'm using a StringBuilder here to avoid creating a lot of `String` objects
for(String element : BattleConsole) {
// I'm assuming element is not null
if(!"".equals(element)) {
consoleString.append(element);
consoleString.append(System.getProperty("line.separator")); // I'm using a constant here.
}
}
update.setText(consoleString.toString());
If you could post the code of BattleConsole I could help you more.
As a footnote: it is encouraged to use camelCase in java. Only class names start with capital letters in java according to the convention.

Categories