Fragment & ViewPager
一、Fragment
1.fragment加载
(1)静态加载fragment
-
创建一个fragment,在其xml布局文件中添加如下代码,实现点击按钮切换文字的效果
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".BlankFragment1"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="40dp" android:id="@+id/textview" android:text="@string/hello_blank_fragment" /> <Button android:layout_width="match_parent" android:layout_height="40dp" android:text="how are you?" android:id="@+id/btn"/> </LinearLayout>
-
在fragment.java文件中,添加逻辑代码
public class BlankFragment1 extends Fragment {
private View root;
private TextView textView;
private Button button;
public BlankFragment1(){}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//如果为空
if (root == null) {
root = inflater.inflate(R.layout.fragment_blank1, container, false);
}
//添加控件的点击事件
textView = root.findViewById(R.id.textview);
button = root.findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
textView.setText("Yes,I am,and you?");
}
});
return root;
}
}
```
刚才创建的fragment要继承Fragment类,里面会自动添加几个方法,这几个方法与fragment的声明周期有关系,可以自己研究一下fragment的生命周期,fragment就是一个小型的activi。
- 在mainactivity的xml布局文件中,添加刚才我们创建的fragment,实现对fragment的绑定
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<fragment android:name="com.example.fragmentbase.BlankFragment1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/fragment1"/>
</LinearLayout>
这样就实现了fragment的静态加载
(2)fragment的动态加载
- 在主活动的xml文件中加上如下代码,通过button实现页面的切换
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn"
android:text="@string/change"></Button>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_2"
android:text="@string/replace"></Button>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/framelayout"
android:background="@color/colorAccent"></FrameLayout>
</LinearLayout>
-
创建一个fragment 名为BlankFragment1
- 创建一个fragment 名为 ItemFragment
-
主活动的.java文件中添加以下代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = findViewById(R.id.btn); button.setOnClickListener(this); Button button2 = findViewById(R.id.btn_2); button2.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn: BlankFragment1 bf = new BlankFragment1(); replaceFragment(bf); break; case R.id.btn_2: replaceFragment(new ItemFragment() ); } } // 动态切换fragment private void replaceFragment(Fragment fragment) { //获取fragment的管理类,来管理fragment FragmentManager fragmentManager = getSupportFragmentManager(); //设置触发器,得到FragmentTransaction,fragment的替换动作由beginTransaction完成 FragmentTransaction transation = fragmentManager.beginTransaction(); //把需要的id替换进去 transation.replace(R.id.framelayout, fragment); //把fragment添加到一个栈里面去 transation.addToBackStack(null); //必须提交才能执行! transation.commit(); } }
至此就完成了fragment的动态添加
" 动态添加fragment的过程分为5步来执行":
1.创建一个待处理的fragment;
2.获取FragmentManager,一般都是通过getSupportFragmentManager();
3.开启一个事务transaction,调用transaction的beginTransaction()
4.使用transaction进行fragment的替换
5.提交事务
2.Activity 与 Fragment 的通信
(1)原生方案:Bundle
-
把上面的主活动中oncreate()代码修改如下:
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn:
//定义一个Bundle
Bundle bundle = new Bundle();
bundle.putString(“message”, " i love you");
//添加一个fragment
BlankFragment1 bf = new BlankFragment1();
//向一个fragment中传递参数
bf.setArguments(bundle);
bf.setFragmentCallback(new IFragmentCallback() {
@Override
public void sendMsgToActivity(String msg) {
Toast.makeText(MainActivity.this,msg, Toast.LENGTH_SHORT).show();
}
@Override
public String getMsgFromActivity(String msg) {
return "hello, I am from activity";
}
});
replaceFragment(bf);
break;
case R.id.btn_2:
replaceFragment(new ItemFragment() );
}
}
##### (2)接口
* 定义一个接口 命名为 IFragmentCallback
```java
public interface IFragmentCallback {
void sendMsgToActivity(String msg);
String getMsgFromActivity(String msg);
}
-
在fragment的xml文件中,添加代码,通过按钮实现数据的传递:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".BlankFragment1"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/hello_blank_fragment" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/btn_3" android:text="数据传递"/> </FrameLayout>
-
在fragment中修改代码;
public class BlankFragment1 extends Fragment { private static final String TAG = "BlankFragment1"; private View rootview; public BlankFragment1() { // Required empty public constructor } private IFragmentCallback fragmentCallback; public void setFragmentCallback(IFragmentCallback callback){ fragmentCallback = callback; } @Override public void onAttach(@NonNull Context context) { super.onAttach(context); Log.d(TAG, "onAttach: "); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle bundle = this.getArguments(); String string = bundle.getString("message"); Log.d(TAG, "onCreate: " + string); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment if (rootview == null){ rootview = inflater.inflate(R.layout.fragment_blank1, container, false); } Button btn = rootview.findViewById(R.id.btn_3); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // fragmentCallback.sendMsgToActivity("hello, I'm from Fragment"); String msg = fragmentCallback.getMsgFromActivity("null"); Toast.makeText(BlankFragment1.this.getContext(), msg, Toast.LENGTH_SHORT).show(); } }); Log.d(TAG, "onCreateView: "); return rootview; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log.d(TAG, "onActivityCreated: "); }
(3)Fragment的生命周期
- 打开页面 onCreate()-> onCreateView() -> onActivityCreated() -> onStart() -> onResume()
- 按下主屏键 onPause() -> onStop()
- 重新打开界面 onStart() -> onResume()
- 按back键 onPause() -> onStop() -> onDestroyView() -> onDestroy() -> onDetach()
二、ViewPager
1.viewpager用法:
-
创建几个layout做准备(两个或两个以上,代码不展示了)
-
主活动xml文件中 添加以下代码当做viewpage的容器
<androidx.viewpager.widget.ViewPager android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/vp" />
-
在主活动 .java 文件中绑定ViewPagr控件
ViewPager viewPager = findViewById(R.id.vp);
-
创建viewPager适配器
public class MyAdapter extends PagerAdapter { private List<View> mlist; public MyAdapter(List<View> mlist){ this.mlist = mlist; } //返回viewPager的数量 @Override public int getCount() { return mlist.size(); } @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { //拿到对应位置的view container.addView(mlist.get(position),0); return mlist.get(position); } //判断是否相等 @Override public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { return false; } }
-
主活动中添加如下代码:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager viewPager = findViewById(R.id.vp); //进行数据的渲染,拿到数据 LayoutInflater lf = getLayoutInflater().from(this); View view1 = lf.inflate(R.layout.layout1,null); View view2 = lf.inflate(R.layout.layout2,null); View view3 = lf.inflate(R.layout.layout3,null); //渲染数据到主界面上 List<View> viewList = new ArrayList<>(); viewList.add(view1); viewList.add(view1); viewList.add(view1); MyAdapter myAdapter = new MyAdapter(viewList); viewPager.setAdapter(myAdapter); } }
然后运行项目就可以了。viewpager滑动效果就可以了
2.viewPager与Fragment 嵌套使用形成翻页效果
- 在主活动的xml文件中修改代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/viewPager"
android:background="@color/colorAccent">
</androidx.viewpager2.widget.ViewPager2>
</LinearLayout>
-
添加一个ViewPager数据适配器
public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.ViewPagerViewHolder> { private List<String> titles = new ArrayList<>(); private List<Integer> colors = new ArrayList<>(); public ViewPagerAdapter(){ titles.add("1"); titles.add("2"); titles.add("3"); titles.add("4"); titles.add("5"); titles.add("6"); titles.add("7"); titles.add("8"); titles.add("9"); titles.add("10"); colors.add(R.color.white); colors.add(R.color.black); colors.add(R.color.red); colors.add(R.color.colorAccent); colors.add(R.color.colorPrimary); colors.add(R.color.white); colors.add(R.color.black); colors.add(R.color.red); colors.add(R.color.colorPrimary); colors.add(R.color.white); } @NonNull @Override public ViewPagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new ViewPagerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_pager, parent, false)); } @Override public void onBindViewHolder(@NonNull ViewPagerViewHolder holder, int position) { holder.mTv.setText(titles.get(position)); holder.mContainer.setBackgroundResource(colors.get(position)); } @Override public int getItemCount() { return 10; } class ViewPagerViewHolder extends RecyclerView.ViewHolder{ TextView mTv; RelativeLayout mContainer; public ViewPagerViewHolder(@NonNull View itemView) { super(itemView); mContainer = itemView.findViewById(R.id.container); mTv = itemView.findViewById(R.id.tvTitle); } } }
这个适配器和 RecycleView 的数据适配器其实一样的,不懂得可以看看我的另外一篇文章RecycleView的使用及优化
-
新建一个xml文件,作为viewPager的页面展示效果
<?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:id="@+id/container">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvTitle"
android:layout_centerInParent="true"
android:textColor="#ff4532"
android:textSize="32dp"
android:text="hello"></TextView>
</RelativeLayout>
-
最后在主活动中修改代码:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager2 viewPager = findViewById(R.id.viewPager); ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(); viewPager.setAdapter(viewPagerAdapter); } }