用户界面将由一个名为CrimeFragment的UI fragment进行管理。CrimeFragment的
实例将通过一个名为CrimeActivity的activity来托管。
CrimeActivity视图由FrameLayout组件组成,FrameLayout组件为CrimeFragment要显示
的视图安排了存放位置。
CrimeFragment 的视图由一个 LinearLayout 组件及一个 EditText 组件组成。
CrimeFragment类中有一个存储EditText的成员变量(mTitleField)。mTitleField上设有监
听器,当EditText上的文字发生改变时,用来更新模型层的数据。
FragmentActivity是Activity的子类,具有新系统版本
Activity类管理fragment的能力,即便是在较早版本的Android设备上也可对fragment进行管理。
创建CrimeActivity
托管 UI fragment
为托管UI fragment,activity必须做到:
在布局中为fragment的视图安排位置;
管理fragment实例的生命周期。
定义容器视图
修改activity_crime.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragmentContainer">
</FrameLayout>
创建 UI fragment
fragment视图的布局文件(fragment_crime.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=".CrimeFragment">
<EditText
android:id="@+id/crime_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入标题" />
</FrameLayout>
创建CrimeFragment
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.Toast;
import yu.app.criminalintent.model.Crime;
/**
*
*/
public class CrimeFragment extends Fragment {
private Crime mCrime;
private EditText mTitleField;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCrime=new Crime();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.fragment_crime, container, false);
mTitleField = v.findViewById(R.id.crime_title);
mTitleField.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence c, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence c, int start, int before, int count) {
mCrime.setmTitle(c.toString());
Toast.makeText(getContext(), c.toString(), Toast.LENGTH_SHORT).show();
}
@Override
public void afterTextChanged(Editable editable) {
}
});
// Inflate the layout for this fragment
return v;
}
}
Fragment.onCreateView(...)方法中的组件引用几乎等同于Activity.onCreate(...)
方法的处理。唯一的区别是我们调用了当前fragment视图的View.findViewById(int)方法。以前使
用的Activity.findViewById(int)方法十分便利,能够在后台自动调用View.findView
ById(int)方法。而Fragment类没有对应的便利方法,因此我们必须自己完成调用。
fragment中监听器方法的设置和activity中的处理完全一样。创建实现TextWatcher监听器接口的匿名内部类。TextWatcher有三种方法,不过我们现在只需关注其中 的onTextChanged(...)方法。
在onTextChanged(...)方法中,调用CharSequence(代表用户输入)的toString()方法。
该方法最后返回用来设置Crime标题的字符串。
CrimeFragment类的代码实现部分完成了。但现在还不能运行应用查看用户界面和检验代
码。因为fragment无法将自己的视图显示在屏幕上。接下来我们首先要把CrimeFragment添加给
CrimeActivity。
添加 UI fragment 到 FragmentManager
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import android.os.Bundle;
public class CrimeActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime);
//获取碎片管理
FragmentManager fm = getSupportFragmentManager();
//获取碎片存放的容器
Fragment f = fm.findFragmentById(R.id.fragmentContainer);
if (f==null){
//实例化碎片
f=new CrimeFragment();
//碎片管理开启事务添加实例化碎片到碎片存放容器中并提交事务
fm.beginTransaction().add(R.id.fragmentContainer, f).commit();
}
}
}
fragment事务被用来添加、移除、附加、分离或替换fragment队列中的fragment。这是使用
fragment在运行时组装和重新组装用户界面的核心方式。FragmentManager管理着fragment事务
的回退栈。
FragmentManager.beginTransaction()方法创建并返回FragmentTransaction实例。
FragmentTransaction类使用了一个fluent interface接口方法,通过该方法配置FragmentTran
saction返回FragmentTransaction类对象,而不是void,由此可得到一个FragmentTransa
ction队列。
add(...)方法是整个事务的核心部分,并含有两个参数,即容器视图资源ID和新创建的
CrimeFragment。容器视图资源ID我们应该很熟悉了,它是定义在activity_crime.xml中的
FrameLayout组件的资源ID。容器视图资源ID主要有两点作用:
告知FragmentManagerfragment视图应该出现在activity视图的什么地方;
是FragmentManager队列中fragment的唯一标识符。
升级Crime类
import java.util.Date;
import java.util.UUID;
public class Crime {
private UUID mID;
private String mTitle;
private Date mDate;
private boolean mSolved;
public Crime(){
//生成唯一标识符
mID=UUID.randomUUID();
mDate=new Date();
}
public UUID getmID() {
return mID;
}
public String getmTitle() {
return mTitle;
}
public void setmTitle(String mTitle) {
this.mTitle = mTitle;
}
public Date getmDate() {
return mDate;
}
public void setmDate(Date mDate) {
this.mDate = mDate;
}
public boolean ismSolved() {
return mSolved;
}
public void setmSolved(boolean mSolved) {
this.mSolved = mSolved;
}
}
更新fragment_crime.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=".CrimeFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/mCrime_title"
style="?android:listSeparatorTextViewStyle"/>
<EditText
android:id="@+id/crime_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/crime_title" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/crime_detail"
style="?android:listSeparatorTextViewStyle"/>
<Button
android:id="@+id/crime_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
/>
<CheckBox
android:id="@+id/crime_solved"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:text="@string/isSolved"/>
</LinearLayout>
</FrameLayout>
更新CrimeFragment
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Toast;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import yu.app.criminalintent.model.Crime;
/**
*
*/
public class CrimeFragment extends Fragment {
private Crime mCrime;
private EditText mTitleField;
private Button mDateBtn;
private CheckBox mSolvedCbox;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCrime=new Crime();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.fragment_crime, container, false);
mTitleField = v.findViewById(R.id.crime_title);
mTitleField.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence c, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence c, int start, int before, int count) {
mCrime.setmTitle(c.toString());
Toast.makeText(getContext(), c.toString(), Toast.LENGTH_SHORT).show();
}
@Override
public void afterTextChanged(Editable editable) {
}
});
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd E a HH:mm:ss");
mDateBtn = v.findViewById(R.id.crime_date);
mDateBtn.setText(dateFormat.format(mCrime.getmDate()));
mDateBtn.setEnabled(false);
mSolvedCbox = v.findViewById(R.id.crime_solved);
mSolvedCbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
mCrime.setmSolved(b);
Toast.makeText(getContext(), String.valueOf(mCrime.ismSolved()) , Toast.LENGTH_SHORT).show();
}
});
// Inflate the layout for this fragment
return v;
}
}
使用ListFragment显示列表
应用的模型层将新增一个CrimeLab对象,该对象是一个数据集中存储池,用来存储Crime对象。
显示crime列表需在应用的控制层新增一个activity和一个fragment,即CrimeListActivity
和CrimeListFragment。
CrimeListFragment 是 ListFragment 的子类, ListFragment 是 Fragment 的子类。
Fragment内置列表显示支持功能。控制层对象间、控制层对象与CrimeLab对象间彼此交互,进
行模型层数据的存取。
ArrayList<E>是一个支持存放指定数据类型对象的Java有序数组类,具有获取、新增及删除
数组中元素的方法。
创建CrimeLab
import android.content.Context;
import java.util.ArrayList;
import java.util.UUID;
public class CrimeLab {
private ArrayList<Crime> mCrimes;
private static CrimeLab crimeLab;
private Context appContext;
private CrimeLab(Context appContext){
this.appContext=appContext;
this.mCrimes=new ArrayList<>();
//测试 先往数组列表中批量存入100个Crime对象
for (int i=1;i<=100;i++){
Crime c=new Crime();
c.setmTitle("Crime标题#"+i);
c.setmSolved(i%2==0);
mCrimes.add(c);
}
}
public static CrimeLab get(Context c){
if (crimeLab==null){
crimeLab = new CrimeLab(c.getApplicationContext());
}
return crimeLab;
}
public ArrayList<Crime> getmCrimes() {
return mCrimes;
}
public Crime getCrime(UUID id){
for (Crime c : mCrimes){
if (c.getmID().equals(id)){
return c;
}
}
return null;
}
}
创建CrimeListActivity
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import yu.app.criminalintent.base.SingleFragmentActivity;
import yu.app.criminalintent.fragment.CrimeListFragment;
public class CrimeListActivity extends SingleFragmentActivity {
@Override
protected Fragment createFragment() {
return new CrimeListFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_crime_list_list, container, false);
return view;
}
}
创建CrimeListFragment
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.ListFragment;
import java.util.ArrayList;
import yu.app.criminalintent.R;
import yu.app.criminalintent.base.SingleFragmentActivity;
import yu.app.criminalintent.model.Crime;
import yu.app.criminalintent.model.CrimeLab;
/**
* A fragment representing a list of Items.
*/
public class CrimeListFragment extends ListFragment {
private static final String TAG = "CrimeListFragment";
private ArrayList<Crime> mCrimes;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCrimes = CrimeLab.get(getActivity()).getmCrimes();
ArrayAdapter<Crime> adapter = new ArrayAdapter<Crime>(getActivity(), android.R.layout.simple_expandable_list_item_1, mCrimes);
setListAdapter(adapter);
}
@Override
public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Crime c = (Crime) getListAdapter().getItem(position);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("提示信息");
builder.setMessage(c.toString());
builder.setPositiveButton("确定",new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//
}
});
AlertDialog alertDialog=builder.create();
alertDialog.show();
}
}
修改AndroidMainfest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.YuApp">
<activity
android:name=".CrimeListActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>
</manifest>
fragment_crime_list_list.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView 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/list"
android:name="yu.app.criminalintent.fragment.CrimeListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context=".fragment.CrimeListFragment"
tools:listitem="@layout/fragment_crime_list" />
创建SingleFragmentActivity
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import yu.app.criminalintent.R;
/**
* 通用fragment的抽象类
*/
public abstract class SingleFragmentActivity extends FragmentActivity {
//该抽象方法可实例化新的fragment,SingleFragmentActivity的子类会实现该方法返回一个由activity托管的fragment实例
protected abstract Fragment createFragment();
@Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime);
FragmentManager fm=getSupportFragmentManager();
Fragment f = fm.findFragmentById(R.id.fragmentContainer);
if (f==null){
f=createFragment();
fm.beginTransaction().add(R.id.fragmentContainer, f).commit();
}
}
public abstract View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState);
}
版权归原作者 人海中的海盗 所有, 如有侵权,请联系我们删除。