fragment

发布时间 2023-04-22 22:19:04作者: ZZX11
title:Fragment

碎片的静态注册

每个碎片都有对应的XML布局文件,依据其使用方式可分为静态注册与动态注册两类。静态注册指的是

在XML文件中直接放置fragment节点,类似于一个普通控件,可被多个布局文件同时引用。静态注册一

般用于某个通用的页面部件(如Logo条、广告条等),每个活动页面均可直接引用该部件。

下面是碎片页对应的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">
    <TextView
    android: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" />
    <ImageView
    android: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>

下面是与上述XML布局对应的碎片代码,除了继承自Fragment与入口方法onCreateView两点,其他地

方类似活动页面代码。

public class StaticFragment extends Fragment implements View.OnClickListener {
private static final String TAG = "StaticFragment";
protected View mView; // 声明一个视图对象
protected Context mContext; // 声明一个上下文对象
// 创建碎片视图
	@Override
public 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; // 返回该碎片的视图对象
}
	@Override
	public 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();
	}
  }
}

Toast函数

public class ToastUtil {
    public static void show(Context ctx, String desc) {
        Toast.makeText(ctx, desc, Toast.LENGTH_SHORT).show();
    }

}

inflater.inflate(R.layout.fragment_static, container, false);

LayoutInflater.inflate()方法是将一个XML文件转换成一个视图对象的重要函数,它需要传入需要实例化的布局文件、父容器等参数,以实现动态创建界面的功能。

若想在活动页面的XML文件中引用上面定义的StaticFragment,可以直接添加一个fragment节点,但需

注意下列两点:

(1)fragment节点必须指定id属性,否则App运行会报错。

(2)fragment节点必须通过name属性指定碎片类的完整路径。

<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指明了碎片来源 -->
    <fragment
    android:id="@+id/fragment_static"
    android:name="com.example.chapter08.fragment.StaticFragment"
    android:layout_width="match_parent"
    android:layout_height="60dp" />
    
    <TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:text="这里是每个页面的具体内容"
    android:textColor="#000000"
    android:textSize="17sp" />
</LinearLayout>

同时碎片也有自己的生存周期

总结一下,在静态注册时,除了碎片的创建操作在页面创建之前,其他操作没有僭越页面范围。就像老

实本分的下级,上级开腔后才能说话,上级要做总结性发言前赶紧闭嘴。

碎片的动态注册

实际开发中动态注册用得更多。静态注册是在XML文件中直接添加fragment节点,而动态注册迟至代码执行时才动态添加碎片。动态生成的碎片基本给翻页视图使用,要知道ViewPager和Fragment可是一对好搭档。

public class FragmentDynamicActivity extends AppCompatActivity {

    private ArrayList<GoodsInfo> mGoodsList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment_dynamic);
        initPagerStrip();
        initViewPager();
    }

    // 初始化翻页标签栏
    private void initPagerStrip() {
        PagerTabStrip pts_tab = findViewById(R.id.pts_tab);
        // 设置翻页标签栏的文本大小
        pts_tab.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
        pts_tab.setTextColor(Color.BLACK);
    }

    // 初始化翻页视图
    private void initViewPager() {
        ViewPager vp_content = findViewById(R.id.vp_content);
        mGoodsList = GoodsInfo.getDefaultList();
        MobilePagerAdapter adapter = new MobilePagerAdapter(getSupportFragmentManager(), mGoodsList);
        vp_content.setAdapter(adapter);
    }
}

R.layout.activity_fragment_dynamic 该文件和前文的一样

<androidx.viewpager.widget.ViewPager
    android:id="@+id/vp_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.viewpager.widget.PagerTabStrip
        android:id="@+id/pts_tab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</androidx.viewpager.widget.ViewPager>

适配器如下:

public class MobilePagerAdapter extends FragmentPagerAdapter {

    private final List<GoodsInfo> mGoodsList;

    public MobilePagerAdapter(@NonNull FragmentManager fm, List<GoodsInfo> goodsList) {
        // 会将当前fragment设置为Resume的状态,把上个fragment设置成Start的状态。
        // 从而可以通过fragment的onResume()来懒加载数据。
        super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
        this.mGoodsList = goodsList;
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        GoodsInfo info = mGoodsList.get(position);
        return DynamicFragment.newInstance(position, info.pic, info.description);
    }

    @Override
    public int getCount() {
        return mGoodsList.size();
    }

    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        return mGoodsList.get(position).name;
    }
}

上面的适配器代码在getItem方法中不调用碎片的构造方法,却调用了newInstance方法,目的是给碎片对象传递参数信息。由newInstance方法内部先调用构造方法创建碎片对象,再调用setArguments方法塞进请求参数,然后在onCreateView中调用getArguments方法才能取出请求参数。

接下来是Fragment

public class DynamicFragment extends Fragment {

    private static final String TAG = "fragment";

    public static DynamicFragment newInstance(int position, int image_id, String desc) {
        DynamicFragment fragment = new DynamicFragment();
        // 把参数打包,传入fragment中
        Bundle args = new Bundle();
        args.putInt("position", position);
        args.putInt("image_id", image_id);
        args.putString("desc", desc);
        fragment.setArguments(args);
        return fragment;
    }

    // 从包裹取出位置序号
    private int getPosition(){
        return getArguments().getInt("position", 0);
    }

    @Override
    public void onAttach(@NonNull Context context) { // 把碎片贴到页面上
        super.onAttach(context);
        Log.d(TAG, "fragment onAttach position=" + getPosition());
    }

    @Override
    public void onCreate(Bundle savedInstanceState) { // 页面创建
        super.onCreate(savedInstanceState);
        Log.d(TAG, "fragment onCreate position=" + getPosition());
    }

    // 创建碎片视图
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 根据布局文件fragment_dynamic.xml生成视图对象
        View view = inflater.inflate(R.layout.fragment_dynamic, container, false);
        Bundle arguments = getArguments();
        if (arguments != null){
            ImageView iv_pic = view.findViewById(R.id.iv_pic);
            TextView tv_desc = view.findViewById(R.id.tv_desc);
            iv_pic.setImageResource(arguments.getInt("image_id",R.drawable.huawei));
            tv_desc.setText(arguments.getString("desc"));
        }
        Log.d(TAG, "fragment onCreateView position=" + getPosition());
        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) { //在活动页面创建之后
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG, "fragment onActivityCreated position=" + getPosition());
    }
}

fragment_dynamic.xml

<ImageView
    android:id="@+id/iv_pic"
    android:layout_width="match_parent"
    android:layout_height="360dp"
    android:scaleType="fitCenter" />

<TextView
    android:id="@+id/tv_desc"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="left"
    android:textColor="@color/black"
    android:textSize="17sp" />