How can I catch that View become visible - android

I inflate Views on ScrollView.
And I need to get event, when on scrolling one of this Views (last, for example, or special type) becomes visible (in screen zone).

If a view changes visibility, the onlayout method is called, you could try overwriting that method and check it's state.

You need to override the view's onVisibilityChanged(). This is also called when one of the view's ancestors changes visibility.

This I inflated my GridView and get what you want
public class MyGrideView extends GridView {
boolean expanded = false;
public MyGrideView(Context context) {
super(context);
}
public MyGrideView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyGrideView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// HACK! TAKE THAT ANDROID!
if (isExpanded()) {
// Calculate entire height by providing a very large height hint.
// But do not use the highest 2 bits of this integer; those are
// reserved for the MeasureSpec mode.
int expandSpec = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
}

Related

RecyclerView inside NestedScrollView takes too much time when loading large amount of data

RecyclerView inside NestedScrollView freezes the Activity when loading large amount of data. It loads much faster with ScrollView, but scrolling is affected in that case.
I tried setting attributes like setAutoMeasure and setNestedScrollingEnabled which did not help.
Any suggestions?
Recycling of views is not supported inside NestedScrollViews as I understand, so the suggestion would be to try to change your layout.
This help to increase the speed of recycler view scrolling.
SpeedyLinearLayoutManager linearLayoutManager = new SpeedyLinearLayoutManager(MainActivity.this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
myRecyclerView.setLayoutManager(linearLayoutManager);
SpeedyLinearLayoutManager.class
public class SpeedyLinearLayoutManager extends LinearLayoutManager {
private static final float MILLISECONDS_PER_INCH = 2f; //default is 25f (bigger = slower)
public SpeedyLinearLayoutManager(Context context) {
super(context);
}
public SpeedyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public SpeedyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
final LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
#Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return SpeedyLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
Use Custom list view instead of Recycler view inside scroll view...
Check this Answer
Custom List View
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ListView;
public class ExpandableHeightListView extends ListView {
boolean expanded = true;
public ExpandableHeightListView(Context context) {
super(context);
}
public ExpandableHeightListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandableHeightListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// HACK! TAKE THAT ANDROID!
if (isExpanded()) {
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
}
you can include app:layout_behavior="#string/appbar_scrolling_view_behavior"
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
or disable the nested scrolling behavior for the recycler view.
recyclerView.setNestedScrollingEnabled(false);

ExpandableGridView onScrollListener not Working

I've tried almost every Answers and solution related to this but it doesn't works for me. Help me out.
Here is my code of my ExpandableGridView. Please through it.
This is my ExpnadableView:-
public class ExpandableHeightGridView extends GridView {
boolean expanded = false;
public ExpandableHeightGridView(Context context) {
super(context);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// HACK! TAKE THAT ANDROID!
if (isExpanded()) {
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
and implementation of it:-
mGridView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int
visibleItemCount, int totalItemCount) {
int currentFirstVisPos = view.getFirstVisiblePosition();
System.out.println("UUUUUUUUU "+myLastVisiblePos);
myLastVisiblePos = currentFirstVisPos;
}
});

How do I make RecyclerView grid "full height"?

Before RecyclerView, I used this class to make grid's height dependant on it's childs(so it works fine in scrollview):
public class FullHeightGridView extends GridView
{
public FullHeightGridView(Context context)
{
super(context);
}
public FullHeightGridView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public FullHeightGridView(Context context, AttributeSet attrs,
int defStyle)
{
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
How can I modify GridLayoutManager to behave in the same way?

Android Setting GridView Height

I have a GridView with variable height cells. I want the row to be as high as all the largest cell in the row. I am able to adjust the cell heights to be consistent on a row, but I cannot set the Height of the GridView and have it actually change.
Another problem is that this GridView is in a ScrollView, so having a scroll bar is out of the question.
This is a problem because the way the GridView determines the height of the entire Grid is to take the first cell and multiply it by the number of rows. This is an obvious problem if the rows can have different heights. For example:
I have tried numerous ways to update it, but I am sure I am missing something simple. I am trying to do the update in a ViewTreeObserver so I know that the GridView has rendered so my calcs are correct (and they are). The code:
ViewTreeObserver treeListener = mGridView.getViewTreeObserver();
treeListener.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
mGridView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
else {
mGridView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
// Calculate the new height we want for the GridView
int newHeight = determineCellHeight(mGridView, mNumberOfColumns, mRows);
ViewGroup.LayoutParams params = mGridView.getLayoutParams();
params.height = newHeight;
mGridView.setLayoutParams(params);
// Have tried all of these too!!!
// mAdapter.notifyDataSetChanged();
// mGridView.requestLayout();
// mGridView.invalidateViews();
// mGridView.refreshDrawableState();
// mGridView.setLayoutParams(new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, newHeight + 10));
// mGridView.setLayoutParams(new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, newHeight + 10));
// View lastChild = mGridView.getChildAt( mGridView.getChildCount() - 1 );
// mGridView.setLayoutParams( new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, lastChild.getBottom() ) );
// mAdapter.notifyDataSetChanged();
// mGridView.invalidateViews();
// mGridView.setMinimumHeight(newHeight);
// mGridView.requestLayout();
// mGridView.refreshDrawableState();
}
});
I am beginning to wonder if this is even possible, though the numerous Stackflows seem to suggest it is...
I did come across this problem too several months ago, so there's an easy solution. You need to subclass your own GridView, and override the "onMeasure()" method so as to calculate the actual height of your needs. Here is the implementation.
public class ExpandableHeightGridView extends GridView {
boolean expanded = false;
public ExpandableHeightGridView(Context context) {
super(context);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isExpanded()) {
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
Hope it helps.

Gridview height gets cut

I'm trying to display 8 items inside a gridview. Sadly, the gridview height is always too little, so that it only shows the first row, and a little part of the second.
Setting android:layout_height="300dp" makes it work. wrap_content and fill_parent apparently not.
My grid view:
<GridView
android:id="#+id/myId"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:horizontalSpacing="2dp"
android:isScrollContainer="false"
android:numColumns="4"
android:stretchMode="columnWidth"
android:verticalSpacing="20dp" />
My items resource:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:minHeight="?android:attr/listPreferredItemHeight" >
<ImageView
android:id="#+id/appItemIcon"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#android:drawable/ic_dialog_info"
android:scaleType="center" />
<TextView
android:id="#+id/appItemText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="My long application name"
android:gravity="center_horizontal"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
The issue does not seem related to a lack of vertical space.
What can I do ?
After (too much) research, I stumbled on the excellent answer of Neil Traft.
Adapting his work for the GridView has been dead easy.
ExpandableHeightGridView.java:
package com.example;
public class ExpandableHeightGridView extends GridView
{
boolean expanded = false;
public ExpandableHeightGridView(Context context)
{
super(context);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ExpandableHeightGridView(Context context, AttributeSet attrs,
int defStyle)
{
super(context, attrs, defStyle);
}
public boolean isExpanded()
{
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// HACK! TAKE THAT ANDROID!
if (isExpanded())
{
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}
Include it in your layout like this:
<com.example.ExpandableHeightGridView
android:id="#+id/myId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:horizontalSpacing="2dp"
android:isScrollContainer="false"
android:numColumns="4"
android:stretchMode="columnWidth"
android:verticalSpacing="20dp" />
Lastly you just need to ask it to expand:
mAppsGrid = (ExpandableHeightGridView) findViewById(R.id.myId);
mAppsGrid.setExpanded(true);
After using the answer from #tacone and making sure it worked, I decided to try shorting down the code. This is my result. PS: It is the equivalent of having the boolean "expanded" in tacones answer always set to true.
public class StaticGridView extends GridView {
public StaticGridView(Context context) {
super(context);
}
public StaticGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StaticGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST));
getLayoutParams().height = getMeasuredHeight();
}
}
Another similar approach that worked for me, is to calculate the height for one row and then with static data (you may adapt it to paginate) you can calculate how many rows you have and resize the GridView height easily.
private void resizeGridView(GridView gridView, int items, int columns) {
ViewGroup.LayoutParams params = gridView.getLayoutParams();
int oneRowHeight = gridView.getHeight();
int rows = (int) (items / columns);
params.height = oneRowHeight * rows;
gridView.setLayoutParams(params);
}
Use this code after setting the adapter and when the GridView is drawn or you will get height = 0.
gridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!gridViewResized) {
gridViewResized = true;
resizeGridView(gridView, numItems, numColumns);
}
}
});
Found tacones answer helpfull... so i ported it to C# (Xamarin)
public class ExpandableHeightGridView: GridView
{
bool _isExpanded = false;
public ExpandableHeightGridView(Context context) : base(context)
{
}
public ExpandableHeightGridView(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public ExpandableHeightGridView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{
}
public bool IsExpanded
{
get { return _isExpanded; }
set { _isExpanded = value; }
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// HACK! TAKE THAT ANDROID!
if (IsExpanded)
{
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.MakeMeasureSpec( View.MeasuredSizeMask, MeasureSpecMode.AtMost);
base.OnMeasure(widthMeasureSpec,expandSpec);
var layoutParameters = this.LayoutParameters;
layoutParameters.Height = this.MeasuredHeight;
}
else
{
base.OnMeasure(widthMeasureSpec,heightMeasureSpec);
}
}
}
Jacob R solution in Kotlin:
class ExpandableHeightGridView #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : GridView(context, attrs, defStyleAttr) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST)
super.onMeasure(widthMeasureSpec, expandSpec)
layoutParams.height = measuredHeight
}
}
After adding GridView to RecyclerView I got a full-size GridView (all rows are visible), as expected.
Just calculate the height for AT_MOST and set to on measure. Here GridView Scroll will not work so. Need to use Vertical Scroll View explicitly.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightSpec;
if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) {
heightSpec = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
}
else {
// Any other height should be respected as is.
heightSpec = heightMeasureSpec;
}
super.onMeasure(widthMeasureSpec, heightSpec);
}

Categories

Resources