Android studio开发实战之碎片Fragment

ops/2025/1/22 7:13:19/

        一、碎片化的概念

        碎片化(Fragment)是 Android 应用开发中的一个重要概念,它的设计初衷是增强界面模块化,便于开发者灵活构建和管理复杂的界面。

  • 什么是模块化?
    • 将应用界面拆分成多个可复用的小模块(Fragment),每个模块可以独立定义自己的布局、逻辑和交互。
  • 为什么需要模块化?
    • 当界面变得复杂时,将整个界面写在一个 Activity 中会导致代码混乱、维护困难。
    • 使用 Fragment,可以将界面逻辑独立开来,方便开发、调试和测试。

举例:在一个购物应用中:

  • 商品列表是一个 Fragment。
  • 商品详情是另一个 Fragment。
  • 购物车页面又是一个 Fragment。

这样,每个模块的开发和调试是独立的,避免了代码耦合。

Fragment 同样可以解决 手机屏幕和平板屏幕差异。Fragment 作为一个独立的 UI 模块,可以被多个 Activity 复用。

  • 在小屏设备上(如手机):
    • 每个 Fragment 通常占据一个 Activity,全屏显示,用户需要通过页面跳转查看不同内容。
  • 在大屏设备上(如平板):
    • 可以在同一个 Activity 中显示多个 Fragment,比如左侧是导航列表,右侧是详情界面。
  • 不同 Activity 都可以加载这个 Fragment,而不需要重复写界面和逻辑代码。

 二、碎片的静态注册

        每个Activity有自己的xml布局文件,作为Activity的一个模块,fragment也需要写自己的xml布局文件。

例如书中案例:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:background="#bbffbb"><TextViewandroid:id="@+id/tv_adv"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:text="广告图片"android:textColor="#000000"android:textSize="17sp" /><ImageViewandroid:id="@+id/iv_adv"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="4"android:src="@drawable/adv"android:scaleType="fitCenter" /></LinearLayout>

一个简单的线性布局,水平方向上有两个组件,按照1:4的比例水平分布,效果如下:

        上面已经说了,这里再强调一遍“将应用界面拆分成多个可复用的小模块(Fragment),每个模块可以独立定义自己的布局、逻辑和交互。

        因此上面的xml布局文件不必直接用于Activity,而是拥有自己的逻辑和交互代码。

例如:

public class StaticFragment extends Fragment implements View.OnClickListener {private static final String TAG = "StaticFragment";protected View mView; // 声明一个视图对象protected Context mContext; // 声明一个上下文对象// 创建碎片视图@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {mContext = getActivity(); // 获取活动页面的上下文// 根据布局文件fragment_static.xml生成视图对象mView = inflater.inflate(R.layout.fragment_static, container, false);TextView tv_adv = mView.findViewById(R.id.tv_adv);ImageView iv_adv = mView.findViewById(R.id.iv_adv);tv_adv.setOnClickListener(this); // 设置点击监听器iv_adv.setOnClickListener(this); // 设置点击监听器Log.d(TAG, "onCreateView");return mView; // 返回该碎片的视图对象}@Overridepublic void onClick(View v) {if (v.getId() == R.id.tv_adv) {Toast.makeText(mContext, "您点击了广告文本", Toast.LENGTH_LONG).show();} else if (v.getId() == R.id.iv_adv) {Toast.makeText(mContext, "您点击了广告图片", Toast.LENGTH_LONG).show();}}
  • FragmentStaticFragment 是一个 Fragment 类,用来定义用户界面的一部分,可以被嵌入到 Activity 中。
  • implements View.OnClickListener:实现了 View.OnClickListener 接口,用于处理视图的点击事件。

碎片视图代码详细分析:

  1. mContext = getActivity();

    • getActivity() 获取当前 Fragment 所附加的 Activity,即 Fragment 的宿主。
    • 这里将 Activity 的上下文赋值给 mContext,方便后续在 Fragment 中使用。
    • 为什么这么写?Fragment 不能直接访问全局上下文(如 this),而是依附于宿主 Activity。因此需要通过 getActivity() 获取。
    • 用途:上下文在后续创建视图、设置监听器、弹出 Toast 等操作中使用。
  2. inflater.inflate(R.layout.fragment_static, container, false)

