Android編程權(quán)威指南(第二版)學(xué)習(xí)筆記(十七)—— 第17章 Master-Detail 用戶界面

本章介紹了如何寫一個雙版面 fragment 的布局,并對符合要求的設(shè)備進(jìn)行適配,還介紹了回調(diào)接口的使用胞谈。
GitHub 地址:
完成17章

對平板設(shè)備來說填具,使用主從用戶界面將會得到更好的體驗,在這章我們將對其使用艰额,傳遞數(shù)據(jù)的方式進(jìn)行探究澄港。

1. 增加布局靈活性

要實現(xiàn)雙版面的布局,需要完成如下任務(wù):

  1. 修改 SingleFragmentActivity柄沮,使其不再硬編碼實例化布局
  2. 創(chuàng)建包含兩個 fragment 容器的布局
  3. 修改 CrimeListActivity回梧,實現(xiàn)在手機設(shè)備上實例化單版面布局,在平板設(shè)備上實例化雙版面布局

1.1 修改抽象類 SingleFragmentActivity

在其中加入一個 protected 方法祖搓,返回 activity 需要的 ResId狱意,這樣對于繼承 SingleFragmentActivity 的 activity 可以重寫該函數(shù)以返回自己需要的 ResId。

@LayoutRes
protected int getLayoutResId() {
    return R.layout.activity_fragment;
}

1.2 使用別名資源

我們想讓最小屏幕寬度 600dp 的設(shè)備使用雙版面界面拯欧,其他的使用單版面界面详囤,那么對于不同的設(shè)備,使用的布局就不同镐作。要讓不同的設(shè)備使用不同的布局資源藏姐,有兩種方法:

  1. 讓 res/layout/目錄中的文件使用資源修飾符。如果想使用activity_masterdetail.xml布局文件该贾, 就需要將activity_fragment.xml的內(nèi)容復(fù)制到res/layout/activity_masterdetail.xml中包各,將activity_twopane.xml的內(nèi)容復(fù)制到res/layout-sw600dp/activity_masterdetail.xml中。這樣做最明顯的缺點就是數(shù)據(jù)冗余靶庙,因為每個布局文件都要復(fù)制一份问畅。

  2. 使用別名資源。別名資源是一種指向其他資源的特殊資源六荒。它存放在 res/values/目錄下护姆,并按照約定定義在 refs.xml 文件中。比如在默認(rèn)的 values 文件夾下面新建一個 refs.xml掏击,然后寫入代碼:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <item name="activity_masterdetail" type="layout">@layout/activity_fragment</item>
    </resources>
    

    再新建一個最小寬度600dp 的 refs.xml(即在 values-sw600dp 目錄下)卵皂,寫入雙版面的 layout 資源:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <item name="activity_masterdetail" type="layout">@layout/activity_twopane</item>
    </resources>
    

    這樣,在 CrimeListActivity 中只要引用 R.layout.activity_masterdetail 即可

2. Activity:Fragment 的托管者

為了保證 fragment 的獨立性砚亭,即不需要了解其托管者的工作灯变,但要想在 fragment 生命周期沒有結(jié)束的時候傳遞數(shù)據(jù)出去殴玛,就要使用回調(diào)接口。

回調(diào)就相當(dāng)于一個委托添祸,首先 fragment 自己定義回調(diào)的接口滚粟,托管的 acitivity 來實現(xiàn)這個接口,接著 fragment 需要持有實現(xiàn)了自己定義接口的對象刃泌,以便自己可以實時調(diào)用凡壤。

對于一個回調(diào)接口而言,fragment 只要求實現(xiàn)這個接口的類在函數(shù)里要做的是什么耙替,卻不知道實現(xiàn)類到底會做什么亚侠,每個實現(xiàn)類有自己的方法來實現(xiàn)。

2.1 CrimeListFragment 的回調(diào)接口

對于 CrimeListFragment俗扇,其所能響應(yīng)的就是點擊列表中的某一項硝烂,那么它的回調(diào)接口定義如下:

public interface Callbacks {
    void onCrimeSelected(Crime crime);
}

然后應(yīng)該在需要托管的 Activity 中實現(xiàn)該接口,在這里是 CrimeListActivity:

// 省略 implement 以節(jié)約版面
@Override
public void onCrimeSelected(Crime crime) {
    // 如果發(fā)現(xiàn)布局里沒有包含詳情 fragment 容器的 id铜幽,
    // 就啟動單獨的 activity 用于顯示詳情
    if (findViewById(R.id.detail_fragment_container) == null) {
        Intent intent = CrimePagerActivity.newIntent(this, crime.getId());
        startActivity(intent);
    } else {
    // 否則就將 detail 頁面放到 fragment 容器中
        Fragment newDetail = CrimeFragment.newInstance(crime.getId());

        getSupportFragmentManager().beginTransaction()
                .replace(R.id.detail_fragment_container, newDetail)
                .commit();
    }
}

在 CrimeListFragment 中持有實現(xiàn)接口的 activity 的引用滞谢,然后在生命周期末去除引用以便內(nèi)存的回收

// CrimeListFragment
private Callbacks mCallbacks;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    mCallbacks = (Callbacks) context;
}

// 中間的函數(shù)……

@Override
public void onDetach() {
    super.onDetach();
    mCallbacks = null;
}

最后修改 onClick 事件,調(diào)用 mCallbacks.onCrimeSelected(Crime crime) 即可啥酱。這樣以后爹凹,在雙版面視圖中點擊列表中的某一項,在詳情版面中就會顯示相應(yīng)的信息镶殷。

但是有一個問題禾酱,那就是在詳情頁(CrimeFragment)更改信息,在列表頁沒有任何響應(yīng)绘趋,因為 CrimeListFragment 不會暫停颤陶,所以也就不會刷新,所以下一步要在 CrimeFragment 中定義回調(diào)接口陷遮, 讓托管 activity 去更新 CrimeListFragment滓走。

2.2 CrimeFragment 的回調(diào)接口

首先定義回調(diào)接口,這里想讓托管者做的就是在 Crime 詳情進(jìn)行更新時更新列表

// CrimeFragment
private Callbacks mCallbacks;

public interface Callbacks {
    void onCrimeUpdated(Crime crime);
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    mCallbacks = (Callbacks) context;
}

// 中間的函數(shù)……

@Override
public void onDetach() {
    super.onDetach();
    mCallbacks = null;
}

在 CrimeListActivity 中實現(xiàn)該接口:

@Override
public void onCrimeUpdated(Crime crime) {
    CrimeListFragment listFragment = (CrimeListFragment)
            getSupportFragmentManager()
                    .findFragmentById(R.id.fragment_container);
    listFragment.updateUI();
}

由于只要托管 CrimeFragment 的 activity 都應(yīng)該實現(xiàn)其回調(diào)接口帽馋,所以在 CrimePagerActivity 中提供一個空的接口實現(xiàn)

之后在每次數(shù)據(jù)發(fā)生更改時都調(diào)用 mCallbacks.onCrimeUpdated(mCrime);即可搅方。書上將更新模型層也放到了一起。

3. 挑戰(zhàn)的后遺癥:刪除 Crime

還記得我們在 ToolBar 那一章加入的挑戰(zhàn)嗎绽族,就是刪除一個 Crime姨涡,對于 CriminalIntent 這個應(yīng)用來說,雙版面和單版面的刪除操作應(yīng)該有著不同的結(jié)果吧慢,但這些行為在書上沒有定義涛漂,所以我們再自己想一種解決方案,以便確立如何寫接下來的補充程序。

  1. 雙版面的界面下匈仗,點擊刪除應(yīng)該要讓左邊的列表中去掉刪除的那一項瓢剿,并且詳情頁也要改為已存在的某一項的詳情,為了方便實現(xiàn)悠轩,我們在這里改為已存在的第一項间狂。如果只有最后一項并且點擊了刪除,那么右邊應(yīng)該要變成空白哗蜈。
  2. 單版面的界面下前标,點擊刪除就直接刪去該條記錄坠韩,然后結(jié)束 activity距潘。

在這里我在 CrimeFragment 的 Callbacks 接口中加入了 onCrimeDelete(Crime crime) 方法與 onCrimeAllDeleted(Crime crime) 方法,在 CrimeListActivity 中實現(xiàn)如下:

@Override
public void onCrimeDeleted(Crime crime) {
    // 如果只是刪除了一個只搁,而還有其他的 Crime 的話音比,
    // 就相當(dāng)于選中一個 Crime,這里傳過來的應(yīng)該是第一個 Crime
    onCrimeSelected(crime);
}

@Override
public void onCrimeAllDeleted(Crime crime) {
    // 如果全部刪除氢惋,就直接將該 fragment 移去
    CrimeFragment fragment = (CrimeFragment)
            getSupportFragmentManager()
                    .findFragmentById(R.id.detail_fragment_container);
    if (fragment != null) {
        getSupportFragmentManager()
                .beginTransaction()
                .remove(fragment)
                .commit();
    }
    // 并且更新列表頁
    onCrimeUpdated(crime);
}

在 CrimePagerActivity 中也要實現(xiàn)這兩個方法洞翩,但是對于這個 activity 來說只要進(jìn)行 finish() 即可。

在刪除按鈕的選中監(jiān)聽中:

CrimeLab.get(getActivity()).deleteCrime(mCrime);
if (CrimeLab.get(getActivity()).getCrimes().isEmpty()) {
    mCallbacks.onCrimeAllDeleted(mCrime);
} else {
    mCrime = CrimeLab.get(getActivity()).getCrimes().get(0);
    mCallbacks.onCrimeDeleted(mCrime); // 這里相當(dāng)于選中第一個
    updateCrime(); // 這里面升級了數(shù)據(jù)層并且更新了列表
}
return true;

整個程序就此完成啦~


GitHub Page: kniost.github.io
簡書:http://www.reibang.com/u/723da691aa42

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焰望,一起剝皮案震驚了整個濱河市骚亿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌熊赖,老刑警劉巖来屠,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異震鹉,居然都是意外死亡俱笛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門传趾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迎膜,“玉大人,你說我怎么就攤上這事浆兰】慕觯” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵簸呈,是天一觀的道長榕订。 經(jīng)常有香客問我,道長蝶棋,這世上最難降的妖魔是什么卸亮? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮玩裙,結(jié)果婚禮上兼贸,老公的妹妹穿的比我還像新娘段直。我一直安慰自己,他們只是感情好溶诞,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布鸯檬。 她就那樣靜靜地躺著,像睡著了一般螺垢。 火紅的嫁衣襯著肌膚如雪喧务。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天枉圃,我揣著相機與錄音功茴,去河邊找鬼。 笑死孽亲,一個胖子當(dāng)著我的面吹牛坎穿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播返劲,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼玲昧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了篮绿?” 一聲冷哼從身側(cè)響起孵延,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎亲配,沒想到半個月后尘应,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡弃榨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年菩收,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲸睛。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡娜饵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出官辈,到底是詐尸還是另有隱情箱舞,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布拳亿,位于F島的核電站晴股,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏肺魁。R本人自食惡果不足惜电湘,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寂呛,春花似錦怎诫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至劫拢,卻和暖如春肉津,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舱沧。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工妹沙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狗唉。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓初烘,卻偏偏與公主長得像涡真,于是被迫代替她去往敵國和親分俯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評論 25 707
  • 自控力 桃子 作者是美女科學(xué)家 Kelly McGonigal哆料,本書英文名稱是 Will Power 意志力缸剪,講的...
    百萬機器貓閱讀 292評論 0 0
  • 最近一直在學(xué)習(xí)新內(nèi)容的同時,在復(fù)習(xí)以前的內(nèi)容 看著曾經(jīng)的劃線重點东亦,臆想當(dāng)日的我會寫出什么樣的感想?今天同樣的話題杏节,...
    大麥茶的故事閱讀 272評論 0 0
  • 2017年9月7日 距離18考研107天 早晨6點半起床,7點半左右到達(dá)教室典阵。 首先復(fù)習(xí)單詞奋渔,首要的是閱讀中的單詞...
    sy_yunyi閱讀 68評論 0 0
  • 從拇指到小指歹啼,再從小指到拇指玄渗, 蛛兒在佛手上爬來爬去,無聊地結(jié)著絲狸眼,無聊地蕩著秋千藤树。 師傅,師傅拓萌,你成日里受眾生叩...
    黃點點閱讀 509評論 0 1