android fill all screen by gridview - android

I have a gridview and make a custom adapter for fill it, user can set by spinner rows and columns of my grid. In each cell of grid I set a videoview.
So I need to set dinamically the size for each videoview in my custom Adapter in order to fill the remaining part of the screen. Following this I can do the task, I take display size and set layout for my view dividing by the number of rows and columns.
The problem is that principal layout has action-bar and a textview . So, windows size is not correct. I need to subtract action-bar and textview size.
I find a solution for know action-bar size, but when get height of my textview it is always 0.
As suggest here I should take textview size after rendering, but for render my gridview I need to know this size !!
There are other ways to do it ? It's necessary to manually calculate view size ??
this is my layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context="it.nexera.visiamobile.ViewLiveMultiActivity"
>
<TextView
android:id="#+id/txt_grid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#454545"
android:gravity="left"
android:text="#string/sel_grid" />
<Spinner
android:id="#+id/grid_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/gridview"
android:layout_toRightOf="#+id/txt_grid" />
<GridView
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchMode="columnWidth"
android:layout_below="#+id/txt_grid"
android:gravity="center"
/>
</RelativeLayout>
and this is my getView method for custom adapter :
// create a new VideoView for each item referenced by the Adapter
#SuppressLint("NewApi")
public View getView(int position, View convertView, ViewGroup parent) {
VideoView videoView;
if (convertView == null) { // if it's not recycled, initialize some attributes
videoView = new VideoView(mContext);
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int width=0;
int height=0;
if (android.os.Build.VERSION.SDK_INT >= 13){
Point size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
}
else{
width = display.getWidth();
height = display.getHeight();
}
// Calculate ActionBar height
TypedValue tv = new TypedValue();
int actionBarHeight=0;
if (mContext.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
{
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,mContext.getResources().getDisplayMetrics());
}
TextView textview = (TextView) ((Activity) mContext).findViewById (it.nexera.visiamobile.R.id.txt_grid);
int textview_height=textview.getHeight();
height=height-actionBarHeight-textview_height;
AbsListView.LayoutParams param = new AbsListView.LayoutParams(
(width/COL_NUMBER),
(height/ROW_NUMBER));
videoView.setLayoutParams(param);
Uri video = Uri.parse(mvideoSrc[position]);
videoView.setVideoURI(video);
videoView.start();
} else {
videoView = (VideoView) convertView;
}
return videoView;
}

Your problem is that you retrieve at the beginning the size of the whole screen of your device.
So ActionBar must be substracted, but any other views if your layout doesn't take all the remaining space. So your method contradicts android modularity, for example, if your view is used in different ways depending on the size of the device.
I think what you need instead is using ViewTreeObserver, like this :
final View myView = ... // The RelativeLayout that's declared as root of your layout file
myView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// You can here use View.getMeasuredWidth() or View.getMeasuredHeight() which correspond to the available space for the view containing your GridView and your TextView and then set your TextView's size
}
}
Edit : To make the gridview fill all remaining space you can instead use a LinearLayout, using its weight attribute :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="1"
tools:context="it.nexera.visiamobile.ViewLiveMultiActivity"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/txt_grid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#454545"
android:gravity="left"
android:text="#string/sel_grid" />
<Spinner
android:id="#+id/grid_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<GridView
android:id="#+id/gridview"
android:layout_width="0dp"
android:layout_height="0dp"
android:stretchMode="columnWidth"
android:gravity="center"
android:layout_weight="1"
/>
</LinearLayout>

Have you tried by adding a RelativeLayout under the Grid, and adding two hidden views on it, one in the topleft corner, and another one in the bottoright corner (1dip height/width, for example). Then, from code you can findViewById them, and call getLocationOnScreen. It's just the first dirty idea that came to my mind. That way you can get the exact size in pixels (or dpi) of the Grid.

Related

How to show image in table row based on size

