在前一次利用ViewPager實(shí)現(xiàn)仿微信Tab效果的后工育,又學(xué)習(xí)了利用Fragment實(shí)現(xiàn)該效果,剛好是對Fragment的一次學(xué)習(xí)理解冯痢。
效果圖就不展示了呜师,和ViewPager的界面類似,唯一的缺點(diǎn)就是双炕,利用單純的Fragment無法實(shí)現(xiàn)像ViewPager一樣的左右滑切換狞悲。就當(dāng)做一次對Fragment的理解學(xué)習(xí)吧。
這個Demo的難點(diǎn)總結(jié):
1.Fragment的理解與使用妇斤。
2.FragmentTransaction與Fragment生命周期的關(guān)系摇锋。
3.FragmentTransaction中不同操作的區(qū)別。(此處遇到問題U境)
接下來來詳細(xì)闡述一下以上兩點(diǎn):
一荸恕、Fragment的理解使用。
原來一直都是在書上看完了Fragment的使用死相,只是知道Fragment的是用來在一個Activity中便于實(shí)現(xiàn)大量控件與事件的分類處理融求。利用這次機(jī)會剛好初步學(xué)習(xí)了一下Fragment的使用與理解。
http://blog.csdn.net/lmj623565791/article/details/37970961這篇大神的博客已經(jīng)很詳細(xì)的講解了有關(guān)Fragment的理解與使用算撮∷簦看完過后知道了Fragment的基礎(chǔ)使用方式兩種:
(1)靜態(tài)的使用Fragment
(2)動態(tài)的使用Fragment。
而本例中使用的就是第二種使用方式钮惠,利用FragmentTransaction實(shí)現(xiàn)動態(tài)使用Fragment。一開始還不理解動態(tài)的使用的含義七芭,看完那篇博客后素挽,了解到,就是利用FragmentManager在Activity中操作Fragment狸驳。
也就是說在Activity中動態(tài)的管理Fragment预明。具體方式步驟如下:
1.定義自己的mFragment繼承Fragment(此處有一個要點(diǎn)就是:包名要一致缩赛,如果導(dǎo)入的是android.app.Fragment后面導(dǎo)入的都要是app下的包例如android.app.FragmentManager;而如果導(dǎo)入的是android.support.v4.app.Fragment撰糠,后面要一致導(dǎo)入v4包酥馍,不然會產(chǎn)生錯誤)。重寫onCreateView方法:如下
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i("Tag", "onCreateView");
// TODO Auto-generated method stub
return inflater.inflate(R.layout.tab1, container, false);
}
2.獲取FragmentManage阅酪,利用getFragmentManager()(v4中旨袒,getSupportFragmentManager)得到FragmentManage。
FragmentManager fm = getFragmentManager();
3.開啟一個事務(wù)FragmentTransaction术辐。
FragmentTransaction transaction = fm.beginTransaction();
4.調(diào)用add(),show(),remove(),replace(),hide()等相關(guān)操作實(shí)現(xiàn)所需功能砚尽。
代碼如下:
MainActivity.java
package com.example.fragmenttab;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends Activity implements OnClickListener{
private LinearLayout l1, l2, l3, l4;
private ImageView pic1, pic2, pic3, pic4;
private Fragment f1,f2,f3,f4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initView();
initEvent();
setSelect(0);
}
private void initEvent() {
// TODO Auto-generated method stub
l1.setOnClickListener(this);
l2.setOnClickListener(this);
l3.setOnClickListener(this);
l4.setOnClickListener(this);
}
private void initView() {
// TODO Auto-generated method stub
l1 = (LinearLayout) findViewById(R.id.lin1);
l2 = (LinearLayout) findViewById(R.id.lin2);
l3 = (LinearLayout) findViewById(R.id.lin3);
l4 = (LinearLayout) findViewById(R.id.lin4);
pic1 = (ImageView) findViewById(R.id.pic1);
pic2 = (ImageView) findViewById(R.id.pic2);
pic3 = (ImageView) findViewById(R.id.pic3);
pic4 = (ImageView) findViewById(R.id.pic4);
}
private void setSelect(int i){
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
hideFragment(transaction);
switch (i) {
case 0:
if(f1 == null){
f1 = new OneFragment();
transaction.add(R.id.content, f1);
}else{
transaction.show(f1);
}
pic1.setImageResource(R.drawable.tab_weixin_pressed);
break;
case 1:
if(f2 == null){
f2 = new SecondFragment();
transaction.add(R.id.content, f2);
}else{
transaction.show(f2);
}
pic2.setImageResource(R.drawable.tab_find_frd_pressed);
break;
case 2:
if(f3 == null){
f3 = new ThirdFragment();
transaction.add(R.id.content, f3);
}else{
transaction.show(f3);
}
pic3.setImageResource(R.drawable.tab_address_pressed);
break;
case 3:
if(f4== null){
f4 = new FourthFragment();
transaction.add(R.id.content, f4);
}else{
transaction.show(f4);
}
pic4.setImageResource(R.drawable.tab_settings_pressed);
break;
}
transaction.commit();
}
private void hideFragment(FragmentTransaction transaction) {
//隱藏所有Fragment
if(f1 != null){
transaction.hide(f1);
}
if(f2 != null){
transaction.hide(f2);
}
if(f3 != null){
transaction.hide(f3);
}
if(f4 != null){
transaction.hide(f4);
}
}
@Override
public void onClick(View v) {
resetImage();
switch (v.getId()) {
case R.id.lin1:
setSelect(0);
break;
case R.id.lin2:
setSelect(1);
break;
case R.id.lin3:
setSelect(2);
break;
case R.id.lin4:
setSelect(3);
break;
}
}
private void resetImage() {
// 重置所有圖片
pic1.setImageResource(R.drawable.tab_weixin_normal);
pic2.setImageResource(R.drawable.tab_find_frd_normal);
pic3.setImageResource(R.drawable.tab_address_normal);
pic4.setImageResource(R.drawable.tab_settings_normal);
}
}
OneFragment.java
package com.example.fragmenttab;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class OneFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i("Tag", "onCreateView");
// TODO Auto-generated method stub
return inflater.inflate(R.layout.tab1, container, false);
}
}
activity_main.xml
<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="vertical">
<include layout="@layout/top" />
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"></FrameLayout>
<include layout="@layout/bottom" />
</LinearLayout>
其他界面和前一個例子相同。
以上就是這次所有的總結(jié)辉词,這樣就結(jié)束了嗎必孤?NO!NO!NO!
在這個例子中一個無意的操作引發(fā)了一個自己無法解決的問題。
問題如下:
在這個例子中原理就是瑞躺,每次點(diǎn)擊之前都回執(zhí)行hideFragment()方法用戶將所有的Fragment利用transaction.hide()方法隱藏掉敷搪,然后再二次點(diǎn)擊時利用show()方法顯示。這些看似很基礎(chǔ)幢哨,但是我一開始寫的時候赡勘,不小心將hide()方法寫成了remove()方法,這時候問題來了V雒础Jê!運(yùn)行效果是第一次點(diǎn)擊都是好的曼振,但是第二次點(diǎn)擊后界面就為空白了几迄。
問題原因:
設(shè)置斷點(diǎn)調(diào)試,發(fā)現(xiàn)原因很簡單冰评,執(zhí)行remove后映胁,二次點(diǎn)擊在這一步:
if(f1 == null){
f1 = new OneFragment();
transaction.add(R.id.content, f1);
}else{
transaction.show(f1);
}
這時f1不為null,執(zhí)行show()方法甲雅,而f1已經(jīng)被remove了所以show是空白解孙。
但是看似簡單的問題原因,仔細(xì)一想抛人,F(xiàn)ragmentTransaction的remove方法定義是從Activity中移除一個Fragment弛姜,如果被移除的Fragment沒有添加到回退棧(回退棧后面會詳細(xì)說),這個Fragment實(shí)例將會被銷毀妖枚。
銷毀廷臼?對,你沒有看錯,銷毀后不應(yīng)該為null嗎荠商?為什么判斷的時候不是null哪寂恬?糾結(jié)啊,看了Fragment的源碼和FragmentTransaction的源碼還是無法理解原因莱没,Tag了Fragment的生命周期發(fā)現(xiàn)初肉,remove后確實(shí)執(zhí)行了onDetach()方法,也就是說該Fragment已經(jīng)的確被銷毀了饰躲,但是判null的時候不是null,糾結(jié)把烙健!J籼眠寿!希望有大神能解決這個問題啊。我自己也在尋找原因焦蘑,希望下次博客能夠發(fā)出解決貼吧盯拱!