CrimeFragment的UI fragment进行管理
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
用户界面将由一个名为
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
主要有两点作用
告知
FragmentManager
fragment
视图应该出现在
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 {
//该抽象方法可实例化新的fragmentSingleFragmentActivity的子类会实现该方法返回一个由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);
}