Have 2x2 grid(Dynamic using TableLayout) need to show image on that. now based on image size, means-- if image fit for 1 cell means 1 cell,else big means 2 cells or 4 cells based on size( I know how many cells it will occupy)
i can show image in 1 cell, but problem is if image need 2 cells(1st column) how can show image in 2cell(With out disturbing the grid)
Without disturbing the grid, the workaround I see is to dynamically set image on top of your TableLayout.
Then you can archive this:
I've uploaded the code of the test project here;
You initialize overlappingImage and once you need to set image to your cell - you just add it to the layout and setting height and width params based on number of cells you want to fill.
TableLayout generates dynamically, the cell's layout xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<View
android:layout_margin="4dp"
android:background="#aacc00"
android:layout_height="40dp"
android:layout_width="40dp"/>
</FrameLayout>
The Activity's layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/container"
android:padding="16dp"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<TableLayout
android:id="#+id/tableLayout"
android:layout_width="match_parent"
android:layout_height="280dp"/>
<LinearLayout
android:id="#+id/buttonsLinearLayout"
android:layout_below="#+id/tableLayout"
android:layout_marginTop="16dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:text="1x1"
android:id="#+id/button11"
android:onClick="onClick11"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:text="4x1"
android:id="#+id/button21"
android:onClick="onClick41"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:text="2x3 at (2;2)"
android:id="#+id/button12"
android:onClick="onClick32"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:text="2x2"
android:id="#+id/button22"
android:onClick="onClick22"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
And the Activity code to handle button clicks & generates table:
public class MainActivity extends AppCompatActivity {
RelativeLayout container;
int cellWidth = 0, cellHeight = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
tableLayout.setStretchAllColumns(true);
for (int i = 0; i < 4; i++) {
TableRow tableRow = new TableRow(this);
for (int j = 0; j < 10; j++) {
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View cell = layoutInflater.inflate(R.layout.table_cell, null, false);
if (cellHeight == 0 ) {
cell.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
cellWidth = cell.getMeasuredWidth();
cellHeight = cell.getMeasuredHeight();
}
tableRow.addView(cell);
}
tableLayout.addView(tableRow);
}
container = (RelativeLayout)findViewById(R.id.container);
overlappingImage = new ImageView(this);
overlappingImage.setScaleType(ImageView.ScaleType.FIT_XY);
}
ImageView overlappingImage;
private void restoreTableLayout() {
container.removeView(overlappingImage);
}
public void onClick11(View view) {
restoreTableLayout();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth, cellHeight);
overlappingImage.setLayoutParams(params);
overlappingImage.setImageResource(R.drawable.horizontal_cat);
container.addView(overlappingImage);
}
public void onClick41(View view) {
restoreTableLayout();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth*4, cellHeight);
overlappingImage.setLayoutParams(params);
overlappingImage.setImageResource(R.drawable.horizontal_cat);
container.addView(overlappingImage);
}
public void onClick32(View view) {
restoreTableLayout();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth*3, cellHeight*2);
params.setMargins(cellWidth*2, cellHeight*2, 0 ,0);
overlappingImage.setLayoutParams(params);
overlappingImage.setImageResource(R.drawable.vertical_cat);
container.addView(overlappingImage);
}
public void onClick22(View view) {
restoreTableLayout();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(cellWidth*2, cellHeight*2);
overlappingImage.setLayoutParams(params);
overlappingImage.setImageResource(R.drawable.horizontal_cat);
container.addView(overlappingImage);
}
}
I hope, it helps.
Create separate layout files for rows that would need one cell and two cell as follows:
one_cell_table_row.xml (Notice the android:layout_span="2" for the ImageView
<?xml version="1.0" encoding="utf-8"?>
<TableRow
android:background="#drawable/bg_gray"
android:layout_marginTop="5dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/imgMyImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_span="2" />
</TableRow>
two_cell_table_row.xml (The TextView placed just as a placeholder for the second cell) (No layout_span required here as in the above layout)
<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/imgMyImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_weight="1"
android:text="..."
android:textColor="#767575"
android:id="#+id/txtJustAPlaceholder"
android:textSize="14dp" />
</TableRow>
Note: The id for the ImageView to be kept same in both layout for the java code below to work correctly.
The above is assuming your grid is 2x2. If your grid size is different create more layout for each kind of row you want and add extra conditions in the java code below.
Adding the TableRow with the right layout inflated:
Then programatically determine which layout needs to be inflated. Inflate the required layout for table row and add it to your table layout:
Following code is assuming that you are using a fragnemt. If you are doing directly in an activity replace code to work for Activity accordingly.
TableLayout table = (TableLayout) getView().findViewById(R.id.youtTableLayout);
if(<your image size needs two cells>) {
TableRow row = (TableRow) LayoutInflater.from(getActivity().getApplicationContext())
.inflate(R.layout.two_cell_table_row, null);
}
else if(<your image size needs one cell) {
TableRow row = (TableRow) LayoutInflater.from(getActivity().getApplicationContext())
.inflate(R.layout.one_cell_table_row, null);
}
...
...
// add more conditions and respective layouts as you need.
...
...
ImageView myImgView = (ImageView) row.findViewById(R.id.txtCrdSectionHeader);
// set the image for your image view here.
table.addView(row);
table.requestLayout();
Again, the above was assuming that your TableLayout has a 2x2 grid. If you plan to use a different one, update the layout files for TableRows we created above accordingly or set them dynamically using your java code.
You can calculate the image size and the screen size at runtime.Based on the calculations you can set the table properties at runtime. For example if the image is going to take two columns set the span property on that row programmatically.
I would suggest for your requirement you can consider creating the layout in code itself-rather than using any xml.
You can also have a look at Recycler view. It has more powerful ways to control the layout of the children. Have a look at this video-Mastering Recycler View -It is trying to do similar thing what you are looking for.

Put on the right the indicator of an ExpandableListView in Android

I have to move the indicator from the left to the right (because of the plane image). I couldn't succeed also because the expandableviewlist is inside a fragment and not inside a whole activity. Any idea? Thanks!
I don't know a way to do that from XML but i'll tell you a way to do so dynamically in your adapter.
First you have to remove group indicator from your xml
<ExpandableListView [...]
android:groupIndicator="#null" />
Then in your layout of the parent add an imageview in the right position of your layout.
Then in your custom adapter do the following
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
...
if (isExpanded) {
groupHolder.img.setImageResource(R.drawable.group_down);
} else {
groupHolder.img.setImageResource(R.drawable.group_up);
}
...
}
One more solution is:
1) First set groupIndicator in your ExpandableListView to #null:
<ExpandableListView [...]
android:groupIndicator="#null" />
2) Then create group_indicator.xml file with following details:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/down_icon" android:state_selected="false"></item>
<item android:drawable="#drawable/up_icon" android:state_selected="true"></item>
<item android:drawable="#drawable/down_icon"></item>
</selector>
3) Then create group_header.xml layout with following details and inflate this layout in getGroupView() method of ExpandableListAdapter.java:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<TextView
android:id="#+id/tvHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:textColor="#color/white"
android:layout_centerVertical="true"
android:textSize="16sp"/>
<ImageView
android:id="#+id/ivGroupIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/group_indicator"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"/>
</RelativeLayout>
3) In getGroupView() method of your ExpandableListAdapter.java class, just set the following:
ivGroupIndicator.setSelected(isExpanded);
With this approach, your down_icon and up_icon will work properly.
Hope this helps.
put this into your xml view:
<ExpandableListView
...
android:layoutDirection="rtl" />
than you can set the gravity of your text title in your layout item according your preference.
your text view parent list item:
<TextView
...
android:gravity="center"/>
eg. result:
another solution to put the indicator on the right programmatically:
expandableListView = (ExpandableListView) findViewById(R.id.expandableListView);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
Resources r = getResources();
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
50, r.getDisplayMetrics());
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
expandableListView.setIndicatorBounds(width - px, width);
} else {
expandableListView.setIndicatorBoundsRelative(width - px, width);
}
where expandableListView is your ExpandableListview
In your groupcustom.xml file you can use Relativelayout and put that image to
android:alignParentRight = "true";

