使用Fragment建立动态UI

使用Fragment建立动态UI

         为了在Android上为用户提供动态的、多窗口的交互体验,我们需要将UI组件和Activity操作封装成模块进行使用,使得我们可以在activity中对这些模块进行切入切出操作。可以用Fragment来创建这些模块,Fragment就像一个嵌套的activity,拥有自己的布局(layout)并管理自己的生命周期。接收自己的输入事件,可以在acvitity运行过程中添加或者移除(有点像"子activity",可以在不同的activity里面重复使用)。一个fragment定义了自己的布局后,它可以在activity中与其他的fragment生成不同的组合,从而为不同的屏幕尺寸生成不同的布局(一个小的屏幕一次也许只能一个fragment,大的屏幕则可以显示更多)。

         一 . 创建一个Fragment类

         创建一个fragment,首先需要继承Fragment类,然后在关键的生命周期方法中插入APP的逻辑,就像Activity一样。其中一个区别是当创建Fragment的时,必须重写onCreateView()回调方法来定义布局。事实上,这是使Fragment运行起来,唯一一个需要我们重写的回调方法。比如,下面是一个自定义布局的示例fragment.

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.ViewGroup;
 
public class ArticleFragment extends Fragment {
    @Override
   public View onCreateView(LayoutInflaterinflater, ViewGroup container,
       Bundle savedInstanceState){
       // Inflate the layout for this fragment
       return inflater.inflate(R.layout.article_view,container,false);
    }
}


就像activity一样,当fragment从activity添加或者移除、当activity生命周期发生变化时,fragment通过生命周期回调函数管理其状态。例如,当activity的onPause()被调用时,它里面的所有fragment的onPause()方法也会被触发。

    .XMLFragment添加到Activity

fragments是可重用的,模块化的UI组件,每个Fragment的实例都必须与一个FragmentActivity关联。我们可以在activity的XML布局文件中定义每一个fragment来实现这种关联。FragmentActivity是Support Library提供的一个特殊activity ,用于处理API11版本以下的fragment。如果我们APP中的最低版本大于等于11,则可以使用普通的Activity

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
 
   <fragment 
             android:id="@+id/headlines_fragment"
             android:layout_weight="1"
             android:layout_width="0dp"
             android:layout_height="match_parent" />
 
   <fragment
             android:id="@+id/article_fragment"
             android:layout_weight="2"
             android:layout_width="0dp"
             android:layout_height="match_parent" />
 
</LinearLayout>


然后再将这个布局添加到Activity中

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
 
public class MainActivity extends FragmentActivity {
    @Override
   public void onCreate(BundlesavedInstanceState){
       super.onCreate(savedInstanceState);
       setContentView(R.layout.news_articles);
    }
}


如果用的是 v7 appcompat library,activity应该改为继承ActionBarActivity,ActionBarActivity是FragmentActivity的一个子类。当通过XML布局文件的方式将Fragment添加进activity时,Fragment是不能被动态移除的。如果想要在用户交互的时候把fragment切入与切出,必须在activity启动后,再将fragment添加进activity

       .建立灵活动态的UI

比如,一个手持设备可能适合一次只有一个fragment的单面板用户交互。而在更大屏幕尺寸的平板电脑上,我们可能更想要两个fragment并排在一起,用来向用户展示更多信息。两个fragments,在同一个activity不同屏幕尺寸中用不同的配置来展示。在大屏幕上,两个fragment被并排放置,在手持设备上,一次只放置一个fragment,所以在用户导航中,两个fragment必须进行替换。FragmentManager类为在activity运行时对fragment进行添加,移除,替换等操作提供了方法,来实现动态的用户体验

 

         .Activity运行时动态添加Fragment

比起用<fragment>标签在activity的布局文件中定义fragment,我们还可以在activity运行时动态添加fragment,如果打算在activity的生命周期内替换fragment,这是必须的。为了执行fragment的增加或者移除操作,必须通过FragmentManager创建一个FragmentTransaction对象,FragmentTransaction提供了用来增加、移除、替换以及其它一些操作的APIS。如果我们的activity允许fragment移除或者替换,我们应该在activity的onCreate()方法中添加初始化fragment(s)

