什么是Fragment?
1:具备生命周期,小Activity
2:必须委托在activity中才能运行
Fragment初体验
1、创建fragment_blank.xml
<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="com.example.fragment.BlankFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="@string/hello_blank_fragment" />
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="how are you?"/>
</LinearLayout>
2、创建Fragment
package com.example.fragment;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.example.chapter01.R;
public class BlankFragment extends Fragment {
private View root;
private TextView tv;
private Button btn;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// 用解析器解析,与Activity不同
if (root == null) {
root = inflater.inflate(R.layout.fragment_blank, container, false);
}
tv = root.findViewById(R.id.tv);
btn = root.findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tv.setText("Yes,I am,and you?");
}
});
return root;
}
}
3、在activity_main.xml文件中加入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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.fragment.MainActivity">
<fragment android:name="com.example.fragment.BlankFragment"
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/fragment_blank" />
</LinearLayout>
如何在activity中添加2个fragment?
再次创建一个Fragment并添加在activity_main.xml
动态添加Fragment
动态添加Fragment步骤:
1)创建一个待处理的fragment
2)获取FragmentManager,一般都是通过getSupportFragmentManager()
3)开启一个事务transaction,一般调用fragmentManager的beginTransaction()
4) 使用transaction进行 fragment的替换
5)提交事务
1、在activity_main.xml中创建2个Button,1个FrameLayout
<?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="com.example.fragmentbase.Main2Activity">
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/change"></Button>
<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/replace"></Button>
<FrameLayout
android:id="@+id/framelayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ffff"></FrameLayout>
</LinearLayout>
2、创建两个Fragment用于动态切换
3、在MainActivity中为2个Button设置监听并创建动态切换Fragment的方法
package com.example.fragmentbase;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.example.myapplication.R;
public class Main2Activity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Button button1 = findViewById(R.id.btn1);
button1.setOnClickListener(this);
Button button2 = findViewById(R.id.btn2);
button2.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.btn1) {
replaceFragment(new BlankFragment());
} else if (view.getId() == R.id.btn2) {
replaceFragment(new ItemFragment());
}
}
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.framelayout,fragment);
fragmentTransaction.commit();
}
}
下面这段代码是核心代码
增加一个需求:按返回键会返回到上一个Fragment界面,而不是直接回到主界面。
解决方法:添加栈;方法addToBackStack();用法如图:
Activity和Fragment的通信
有三种情况:
1.Activity发消息给Fragment
2.Fragment➡Activity
3.Fragment➡Fragment
首先先学习1.Activity发消息给Fragment
原生方案
1.在Activity里把需要发送给Fragment的消息存在Bundle里
2.在Fragment中获取存在Bundle里的消息并打印
运行点击后
接口方案
Fragment向Activity发送消息
1、创建接口
package com.example.fragmentbase;
public interface IFragmentCallBack {
void sendMsg2Activity(String msg);
String getMsg4Fragment(String msg);
}
2、在Fragment中创建接口对象并用方法封装;在点击按钮事件里放入要发送的消息
3、在Activity中调用Fragment封装的方法获取消息(具体用方法Toast.makeText()实现)
注:此处Toast.makeText()的形参不能用this,他代表的是匿名内部类本身,需传入Activity对象的this。
Activity发送消息给Fragment
在原有基础上改动代码即可。
1、由Activity发送的消息存在接口方法中
2、由Fragment的点击事件接收消息
注:此处传入方法的形参BlankFragment.this没有上下文context,需要获取后传入,所以传入BlankFragment.this.getContext().
其他方案:eventBus,LiveData...
他们都包含设计模式:观察者,发布订阅。
Fragment生命周期
Fragment不能独立存在,必须嵌入Activity,所以Fragment生命周期直接受所在的Activity影响 。
当Activity创建Fragment时,Fragment处于启动状态,当Activity被暂停时, 它所拥有的所有Fragment也被暂停,当Activity被销毁时,所有在该Activity中的Fragment也被销毁 。
当一个Activity处于运行状态时,可以单独地对每一个Fragment进行操作,如添加或删除,当添加时,Fragment处于启动状态。当删除时,Fragment处于销毁状态。
DialogFragment
创建DialogFragment的方法
用DialogFragment实现登录退出的弹窗效果
1、MainActivity
package com.example.myapplication4;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.DialogFragment;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements LoginInputListener{
private Button btn_login, btn_logout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_login = findViewById(R.id.button);
btn_logout = findViewById(R.id.button2);
btn_logout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
DialogFragment dialogFragment = new DialogLogoutFragment();
dialogFragment.show(getSupportFragmentManager(), "退出");
}
});
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
DialogLoginFragment dialogLoginFragment = new DialogLoginFragment();
dialogLoginFragment.show(getSupportFragmentManager(), "登录");
}
});
}
@Override
public void onDialogPositiveClick(String username, String password) {
Toast.makeText(this, username +"你好" + password, Toast.LENGTH_SHORT).show();
}
@Override
public void onDialogNegativeClick(DialogFragment dialogFragment) {
Toast.makeText(this, "取消", Toast.LENGTH_SHORT).show();
}
}
2、登录弹窗DialogLoginFragment
package com.example.myapplication4;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import java.util.Objects;
public class DialogLoginFragment extends DialogFragment {
private LoginInputListener listener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.login_dialog, container);
EditText editName = view.findViewById(R.id.editPersonName);
EditText editPassword = view.findViewById(R.id.editPassword);
Button btnLoginDialogcheck = view.findViewById(R.id.btnLoginCheck);
Button btnLoginDialogcan = view.findViewById(R.id.btnLoginCan);
btnLoginDialogcan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onDialogNegativeClick(DialogLoginFragment.this);
DialogLoginFragment.this.dismiss();
}
});
btnLoginDialogcheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String username = editName.getText().toString();
String password = editPassword.getText().toString();
listener.onDialogPositiveClick(username, password);
DialogLoginFragment.this.dismiss();
}
});
return view;
}
@Override
public void onAttach(@NonNull Context context) {
listener = (LoginInputListener) context;
super.onAttach(context);
}
@Override
public void onStart() {
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
Objects.requireNonNull(getDialog().getWindow());
super.onStart();
}
}
3、退出弹窗DialogLogoutFragment
package com.example.myapplication4;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
public class DialogLogoutFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog builder = new AlertDialog.Builder(getActivity())
.setTitle("Logout")
.setMessage("Are you sure you want to logout?")
.setPositiveButton("Yes", (dialog, which) -> {
dialog.dismiss();
getActivity().finish();
})
.setNegativeButton("No", (dialog, which) -> {
dialog.dismiss();
})
.create();
return builder;
}
}
4、创建一个接口LoginInputListener.java
package com.example.myapplication4;
import androidx.fragment.app.DialogFragment;
public interface LoginInputListener {
public void onDialogPositiveClick(String username, String password);
public void onDialogNegativeClick(DialogFragment dialogFragment);
}
5、activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登录"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.415" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="退出"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.499" />
</androidx.constraintlayout.widget.ConstraintLayout>
6、login_dialog.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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srcCompat="@mipmap/ic_launcher" />
<EditText
android:id="@+id/editPersonName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:hint="Please input Name" />
<EditText
android:id="@+id/editPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPassword"
android:hint="Please input password"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="@+id/btnLoginCheck"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="确认"
android:layout_marginTop="10dp"/>
<Button
android:id="@+id/btnLoginCan"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="取消"
android:layout_marginTop="10dp"/>
</LinearLayout>
</LinearLayout>