How to find layout_marginTop

I have an XML file with the following attritubes:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/al_cs_layout1"
android:gravity="center_vertical">
<ImageView android:id="#+id/cs_track"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/fader_background5"
android:layout_marginLeft="0dp"
android:layout_marginTop="20dp" >
</ImageView>
...
and here is my java code:
public void initialize(Context context)
{
Log.d("initialize (MySeekBar)","initialize");
setWillNotDraw(false);
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view1 = inflater.inflate(R.layout.custom_seekbar, this);
layout1 = (RelativeLayout)view1.findViewById(R.id.al_cs_layout1);
track = (ImageView)layout1.findViewById(R.id.cs_track);
thumb = (ImageView)layout1.findViewById(R.id.cs_thumb);
...
I am working on a custom seekbar which determines the top by using a variable marginTop = 20; however this was oringally made on a phone much older by a different programmer. The 20 suppose to represent the margin top defined in the XML however it is using dp and not pixels. how can I find the marginTop attribute of R.id.cs_track? It works great on the old phone but on any phone does doesn't have the same screen size of dp it will create an undesired offset.
Use MarginLayoutParams to get value in pixels:
track = (ImageView)layout1.findViewById(R.id.cs_track);
MarginLayoutParams params = (MarginLayoutParams)track.getLayoutParams();
int marginTopPixelSize = params.topMargin;

Move two side by side textviews to be one under another if text is too long

I have two textviews like this:
=======================
= TextView1 TextView2 =
=======================
And I would like to detect when the textviews are too long such that they are displayed like this:
=======================
= TextView1 =
= TextView2 =
=======================
currently for longer text, it is displayed like this:
=======================
= TextView1 Text =
= View2 =
=======================
how can I do this, such that when the text is short the textviews are side by side and when it is too long, the second textview is not splitted but moved to the second line?
I tought at a solution to create a single textview and build the text according to length (text 1 + padding + text 2 if short, and text 1 + "\n" + text 2 if long) but I do not like this solution.
Is there any way to detect if the second text will be split such that to change the orientation of the layout that contains the textviews from horizontal cu vertical?
UPDATE
This is my xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<TextView
android:id="#+id/my_text_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:text="#string/text1"/>
<TextView
android:id="#+id/my_text_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="5dp"/>
</LinearLayout>
I have found a better solution. Changed my textviews into autoresizable textviews (more info here)
Also, each textview is in a separate layout, to make sure both textviews are resized to the same value.
My xml looks like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/value_linear_layout"
android:gravity="center">
<LinearLayout
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content">
<com.mihaela.view.AutoResizeTextView
android:id="#+id/my_text_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content">
<com.mihaela.view.AutoResizeTextView
android:id="#+id/my_text_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
and I have implemented the OnTextResizeListener from AutoResizeTextView to do this:
public class TextWidthResizeListener implements OnTextResizeListener {
#Override
public void onTextResize(TextView textView, float oldSize, float newSize) {
TextPaint paint = textView.getPaint();
if (paint.measureText(textView.getText().toString()) > (valueLinearLayout.getWidth() / 2)){
valueLinearLayout.setOrientation(LinearLayout.VERTICAL);
}
}
}
where valueLinearLayout is:
valueLinearLayout = (LinearLayout)findViewById(R.id.value_linear_layout);
This solution best fits for me, as the textviews are dimensioned when they are side by side until a minimum size. When the minimum size is reached, and the text still does not fit, the textviews will be aligned one under another.
Also, this idea with the listener can be applied to non-resizable textviews also.
I will set this answer as the correct one.
You should use a single, multi-line TextView and set the text as follows :
mTextView.setText(text1+" "+text2);
or
mTextView.setText(text1+"\n"+text2);
depending on your particular needs.
EDIT: you could specify your text in html, and then use Html.fromHtml(htmlString) and display this text in your TextView.
String text1 ="<font color=\"red\">This is some text!</font>"
String text2="<font color=\"blue\">This is some other text!</font>"
textView.setText(Html.fromHtml(text1+ "<br/>"+ text2);
I made a slightly different version of the accepted answer. I did not alter my layout xml in any way and did not use onTextResize() or AutoResizeTextView as that seemed an overkill for my situation. I needed my LinearLayout to switch from Horizontal orientation to Vertical orientation if the device's language setting caused a long string to be used.
Layout
<LinearLayout
android:id="#+id/customer_care_bottom_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:layout_marginBottom="#dimen/lmargin_bottom_10">
<TextView
android:id="#+id/customer_care_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/CUSTOMER_CARE_TITLE" />
<TextView
android:id="#+id/customer_care_number_information"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/CUSTOMER_CARE_INFORMATION"/>
</LinearLayout>
Java
private void setCustomerServiceLayoutOrientationBasedOnTextWidth() {
TextPaint paint = customer_care_number_text.getPaint();
TextView tvCustomerCareTitle = (TextView) findViewById(R.id.customer_care_title);
TextView tvCustomerCareInformation = (TextView) findViewById(R.id.customer_care_information);
int halfCustomerServiceLayoutWidth = getScreenWidth() / 2;
boolean isCustomerCareTitleTooLong = paint.measureText(tvCustomerCareTitle.getText().toString()) > customerServiceLayoutWidth;
boolean isCustomerCareInformationTooLong = paint.measureText(tvCustomerCareInformation.getText().toString) > customerServiceLayoutWidth;
if (isCustomerCareTitleTooLong || isCustomerCareInformationTooLong) {
LinearLayout llCustomerCareBottom = (LinearLayout) findViewById(R.id.customer_care_bottom_layout);
llCustomerCareBottom.setOrientation(LinearLayout.VERTICAL);
}
}
private int getScreenWidth() {
int screenWidth;Display display = getWindowManager().getDefaultDisplay();
if (Build.VERSION.SDK_INT < 13) {
screenWidth = display.getWidth();
} else {
Point point = new Point();
display.getSize(point);
screenWidth = point.x;
}
return screenWidth;
}

How do I calculate the required height of a GridView that is inside of a ScrollView on Android?

I have a GridView inside of a LinearLayout inside of a ScrollView that pages in data from the server. Beneath the GridView is a button to load more data. My GridView will have an ultimate height that is larger than the screen. If I set the height of my GridView to either wrap_content or parent_fill, it sizes itself to the exact available on-screen height and does not scroll at all, cropping out the extra rows. If I explicitly set the layout_height to something large, like 1000dip, scrolling behaves properly, however I cannot predict the final height of my scroll view apriori.
How do I programmatically determine the necessary height of a GridView to get the desired behaviour?
Here is my layout below. As you can see I set the height to 1000dip, but that is bogus, I need that value to get set automatically/programmatically:
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true"
android:layout_weight="1"
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid"
android:layout_width="fill_parent"
android:layout_height="1000dip"
android:columnWidth="70dp"
android:numColumns="auto_fit"
android:verticalSpacing="0dp"
android:horizontalSpacing="0dp"
android:stretchMode="columnWidth"
android:gravity="center"
android:background="#000000"
android:layout_weight="1"
/>
<Button
android:id="#+id/load_more"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Load More Foo"
/>
</LinearLayout>
</ScrollView>
Here is one way to do this, if someone needs it. A bit of a hack but does the trick. You have to set GridView initially big enough for all the views (e.g. 10000dip)
final GridView imageContainer = // your GridView
imageContainer.getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
imageContainer.getViewTreeObserver().removeGlobalOnLayoutListener( this );
View lastChild = imageContainer.getChildAt( imageContainer.getChildCount() - 1 );
imageContainer.setLayoutParams( new LinearLayout.LayoutParams( LayoutParams.FILL_PARENT, lastChild.getBottom() ) );
}
});
I know it's an old case, but I had a similar problem where my ScrollView contained multiple LinearLayouts, which in their turn contained a header and a GridView.
Basically I made categorised sections with headers containing images belonging to that category.
The GridView had to have a flexible height.
I found a lot of answers about overriding onMeasure(), but it worked only on some devices, not all. The height would eventually be 1, or 3 or just 0, displaying only a few pixels of the image.
StretchingGridView class
I overrode the drawableStateChanged() method with this code, inspired by #Karitsa's solution:
#Override
public void drawableStateChanged() {
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
getViewTreeObserver().removeOnGlobalLayoutListener( this );
View lastChild = getChildAt( getChildCount() - 1 );
if (lastChild != null) {
int height = Math.max(lastChild.getBottom(), getColumnWidth());
float child = getAdapter().getCount();
float col = getNumColumns();
int rows = (int) Math.ceil(child / col);
height = rows * getColumnWidth() + (getHorizontalSpacing() * rows-1);
setLayoutParams( new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, height ) );
}
}
});
}
Note: My GridView uses square images, so I base the height on their width. I don't think it works well with flexible grid item heights.
Apparently GridViews inside ScrollViews are not kosher in Android-land. Switching to ListView with custom-made rows. That seems to behave better.

Categories

Resources