草庐IT

CrimeFragment的UI fragment进行管理

人海中的海盗 2023-04-05 原文
用户界面将由一个名为 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 {
    //该抽象方法可实例化新的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);
}

有关CrimeFragment的UI fragment进行管理的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  3. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  4. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  5. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  6. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  7. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  8. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了ruby​​版本管理器,并将RVM安装的ruby​​实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby​​。有没有办法让emacs像shell一样尊重ruby​​的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el

  9. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  10. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

随机推荐