运用fragment(尤其是那些在运行时添加的)的一个很重要的规则就是在布局中必须有一个容器View,fragment的layout将会放在这个view里面。activity中,用Support Library APIs调用 getSupportFragmentManager()方法获取FragmentManager对象,然后调用 beginTransaction() 方法创建一个FragmentTransaction对象,然后调用add()方法添加一个fragment.可以使用同一个 FragmentTransaction进行多次fragment事务。完成这些变化操作,准备开始执行改变时,必须调用commit()方法。

下例显示了如何添加一个fragment到之前的layout中

importandroid.os.Bundle;
importandroid.support.v4.app.FragmentActivity;
 
publicclassMainActivityextendsFragmentActivity {
    @Override
   publicvoidonCreate(BundlesavedInstanceState){
       super.onCreate(savedInstanceState);
        setContentView(R.layout.news_articles);
       if (findViewById(R.id.fragment_container) !=null) {
           if (savedInstanceState !=null) {
               return;
           }
           HeadlinesFragment firstFragment =newHeadlinesFragment();
           firstFragment.setArguments(getIntent().getExtras());
           getSupportFragmentManager().beginTransaction()
                   .add(R.id.fragment_container, firstFragment).commit();
       }
    }
}   


    五 .替换Fragment

替换fragment的过程类似于添加过程,只需要将add()方法替换为 replace()方法。记住在执行fragment事务时,如移除或者替换,我们经常要适当地让用户可以向后导航与"撤销"这次改变。为了让用户向后导航fragment事务,我们必须在FragmentTransaction提交前调用addToBackStack()方法。

Note当移除或者替换一个fragment并把它放入返回栈中时,被移除的fragment的生命周期是stopped(不是destoryed).当用户返回重新恢复这个fragment,它的生命周期是restarts。如果没有把fragment放入返回栈中,那么当它被移除或者替换时,其生命周期是destoryed。

 

下面是一个fragment替换的例子

 

ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
 
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
 
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
 
transaction.commit();


addToBackStack()方法提供了一个可选的String参数为事务指定了一个唯一的名字。除非打算用FragmentManager.BackStackEntry APIs来进行一些高级的fragments操作,这个名字不是必须的。
     

六 . Frgament 之间的交互

通常fragment之间可能会需要交互,比如基于用户事件改变fragment的内容。所有fragment之间的交互需要通过他们关联的activity,两个fragment之间不应该直接交互。
1 . 定义一个接口
  为了让Fragmentactivity交互可以在Fragment中定义一个接口并在Activity中实现,Fragment在它们的生命周期的onAttach()方法中获取接口的实现然后调用接口的方法与Activity交互。
public class TestFragment extends ListFragment {
OnHeadlineSelected mCallBack;
    Int position;
    public interface OnHeadlineSelected{
        public void onArticleSelected(int position);
    }
 
    public void onAttach(Activity activity){
        super.onAttach(activity);
        mCallBack = (OnHeadlineSelected)activity;
    }
 
    public void getPosition(){
        this.position = position;
    }
}


现在Fragment就可以通过OnHeadlineSelectedListener 接口实例mCallBack中的OnArticleSelected()方法与Activity传递消息。
比如在Fragment中点击ListView的一个条目时调用OnArticleSelected()方法Fragment通过回调接口来传递事件给父Activity
2 . Activity中实现接口
public class TestActivity extends Activity implements TestFragment.OnHeadlineSelected{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
 
    @Override
    public void onArticleSelected(int position) {
        /**
         * doing something
         */
    }
}


3 . 传消息给Fragment
Activity中获取Fragment实例然后直接调用getPosition()方法向Fragment传递消息。
 
假定上面的Activity中包含另外一个Fragment这个Fragment用来展示从上面的回调方法中返回的指定的数据,在这种情况下Activity可以把回调方法中接收到的消息传递给这个展示数据的Fragment
public class TestActivity extends FragmentActivity implements TestFragment.OnHeadlineSelected{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment);
        TestFragment fragment = (TestFragment)getSupportFragmentManager().findFragmentById(R.id.fragment);
        if(fragment != null) {
            fragment.setPosition(0);
        } else {
            TestFragment testFragment = new TestFragment();
            Bundle bundle = new Bundle();
            bundle.putInt("position", 0);
            testFragment.setArguments(bundle);
            android.support.v4.app.FragmentTransaction transaction =
                    getSupportFragmentManager().beginTransaction();
            transaction.replace(R.id.fragment, testFragment);
            transaction.commit();
        }
 
    }
 
    @Override
    public void onArticleSelected(int position) {
        /**
         * doing something
         */
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值