    • inflater 是布局填充器,用于将 XML 布局文件(fragment_static.xml)转换为对应的视图对象。LayoutInflater 是 Android 用来解析 XML 布局文件并将其转化为实际的 View 对象的工具。
    • container 是宿主 Activity 中用于容纳当前 Fragment 的容器。传入这个参数可以让视图正确地嵌入父容器中。
    • false 表示是否立即将解析后的视图添加到父容器中。通常传 false,因为实际添加操作由系统完成。
  3. 视图查找与点击监听

    • mView.findViewById(...):从加载的视图中查找指定 ID 的控件。
    • setOnClickListener(this):将 StaticFragment 本身作为点击事件的监听器。

        在 Fragment 中必须通过 视图对象 调用 findViewById,而不能像 Activity 那样直接调用,这是由 Fragment 的设计原理和生命周期决定的。

Activity 的 findViewById
在 Activity 中,findViewById 是直接调用的,因为 Activity 会直接加载布局文件并管理所有控件。

setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
  • setContentView 将布局文件加载到 Activity 的根视图中。
  • findViewById 会在整个视图树(View hierarchy)中查找指定的控件。

 

Fragment 的 findViewById
Fragment 的视图是通过 onCreateView 动态生成的,并不直接属于 Activity 的视图树。
因此:

  • 只能通过 Fragment 的根视图(mView)调用 findViewById,在其对应的视图范围内查找控件。
mView = inflater.inflate(R.layout.fragment_static, container, false);
TextView textView = mView.findViewById(R.id.text_view);
  • Fragment 的视图是在 onCreateView 中动态加载的,而 Activity 的视图是随着 setContentView 初始化的。
  • 原因: 在 Fragment 中,控件只存在于 onCreateView 加载的布局中,只有通过 mView(Fragment 的根视图)才能访问这些控件。如果尝试直接调用 findViewById会导致空指针异常,因为 Fragment 的控件并没有加入到 Activity 的视图树中,Activity 无法找到这些控件。

 

好,现在碎片准备完毕,逻辑是点击碎片部分,会在活动页面上显示文本。下面要在活动页面上引用上面定义的碎片代码:步骤是先引用碎片控件,再在活动页面引入布局文件。

活动界面的xml布局文件如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><!-- 把碎片当作一个控件使用,其中android:name指明了碎片来源 --><fragmentandroid:id="@+id/fragment_static"android:name="com.example.testapplication.fragment.StaticFragment"android:layout_width="match_parent"android:layout_height="60dp" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="这里是每个页面的具体内容"android:textColor="#000000"android:textSize="17sp" />
</LinearLayout>

<fragment> 元素:

  • 是一个特殊的 XML 标签,用于在布局文件中静态嵌入 Fragment。
  • 系统会根据 android:name 指定的 Fragment 类,将其加载到 <fragment> 标签的位置,并显示其视图。
  • android:name 指定需要加载的 Fragment 的类的完整路径(包名+类名)。

活动页面的代码如下:

public class FragmentStaticActivity extends AppCompatActivity {private static final String TAG = "FragmentStaticActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_fragment_static);Log.d(TAG, "onCreate");}@Overrideprotected void onDestroy() {super.onDestroy();Log.d(TAG, "onDestroy");}

运行测试结果正常,那么碎片和活动页面的生命周期是怎样的呢?

单独看碎片的生命周期:

  • onAttach()
    • Fragment 被添加到 Activity 上时调用。可以获取 Activity 的引用。
  • onCreate()
    • Fragment 被创建时调用,适合初始化非视图相关的资源或逻辑。
  • onCreateView()
    • 为 Fragment 创建视图时调用。必须返回根视图对象。
  • onActivityCreated()
    • 宿主 Activity 的 onCreate() 方法完成后调用。
  • onStart()
    • Fragment 对用户可见时调用。
  • onResume()
    • Fragment 与用户交互时调用。
  • onPause()
    • Fragment 进入后台时调用,适合保存非持久数据。
  • onStop()
    • Fragment 不再对用户可见时调用。
  • onDestroyView()
    • Fragment 的视图被销毁时调用。
  • onDestroy()
    • Fragment 自身被销毁时调用。
  • onDetach()
    • Fragment 从 Activity 中移除时调用。

