先上图
(好多效果文章都不带图,我觉得先放图也能给大家节省时间,合适了在往下看)
今天在开发的时候有这样的一种需求,百度好久,没有满意的,基本上代码扔一堆太复杂而且也没有整理,没心情看,最后放弃。
决定自己研究,尝试了两种思路:为了方便,给要固定的那一栏起个名字叫 A
1.最初我想通过两个ScrollView,第一个Scroll里面放(内容,A和 第二个Scroll)。当第一个Scroll大小滑完之后,会留A和第二个Scroll占满全屏,继续滑动的时候当然只会滑动第二个Scroll,自然A就保持在顶部,这个最好想,应该可以实现,但是每个手机分辨率不一样,刻意去设置大小可能会不兼容。放弃这个思路。
重点在这
2.第二个是判断当A滑出屏外的时候,把A从Scroll拿出来,然后放到顶部。当判断A滑入屏幕里面在把A放入Scroll里面。上图就是第二种,看起来固定的很完美,我反正是看不出来有什么瑕疵
看布局代码,这个主要是理解,理解之后就能72变,布局代码
//最外层用相对布局,为了让放置A的容器固定在屏幕顶部,并且挡住ScrollView
<RelativeLayout>
//蓝色是滑动控件和线性布局组合
<ScrollView>
<LinearLayout >
//这个是放A的容器
<LinearLayout>
//这是A
<LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
//这是悬浮A的容器,想放哪都行,根据需要 放左 放右 放上 放下。
<RelativeLayout>
</RelativeLayout>
</RelativeLayout>
这个布局总的来讲就是需要给A准备两个盛放容器,一个滑动的,一个固定的
然后java代码很少,仅仅给ScrollView 设置滑动监听、然后里面进行简单 if 就可以了
下面代码里 linewai1 是滑动容器中放 A 的容器,re1是放 A 悬浮容器
public void listener(){
scrol.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if(scrollY>=linewai1.getY()){
removeOneself(A);
re1.addView(A);
}else if(linewai1.indexOfChild(A)<0){//这里判断A是否在A原来的容器里,没有的话就把A从悬浮容器移除
removeOneself(A);
linewai1.addView(A);//放置到滑动容器
}
}
});
}
这里提一下,如何判断一个控件是否被滑出屏幕,这个也是问题,百度没找到答案,我是根据控件的相对坐标来进行判定的,这里利用ScrollView的滑动距离和放置A的容器的getY( )来判断的,实验发现,当一个控件被滑出屏幕,那滑动距离一定大于该控件的相对Y坐标。当小于的时候该控件是应该显示出来的。
当A滑出屏幕,就从原容器移除,放到悬浮容器中,当A滑入屏幕,反向操作。
这里值得注意的是,从容器中移除A,不能简单的利用layout.removeview(View view)这个方法,会报错的,只能从父控件中移除子控件,但是布局和A并不是直接的父子关系,需要调入如下方法,这个方法是借鉴一位大佬的方法。
public static void removeOneself(View child){
if (child != null){
ViewGroup parent = (ViewGroup)child.getParent();
if (parent != null && parent instanceof ViewGroup) {
parent.removeView(child);
}
}
}
这个方法直接用就可以了
只要布局设置好,只要一个滑动监听就够了,是不是代码很少?前面提到的72变,理解了这个,是不是底部悬浮,左侧悬浮,右侧悬浮,乱七八糟的悬浮都OK了,😄😄😄😄😄😄
还有比这个简单的么,欢迎留言😛😛😛😛😛
小小的踩坑经验分享完毕,有帮助的话给我个提醒赞哦
附件完整样例
xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".MainActivity">
<ScrollView
android:id="@+id/scrol"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#B17AFF"
android:text="填充1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#8BC8F8"
android:text="填充1"/>
<LinearLayout
android:id="@+id/sliding_box"
android:layout_width="match_parent"
android:layout_height="80dp"
android:orientation="vertical">
<HorizontalScrollView
android:id="@+id/A"
android:layout_width="match_parent"
android:background="#ffffff"
android:scrollbars="none"
android:layout_height="80dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="80dp"
android:orientation="horizontal">
<Button
android:layout_width="200dp"
android:layout_height="70dp"
android:layout_gravity="center_vertical"
android:backgroundTint="#FFDE7A"
android:text="1"/>
<Button
android:layout_width="200dp"
android:layout_height="70dp"
android:layout_gravity="center_vertical"
android:backgroundTint="#51E8CA"
android:text="2"/>
<Button
android:layout_width="200dp"
android:layout_height="70dp"
android:layout_gravity="center_vertical"
android:backgroundTint="#F19D97"
android:text="3"/>
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="500dp"
android:background="#FFF06A"
android:text="填充2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="500dp"
android:background="#77EF7C"
android:text="填充2"/>
</LinearLayout>
</ScrollView>
<RelativeLayout
android:id="@+id/top_box"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_alignParentTop="true">
</RelativeLayout>
</RelativeLayout>
java:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
public class MainActivity extends AppCompatActivity {
private RelativeLayout top_box;
private ScrollView scrol;
private LinearLayout sliding_box;
private HorizontalScrollView A;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
listener();
}
public void init(){
top_box=findViewById(R.id.top_box);
scrol=findViewById(R.id.scrol);
sliding_box=findViewById(R.id.sliding_box);
A=findViewById(R.id.A);
}
public void listener() {
scrol.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if (scrollY >= sliding_box.getY()) {
removeOneself(A);
top_box.addView(A);
} else if (sliding_box.indexOfChild(A) < 0) {//这里判断A是否在A原来的容器里,没有的话就把A从悬浮容器移除
removeOneself(A);
sliding_box.addView(A);//放置到滑动容器
}
}
});
}
public static void removeOneself(View child){
if (child != null){
ViewGroup parent = (ViewGroup)child.getParent();
if (parent != null && parent instanceof ViewGroup) {
parent.removeView(child);
}
}
}
}