-
什么是碎片
碎片是一種可以嵌入在Activity當(dāng)中的UI片段汽抚,它能讓程序更加合理和充分的利用大屏幕空間传货。因此在平板上應(yīng)用非常廣泛柳譬。
1.碎片的簡單實用
使用碎片搭建一個簡單靜態(tài)界面
第一步:創(chuàng)建左邊碎片界面布局
添加一個水平居中的按鈕
<?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:orientation="vertical">
<Button
android:id="@+id/left_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="LeftButton"
/>
</LinearLayout>
第二步:創(chuàng)建右邊碎片界面布局
添加一個背景顏色為綠色的布局,并加入一個標(biāo)簽
<?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:orientation="vertical"
android:background="#00ff00">
<TextView
android:textSize="20sp"
android:text="這是右邊的碎片"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
第三步:創(chuàng)建LeftFragment類
讓LeftFragment類繼承自support-v4庫中的Fragment類症概。
package com.example.anwser_mac.fragmenttest;
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;
/**
* Created by anwser_mac on 2017/4/6.
*/
public class LeftFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//重寫onCreateView方法钢猛,然后通過infalte()方法將剛才定義的left_fragment布局加載進來
View view = inflater.inflate(R.layout.left_fragmen, container, false);
return view;
}
}
第四步:創(chuàng)建RightFragment類
同第三步
package com.example.anwser_mac.fragmenttest;
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;
/**
* Created by anwser_mac on 2017/4/6.
*/
public class RightFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.right_fragment, container, false);
return view;
}
}
第五步:修改activity_main.xml中的代碼
將創(chuàng)建的碎片,加入到界面布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:name="com.example.anwser_mac.fragmenttest.LeftFragment"
android:layout_weight="1"/>
<fragment
android:id="@+id/right_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:name="com.example.anwser_mac.fragmenttest.RightFragment"
android:layout_weight="1"/>
</LinearLayout>
- 運行結(jié)果如下
![Uploading 2017-04-06_17-24-28_256277.gif . . .]
2.動態(tài)添加碎片
碎片真正強大之處在于它可以在程序運行時動態(tài)地添加到活動當(dāng)中。根據(jù)具體的情況添加碎片酪耕,可以將程序界面定制得更加多樣化。
第一步:在1項目的基礎(chǔ)上再創(chuàng)建一個碎片用來切換顯示
<?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="#ffff00"
android:orientation="vertical">
<TextView
android:id="@+id/another_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="20sp"
android:text="這是右邊的另一個碎片"/>
</LinearLayout>
第二步:創(chuàng)建對應(yīng)的Fragment類
package com.example.anwser_mac.fragmenttest;
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;
/**
* Created by anwser_mac on 2017/4/6.
*/
public class AnotherRightFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.another_right_fragment, container, false);
return view;
}
}
第三步: 修改界面布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:name="com.example.anwser_mac.fragmenttest.LeftFragment"
android:layout_weight="1"/>
<FrameLayout
android:id="@+id/right_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
</LinearLayout>
第四步:修改Activity的代碼如下
package com.example.anwser_mac.fragmenttest;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
//給按鈕添加一個點擊事件
Button button = (Button) findViewById(R.id.left_button);
button.setOnClickListener(this);
replaceFragment(new RightFragment());
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.left_button:
TextView textView = (TextView) findViewById(R.id.right_textview);
//判斷哪個碎片需要進行切換
if (textView != null) {
replaceFragment(new AnotherRightFragment());
} else {
replaceFragment(new RightFragment());
}
}
}
///切換右邊顯示的碎片
//fragment : 要切換的碎片
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction tansaction = fragmentManager.beginTransaction();
tansaction.replace(R.id.right_layout, fragment);
tansaction.commit();
}
}
- 運行效果如下:
綜上轨淌,動態(tài)添加碎片可以分為以下5個步驟
- 創(chuàng)建待添加的碎片實例迂烁。
- 獲取FragmentManager(在活動中可以直接通過調(diào)用getSupportFragmentManager()方法得到)
- 開啟一個事務(wù),通過調(diào)用beginTransaction()方法開啟递鹉。
- 向容器內(nèi)添加或替換碎片盟步,一般使用replace()方法實現(xiàn),需要傳入容器的id和待添加的碎片實例躏结。
3. 在碎片中模擬返回棧
在前面的練習(xí)中已經(jīng)實現(xiàn)了動態(tài)添加返回棧却盘,但是當(dāng)切換了幾次之后,按下back鍵程序會直接退出媳拴。所以如果需要給碎片提供一個返回棧的效果黄橘,需要調(diào)用FragmentTransaction中提供的addToBackStack()方法,可以用于將一個事務(wù)添加到返回棧中屈溉。
///切換右邊顯示的碎片
//fragment : 要切換的碎片
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction tansaction = fragmentManager.beginTransaction();
tansaction.replace(R.id.right_layout, fragment);
tansaction.addToBackStack(null);
tansaction.commit();
}
4.碎片和活動之間進行通信
-
在活動中調(diào)用碎片中的方法
通過FragmentManager提供的findFragmentById()方法塞关,獲得碎片實例,從而調(diào)用碎片中的方法
RightFragment rightFragment = (RightFragment) getFragmentManager().findFragmentById(R.id.right_fragment);
在碎片中調(diào)用活動中的方法
在碎片中可以通過調(diào)用getActivity()方法來得到和當(dāng)前碎片相關(guān)聯(lián)的活動實例
```
MainActiviy activity = (MainActivity) getActivity;
####5.碎片的生命周期
> 碎片和活動一樣都有自己的生命周期
1. **運行狀態(tài)**
>當(dāng)一個碎片時可見的子巾,并且它所關(guān)聯(lián)的活動正處于運行狀態(tài)時描孟,該碎片也處于運行狀態(tài)驶睦。
2. 暫停狀態(tài)
> 當(dāng)一個活動進入暫停狀態(tài)時(由于另一個未沾滿屏幕的活動被添加到了棧頂),與它相關(guān)聯(lián)的可見碎片就會進入到暫停狀態(tài)匿醒。
3. 停止?fàn)顟B(tài)
> 當(dāng)一個活動進入停止?fàn)顟B(tài)時场航,與它相關(guān)聯(lián)的碎片就會進入到停止?fàn)顟B(tài),通過調(diào)用FragmentTransaction的remove()廉羔、replace()方法將碎片從活動中移除溉痢;或者在事務(wù)提交前調(diào)用了addToBackStack()方法,這時的碎片也會進入到停止?fàn)顟B(tài)憋他,總的來說孩饼。進入停止?fàn)顟B(tài)的碎片對用戶來說時完全不可見的。有可能會被系統(tǒng)回收竹挡。
4. 銷毀狀態(tài)
> 當(dāng)活動被銷毀時镀娶,與它相關(guān)聯(lián)的碎片就會進入到銷毀狀態(tài)【竞保或者通過調(diào)用FragmentTransaction的remove()梯码、replace()方法將碎片從活動中移除、也或者在事務(wù)提交前調(diào)用了addToBackStack()方法好啰。
#####5.1碎片的狀態(tài)回調(diào)
1. onAttach()
>當(dāng)碎片和活動建立關(guān)聯(lián)的時候調(diào)用轩娶。
2. onCreateView()
> 為碎片創(chuàng)建視圖(加載布局)時調(diào)用
3. onActivityCreated()
> 確保與碎片相關(guān)聯(lián)的活動一定已經(jīng)創(chuàng)建完畢的時候調(diào)用。
4. onDestroyView()
> 當(dāng)與碎片關(guān)聯(lián)的視圖被移除的時候調(diào)用框往。
5. onDetach()
> 當(dāng)碎片和活動解除關(guān)聯(lián)的時候調(diào)用鳄抒。
- 下圖展示了,添加碎片時椰弊,活動級碎片的回調(diào)順序
![2017-04-06_16-25-38.png](http://upload-images.jianshu.io/upload_images/2897594-d0b4537c76f4b7de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 》另外還有一點需要注意的是:在碎片中也
可以通過onSaveInstanceState()方法來保存數(shù)據(jù)许溅。
----
####6.動態(tài)加載布局的技巧
6.1 使用限定符
> 通常在平板中采用的是雙頁模式,在手機采用的是單頁模式秉版,限定符的作用就是系統(tǒng)根據(jù)屏幕的大小贤重,來加載不同的界面布局文件。從而達到自動分頁的效果
第一步:如下圖所示沐飘,創(chuàng)建一個根activity布局文件同名的large布局文件
![2017-04-06_17-41-38.png](http://upload-images.jianshu.io/upload_images/2897594-42a38627ff6e80d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
第二步:寫入在平板下的布局代碼
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:name="com.example.anwser_mac.fragmenttest.LeftFragment"
android:id="@+id/left_fragment"/>
<FrameLayout
android:id="@+id/right_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<!--<fragment-->
<!--android:layout_width="0dp"-->
<!--android:layout_height="match_parent"-->
<!--android:layout_weight="1"-->
<!--android:name="com.example.anwser_mac.fragmenttest.RightFragment"-->
<!--android:id="@+id/right_fragment"/>-->
</LinearLayout>
第三步: 同時也要記得將原來的界面布局改為單頁的界面布局游桩。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.anwser_mac.fragmenttest.LeftFragment"/>
<!--android:layout_weight="1"/>-->
<!--<FrameLayout-->
<!--android:id="@+id/right_layout"-->
<!--android:layout_width="0dp"-->
<!--android:layout_height="match_parent"-->
<!--android:layout_weight="1">-->
<!--</FrameLayout>-->
</LinearLayout>
- 在不同設(shè)備下運行效果分別如下牲迫。
![
![Uploading 2017-04-06_17-34-42_845768.png . . .]
](http://upload-images.jianshu.io/upload_images/2897594-83b233c3e75f01ad.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 下圖是一些常見的限定符耐朴,圖片來自《第一行代碼》
![2017-04-06_17-34-42.png](http://upload-images.jianshu.io/upload_images/2897594-9d74d989ae814fda.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
6.2 使用最小寬度限定符
>最小寬度限定符允許我們對屏幕的寬度制定一個最小值(以dp為單位),然后以這個最小值為臨界點盹憎,屏幕寬度大于這個值的設(shè)備就加載一個布局筛峭。屏幕寬度小于這個值就加載另一個布局。
- 如下圖所示陪每,新建一個**layout_sw600dp**的文件影晓,在這個文件中搭建布局镰吵。也就意味著當(dāng)屏幕寬度大于600dp的時候會加載這個文件;當(dāng)屏幕小于600dp的時候默認(rèn)加載main_layout文件挂签。
![2017-04-06_17-41-38.png](http://upload-images.jianshu.io/upload_images/2897594-df915cdedfc841ed.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)