fragment作为用户交互的组件之一,大家都经常接触到。对于fragment的操作不熟悉,会导致很多逻辑的错误。尤其是对它的生命周期的模糊不清,很容易导致fragment初始化失败。而通过fragment事务的操作,可以让我们写代码的时候更加模块化,所以很有必要了解FragmentTransaction这个东西。其次,fragment经常作为屏幕适配的一个解决方案,所以在后面的例子会讲解同一个屏幕使用双fragment的情况以及fragment与activity的相互交互的情况。下面逐一介绍FragmentTransaction,Fragmentmanger,Fragment,ListFragment,DialogFragment,WebViewFragment。
一、FragmentTransaction
public abstract FragmentTransaction add(int containerViewId, Fragment fragment, String tag)
public abstract FragmentTransaction replace(int containerViewId, Fragment fragment, String tag);
用于替换已经存在的安置于containerViewId的fragment。 注意执行完操作记得使用FragmentManager.commit方法进行事务的提交。此方法等同于通过移除所有与containerViewid的相关的fragment,然后再通过add方法将当前fragment添加进去。
public abstract FragmentTransaction remove(Fragment fragment);
从activity中移除指定的已存在的fragment,如果当前fragment正好添加进了activity的视图容器了,那么fragment的视图也会被移除。
参数解析:
fragment:将要被移除的对象。
④、隐藏fragment的事务操作:
public abstract FragmentTransaction hide(Fragment fragment);
隐藏指定的fragment对象,此方法只有在指定的fragment刚好在activity的视图容器里,才会把fragment的视图隐藏起来。
⑤、显示fragment的事务操作:
public abstract FragmentTransaction show(Fragment fragment);
显示指定的fragment,这个fragment通常是被隐藏的fragment对象并且已经添加到activity的视图容器里,这样才会重新显示被影藏的fragment视图。
⑥、移除fragment视图的事务操作:
public abstract FragmentTransaction detach(Fragment fragment);
此方法用于将fragment的视图销毁,但是fragment仍然是可用的,可通过fragmentManager重新复用(在FragmentManager里面其实保存了一个栈,存放了很多fragment事务)。
⑦、附加fragment视图的事务操作:
public abstract FragmentTransaction attach(Fragment fragment);
⑧、设置在此事务中所有fragment的显示显现动画:
public abstract FragmentTransaction setCustomAnimations(int enter, int exit)
⑨、提交事务的操作:
public abstract int commit();
将事务操作提交,此操作不会立即出发事务的执行,而是会进行排队等待,当线程准备好了才会执行,且必须是在主线程中调用这个方法。此方法必须在包含fragment的activity保存状态之前调用,否则的话会抛出异常。因为在保存状态之后调用commit方法,此fragment的状态就无法得到保存,对于activity恢复状态(比如配置改变了)来说就会发生错误。
细心的读者可以发现,上面所说的所有方法都是抽象方法,也就是说并不能直接被我们所用,那是不是说需要我们自己去实现呢。其实不是的,上面提到的这个方法只是为后面做铺垫。我们真正用于操控fragment的类是FragmentManager,FragmentManager方法有一个实现类叫做FragmentManaegerImpl,这个类里面包含了一个实现了FragmentTransaction的BackStackRecord类,后续的很多操作都是调用这个类来执行fragment的事务操作的。下面介绍一下FragmentManager。
⑩、将事务压入后退栈的操作:
public abstract FragmentTransaction addToBackStack(String name)
fragment的事务可以被压入后退栈(activity维护的一个用于保存fragmentd的事务操作的栈),在执行了commit方法之后,此事务就会被押入栈,之后,我们在按返回键返回的时候,此事务就会出栈并会还原成上次的视图状态出现在用户面前。
参数解析:
name:与当前事务相关的名字,可以为null。
二、FragmentManager
FragmentManager是一个抽象类,里面包含了大量的与Activity中的Fragment进行交互的接口,也是我们直接打交道的进行管理Fragment的类。对于这个类,有以下几点要注意:
①、开始一个Fragment事务。
public abstract FragmentTransaction beginTransaction()
此方法用于启动一系列与当前FragmentManager相关联的Fragment的编辑操作。注意Fragment事务的创建和提交都必须在activity保存状态之前调用(Acitivty.onSaveInstanceState之前),否则会报错。因为fragment的状态也是要保存的。
②、立即执行事务操作:
public abstract boolean executePendingTransactions();
前面说过,事务调用commit方法之后,不是立即执行的,而是会在线程里等待执行。如果需要立即执行的话,就可以调用此方法。此方法必须在主线程里面调用。
③、查找Fragment:
public abstract Fragment findFragmentById(int id);
public abstract Fragment findFragmentByTag(String tag);
对于FragmentManger的比较重要的方法就是这些了,因为这里边的大部分实现都是围绕着FragmentTransaction来开展的,也就是说,了解了FragmentTransaction各个方法的目的就可以实现基本的操作了。下面开始了解Fragment大家族。对于Fragment来说,主要了解它的生命周期和一些需要注意的点就可以了。另外就是需要了解ListFragment,WebViewFragment,DialogFragment的特性以及使用方法。最后会通过一个综合的例子来介绍如何应用。
三、Fragment
四、ListFragment
<?xml version="1.0" encoding="utf-8"?>
* <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:orientation="vertical"
* android:layout_width="match_parent"
* android:layout_height="match_parent"
* android:paddingLeft="8dp"
* android:paddingRight="8dp">
*
* <ListView android:id="@id/android:list"
* android:layout_width="match_parent"
* android:layout_height="match_parent"
* android:background="#00FF00"
* android:layout_weight="1"
* android:drawSelectorOnTop="false"/>
*
* <TextView android:id="@id/android:empty"
* android:layout_width="match_parent"
* android:layout_height="match_parent"
* android:background="#FF0000"
* android:text="No data"/>
* </LinearLayout>
每一项数据的布局文件可通过设置Adpter的时候设置,这个 后面来讲。主要方法盘点:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(com.android.internal.R.layout.list_content,
container, false);
}
可以看到,如果没有自定义布局的需要,我们根本不需要重写这个方法,但是如果我们有这个需求,就必须重写这个方法,并且布局必须含有一个id为@id/android:list的listView,如果希望数据为空的时候,显示提示视图,那么只要将该视图的id设为@id/android:empty即可。
public void onListItemClick(ListView l, View v, int position, long id) {
}
public void setListAdapter(ListAdapter adapter) {
注意必须是ListAdapter的子类,如果对于Adapter不是很了解,可以参考 Adapter大家族详解。每项数据的样式也是通过adpter设置的。
五、WebViewFragment:
六、DialogFragment:
接下来使用一个综合运用了上述所有知识的例子来讲述具体的用法。下面这个例子是关于显示数字的。当处于竖屏模式的时候,会显示一个显示1-10的数字列表,点击其中一个就会跳转到另一个activity显示相应的数据。当时横屏模式的时候,会显示一个有两个fragment的activity ,单击左边的数据会在右边显示出来。
<resources>
<string name="app_name">fragment</string>
<string-array name="number">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
</string-array>
</resources>
布局文件分为竖屏模式和横屏模式,先看目录结构:
layout/activity_main.xml:
<?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"
tools:context="com.cw.fragment.MainActivity">
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</LinearLayout>
<?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="horizontal"
android:weightSum="2"
tools:context="com.cw.fragment.MainActivity">
<FrameLayout
android:id="@+id/container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"></FrameLayout>
<fragment
android:id="@+id/rightFragment"
android:name="com.cw.fragment.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
tools:layout="@layout/right_layout" />
</LinearLayout>
layout/right_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#efefef"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center"
android:text="内容" />
</LinearLayout>
接着定义RightFragment:
package com.cw.fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* Created by Myy on 2016/7/28.
*/
public class RightFragment extends Fragment {
private View view;
private TextView textView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.right_layout, null);
textView = (TextView) view.findViewById(R.id.content);
return view;
}
public void setContent(int i) {
textView.setText(i + "");
}
}
package com.cw.fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
/**
* //用于单Fragment
* Created by Myy on 2016/7/28.
*/
public class RightActivity extends AppCompatActivity {
private TextView textView;
private RightFragment fragment;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragment = new RightFragment();
getSupportFragmentManager().beginTransaction().add(R.id.container, fragment).commit();
}
@Override
protected void onStart() {
super.onStart();
int i = getIntent().getIntExtra("position", 0);
fragment.setContent(i);
}
}
最后是mainActivity:
package com.cw.fragment;
import android.content.Intent;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import java.util.Arrays;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<String> numbers = null;
//注意包的引用
private ListFragment leftFragment;
private RightFragment rightFragment;
private ListView listView;
private boolean isTwoPage = false;//用于判断是否是双fragment模式,在这里竖屏模式设为双fragment模式
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
numbers = Arrays.asList(getResources().getStringArray(R.array.number));
initListFragment();
FragmentManager manager = getSupportFragmentManager();
rightFragment = (RightFragment) manager.findFragmentById(R.id.rightFragment);//当加载的是layout-land布局的fragment才不为null
if (rightFragment != null)
isTwoPage = true;
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.container, leftFragment);
transaction.commit();
// transaction.addToBackStack(null);可以将此事务添加进后退栈里面
//fragment调用activityd的方法。通过getActivity()
//acitivty调用fragment的方法。getFragmentManager().findFragmentById()
}
@Override
protected void onStart() {
super.onStart();
listView = leftFragment.getListView();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (isTwoPage)
rightFragment.setContent(position + 1);
else {
Intent intent = new Intent(MainActivity.this, RightActivity.class);
intent.putExtra("position", position+1);
startActivity(intent);
}
}
});
}
private void initListFragment() {
leftFragment = new ListFragment();
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, numbers);
leftFragment.setListAdapter(adapter);
}
}
上述可以看到用ListFragment添加到左边的Framelayout布局,使用了事务添加操作。
看看竖屏模式的效果:
点击:
切换竖屏模式:
点击:
如上,请读者好好体会这个例子,可以发现fragment和activity的异同以及事务使用的方法。
---------文章写自:HyHarden---------
--------博客地址:http://blog.csdn.net/qq_25722767-----------