当前位置: 首页 > article >正文

Android 整个屏幕可滑动,tab,viewpage是列表,tab不锁在顶

页面整体可滑动,包括顶部黑色控件、Tab 和列表。

步骤 1:主布局文件(activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

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

        <!-- 顶部黑色控件 -->
        <View
            android:id="@+id/topView"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:background="@android:color/black"/>

        <!-- TabLayout -->
        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tabLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabIndicatorColor="@color/black"
            app:tabSelectedTextColor="@color/black"
            app:tabTextColor="@color/gray"/>

        <!-- ViewPager2 -->
        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </LinearLayout>
</androidx.core.widget.NestedScrollView>

步骤 2:MainActivity实现

public class MainActivity extends AppCompatActivity {

    private ViewPager2 viewPager;
    private TabLayout tabLayout;

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

        // 初始化视图
        viewPager = findViewById(R.id.viewPager);
        tabLayout = findViewById(R.id.tabLayout);

        // 设置ViewPager2适配器
        setupViewPager();

        // 联动Tab和ViewPager2
        new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
            tab.setText("Tab " + (position + 1));
        }).attach();
    }

    private void setupViewPager() {
        // 创建Fragment列表
        List<Fragment> fragments = Arrays.asList(
                new ListFragment(),
                new ListFragment()
        );

        // 设置适配器
        viewPager.setAdapter(new FragmentStateAdapter(this) {
            @NonNull
            @Override
            public Fragment createFragment(int position) {
                return fragments.get(position);
            }

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

步骤 3:列表Fragment实现(ListFragment.java)

public class ListFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_list, container, false);
        RecyclerView recyclerView = view.findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.setAdapter(new ListAdapter());
        return view;
    }

    static class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {

        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.item_list, parent, false);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            holder.textView.setText("Item " + (position + 1));
        }

        @Override
        public int getItemCount() {
            return 50; // 模拟50个列表项
        }

        static class ViewHolder extends RecyclerView.ViewHolder {
            TextView textView;

            ViewHolder(@NonNull View itemView) {
                super(itemView);
                textView = itemView.findViewById(R.id.textItem);
            }
        }
    }
}

步骤 4:布局文件补充
fragment_list.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</FrameLayout>

item_list.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textItem"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    android:gravity="center"
    android:textSize="18sp"/>

遇到的问题:ListFragment()的列表高度只有300,ClassifyListFragment有1000,NestedScrollView在ClassifyListFragment滑动到1000的时候,再切换回ListFragment()后,ListFragment()的高度变高了很多,多出的是空白高度

处理方式:
重新计算布局
确保在 ListFragment 中处理布局高度,尤其是在其 onResume() 方法中:

    @Override
    public void onResume() {
        super.onResume();
        if (listSize != 0) {
            if (getContext() != null) {
                // 重新计算布局高度
                View view = getView();
                if (view != null) {
                    // 如果 ListFragment 在显示时,手动更新其布局高度
                    view.post(() -> {
                        int height = getContext().getResources().getDimensionPixelSize(R.dimen.test_tab1_height) * listSize;
                        view.getLayoutParams().height = height;
                        view.requestLayout();
                    });
                }
            }
        }
    }

以下是我的布局
fragment_test_roll