 碎片和活动页面的调用顺序如下,碎片的创建被优先调用,然后才是活动页面的视图创建。

三、碎片的动态注册 

        静态注册是通过在 XML 布局文件中直接声明 Fragment 来实现的。系统在加载布局时会自动实例化并显示 Fragment。

静态注册的特点
  • 简单易用:在 XML 中直接定义 Fragment,系统会自动实例化它,减少了手动代码的书写。
  • 生命周期由系统管理:Fragment 的生命周期由系统自动管理,依赖于宿主 Activity 的生命周期。
  • 无法动态替换:一旦静态注册的 Fragment 加载进来,它的存在就固定了,无法像动态注册那样在运行时进行替换或移除。

        动态注册是通过代码中手动创建并管理 Fragment 的实例,以及使用 FragmentTransaction 来进行 Fragment 的添加、替换、移除等操作。        

动态注册的特点
  • 更高的灵活性:可以在运行时动态决定哪些 Fragment 需要显示或隐藏,支持 Fragment 的动态添加、替换、移除等操作。
  • 控制生命周期:通过 FragmentTransaction 手动控制 Fragment 的生命周期,例如添加、移除或替换 Fragment 时,可以通过事务来管理这些操作。
  • 适应性强:适合那些需要动态变化、经常切换内容的页面。例如,Tab 页的切换、登录/注册界面的切换等。

动态注册最常用与翻页类视图并用,因此先回顾翻页类视图是怎样的:

3.1翻页类视图案例

        1创建布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="5dp"><!-- 注意翻页视图ViewPager的节点名称要填全路径 --><androidx.viewpager.widget.ViewPagerandroid:id="@+id/vp_content"android:layout_width="match_parent"android:layout_height="370dp" />
</LinearLayout>

   ViewPager 是 Android 中用于实现 翻页效果(即滑动切换不同页面)的专用组件。 

   ViewPager 被用来显示多个页面,可以是图片、文本或其他视图。关于 ViewPager 的使用,有几个要点需要注意 :

   ViewPager 必须通过适配器来管理它的页面内容。在你的布局文件中,ViewPager 并没有定义任何内容,它只是一个容器。你需要为它指定一个 PagerAdapter,通常是 FragmentPagerAdapterPagerAdapter 的子类。

   ViewPager 提供了页面滑动的效果,用户可以左右滑动页面。如果你希望定制滑动效果(例如,设置切换动画、切换速度等),你可以通过修改 ViewPager 的配置或使用 PageTransformer 来实现。

