fragment
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" />