<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

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

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="206dp"
                android:src="@mipmap/bg_test_top" />

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="54dp"
                android:layout_gravity="bottom"
                android:layout_marginStart="14dp"
                android:layout_marginTop="14dp"
                android:layout_marginEnd="14dp"
                android:clipChildren="false">

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="54dp"
                    android:scaleType="fitXY"
                    android:src="@mipmap/bg_text_sroll" />

                <com.jiuhong.mbtirgtest.ui.customView.TwoLineMarqueeView
                    android:id="@+id/marqueeView"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="7dp" />

            </FrameLayout>
        </FrameLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="226dp"
            android:layout_marginTop="17dp"
            android:orientation="horizontal">

            <LinearLayout
                android:id="@+id/ll_hot_test_one"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:paddingStart="14dp"
                android:orientation="vertical">

                <ImageView
                    android:id="@+id/iv_hot_test_one"
                    android:layout_width="161dp"
                    android:layout_height="103dp"
                    android:layout_marginBottom="10dp"
                    android:scaleType="fitXY" />

                <ImageView
                    android:id="@+id/iv_hot_test_two"
                    android:layout_width="161dp"
                    android:layout_height="103dp"
                    android:scaleType="fitXY" />
            </LinearLayout>

            <ImageView
                android:id="@+id/iv_hot_test_three"
                android:layout_width="168dp"
                android:layout_height="226dp"
                android:scaleType="fitXY"
                android:layout_marginStart="10dp"
                android:layout_gravity="bottom"
                android:layout_marginEnd="5dp"/>
        </LinearLayout>

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tabLayout"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            app:tabIndicatorColor="#FF5449C8"
            app:tabGravity="fill"
            app:tabTextColor="#FF333333"
            app:tabSelectedTextColor="#FF333333"
            app:tabTextAppearance="@style/CustomTabTextAppearance"
            app:tabMode="fixed"
            android:layout_marginStart="14dp"
            android:layout_marginTop="15dp"
            android:layout_marginBottom="10dp"/>

        <!-- ViewPager2 -->
        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingStart="13dp"
            android:paddingEnd="13dp"/>

    </LinearLayout>
</androidx.core.widget.NestedScrollView>

TestRollFragment

package com.jiuhong.mbtirgtest.ui.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.jiuhong.mbtirgtest.R;
import com.jiuhong.mbtirgtest.common.EventKey;
import com.jiuhong.mbtirgtest.common.Global;
import com.jiuhong.mbtirgtest.handle.MyUriHandler;
import com.jiuhong.mbtirgtest.ui.customView.TwoLineMarqueeView;
import com.jiuhong.mbtirgtest.util.GlideUtils;
import com.songcha.library_business.helper.UMengHelper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

public class TestRollFragment extends Fragment {
    private ViewPager2 viewPager;
    private TabLayout tabLayout;

    TwoLineMarqueeView marqueeView;

    ImageView  iv_hot_test_one, iv_hot_test_two, iv_hot_test_three;

    String hotTopUrlOne = "";
    String hotTopUrlTwo = "";
    String hotTopUrlThree = "";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 返回 Fragment 的布局
        View rootView = inflater.inflate(R.layout.fragment_test_roll, container, false);
        // 初始化视图
        viewPager = rootView.findViewById(R.id.viewPager);
        tabLayout = rootView.findViewById(R.id.tabLayout);

        // 设置ViewPager2适配器
        setupViewPager();

