實作Android導覽教學(fragment)

這次的案子是要把原有的app增加一個新手導覽教學的功能 但是不是整頁換頁的方式(像是用setContent把整頁內容改變),而是以原本存在的頁面上面蓋上一層透明的頁面,然後導覽使用者點下按鈕之後才會繼續下一步。 全部的導覽結束之後,這個透明的頁面會消失,然後恢復原本的使用介面。

大概長得像是這樣:
 
需要用到的主要概念有三個:

1. 使用不揮發變數(SharedPreference)來設立一個初始值為false的flag,讓教學導覽結束之後把flag調回true,以免使用者下次打開之後又開始教學導覽

2. 調整style.xml檔案,用AndroidManifest.xml指定activity後用setContent鋪上透明主題頁面

3. fragment的增加,覆蓋,以及在最後結束時關閉透明頁面
(如果你是想要跟上圖一樣只有這樣一個介面,按下螢幕之後就結束的話,可能不需要fragment)

--- 1. 不揮發變數 ---

放一個flag的變數進去SharedPreference

SharedPreferences sharedPreferences = getSharedPreferences("flag" , MODE_PRIVATE);
//取得SharedPreferences , 丟入的參數為("名稱" , 存取權限)

關於存取權限:

MODE_PRIVATE 只允許本應用程式內存取。

MODE_MULTI_PROCESS 允許多個行程同時存取,在Android 2.3(含)以前的版本都是預設開啟,但2.3之後要指定這個參數才允許多行程同時存取。

MODE_WORLD_READABLE 讓手機中的所有app都能讀取,因為風險性太高,從API 17版開始就不建議使用了。

如何改變該值:

sharedPreferences.edit().putboolean("flag" , false).apply();
        //存入資料,丟入的參數為(key , value)

如何取出該值:

sharedPreferences.getboolean("flag" , false);
        //取出資料, 丟入的參數為(key , 若是沒值,預設為多少)


--- 2. 透明頁面 ---

在style.xml下面多寫一個主題,讓背景變灰階透明

<drawable name="transparameter">#7f000000</drawable>
    <style name="Theme.TranslucentBackground" parent="AppTheme">
        <item name="android:windowBackground">@drawable/transparameter</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowNoTitle">true</item>
    </style>

然後在layout資料夾下做一個什麼都沒有的空白頁面,ID命名為transparentpage.xml

然後在AndroidManifest.xml下面找到寫有application的框框內
多下這一行

        <activity
            android:name="你要執行setContent的Activity路徑"
            android:hardwareAccelerated="false"
            android:screenOrientation="portrait"
            android:configChanges = "fontScale"
            android:theme="@style/Theme.TranslucentBackground" />


這樣子設定主要是讓你的activity下的setContent可以改變主題

然後
setContentView(R.layout.tutorial_transparentpage);
就可以鋪上一個透明頁面了~

如果之後要關閉這個透明頁面的話就寫個
finish();
就可以了。
但是!只有這樣寫的話,在關閉這個頁面的時候會有一個很多餘的滑出動畫,讓整個畫面結束的感覺有點LOW。

這時候多加一個

    public void finish(){
        //cancel the animation when finish activity
        super.finish();
        overridePendingTransition(0,0);
    }

這樣就不會有一個滑出動畫了。

掰惹位,有些使用者可能會手滑按到後退鍵結果導致整個導覽消失。
多加這個防止他們按到:

//backKey無效
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction()==KeyEvent.ACTION_DOWN) {
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_BACK:
                    return true;
            }
        }
        return super.dispatchKeyEvent(event);
    }


--- 3.Fragment --

有時候會有需求要在透明的頁面上加圖案或者加按鈕什麼的
這時候就要再新增一個layout,用fragment的方法來加上去
首先先做個fragment的java檔

public class TutorialFragment extends Fragment{
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater,container,savedInstanceState);
        return inflater.inflate(要蓋上去的新layout, container, false);
    }
}

然後在Activity內下一個replace的指令就可以蓋上去了。

    private FragmentManager fragmentManager;
    private Fragment fragment = new Fragment();
   fragment = new TutorialFragment();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(containerViewIdint,fragment);
        transaction.addToBackStack(null);
        transaction.commit();

補充:

當然一個fragment也不會只有蓋上去這個方法,往上疊加或者去掉最前面的fragment也是都可以做得到的,但是一定要考慮到Android的生命週期。可以參考這個網站有詳細的解說。
直接把重點節錄下來就是:

FragmentTransaction有一些基本方法,下面給出調用這些方法時,Fragment生命週期的變化:

* add(): onAttach()->…->onResume()。
* remove(): onPause()->…->onDetach()。
* replace(): 相當於舊Fragment調用remove(),新Fragment調用add()。
* show(): 不調用任何生命週期方法,調用該方法的前提是要顯示的Fragment已經被添加到容器,只是純粹把Fragment UI的setVisibility為true。
* hide(): 不調用任何生命週期方法,調用該方法的前提是要顯示的Fragment已經被添加到容器,只是純粹把Fragment UI的setVisibility為false。
* detach(): onPause()->onStop()->onDestroyView()。UI從佈局中移除,但是仍然被FragmentManager管理。 * attach(): onCreateView()->onStart()->onResume()。


抱歉這次沒辦法提供程式碼,而且必須要刪掉一些公司用的東西,很有可能會漏掉一小部分,如果有問題可以留言。我會再補上來。

留言

這個網誌中的熱門文章

利用Accuweather實作天氣APP