        例如,使用 PageTransformer 实现视差效果:

viewPager.setPageTransformer(true, new ViewPager.PageTransformer() {@Overridepublic void transformPage(@NonNull View page, float position) {page.setRotationY(position * -30);  // 例如:左右翻转效果}
});

 

        2创建手机商品实体类:

public class GoodsInfo {public long rowid; // 行号public int xuhao; // 序号public String name; // 名称public String desc; // 描述public float price; // 价格public String pic_path; // 大图的保存路径public int pic; // 大图的资源编号public GoodsInfo() {rowid = 0L;xuhao = 0;name = "";desc = "";price = 0;pic_path = "";pic = 0;}// 声明一个手机商品的名称数组private static String[] mNameArray = {"iPhone11", "Mate30", "小米10", "OPPO Reno3", "vivo X30", "荣耀30S"};// 声明一个手机商品的描述数组private static String[] mDescArray = {"Apple iPhone11 256GB 绿色 4G全网通手机","华为 HUAWEI Mate30 8GB+256GB 丹霞橙 5G全网通 全面屏手机","小米 MI10 8GB+128GB 钛银黑 5G手机 游戏拍照手机","OPPO Reno3 8GB+128GB 蓝色星夜 双模5G 拍照游戏智能手机","vivo X30 8GB+128GB 绯云 5G全网通 美颜拍照手机","荣耀30S 8GB+128GB 蝶羽红 5G芯片 自拍全面屏手机"};// 声明一个手机商品的价格数组private static float[] mPriceArray = {6299, 4999, 3999, 2999, 2998, 2399};// 声明一个手机商品的大图数组private static int[] mPicArray = {R.drawable.iphone, R.drawable.huawei, R.drawable.xiaomi,R.drawable.oppo, R.drawable.vivo, R.drawable.rongyao};// 获取默认的手机信息列表public static List<GoodsInfo> getDefaultList() {List<GoodsInfo> goodsList = new ArrayList<GoodsInfo>();for (int i = 0; i < mNameArray.length; i++) {GoodsInfo info = new GoodsInfo();info.name = mNameArray[i];info.desc = mDescArray[i];info.price = mPriceArray[i];info.pic = mPicArray[i];goodsList.add(info);}return goodsList;}}

        在 Android 开发中,适配器(Adapter) 是一个用于连接数据源和视图组件的桥梁。它的主要作用是将数据映射到界面元素上,从而使数据能够在界面中展示。

        适配器的作用:数据与视图的桥梁——适配器从数据源中获取数据,然后将这些数据绑定到视图组件上。

        翻页类视图有自己的适配器,通过构造方法传入商品列表,再用instantiateItem实例化视图对象,并添加到容器。

        3翻页类适配器代码如下:

public class ImagePagerAdapater extends PagerAdapter {// 声明一个图像视图列表private List<ImageView> mViewList = new ArrayList<ImageView>();// 声明一个商品信息列表private List<GoodsInfo> mGoodsList = new ArrayList<GoodsInfo>();// 图像翻页适配器的构造方法,传入上下文与商品信息列表public ImagePagerAdapater(Context context, List<GoodsInfo> goodsList) {mGoodsList = goodsList;// 给每个商品分配一个专用的图像视图for (int i = 0; i < mGoodsList.size(); i++) {ImageView view = new ImageView(context); // 创建一个图像视图对象view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));view.setImageResource(mGoodsList.get(i).pic);mViewList.add(view); // 把该商品的图像视图添加到图像视图列表}}// 获取页面项的个数public int getCount() {return mViewList.size();}// 判断当前视图是否来自指定对象public boolean isViewFromObject(View view, Object object) {return view == object;}// 从容器中销毁指定位置的页面public void destroyItem(ViewGroup container, int position, Object object) {container.removeView(mViewList.get(position));}// 实例化指定位置的页面,并将其添加到容器中public Object instantiateItem(ViewGroup container, int position) {container.addView(mViewList.get(position));return mViewList.get(position);}// 获得指定页面的标题文本public CharSequence getPageTitle(int position) {return mGoodsList.get(position).name;}}

        这段代码是一个自定义的 PagerAdapter,用于在 Android 中实现 ViewPager 的图像滑动展示。PagerAdapter 是一种适配器,用来管理 ViewPager 中的页面数据。具体来说,这段代码将商品信息(GoodsInfo)和对应的商品图片(ImageView)绑定在一起,能够在 ViewPager 中进行滑动展示。

        ImagePagerAdapater 继承了 PagerAdapter,是一个自定义适配器,用于管理 ViewPager 中的页面。

  • mViewList:用于存储 ImageView 对象的列表,每个 ImageView 对应一个商品的图片。
  • mGoodsList:用于存储商品信息的列表,每个商品包含商品名称和商品图片等信息。
  • 构造方法接收一个 Context 和一个 List<GoodsInfo> 类型的商品列表。
  • 通过商品列表中的信息,为每个商品创建一个 ImageView。每个商品对应一张图片,图片来源于 GoodsInfo 对象的 pic 属性。
  • 设置每个 ImageView 的布局参数为 MATCH_PARENTWRAP_CONTENT,使得图片能够填充整个屏幕宽度并自适应高度。
  • 将每个创建的 ImageView 添加到 mViewList 列表中,供 ViewPager 显示。
  • 构造方法接收一个 Context 和一个 List<GoodsInfo> 类型的商品列表。
  • 通过商品列表中的信息,为每个商品创建一个 ImageView。每个商品对应一张图片,图片来源于 GoodsInfo 对象的 pic 属性。
  • 设置每个 ImageView 的布局参数为 MATCH_PARENTWRAP_CONTENT,使得图片能够填充整个屏幕宽度并自适应高度。
  • 将每个创建的 ImageView 添加到 mViewList 列表中,供 ViewPager 显示。
public int getCount() {return mViewList.size();
}

返回适配器中总共的页面数量,也就是 mViewList 列表中 ImageView 的数量,即商品的数量。

public boolean isViewFromObject(View view, Object object) {return view == object;
}
  • 该方法用于判断一个视图是否与一个对象关联。view 是当前显示的视图,objectinstantiateItem() 方法返回的对象。
  • 这里判断 view 是否等于 object,即判断当前页面的视图是否是该适配器实例化的视图。
public void destroyItem(ViewGroup container, int position, Object object) {container.removeView(mViewList.get(position));
}
  • 该方法用于销毁 ViewPager 中某个位置的页面视图。当用户滑动到下一个页面时,当前页面的视图会被销毁以节省内存。
  • 通过 container.removeView()ViewGroup 中移除视图。
public Object instantiateItem(ViewGroup container, int position) {container.addView(mViewList.get(position));return mViewList.get(position);
}
  • 该方法用于实例化并返回 ViewPager 中某个位置的页面视图。通过 container.addView()mViewList 中对应位置的 ImageView 添加到 ViewPager 容器中。
  • instantiateItem() 方法的返回值会作为 destroyItem() 中的 object 参数来使用。
public CharSequence getPageTitle(int position) {return mGoodsList.get(position).name;
}
  • 该方法用于返回每一页的标题。这里的标题来自商品信息列表 mGoodsList 中每个商品的 name 属性。

        4、活动代码

public class ViewPagerActivity extends AppCompatActivity implements OnPageChangeListener {private List<GoodsInfo> mGoodsList; // 手机商品列表@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_view_pager);mGoodsList = GoodsInfo.getDefaultList();// 构建一个商品图片的翻页适配器ImagePagerAdapater adapter = new ImagePagerAdapater(this, mGoodsList);// 从布局视图中获取名叫vp_content的翻页视图ViewPager vp_content = findViewById(R.id.vp_content);vp_content.setAdapter(adapter); // 设置翻页视图的适配器vp_content.setCurrentItem(0); // 设置翻页视图显示第一页vp_content.addOnPageChangeListener(this); // 给翻页视图添加页面变更监听器
//        // 给翻页视图添加简化版的页面变更监听器
//        vp_content.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
//            @Override
//            public void onPageSelected(int position) {
//                Toast.makeText(ViewPagerActivity.this, "您翻到的手机品牌是:"
//                        + mGoodsList.get(position).name, Toast.LENGTH_SHORT).show();
//            }
//        });}// 翻页状态改变时触发。state取值说明为:0表示静止,1表示正在滑动,2表示滑动完毕// 在翻页过程中,状态值变化依次为:正在滑动→滑动完毕→静止public void onPageScrollStateChanged(int state) {}// 在翻页过程中触发。该方法的三个参数取值说明为 :第一个参数表示当前页面的序号// 第二个参数表示页面偏移的百分比,取值为0到1;第三个参数表示页面的偏移距离public void onPageScrolled(int position, float ratio, int offset) {}// 在翻页结束后触发。position表示当前滑到了哪一个页面public void onPageSelected(int position) {Toast.makeText(this, "您翻到的手机品牌是:" + mGoodsList.get(position).name, Toast.LENGTH_SHORT).show();}
}

效果,通过左右滑动,可以显示不同的手机图片:

3.2 碎片动态注册代码

1、布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="5dp"><androidx.viewpager.widget.ViewPagerandroid:id="@+id/vp_content"android:layout_width="match_parent"android:layout_height="wrap_content"><androidx.viewpager.widget.PagerTabStripandroid:id="@+id/pts_tab"android:layout_width="wrap_content"android:layout_height="wrap_content" /></androidx.viewpager.widget.ViewPager>
</LinearLayout>

        这段代码定义了一个简单的 Android 布局,包含一个 ViewPager 组件和其内嵌的 PagerTabStrip,用于实现页面翻页功能,同时为翻页视图添加顶部的标签条(Tab Strip)来标识当前页面。

androidx.viewpager.widget.ViewPager:这是一个翻页视图容器,用于实现页面的滑动切换。上面已经讲过。

androidx.viewpager.widget.PagerTabStripPagerTabStripViewPager 的一个子组件,用于在顶部显示页面标题,并标识当前页面。PagerTabStrip 会自动显示与当前页面对应的标题信息。它需要配合 PagerAdapter 来提供标题。

2、碎片适配器

public class MobilePagerAdapter extends FragmentPagerAdapter {private List<GoodsInfo> mGoodsList = new ArrayList<GoodsInfo>(); // 声明一个商品列表// 碎片页适配器的构造方法,传入碎片管理器与商品信息列表public MobilePagerAdapter(FragmentManager fm, List<GoodsInfo> goodsList) {super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);mGoodsList = goodsList;}// 获取碎片Fragment的个数public int getCount() {return mGoodsList.size();}// 获取指定位置的碎片Fragmentpublic Fragment getItem(int position) {return DynamicFragment.newInstance(position,mGoodsList.get(position).pic, mGoodsList.get(position).desc);}// 获得指定碎片页的标题文本public CharSequence getPageTitle(int position) {return mGoodsList.get(position).name;}
}

MobilePagerAdapter 通过提供 Fragment 的内容和标题,将商品信息(GoodsInfo)展示为滑动页面,用户可以通过滑动切换不同商品的详情页。

public MobilePagerAdapter(FragmentManager fm, List<GoodsInfo> goodsList) {super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);mGoodsList = goodsList;
}
  • 参数解析
    • FragmentManager fm:由外部传入的碎片管理器,用于管理 Fragment 的添加、移除和切换。
    • List<GoodsInfo> goodsList:商品信息列表,由外部传入适配器,用于为每个页面提供商品数据。
  • super 调用
    • BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT:表示只保留当前显示的 Fragment 的视图状态,节省内存和性能。
  • 功能:构造方法将商品信息列表传递给适配器。
public int getCount() {return mGoodsList.size();
}
  • 功能:返回商品信息列表的长度,即页面的总数。
  • 适配器作用ViewPager 会调用此方法,确定总共需要显示多少个页面。
public Fragment getItem(int position) {return DynamicFragment.newInstance(position,mGoodsList.get(position).pic, mGoodsList.get(position).desc);
}
  • 参数解析
    • position:页面索引,表示当前请求的页面在列表中的位置。
  • 功能
    • 创建并返回一个新的 DynamicFragment 实例。
    • DynamicFragment.newInstance 是一个静态方法,用于创建包含特定数据的 Fragment
    • 通过 position 获取对应商品的图片(pic)和描述(desc),并将其传递给 DynamicFragment
  • 适配器作用ViewPager 会调用此方法,为每个页面提供实际的 Fragment 内容。
public CharSequence getPageTitle(int position) {return mGoodsList.get(position).name;
}
  • 参数解析
    • position:页面索引。
  • 功能
    • 获取当前页面对应商品的名称(name)作为标题。
    • 返回的标题会显示在配套的标签组件(如 PagerTabStrip)中。

 

运行时的具体流程

  1. 初始化适配器

    • 外部通过 new MobilePagerAdapter(fm, goodsList) 初始化适配器,将商品列表传入。
  2. 绑定到 ViewPager

    • ViewPager 设置此适配器后,会调用适配器的 getCount 方法,确定总页面数。
  3. 加载页面内容

    • 当某个页面需要显示时,ViewPager 会调用 getItem 方法,从适配器获取对应的 Fragment
    • DynamicFragment.newInstance 会根据商品的图片和描述生成一个对应的页面。
  4. 显示标题

    • 如果布局中有标签组件(如 PagerTabStrip),会调用 getPageTitle 方法获取标题,显示为对应页面的标签。

3、碎片代码

public class DynamicFragment extends Fragment {private static final String TAG = "DynamicFragment";protected View mView; // 声明一个视图对象protected Context mContext; // 声明一个上下文对象private int mPosition; // 位置序号private int mImageId; // 图片的资源编号private String mDesc; // 商品的文字描述// 获取该碎片的一个实例public static DynamicFragment newInstance(int position, int image_id, String desc) {DynamicFragment fragment = new DynamicFragment(); // 创建该碎片的一个实例Bundle bundle = new Bundle(); // 创建一个新包裹bundle.putInt("position", position); // 往包裹存入位置序号bundle.putInt("image_id", image_id); // 往包裹存入图片的资源编号bundle.putString("desc", desc); // 往包裹存入商品的文字描述fragment.setArguments(bundle); // 把包裹塞给碎片return fragment; // 返回碎片实例}// 创建碎片视图public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {mContext = getActivity(); // 获取活动页面的上下文if (getArguments() != null) { // 如果碎片携带有包裹,就打开包裹获取参数信息mPosition = getArguments().getInt("position", 0); // 从包裹取出位置序号mImageId = getArguments().getInt("image_id", 0); // 从包裹取出图片的资源编号mDesc = getArguments().getString("desc"); // 从包裹取出商品的文字描述}// 根据布局文件fragment_dynamic.xml生成视图对象mView = inflater.inflate(R.layout.fragment_dynamic, container, false);ImageView iv_pic = mView.findViewById(R.id.iv_pic);TextView tv_desc = mView.findViewById(R.id.tv_desc);iv_pic.setImageResource(mImageId);tv_desc.setText(mDesc);Log.d(TAG, "onCreateView position=" + mPosition);return mView; // 返回该碎片的视图对象}@Overridepublic void onAttach(Activity activity) { // 把碎片贴到页面上super.onAttach(activity);Log.d(TAG, "onAttach position=" + mPosition);}@Overridepublic void onCreate(Bundle savedInstanceState) { // 页面创建super.onCreate(savedInstanceState);Log.d(TAG, "onCreate position=" + mPosition);}@Overridepublic void onDestroy() { // 页面销毁super.onDestroy();Log.d(TAG, "onDestroy position=" + mPosition);}@Overridepublic void onDestroyView() { // 销毁碎片视图super.onDestroyView();Log.d(TAG, "onDestroyView position=" + mPosition);}@Overridepublic void onDetach() { // 把碎片从页面撕下来super.onDetach();Log.d(TAG, "onDetach position=" + mPosition);}@Overridepublic void onPause() { // 页面暂停super.onPause();Log.d(TAG, "onPause position=" + mPosition);}@Overridepublic void onResume() { // 页面恢复super.onResume();Log.d(TAG, "onResume position=" + mPosition);}@Overridepublic void onStart() { // 页面启动super.onStart();Log.d(TAG, "onStart position=" + mPosition);}@Overridepublic void onStop() { // 页面停止super.onStop();Log.d(TAG, "onStop position=" + mPosition);}@Overridepublic void onActivityCreated(Bundle savedInstanceState) { //在活动页面创建之后super.onActivityCreated(savedInstanceState);Log.d(TAG, "onActivityCreated position=" + mPosition);}}

4、活动页面

public class ViewPagerActivity extends AppCompatActivity implements OnPageChangeListener {private List<GoodsInfo> mGoodsList; // 手机商品列表@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_view_pager);mGoodsList = GoodsInfo.getDefaultList();// 构建一个商品图片的翻页适配器ImagePagerAdapater adapter = new ImagePagerAdapater(this, mGoodsList);// 从布局视图中获取名叫vp_content的翻页视图ViewPager vp_content = findViewById(R.id.vp_content);vp_content.setAdapter(adapter); // 设置翻页视图的适配器vp_content.setCurrentItem(0); // 设置翻页视图显示第一页vp_content.addOnPageChangeListener(this); // 给翻页视图添加页面变更监听器
//        // 给翻页视图添加简化版的页面变更监听器
//        vp_content.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
//            @Override
//            public void onPageSelected(int position) {
//                Toast.makeText(ViewPagerActivity.this, "您翻到的手机品牌是:"
//                        + mGoodsList.get(position).name, Toast.LENGTH_SHORT).show();
//            }
//        });}// 翻页状态改变时触发。state取值说明为:0表示静止,1表示正在滑动,2表示滑动完毕// 在翻页过程中,状态值变化依次为:正在滑动→滑动完毕→静止public void onPageScrollStateChanged(int state) {}// 在翻页过程中触发。该方法的三个参数取值说明为 :第一个参数表示当前页面的序号// 第二个参数表示页面偏移的百分比,取值为0到1;第三个参数表示页面的偏移距离public void onPageScrolled(int position, float ratio, int offset) {}// 在翻页结束后触发。position表示当前滑到了哪一个页面public void onPageSelected(int position) {Toast.makeText(this, "您翻到的手机品牌是:" + mGoodsList.get(position).name, Toast.LENGTH_SHORT).show();}
}

效果:


http://www.ppmy.cn/ops/152131.html

相关文章

Vue平台开发三——项目管理页面

前言 对于多个项目的使用&#xff0c;可能需要进行项目切换管理&#xff0c;所以这里创建一个项目管理页面&#xff0c;登录成功后跳转这个页面&#xff0c;进行选择项目&#xff0c;再进入Home页面展示对应项目的内容。 一、实现效果图预览 二、页面内容 功能1、项目列表展…

Mybatis 进阶 / Mybatis—Puls (详细)

目录 一.动态SQL 1.1标签 1.2 标签 1.3标签 1.4标签 1.5标签 1.6标签 mybatis总结&#xff1a; 二.Mybatis-Puls 2.1准备工作 2.2CRUD单元测试 2.2.1创建UserInfo实体类 2.2.2编写Mapper接⼝类 2.2.3 测试类 2.3 常见注解 2.3.1TableName 2.3.2TableField 2.4打印日…

Vue3 中使用组合式API和依赖注入实现自定义公共方法

组合式API 1.在项目根目录 src 文件夹下创建文件夹 utils &#xff0c;创建 index.js 文件 2.抛出想要对外暴露的方法&#xff0c;以下是一个判断数据类型的方法 export function getType(params) {// 判断是否是基本类型let res typeof paramsif (res ! object) {return re…

ubuntu_查询连接当前服务器的用户ip

在Ubuntu系统中&#xff0c;如果你想查询当前连接到服务器的用户的IP地址&#xff0c;你可以通过以下几种方法来实现&#xff1a; 1. 使用last和awk命令 last命令可以显示最近登录到系统的用户信息&#xff0c;包括他们的IP地址&#xff08;如果他们是远程登录的&#xff09;…

Linux 时间操作详解

Linux 时间操作详解 1. Linux 中的时间概念2. time_t&#xff1a;表示时间的基本数据类型示例代码&#xff1a;获取当前时间 3. 格式化时间&#xff1a;tm 结构体与 localtime() 函数示例代码&#xff1a;将 time_t 转换为本地时间 4. 高精度时间操作&#xff1a;chrono 库示例…

Java TCP可靠传输(1)

TCP 可靠传输 一. 确认应答 由发送方填充&#xff0c;再由接收方在序号的基础上1&#xff0c;填充到确认序号中&#xff0c;来表示已经接收到前面发送的&#xff0c;表明下一个从哪个位置发送。 二. 超时重传 数据在网络上传输时会经过很多网络设备&#xff0c;如果其中一个…

嵌入式知识体系分析+数据结构概念+时间复杂度计算规则+顺序表的原理与实现

数据结构概述 基本概念 数据结构指的是计算机存储数据和组织数据的方式&#xff0c;存储数据和组织数据的目的是为了后期对数据的再次利用&#xff0c;所以存储的数据一般是具有一个或者多个特定关系的集合&#xff0c;利用不同的数据结构可以提高数据的访问效率。 思考&am…

26岁备考PMP,经验分享

26岁普通女孩因考了个PMP.... 突然好喜欢现在的自己&#xff5e; 现在的生活尽管没有很富有&#xff0c;但我现在工作真的很满意&#xff0c;周末双休薪资也不错&#xff0c;没有依靠任何人&#xff0c;全都是我自己努力得来的。 想想以前的我因为学历自卑&#xff0c;到处讨好…