        // 联动Tab和ViewPager2
        new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
            tab.setText("Tab " + (position + 1));
        }).attach();


        marqueeView = rootView.findViewById(R.id.marqueeView);
        iv_hot_test_one = rootView.findViewById(R.id.iv_hot_test_one);
        iv_hot_test_two = rootView.findViewById(R.id.iv_hot_test_two);
        iv_hot_test_three = rootView.findViewById(R.id.iv_hot_test_three);

        //设置滚动文字
        setMarqueeText();

        iv_hot_test_one.setOnClickListener(v -> {
            MyUriHandler.handle(hotTopUrlOne);
            postKey("top");
        });

        iv_hot_test_two.setOnClickListener(v -> {
            MyUriHandler.handle(hotTopUrlTwo);
            postKey("bottom");
        });

        iv_hot_test_three.setOnClickListener(v -> {
            MyUriHandler.handle(hotTopUrlThree);
            postKey("right");
        });

        //顶部热门测评
        setHotTest();

        return rootView;
    }

    private void postKey(String position) {
        if (getContext() != null) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("position", position);
            UMengHelper.onUMEvent(getContext(), EventKey.CLICK_HOME_FLOAT, map);
        }
    }

    private void setMarqueeText() {
        // 设置新的文本列表
        List<String> texts = new ArrayList<>();

        if (!Global.textRollModelList.isEmpty()) {
            for (int i = 0; i < Global.textRollModelList.size(); i++) {
                texts.add(Global.textRollModelList.get(i).getText());
            }
            marqueeView.setTexts(texts);

            // 设置滚动速度
            marqueeView.setSpeed(1.5f);
        }
    }

    private void setupViewPager() {
        // 创建Fragment列表
        List<Fragment> fragments = Arrays.asList(
                new ListFragment(),
                ClassifyListFragment.newInstance(3)
        );

        // 设置适配器
        viewPager.setAdapter(new FragmentStateAdapter(this) {
            @NonNull
            @Override
            public Fragment createFragment(int position) {
                return fragments.get(position);
            }

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


    private void setHotTest() {
        for (int i = 0; i < Global.hotTestLists.size(); i++) {
            if (getActivity() != null) {
                if (!Global.hotTestLists.isEmpty()) {
                    GlideUtils.loadImageNoCache(getActivity(), Global.hotTestLists.get(0).getImage(), iv_hot_test_one);
//                    tv_hot_test_one.setText(Global.hotTestLists.get(0).getTitle());
                    hotTopUrlOne = Global.hotTestLists.get(0).getUri();
                }
                if (Global.hotTestLists.size() > 1) {
                    GlideUtils.loadImageNoCache(getActivity(), Global.hotTestLists.get(1).getImage(), iv_hot_test_two);
//                    tv_hot_test_two.setText(Global.hotTestLists.get(1).getTitle());
                    hotTopUrlTwo = Global.hotTestLists.get(1).getUri();
                }
                if (Global.hotTestLists.size() > 2) {
                    GlideUtils.loadImageNoCache(getActivity(), Global.hotTestLists.get(2).getImage(), iv_hot_test_three);
//                    tv_hot_test_three.setText(Global.hotTestLists.get(2).getTitle());
                    hotTopUrlThree = Global.hotTestLists.get(2).getUri();
                }
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

fragment_list

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</FrameLayout>

ListFragment

package com.jiuhong.mbtirgtest.ui.fragment;

import static android.content.ContentValues.TAG;

import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.google.gson.Gson;
import com.jiuhong.mbtirgtest.R;
import com.jiuhong.mbtirgtest.common.EventKey;
import com.jiuhong.mbtirgtest.common.Global;
import com.jiuhong.mbtirgtest.handle.MyUriHandler;
import com.jiuhong.mbtirgtest.httpUtil.HttpUtil;
import com.jiuhong.mbtirgtest.httpUtil.api;
import com.jiuhong.mbtirgtest.model.GetTestModel;
import com.jiuhong.mbtirgtest.ui.adapter.MainTabAdapter;
import com.songcha.library_business.helper.UMengHelper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ListFragment extends Fragment {
    RecyclerView recyclerView;
    int listSize = 0;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_list, container, false);
        recyclerView = view.findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        getHttpData();
        recyclerView.setNestedScrollingEnabled(false);
        return view;
    }

    private void getHttpData() {
        //获取签到的数量
        Map<String, String> extraParams = new HashMap<>();
        HttpUtil.sendGetRequest(getContext(), api.getMbttMoney, new HttpUtil.HttpCallback() {
            @Override
            public void onSuccess(String responseBody) {
                if (getActivity() != null) {
                    getActivity().runOnUiThread(() -> {
                        Log.d("测试列表", responseBody);
                        Gson gson = new Gson();
                        List<GetTestModel.DataBean> finalData = new ArrayList<>();
                        GetTestModel getSignNumModel = gson.fromJson(responseBody, GetTestModel.class);
                        for (int i = 0; i < Global.testH5Url.size(); i++) {
                            for (int a = 0; a < getSignNumModel.getData().size(); a++) {
                                if (Global.testH5Url.get(i).getVersion().equals(getSignNumModel.getData().get(a).getVersion())) {
                                    if (Global.testH5Url.get(i).getBanner() != null && !Global.testH5Url.get(i).getBanner().isEmpty()) {
                                        //使用配置的banner图
                                        getSignNumModel.getData().get(a).setImg(Global.testH5Url.get(i).getBanner());
                                    }
                                    if (Global.testH5Url.get(i).getTitle() != null && !Global.testH5Url.get(i).getTitle().isEmpty()) {
                                        //使用配置的标题
                                        getSignNumModel.getData().get(a).setDescription(Global.testH5Url.get(i).getTitle());
                                    }
                                    if (Global.testH5Url.get(i).getDesc() != null && !Global.testH5Url.get(i).getDesc().isEmpty()) {
                                        //描述
                                        getSignNumModel.getData().get(a).setDescriptionExplain(Global.testH5Url.get(i).getDesc());
                                    }
                                    //version相同
                                    if (Global.testH5Url.get(i).getSort() != 0) {
                                        //sort不为0
                                        if ((getSignNumModel.getData().get(a).getSign().equals("10085")) && getSignNumModel.getData().get(a).getStage() == 3) {
                                            finalData.add(getSignNumModel.getData().get(a));
                                        }
                                    }
                                }
                            }
                        }

                        listSize = finalData.size();
                        Log.d("", "" + finalData);
                        MainTabAdapter adapter = new MainTabAdapter(finalData, new MainTabAdapter.OnItemClickListener() {
                            @Override
                            public void onItemClick(int position) {
                                GetTestModel.DataBean item = finalData.get(position);

                                for (int i = 0; i < Global.testH5Url.size(); i++) {
                                    if (item.getVersion().equals(Global.testH5Url.get(i).getVersion())) {
                                        MyUriHandler.handle(Global.testH5Url.get(i).getUri());
                                    }
                                }

                                if (getContext() != null) {
                                    HashMap<String, Object> map = new HashMap<>();
                                    map.put("version", item.getVersion());
                                    UMengHelper.onUMEvent(getContext(), EventKey.CLICK_DAILY_TEST_ITEM, map);
                                }
                            }
                        });
                        recyclerView.setAdapter(adapter);
                    });
                }
            }

            @Override
            public void onFailure(Exception e) {
                // 请求失败,处理错误
                Log.e(TAG, "Error123: " + e.getMessage(), e);
            }
        }, extraParams);
    }

    @Override
    public void onResume() {
        super.onResume();
        if (listSize != 0) {//拿到数据才计算,第一次进来是没有数据的,不重新计算
            // 重新计算布局高度
            View view = getView();
            if (view != null) {
                // 如果 ListFragment 在显示时,手动更新其布局高度
                view.post(() -> {
                    int height = getContext().getResources().getDimensionPixelSize(R.dimen.test_tab1_height) * listSize;
                    view.getLayoutParams().height = height;
                    view.requestLayout();
                });
            }
        }
    }
}

http://www.kler.cn/a/533448.html

相关文章:

  • C++11详解(二) -- 引用折叠和完美转发
  • 【人工智能】通用人工智能 AGI
  • 更换IP属地会影响网络连接速度吗
  • VMware Workstation Pro安装了Ubuntu 24.04实现与Windows10之间的复制粘贴
  • macos系统jmap执行异常
  • 跟李沐学AI:视频生成类论文精读(Movie Gen、HunyuanVideo)
  • 如何在自己mac电脑上私有化部署deep seek
  • [Android] IKTV专享版
  • Meta推动虚拟现实:Facebook如何进入元宇宙时代
  • 107,【7】buuctf web [CISCN2019 华北赛区 Day2 Web1]Hack World
  • JavaScript(简称:js)
  • SQL server 创建DB Link 详解
  • 亚马逊自养号测评系统搭建的全面指南
  • (2025|ICLR,音频 LLM,蒸馏/ALLD,跨模态学习,语音质量评估,MOS)音频 LLM 可作为描述性语音质量评估器
  • 复工大吉!全面掌握淘宝API接口,助力电商业务高效重启
  • Ollama+deepseek+Docker+Open WebUI实现与AI聊天
  • can not add outlook new accounts on the outlook
  • ARM Linux Qt使用JSON-RPC实现前后台分离
  • 设计模式学习(三)
  • Unity扩展编辑器使用整理(一)
  • Vue Router如何配置404页面
  • Ansible在多台服务器上运行python脚本
  • PostgreSQL rownum实现方法
  • Spark--算子执行原理
  • 莱佛士设计之旅:四城巡讲,启发未来设计之路
  • spring security与gateway结合进行网关鉴权和授权