其实关于悬停,自己总结有如下几种方案:
第一种:最早的时候几乎都是利用FrameLayout,在需要悬浮的地方放置一个假的悬停控件,监听滚动事件,从而进行显示和隐藏。
优点:
①几乎没有技术难度
②任意扩展
缺点:
需要维护两套悬停控件(当仅仅是指示剂的还好维护,如果悬停的是类似商城的那种多样式的下拉选择框的,几乎就是准备跑路吧)
第二种:多亏谷歌大佬心疼我们,给我们提供了协调者布局,可以很好的实现单个悬停效果(当然对属性和使用方法很熟悉的前提下,是可以实现更多种悬停样式,但是也有边界)
优点:
①原生控件,体验很好
②多种组合属性,实现各种复杂效果
缺点:
①学习成本高,截止目前还有很多Android开发者不会用协调者布局,甚至都没听过
②复杂场景下,很难达到效果
第三种:是自己想尝试的,就是在原来的滚动布局中移除悬停的控件,直接add到悬停的位置
优点:
①减少维护一套UI成本
②扩展性兼容性好
缺点:
①复杂场景不行
②体验不是很好
但是经过自己用第三种方式的多次试验,其实发现扩展性极强,能够实现自己想要的很多要求,这个需要具体场景具体分析,大家真碰到了,可以用下面源码进行改造实现,看看能否实现自己想要的动效。
下面附上第三种方案的源码和录屏:
录屏:
悬浮效果
源码
测试页面MainActivity2
package com.example.myapplication00;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
public class MainActivity2 extends AppCompatActivity {
private LinearLayout ll01, ll02, ll022;
private TextView tv02, tvSet;
private ScrollViewCustomJava scv;
private int offset;
private boolean isFloat;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ll01 = findViewById(R.id.ll01);
ll02 = findViewById(R.id.ll02);
ll022 = findViewById(R.id.ll022);
tv02 = findViewById(R.id.tv02);
tvSet = findViewById(R.id.tvSet);
scv = findViewById(R.id.scv);
offset = dip2px(this, 420);
scv.setOnScrollListener(new ScrollViewCustomJava.OnScrollListener() {
@Override
public void onScroll(int startScrollX, int startScrollY, int endScrollX, int endScrollY) {
tv02.setText("endScrollY::" + endScrollY);
Log.d("onScroll---endScrollY::", endScrollY + "---offset::" + offset);
if(endScrollY >= offset){
if(!isFloat){
isFloat = true;
ll022.removeView(tv02);
ll02.addView(tv02);
}
}else{
if(isFloat){
isFloat = false;
ll02.removeView(tv02);
ll022.addView(tv02);
}
}
}
});
tvSet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ll022.removeView(tv02);
ll02.addView(tv02);
}
});
}
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
自定义的能监听Scrollview的滚动的控件(主要是系统没提供,需要自己实现)
package com.example.myapplication00;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;
public class ScrollViewCustomJava extends ScrollView {
private OnScrollListener onScrollListener;
public void setOnScrollListener(OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}
public ScrollViewCustomJava(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (onScrollListener != null) {
//一定要注意着的int值都是像素值,而我们实际用的时候应该是dp,记得自己进行转换
onScrollListener.onScroll(oldl, oldt, l, t);
}
}
interface OnScrollListener {
/**
* 回调坐标值 一般ScrollView只有Y值变化, HorizontalScrollView是x值变化
*
* @param startScrollX 滑动之前的值
* @param startScrollY 滑动之前的值
* @param endScrollX 滑动之后的值
* @param endScrollY 滑动之后的值
*/
void onScroll(int startScrollX, int startScrollY, int endScrollX, int endScrollY);
}
}
这是MainActivity2的xml布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity2">
<com.example.myapplication00.ScrollViewCustomJava
android:id="@+id/scv"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/ll01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp"
android:background="#ff0000">
<TextView
android:id="@+id/tv01"
android:layout_width="match_parent"
android:layout_height="400dp"
android:textSize="14sp"
android:text="北京的秋雨,如同一曲悠扬的古筝,在空气中弥漫着淡淡的诗意。在这座繁华都市的某个角落,我静静地感受着秋雨带来的独特魅力。
雨后的北京,仿佛被洗涤过的画卷。古老的建筑在雨后显得更加庄重典雅,泛着历史的光华。湿润的街道映衬着红黄绿三色交织的树叶,萧索中透露出深沉的美感。西山国家森林公园的枫叶在雨中更加娇艳,让人不禁陶醉在这片秋色之中。
秋雨中的北京人,也别有一番韵味。街头的商贩在雨中忙碌地摆摊,为生活奏响了一曲曲朴实的乐章。行人在雨中疾走,似乎在追赶着什么,又似乎在寻找着什么。还有那些骑车人,披着雨衣在马路上穿梭,犹如一道道流动的风景线。
在这座城市里,秋雨不仅仅是一种自然现象,更是一种文化情感的体现。古老的胡同在雨中显得更加有韵味,让人不禁想起那些传世的历史文化。在雨中漫步于南锣鼓巷,感受着传统与现代的文化冲击。这里不仅有老北京的味道,还有年轻人的活力。手工艺人们在雨中认真地制作着各种小玩意,为这座城市增添了一份匠心之美。
在这场秋雨中,我也有了许多思考。生活在北京这个繁华都市,我们每天都在为了梦想而奔波。然而,在这场秋雨中,我意识到我们需要在忙碌中学会慢下来,去感受大自然的美好,去体会生活的本质。只有这样,我们才能更好地理解这个世界,更好地理解自己。
总之,北京的秋雨是一种独特的魅力,是一种诗意的存在。它让我们感受到自然的美好,体会到生活的韵味。在这场秋雨中,我们不仅可以感受到这座城市的历史与文化,还可以在其中寻找到生活的真谛。让我们一起沉浸在这场秋雨中,感受这份美好,感受这份诗意。"/>
<LinearLayout
android:id="@+id/ll022"
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv02"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="002"
android:gravity="center"
android:background="#ffffff"/>
</LinearLayout>
<TextView
android:id="@+id/tv03"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textSize="30dp"
android:text="北京的秋雨,如同一曲悠扬的古筝,在空气中弥漫着淡淡的诗意。在这座繁华都市的某个角落,我静静地感受着秋雨带来的独特魅力。
雨后的北京,仿佛被洗涤过的画卷。古老的建筑在雨后显得更加庄重典雅,泛着历史的光华。湿润的街道映衬着红黄绿三色交织的树叶,萧索中透露出深沉的美感。西山国家森林公园的枫叶在雨中更加娇艳,让人不禁陶醉在这片秋色之中。
秋雨中的北京人,也别有一番韵味。街头的商贩在雨中忙碌地摆摊,为生活奏响了一曲曲朴实的乐章。行人在雨中疾走,似乎在追赶着什么,又似乎在寻找着什么。还有那些骑车人,披着雨衣在马路上穿梭,犹如一道道流动的风景线。
在这座城市里,秋雨不仅仅是一种自然现象,更是一种文化情感的体现。古老的胡同在雨中显得更加有韵味,让人不禁想起那些传世的历史文化。在雨中漫步于南锣鼓巷,感受着传统与现代的文化冲击。这里不仅有老北京的味道,还有年轻人的活力。手工艺人们在雨中认真地制作着各种小玩意,为这座城市增添了一份匠心之美。
在这场秋雨中,我也有了许多思考。生活在北京这个繁华都市,我们每天都在为了梦想而奔波。然而,在这场秋雨中,我意识到我们需要在忙碌中学会慢下来,去感受大自然的美好,去体会生活的本质。只有这样,我们才能更好地理解这个世界,更好地理解自己。
总之,北京的秋雨是一种独特的魅力,是一种诗意的存在。它让我们感受到自然的美好,体会到生活的韵味。在这场秋雨中,我们不仅可以感受到这座城市的历史与文化,还可以在其中寻找到生活的真谛。让我们一起沉浸在这场秋雨中,感受这份美好,感受这份诗意。"/>
</LinearLayout>
</com.example.myapplication00.ScrollViewCustomJava>
<LinearLayout
android:id="@+id/ll02"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:orientation="vertical"
android:background="#000000ff"/>
<TextView
android:id="@+id/tvSet"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:layout_marginTop="50dp"
android:text="开始变形"
android:visibility="gone"/>
</FrameLayout>