Fragment
1.什么是Fragment
Fragment的两个特性
1)具备生命周期
2)必须委托在activity中才能运行
2.Fragment使用方法
创建一个Activity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
创建一个fragment
public class BlankFragment1 extends Fragment {
private View root;
private TextView textView;
private Button button;
@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.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView.setText("Yes,I am ,and you?");
}
});
return root;
}
}
fragment布局
<?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">
<TextView
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="@string/hello_blank_fragment" />
<Button
android:text="how are you?"
android:layout_width="match_parent"
android:layout_height="40dp"
android:id="@+id/button"/>
</LinearLayout>
activtiy布局
<?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:id="@+id/fragment1"//id必须有
android:name="com.example.fragmenttest.BlankFragment1"//name必须有
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
运行结果,点击按钮,内容变成Yes......
在activity中添加两个fragment
复制fragment1,命名fragment2
public class BlankFragment2 extends Fragment {
private View root;
private TextView textView;
private Button button;
@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.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView.setText("Yes,I am ,and you?");
}
});
return root;
}
}
activtiy布局新增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:id="@+id/fragment1"
android:name="com.example.fragmenttest.BlankFragment1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<fragment
android:id="@+id/fragment2"
android:name="com.example.fragmenttest.BlankFragment2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
/>
</LinearLayout>
点击按钮后的运行结果:
image.png
Fragment的动态添加与管理
创建Activity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn1 = findViewById(R.id.btn1);
btn1.setOnClickListener(this);
Button btn2 = findViewById(R.id.btn2);
btn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn1:
replaceFragment(new BlankFragment());
break;
case R.id.btn2:
replaceFragment(new ItemFragment());
}
}
//动态切换fragment
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.framelayout,fragment);
transaction.commit();
}
}
创建布局
<?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">
<Button
android:id="@+id/btn1"
android:text="change"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn2"
android:text="replace"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="@+id/framelayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent"/>
</LinearLayout>
创建一个BlankFragment 一个listFragment
image.png
运行结果:
点击按钮一change
image.png
点击按钮二replace
image.png
Activity与Fragment之间的通信
原生方案:bundle
在studio中输入logt,就会直接声明出来log中的TAG变量,即:
private static final String TAG = "BlankFragment";
1.从Activtiy发送信息到Fragment
首先在MainActivtiy中的点击事件中添加Bundle
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
Bundle bundle = new Bundle();
bundle.putString("message", "work hard no why");
BlankFragment blankFragment = new BlankFragment();
blankFragment.setArguments(bundle);
replaceFragment(blankFragment);
break;
}
}
其次在Fragment的onCreate中获取
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
String string = bundle.getString("message");
Log.d(TAG, "onCreate: "+string);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
点击第一个按钮后,运行结果就会把刚刚传入的信息打印出来,即work hard no why.
动态添加fragment步骤:
1) 创建一个待处理的fragment
2)获取FragmentManager,一般都是通过getSupportFragmentManager();
3)开启一个事物transaction,一般调用fragmentManager的beginTransaction
4)使用transaction进行fragmenet的替换
5)提交事务 transaction.commit();
fragment与Activity通信的接口方案
Java语言中类与类之间通信的方案:
1.接口回调
首先创建一个接口:
package com.example.fragmanager;
/**
* @author zwp
* @description:
* @date: 2021/5/26 14:28
*/
public interface IFragmentCallBack {
void sendMsgToActivity(String msg);
String getMsgFromActivity(String msg);
}
在fragment中创建一个实现接口的类:
package com.example.fragmanager;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
public class BlankFragment extends Fragment {
private static final String TAG = "BlankFragment";
private View rootView;
public BlankFragment() {
}
private IFragmentCallBack iFragmentCallBack;
public void setIFragmentCallBack(IFragmentCallBack callBack) {
iFragmentCallBack = callBack;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
String string = bundle.getString("message");
Log.d(TAG, "onCreate: " + string);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (rootView == null) {
rootView = inflater.inflate(R.layout.fragment_blank, container, false);
}
Button btn = rootView.findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
iFragmentCallBack.sendMsgToActivity("hello,I am from fragment");//发送消息给activity
}
});
return rootView;
}
@Override
public void onResume() {
super.onResume();
}
}
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=".BlankFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="数据传递" />
</FrameLayout>
在Activtiy中引用
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
Bundle bundle = new Bundle();
bundle.putString("message", "work hard no why");
BlankFragment blankFragment = new BlankFragment();
blankFragment.setArguments(bundle);
//匿名內部类
blankFragment.setIFragmentCallBack(new IFragmentCallBack() {
@Override
public void sendMsgToActivity(String msg) {
Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
}
@Override
public String getMsgFromActivity(String msg) {
return null;
}
});
replaceFragment(blankFragment);
break;
}
}
效果如下图所示,点击数据传递按钮:
image.png
从Activtiy中取消息
Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (rootView == null) {
rootView = inflater.inflate(R.layout.fragment_blank, container, false);
}
Button btn = rootView.findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// iFragmentCallBack.sendMsgToActivity("hello,I am from fragment");//发送消息给activity
String msg = iFragmentCallBack.getMsgFromActivity("从Activity取消息");
Toast.makeText(BlankFragment.this.getContext(), msg, Toast.LENGTH_SHORT).show();
}
});
return rootView;
}
Activity
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
Bundle bundle = new Bundle();
bundle.putString("message", "work hard no why");
BlankFragment blankFragment = new BlankFragment();
blankFragment.setArguments(bundle);
//匿名內部类
blankFragment.setIFragmentCallBack(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(blankFragment);
break;
case R.id.btn2:
replaceFragment(new ItemFragment());
}
}
运行结果:
image.png
通信的其他方案----->Eventbus LiveData
Fragment的生命周期
image.pngonAttach、onDetach
:Fragment与Activtiy之间的绑定和解绑因为Fragment依托于Activity,所以二者要进行绑定,使用结束之后要解绑。
常遇见的问题:在Fragment中获取Activtiy内容,获取到变量为空的时候,根本原因就是没有把相应生命周期执行放在onAttach、onDetach
之间执行。
onCreate
:fragment的创建------对Activtiy传过来的bundle进行解析
onDestroy
:fragment的销毁
onCreateView
:对UI的创建 Inflater.inflate......
onActivtiyCreated
:Activtiy已经创建了
下面的几个生命周期与Activity相对应。
Fragment生命周期
1.打开页面
onCreate()-->onCreateView()-->onActivityCreated()-->onStart()-->onResume()
2.按下主屏键
onpause()-->onStop()
3.重新打开页面
onStart()-->onResume()
4.按后退键
onPause()-->onStop()-->onDestroyView()-->onDestroy()-->onDetach()
Fragment生命周期注意事项
1.将来开发者会围绕fragment生命周期花很多时间来解决问题
2.Fragment的使用一定是需要在生命周期函数onAttach与onDetach之间
3.Fragment的使用一定要遵守生命周期管理的规则,在正确的地方写恰当的代码
案例:Fragment与ViewPager滑动效果
ViewPager的基本应用
ViewPager2依赖:
dependencies {
implementation "androidx.viewpager2:viewpager2:1.0.0"
}
ViewPager2自带懒加载功能
ViewPager使用流程
1.定义ViewPager
2.为ViewPager构建Adapter
创建Activtiy,并在xml中引用viewPager
activity
package com.example.viewpagerandfragment;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
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);
ViewPageAdapter viewPageAdapter = new ViewPageAdapter();
viewPager.setAdapter(viewPageAdapter);
}
}
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"/>
</LinearLayout>
创建一个item,用于显示布局内容
<?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:layout_centerInParent="true"
android:id="@+id/tvTitle"
android:textColor="#ff4532"
android:textSize="32sp"
android:text="hello"/>
</RelativeLayout>
创建adapter:
package com.example.viewpagerandfragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
/**
* @author zwp
* @description:
*/
public class ViewPageAdapter extends RecyclerView.Adapter<ViewPageAdapter.ViewPagerViewHolder> {
private List<String> titles = new ArrayList<>();//每个页面显示的具体内容
private List<Integer> colors = new ArrayList<>();//每个页面的颜色
ViewPageAdapter(){
titles.add("hello");
titles.add("6");
titles.add("7");
titles.add("8");
titles.add("9");
titles.add("1");
titles.add("2");
titles.add("3");
titles.add("4");
titles.add("5");
colors.add(R.color.white);
colors.add(R.color.colorPrimary);
colors.add(R.color.colorPrimaryDark);
colors.add(R.color.black);
colors.add(R.color.red);
colors.add(R.color.colorAccent);
colors.add(R.color.white);
colors.add(R.color.red);
colors.add(R.color.black);
colors.add(R.color.colorPrimary);
}
@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);
}
}
}
运行结果即十个页面显示内容不一致并且可以左右切换滑动