Я нашел хороший способ получать уведомления о том, о чем я спрашивал здесь.
он работает для scrollView с вертикальным LinearLayout, но если вы хотите, вы можете заставить его работать и в других случаях,в зависимости от случая.
Я не уверен, должен ли я обрабатывать метод onSizeChanged (), и если да, что там делать, но во всех других случаях этот код работает нормально.
вот код:
MainActivity.java (для тестирования):
public class MainActivity extends Activity
{
@Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final CustomScrollView scrollView=(CustomScrollView)findViewById(R.id.scrollView1);
scrollView.setOnChildViewVisibilityChangedListener(new onChildViewVisibilityChangedListener()
{
@Override
public void onChildViewVisibilityChanged(final int index,final View v,final boolean becameVisible)
{
Log.d("Applog","index:"+index+" visible:"+becameVisible);
}
});
final ViewGroup container=(ViewGroup)findViewById(R.id.linearLayout);
for(int i=0;i<20;++i)
{
final TextView tv=new TextView(this);
tv.setText("item "+i);
tv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,300));
container.addView(tv);
}
}
}
activity_main.xml
<RelativeLayout 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" >
<com.example.scrollviewvisibilitydetector.CustomScrollView
android:id="@+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</com.example.scrollviewvisibilitydetector.CustomScrollView>
</RelativeLayout>
CustomScrollView.java (реальная сделка ...):
public class CustomScrollView extends ScrollView
{
Set<Integer> _shownViewsIndices =new HashSet<Integer>();
onChildViewVisibilityChangedListener _onChildViewVisibilityChangedListener;
public interface onChildViewVisibilityChangedListener
{
public void onChildViewVisibilityChanged(int index,View v,boolean becameVisible);
}
public CustomScrollView(final Context context)
{
super(context);
}
public CustomScrollView(final Context context,final AttributeSet attrs)
{
super(context,attrs);
}
public CustomScrollView(final Context context,final AttributeSet attrs,final int defStyle)
{
super(context,attrs,defStyle);
}
public void setOnChildViewVisibilityChangedListener(final onChildViewVisibilityChangedListener onChildViewVisibilityChangedListener)
{
_onChildViewVisibilityChangedListener=onChildViewVisibilityChangedListener;
}
@Override
protected void onLayout(final boolean changed,final int l,final int t,final int r,final int b)
{
super.onLayout(changed,l,t,r,b);
checkViewsVisibility(l,t);
}
private void checkViewsVisibility(final int l,final int t)
{
final ViewGroup viewGroup=(ViewGroup)getChildAt(0);
final int childCount=viewGroup.getChildCount();
if(childCount==0)
return;
final int parentBottom=t+getHeight();
// prepare to use binary search to find a view that is inside the bounds
int min=0,max=childCount-1,piv=-1;
int childTop,childBottom;
View v;
// check previously shown views
for(final Iterator<Integer> iterator=_shownViewsIndices.iterator();iterator.hasNext();)
{
final Integer cur=iterator.next();
v=viewGroup.getChildAt(cur);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t)
{
if(piv==-1)
piv=cur;
}
else
{
if(_onChildViewVisibilityChangedListener!=null)
_onChildViewVisibilityChangedListener.onChildViewVisibilityChanged(cur,v,false);
iterator.remove();
}
}
if(piv==-1)
{
// check first view
v=viewGroup.getChildAt(min);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t)
piv=min;
else
{
// check last view
v=viewGroup.getChildAt(max);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t)
piv=min;
}
if(piv==-1)
while(true)
{
piv=(min+max)/2;
v=viewGroup.getChildAt(piv);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t)
break;
if(max-min==1)
return;
if(childBottom<t)
// view above bounds
min=piv;
else max=piv;
}
}
//
for(int i=piv;i<childCount;++i)
{
v=viewGroup.getChildAt(i);
childTop=v.getTop();
childBottom=v.getBottom();
// _shownViewsIndices.
if(childTop<=parentBottom&&childBottom>=t&&!_shownViewsIndices.contains(i))
{
_shownViewsIndices.add(i);
if(_onChildViewVisibilityChangedListener!=null)
_onChildViewVisibilityChangedListener.onChildViewVisibilityChanged(i,v,true);
}
}
for(int i=piv-1;i>=0;--i)
{
v=viewGroup.getChildAt(i);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t&&!_shownViewsIndices.contains(i))
{
_shownViewsIndices.add(i);
if(_onChildViewVisibilityChangedListener!=null)
_onChildViewVisibilityChangedListener.onChildViewVisibilityChanged(i,v,true);
}
}
}
@Override
protected void onScrollChanged(final int l,final int t,final int oldl,final int oldt)
{
super.onScrollChanged(l,t,oldl,oldt);
checkViewsVisibility(l,t);
}
}