首先,我们来看下效果图,如下:
让我们来分析一下这个图,这是一个scrollview,有4个条目,当我们向上滑动的时候,如果条目2滑到顶端,会把
条目1顶上去,然后条目2停留,等待条目3上来,之后条目3会把条目2顶上去,然后停留,后面同理。
那么,这个动态的怎么来实现呢?停留的导航栏是什么呢?
其实,导航栏是一个浮在scrollView上面的一个textView。当条目2滚动到条目1下面的时候,让textview动态的随
着scrollview的滚动而滚动直至条目1滚出屏幕。当条目2滚动到条目1的位置的时候让textView显示在条目1 的位置,
当scrollview继续滚动的时候textview不动,给人一种条目2停留的感觉。以下同理。
好,大概的原理我们已经大致的清楚了,那就开始来看一下布局吧!
<span style="font-size:18px;"><span style="font-size:18px;"><?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="match_parent"
android:layout_height="match_parent">
<com.example.peiwc.iostableview.MyScrollView
android:id="@+id/scv"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title0"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="#ffF19EDB"
android:gravity="center"
android:textStyle="bold"
android:text="条目1" />
<TextView
android:layout_width="match_parent"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:gravity="center"
android:scaleType="fitCenter"
android:text="text1"
android:textSize="26sp" />
<TextView
android:id="@+id/title1"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@color/colorRed"
android:gravity="center"
android:text="条目2"
android:textStyle="bold"
android:textSize="22sp"
android:textColor="@android:color/white"/>
<TextView
android:layout_width="match_parent"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:gravity="center"
android:scaleType="fitCenter"
android:text="text2"
android:textSize="26sp" />
<TextView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:gravity="center"
android:scaleType="fitCenter"
android:text="text3"
android:textSize="26sp" />
<TextView
android:id="@+id/title2"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@color/colorYel"
android:gravity="center"
android:text="条目3"
android:textSize="22sp"
android:textColor="@android:color/white"
android:textStyle="bold"/>
<TextView
android:id="@+id/iv1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:gravity="center"
android:scaleType="fitCenter"
android:text="text4"
android:textSize="26sp" />
<TextView
android:id="@+id/title3"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@color/colorBlue"
android:gravity="center"
android:text="条目4"
android:textSize="22sp"
android:textColor="@android:color/white"
android:textStyle="bold"/>
<TextView
android:layout_width="match_parent"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:gravity="center"
android:scaleType="fitCenter"
android:text="text5"
android:textSize="26sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:gravity="center"
android:scaleType="fitCenter"
android:text="text6"
android:textSize="26sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:gravity="center"
android:scaleType="fitCenter"
android:text="text7"
android:textSize="26sp" />
</LinearLayout>
</com.example.peiwc.iostableview.MyScrollView>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@color/colorZi"
android:gravity="center"
android:textSize="22sp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:text="条目1" />
</RelativeLayout></span></span>这个布局整体是个Relativelayout,里面在scrollview上面有一个textview title,我们给4个条目都设置了id,分别是title0,title1,title2,title3.可以看到scrollview被重写了
为什么要重写scrollview呢?
因为我们要对scrollview进行监听,获得scrollview滑动的距离,从而控制title的位移。可惜sdk并没哟响应的方法,但是scrollview中倒是提供了一个方法
<pre name="code" class="java"><span style="font-size:18px;"> @Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged( x, y, oldx, oldy);
}
}</span>显然这个方法是不能被外界调用的,因此我们要把它暴露出去,方便使用。
下面帖上程序代码我们来具体看下ScrollView:
<pre name="code" class="java"><span style="font-size:18px;">public class MyScrollView extends ScrollView {
private ScrollViewListener scrollViewListener = null;
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public interface ScrollViewListener {
void onScrollChanged( int x, int y, int oldx, int oldy);
}
public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
// onScrollChanged里面有4个参数,l代表滑动后当前ScrollView可视界面的左上角在整个ScrollView的X轴中的位置,oldi也就是滑动前的X轴位置了。
// 同理,t也是当前可视界面的左上角在整个ScrollView的Y轴上的位置,oldt也就是移动前的Y轴位置了。
@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged( x, y, oldx, oldy);
}
}
}
</span>接下来,就是我们华丽丽的Activity闪亮登场啦!先把整篇帖上去,然后我再仔细讲。
<pre name="code" class="java"><span style="font-size:18px;">public class MainActivity extends Activity implements MyScrollView.ScrollViewListener{
private TextView title0,title1,title2,title3,title;
private long topDistance0,topDistance1,topDistance2,topDistance3,height;
private MyScrollView scrollView;
private int distance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
title0=(TextView)findViewById(R.id.title0);
title1=(TextView)findViewById(R.id.title1);
title2=(TextView)findViewById(R.id.title2);
title3=(TextView)findViewById(R.id.title3);
title=(TextView)findViewById(R.id.title);
scrollView=(MyScrollView)findViewById(R.id.scv);
scrollView.setScrollViewListener(this);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus){
topDistance0 = title0.getTop();
topDistance1 = title1.getTop();
topDistance2 = title2.getTop();
topDistance3 = title3.getTop();//按钮左上角相对于父view(LinerLayout)的y坐标
height = title.getMeasuredHeight();
Log.i("","=topDistance0="+topDistance0);
Log.i("","=topDistance1="+topDistance1);
Log.i("","=topDistance2="+topDistance2);
Log.i("","=topDistance3="+topDistance3);
Log.i("","=topDistance3="+topDistance3);
Log.i("","=height="+height);
}
}
@Override
public void onScrollChanged(int x, int y, int oldx, int oldy) {
Log.i("","=topDistance=distance="+"x="+x+";y="+y+";oldx="+oldx+";oldy"+oldy);
distance=y;
distancePlace(topDistance0,topDistance1);
distancePlaceLayout(topDistance1,topDistance0);
distancePlace(topDistance1,topDistance2);
distancePlaceLayout(topDistance2,topDistance1);
distancePlace(topDistance2,topDistance3);
distancePlaceLayout(topDistance3,topDistance2);
if (distance > topDistance3) {
title.layout(0,0,title.getRight(),(int)height);
showText(topDistance3);
}
}
private void distancePlaceLayout(long topDistance1,long topDistance0){
if(distance>topDistance1-height && distance<topDistance1 ){
title.layout(0,(int)(topDistance1-distance-height),title.getRight(),(int)(topDistance1-distance));
showText(topDistance0);
}
}
private void distancePlace(long topDistance0,long topDistance1){
if(distance >= topDistance0&& distance<topDistance1-height){
title.layout(0,0,title.getRight(),(int)height);
showText(topDistance0);
}
}
private void showText(long topDistance){
if(topDistance==topDistance0){
title.setText("条目1");
title.setBackground(getResources().getDrawable(R.color.colorZi));
}
if(topDistance==topDistance1){
title.setText("条目2");
title.setBackground(getResources().getDrawable(R.color.colorRed));
}
if(topDistance==topDistance2){
title.setText("条目3");
title.setBackground(getResources().getDrawable(R.color.colorYel));
}
if(topDistance==topDistance3){
title.setText("条目4");
title.setBackground(getResources().getDrawable(R.color.colorBlue));
}
}
}</span>在onWindowFocusChanged(boolean hasFocus)中,获取了4个条目的getTop值,即条目到scrollview顶端的距离。注意:getTop是控件左上角相对于父布局的y坐标。这个布局中所有条目的父布局都是scrollview,所以我们这里可以直接使用。我们看下打印的结果:
来看下onScrollChange方法:
当条目2到达条目1低端的时候,滑动的距离就应该是topDistance1-height,即title1.getTop-height,height是条目的高度。那么当条目2还没有到达条目1 低端的时候,如图,我们做了如下的判断:
<pre name="code" class="java"><span style="font-size:18px;">if(distance >= topDistance0 && distance<topDistance1-height){
title.layout(0,0,title.getRight(),(int)height);
showText(topDistance0);
}</span>当条目2到达条目1低端和条目1顶端之间的位置,即条目2往上推动条目1的时候
滑动的距离就应该是topDistance1-height和即topDistance1之间,我们做了如下的判断:
<pre name="code" class="java"><span style="font-size:18px;">if(distance>topDistance1-height && distance<topDistance1 ){
title.layout(0,(int)(topDistance1-distance-height),title.getRight(),(int)(topDistance1-distance));
showText(topDistance0);
}</span>此时title是动态的,我们根据滑动的距离实时给title定个位。
剩下的条目依次类推。
把这两个判断做下封装,传入不同的距离值就可以啦!
OK,demo完成!
源码:http://download.youkuaiyun.com/detail/aa_chao/9635014
本文介绍如何在Android中实现类似iOS的TableView分区效果,当ScrollView滑动时,导航栏(TextView)停留在滚动条目顶部。通过重写ScrollView,监听滑动距离,动态调整导航栏位置,当条目滑出屏幕时,导航栏跟随滚动,营造停留感。文章提供详细布局解析和关键代码实现。
4998

被折叠的 条评论
为什么被折叠?



