Android ScrollView指定view的悬停

因项目中的需要实现ScrollView顶部的悬停,也不是太难便自己实现功能,话不多说,先上效果图



这里写图片描述


红色text一到顶上便会悬浮在上面,不会跟随scrollview的滑动而上滑。

原理:

原理其实很简单就是对view的gone和visible,写两个相同的要置顶的view,一个设置为gone,一个为visible,当可见的view超出屏幕范围的时候,将不可以的view设置为visible,不可见的view 与scrollview要同级,这样滑动的时候不会影响到view的位置。

直接上代码


<?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="match_parent">


    <com.lanmai.ObservableScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/scrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                    <!-- 中间就是填充的view就不写了-->
                    <!--指定要置顶的view-->
                <TextView
                    android:id="@+id/specific_text_view"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@android:color/holo_red_dark"
                    android:gravity="center"
                    android:text="text"
                    android:textSize="40sp"/>


                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:background="@android:color/darker_gray"
                    android:gravity="center"
                    android:text="text"
                    android:textSize="40sp"/>
            </LinearLayout>


        </RelativeLayout>

    </com.lanmai.ObservableScrollView>

    <!--指定要置顶的相同的view  visibility设置为gone -->
    <TextView
        android:id="@+id/specific_text_view_gone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_red_dark"
        android:gravity="center"
        android:text="text"
        android:textSize="40sp"
        android:visibility="gone"/>
</RelativeLayout>

接下来要重写scrollview,为什么要重写ScrollView,scrollview的滑动监听事件setOnScrollChangeListener 这个方法是在6.0以上才能用的。为了考虑低版本的的需求,要重写ScrollView把接口开放出来。

重写ScrollView

public class ObservableScrollView extends ScrollView {

    private ScrollViewListener scrollViewListener = null;

    public ObservableScrollView(Context context) {
        super(context);
    }

    public ObservableScrollView(Context context, AttributeSet attrs,
                                int defStyle) {
        super(context, attrs, defStyle);
    }

    public ObservableScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if (scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
        }
    }

    public interface ScrollViewListener {

        void onScrollChanged(ScrollView scrollView, int x, int y, int oldx, int oldy);
    }

}

我把重写的ScrollView命名为ObservableScrollView,重写三个构造方法,都是换汤不换药的作法,这里就不赘述。 最重要的是重写onScrollChanged这个方法,如何把滑动监听事件开放出去呢,其实也就是写一个监听回调,参数和onScrollChanged里面的的参数一样就可以了,当然主要不是用到这些参数,只是为了判断ScrollView的滑动事件,参数对于这个功并不是很重要。那这样,一个简单的自定义就写好了scrollview

如何去用?

用法也是挺简单的,直接上代码

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scroll_view);
        mTextView = ((TextView) findViewById(R.id.specific_text_view));
        mScrollView = ((ObservableScrollView) findViewById(R.id.scrollview));
        mVisibleTextView = ((TextView) findViewById(R.id.specific_text_view_gone));

        mTextView.setOnClickListener(this);

        mScrollView.setScrollViewListener(this);
    }

这里onCreate方法里面的,也简单,拿到view 并且设置监听事件,当然,这里多实现了一个点击view置顶的功能,监听设置好以后,实现相应的接,接下来就是重头戏了

    @Override
    public void onScrollChanged(ScrollView scrollView, int x, int y, int oldx, int oldy) {
        int[] location = new int[2];
        mTextView.getLocationOnScreen(location);
        int xPosition = location[0];
        int yPosition = location[1];
        Log.d("ScrollViewActivity", "yPosition:" + yPosition);
        int statusBarHeight = getStatusBarHeight();
        Log.d("ScrollViewActivity", "statusBarHeight:" + statusBarHeight);
        if (yPosition <= statusBarHeight) {
            mVisibleTextView.setVisibility(View.VISIBLE);
        } else {
            mVisibleTextView.setVisibility(View.GONE);
        }
    }

onScrollChanged这个方法就是自己写的监听回调,里面的参数就是Scrollview滑动的时候回调出来的,里面的参数并不用去关心

 int[] location = new int[2];
        mTextView.getLocationOnScreen(location);
        int xPosition = location[0];
        int yPosition = location[1];
      /*  mTextView就是要悬浮的view,getLocationOnScreen(location)这个方法就是拿到view在屏幕中的位置 ,传入一个数组,最后得到的yPosition就是view在屏幕中的高度,这里面调用了native层的实现方式,所以数组能直接附上值*/
       // 值得注意的是,拿到的这个高度还包括状态栏的高度。只要减掉就可以了,状态栏的高度获取获取附上代码:


public int getStatusBarHeight() {
   int result = 0;
   int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
   if (resourceId > 0) {
       result = getResources().getDimensionPixelSize(resourceId);
   }
    return result;
}
        int statusBarHeight = getStatusBarHeight();
        Log.d("ScrollViewActivity", "statusBarHeight:" + statusBarHeight);
           通过获取到的状态栏高度,如果小于状态栏的高度就表示已经滑出屏幕了,将要置顶的view设置为visibvle否则设置为gone 
        if (yPosition <= statusBarHeight) {
            mVisibleTextView.setVisibility(View.VISIBLE);
        } else {
            mVisibleTextView.setVisibility(View.GONE);
        }

这样scrollview的悬浮置顶的功能就实现了,这里我也给出点击view置顶的代码

 @Override
    public void onClick(View v) {
        int[] location = new int[2];
        v.getLocationOnScreen(location);
        int x = location[0];
        int y = location[1];
        mScrollView.scrollBy(0, location[1] - getStatusBarHeight());
    }
    当然要缓慢的滑动过程用smoothScrollBy替代就可以了

结论:

实现这种效果,找对了思路就可以很容易的写出来了,这是一种比较简单的实现方式了,源码我就不贴出来了,基本已经都在了。如果有不对的地方,请大家指证,谢谢

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值