【问题标题】:How do I show my fab on scroll when the first item in the recycler view is not visible but hide when the first item is visible?当回收站视图中的第一个项目不可见但在第一个项目可见时隐藏时,如何在滚动时显示我的工厂?
【发布时间】:2018-11-19 19:05:51
【问题描述】:

所以我正在尝试实现一个 FAB 按钮,这样,当我滚动我的回收站视图并且第一个项目不可见(向上滚动等)时,fab 按钮应该是可见的,否则如果第一个位置是它应该隐藏显示。现在我已经实现了代码,但它根本没有显示 fab 按钮,只是想知道我做错了什么?

我的xml代码如下:

<Linearlayout ....


    <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        <android.support.v4.widget.SwipeRefreshLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/pullToRefreshLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/myRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </android.support.v4.widget.SwipeRefreshLayout>

            <android.support.design.widget.FloatingActionButton
                android:id="@+id/emailFab"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="16dp"
                android:src="@android:drawable/ic_dialog_email"
                app:layout_anchor="@id/myRecyclerView"
                android:layout_gravity="bottom|end"
                app:layout_behavior="com.example.fab.ScrollAwareFABBehavior"
                app:layout_anchorGravity="bottom|end"
                />
        </FrameLayout>

</LinearLayout>

我的 Kotlin 代码如下:

val positionView = (myRecyclerView.getLayoutManager() as LinearLayoutManager).findFirstVisibleItemPosition()

myRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (dy >0 && positionView > 0) {
                    emailFab.show();
                } else  {
                    emailFab.hide();
                }
            }

有什么想法吗?

谢谢!

【问题讨论】:

  • 是每个 RecyclerView 孩子中的 FAB 还是活动中的一个 FAB? (例如在 Gmail 应用发送按钮中)
  • r u for real ;) 好吧,您可以为此创建一个简单的界面,并跟踪 recyclerview 的移动,并使用线性布局管理器跟踪第一个孩子是否可见等等,给你一些代码
  • @Domin 让我更新代码以显示我如何在 xml 等中使用 fab。希望这会有所帮助
  • 用 xml 更新了代码,就是这样

标签: android kotlin android-recyclerview floating-action-button recyclerview-layout


【解决方案1】:

此代码 100% 有效:

public class TestActivity extends AppCompatActivity {

    private static final String TAG = "TestActivity";

    private ArrayList<String> datas = new ArrayList<>();

    private FloatingActionButton fabButton;
    private RecyclerView recyclerView;
    private LinearLayoutManager linearLayoutManager;
    private DataAdapter dataAdapter;

    private boolean isFabVisible = false;

    private OnFabVisibilityCallback onFabVisibilityCallback;

    public void setOnFabVisibilityCallback(OnFabVisibilityCallback onFabVisibilityCallback) {
        this.onFabVisibilityCallback = onFabVisibilityCallback;
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_contacts);

        datas.add("one");
        datas.add("two");
        datas.add("three");
        datas.add("four");
        datas.add("five");
        datas.add("six");
        datas.add("seven");
        datas.add("eight");
        datas.add("nine");
        datas.add("ten");

        fabButton = (FloatingActionButton)findViewById(R.id.fabButton);
        fabButton.setVisibility(View.GONE);
        recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
        linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(linearLayoutManager);
        dataAdapter = new DataAdapter(this, datas);
        recyclerView.setAdapter(dataAdapter);


        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

                if(linearLayoutManager.findFirstVisibleItemPosition() == 0){
                    //hide
                    if(onFabVisibilityCallback != null){
                        onFabVisibilityCallback.onChange(false);
                    }
                }else{
                    //show
                    if(onFabVisibilityCallback != null){
                        onFabVisibilityCallback.onChange(true);
                    }
                }

            }
        });

        setOnFabVisibilityCallback(new OnFabVisibilityCallback() {
            @Override
            public void onChange(boolean isVisible) {
                if(isVisible){
                    if(!isFabVisible){
                        isFabVisible = true;
                        fabButton.setVisibility(View.VISIBLE);
                    }
                }else{
                    if(isFabVisible){
                        isFabVisible = false;
                        fabButton.setVisibility(View.GONE);
                    }
                }
            }
        });

    }

    private class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

        private Activity activity;
        private ArrayList<String> datas;
        private LayoutInflater layoutInflater;

        public DataAdapter(Activity activity, ArrayList<String> datas) {
            this.activity = activity;
            this.datas = datas;
            this.layoutInflater = LayoutInflater.from(activity);
        }

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new SimpleViewHolder(layoutInflater.inflate(R.layout.unit_test, parent, false));
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            ((SimpleViewHolder)holder).init(datas.get(position));
        }

        @Override
        public int getItemCount() {
            return datas.size();
        }

        private class SimpleViewHolder extends RecyclerView.ViewHolder{

            private TextView text;

            public SimpleViewHolder(View itemView) {
                super(itemView);
                initViews(itemView);
            }

            private void initViews(View v){
                text = (TextView)v.findViewById(R.id.text);
            }

            public void init(String data){
                text.setText(data);
            }

        }

    }

    public interface OnFabVisibilityCallback{

        void onChange(boolean isVisible);

    }

}

活动布局文件:

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

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fabButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="16dp"
        android:src="@drawable/ic_add_black_24dp"
        android:tint="@color/white" />

</RelativeLayout>

这是recyclerview子布局:

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:gravity="center"
    android:background="@color/yellow"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="150dp">

    <TextView
        android:text="data"
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

【讨论】:

  • 没有更简单的方法吗?这似乎是不必要的复杂。有没有一种更简单的方法来检测第一行是否可见,而无需创建用于更改回退的接口,然后将其用作回调,然后在滚动侦听器中使用该回调?
  • 好吧,这只是为了演示,您可以采取另一种方法,在这种方法中,您可以创建自定义回收视图,它为您提供了一个覆盖方法来设置 FAB 可见性,在这种情况下,代码将分为文件和会容易得多,但基本保持不变,您必须在 linearlayoutmanager 中监听滚动变化并设置一个接口来调用该方法。希望你明白这一点
【解决方案2】:

我认为问题在于您应该将findFirstVisibleItemPosition() 拉入OnScrollListener 以在滚动更改中找到可见位置:

myRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {

        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)

            val positionView = (myRecyclerView.getLayoutManager() as LinearLayoutManager).findFirstVisibleItemPosition()

            if (positionView > 0) {
                if(!emailFab.isShown) {
                    emailFab.show();
                }
            } else  {
                if(emailFab.isShown) {
                    emailFab.hide();
                }
            }
        }
    })

【讨论】:

  • 这正是我正在寻找的解决方案,简单且完美!谢谢@aminography!
  • 不客气 :-) 很高兴看到问题解决了。
  • 关于将图像上传到服务器的问题有什么想法吗? :stackoverflow.com/questions/57598276/…(我已经包含了来自邮递员的工作 okhttp 客户端推荐,只需要帮助将其转换为我正在使用的 androidnetworking 库)
  • 它保持丑陋没有动画:(
  • 我用的是旧版本,在AndroiDx中出现动画很漂亮,对不起!
猜你喜欢
  • 1970-01-01
  • 2017-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
  • 2021-04-11
  • 2021-10-02
  • 1970-01-01
相关资源
最近更新 更多