【Android自定义控件】布局悬停在顶部

本文介绍了如何在Android中自定义HoverScrollView,使其布局能在滚动时悬停在顶部。通过继承ScrollView,实现接口传递滚动的Top值,并根据Top值与布局距离上边缘的大小比较,来控制布局的可见性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

语言表达能力有限,我们先来看下效果:



好了,如果你明白了我说的效果,那就继续往下看吧!


思路是这样的:

首先,我们要自定义一个HoverScrollView,继承ScrollView,通过接口把onScrollChanged(int l, int t, int oldl, int oldt)方法里scrollview移动的Top值暴露出来,然后在Activity根据scrollview的Top值以及需要悬浮的布局mHoverLayoutTop距离上边缘的size,通过两者的比较,当Top的值大于等于size时把mHoverLayoutTop设置VISIBLE以及INVISIBLE。

这里有必要先介绍下Left,Top,Right,Bottom这几个值的含义:

下面是暴露出scrollview滑动时的Top值的代码,这里很明显我们开个接口

开接口一般我们记住以下几个步骤:

创建接口,声明接口带参数的抽象方法,声明一个接口类型的引用来指向一个实现给接口的对象,对这个引用赋值,最后别忘记给接口传递的参数赋值(去调用接口的方法)。


下面是自定义HoverScrollView的代码:

public class HoverScrollView extends ScrollView {


	private OnScrollListener onScrollListener;
	
	public interface OnScrollListener{
		public void onScroll(int scrollY);
	};


	public HoverScrollView(Context context) {
		super(context, null, 0);
		// TODO Auto-generated constructor stub
	}


	public HoverScrollView(Context context, AttributeSet attrs) {
		super(context, attrs, 0);
		// TODO Auto-generated constructor stub
	}


	public HoverScrollView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}
	
	public void setOnScrollListener(OnScrollListener onScrollListener){
		this.onScrollListener = onScrollListener;
	}
	
	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		// TODO Auto-generated method stub
		super.onScrollChanged(l, t, oldl, oldt);
		if(onScrollListener!=null){
			onScrollListener.onScroll(t);
		}
	}
}

然后我们来看下布局的代码,这里使用FrameLayout,可以看到悬停的布局位于FrameLayout的上层,这里我们把悬停的布局先gone掉,代码如下:


<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff" >

    <com.mw.yejg.andtest.view.HoverScrollView
        android:id="@+id/hsv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

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

            <ImageView
                android:id="@+id/iv_head"
                android:layout_width="match_parent"
                android:layout_height="@dimen/y100"
                android:background="@drawable/ic_launcher" />

            <LinearLayout
                android:id="@+id/layout_hover_scroll"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#aaaaaa"
                android:orientation="horizontal" >

                <Button
                    android:layout_width="0dip"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="button1" />

                <Button
                    android:layout_width="0dip"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="button2" />
            </LinearLayout>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="@dimen/y100"
                android:gravity="center"
                android:text="text" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="@dimen/y100"
                android:background="#dddddd"
                android:gravity="center"
                android:text="text" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="@dimen/y100"
                android:gravity="center"
                android:text="text" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="@dimen/y100"
                android:background="#dddddd"
                android:gravity="center"
                android:text="text" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="@dimen/y100"
                android:gravity="center"
                android:text="text" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="@dimen/y100"
                android:background="#dddddd"
                android:gravity="center"
                android:text="text" />
        </LinearLayout>
    </com.mw.yejg.andtest.view.HoverScrollView>

    <LinearLayout
        android:id="@+id/layout_hover_top"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#aaaaaa"
        android:orientation="horizontal"
        android:visibility="gone" >

        <Button
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="button1" />

        <Button
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="button2" />
    </LinearLayout>

</FrameLayout>

在Activity里面我们可以通过计算悬停布局上边布局的累加高度取得size,或者如果知道准确的高度可以直接通过getResources().getDimensionPixelSize(R.dimen.xxx)取得,这里还应该知道,控件获取高度的方法getHeight()在onCreate()方法和onResume()方法里调用都是为0的,这是因为此时布局还没有渲染完成,我们写个轮询线程来获取渲染完成后的控件高度,代码如下:

public class TestHoverAct extends Activity implements OnScrollListener {

	private HoverScrollView mHsv;
	private LinearLayout mHoverLayoutTop;
	private int size;
	private ImageView mIvHead;
	// 开个轮询线程,循环直到对size赋上非0的值
	private Handler mHandler = new Handler() {

		public void handleMessage(android.os.Message msg) {
			if (msg.what == 1) {
				// 顶部高度为0时,表示布局未完成,继续轮询
				if (mIvHead.getHeight() == 0) {
					mHandler.sendEmptyMessageDelayed(1, 10);
					return;
				}
				size = mIvHead.getHeight();
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.act_test_hover);
		mHsv = (HoverScrollView) findViewById(R.id.hsv);
		mIvHead = (ImageView) findViewById(R.id.iv_head);
		mHoverLayoutTop = (LinearLayout) findViewById(R.id.layout_hover_top);
		mHsv.setOnScrollListener(this);
		// 如果知道准确的高度,可以直接取得
		// size = getResources().getDimensionPixelSize(R.dimen.y100);
		// 10毫秒循环判断
		mHandler.sendEmptyMessageDelayed(1, 10);
	}

	@Override
	public void onScroll(int scrollY) {
		Log.e("scroll::", "size::" + size + ", scrollY::" + scrollY);
		if (scrollY >= size) {
			mHoverLayoutTop.setVisibility(View.VISIBLE);
		} else {
			mHoverLayoutTop.setVisibility(View.INVISIBLE);
		}
	}

}


本博客部分思路来自夏安明的博客,向他致谢!





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leafseelight

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值