2015年1月9日

【Android】客製化滑動選單、隱藏式抽屜效果實作

各位Android安卓開發者大家好,小黑人這次很快的向大家分享新文章啦!
這篇文章要與大家分享的是"客製化滑動選單",簡單來說就像是抽屜的上升下降效果,那為什麼要用這種滑動選單的效果呢?答案就是要節省手機的畫面空間,例如一些功能選項可以先在畫面藏起來,等需要用到時再展現出來就好,那要怎麼客製滑動選單呢?就讓我們繼續往下看吧~

1. 首先,要客製滑動選單其實很容易,只要在Activity(.java)裡做上下滑動控制就好,再來比較要注意的一點是滑動距離的控制,因為Android的裝置手機有很多解析度,所以每個手機長寬也都不一樣,所以我們在滑動的距離還要另外針對不同解析度來進行判斷,小黑人這個範例是使用全螢幕的狀態下撰寫,所以大家先在AndroidManifest.xml上加入android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen",這樣才會有全螢幕的效果,然後也把Activity鎖定一個方向吧。

例如 :
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
>
    <activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:screenOrientation="portrait"
    >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>          
    </activity>   
</application>

2.
再來就是Layout(.xml)的設定,大家可以自己設計選單的排列方式,小黑人先以一個LinearLayout當作選單來向大家說明。

例如 :
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
>
   
<LinearLayout
    android:id="@+id/menu"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/menu"
    android:orientation="horizontal"
    />

</RelativeLayout>

3.
最後就是重點的地方了,也就是Activity(.java)的控制動作,大家可以看下方完整程式碼。
public class MainActivity extends Activity
{
        //
可滑動的Menu選單
        private LinearLayout mMenu;
        //Menu
的版面控制元件
        private RelativeLayout.LayoutParams mLayoutParams;
        //
配合多解析度畫面,會調整Menu的高度
        private int HEIGHT;
        //
讀取手機裝置資訊元件
        private DisplayMetrics mPhone;
        //
判斷Menu展開或關閉狀態
        private Boolean mState = false;
       
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
               
                //
獲取手機裝置資訊
                mPhone = new DisplayMetrics();
                getWindowManager().getDefaultDisplay().getMetrics(mPhone);
               
                //Menu
的高度
                HEIGHT = (int) (((float) mPhone.heightPixels / (float) 1280) * (float) 154) ;
               //Menu
版面控制的初始設定
               mLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,HEIGHT);
               //
Menu位置調整至底部
               mLayoutParams.topMargin = (mPhone.heightPixels - HEIGHT);
       
               //Menu
元件
               mMenu = (LinearLayout) findViewById(R.id.menu);
               //
將設定帶入
               mMenu.setLayoutParams(mLayoutParams);
               
                //
點擊Menu觸發
                mMenu.setOnClickListener(new OnClickListener()
                {
                        @Override
                        public void onClick(View v)
                        {
                                //
判斷Menu狀態,是展開狀態還是閉合狀態
                                if(mState)
                                {
                                        //Menu
上升
                                        new MoveTask().execute(false);
                                        mState = false;
                                }
                                else
                                {
                                        //Menu
下降
                                        new MoveTask().execute(true);
                                        mState = true;
                                }
                        }
                });
        }
       
        //Menu
滑動類別
        private class MoveTask extends AsyncTask<Boolean, Integer, Boolean>
        {
            @Override
            protected Boolean doInBackground(Boolean... params)
            {
                    //
上升或下降動作判斷
                    if(params[0])
                    {
                            //
滑動動作分成10個階段
                            for(int i = 1 ; i < 11 ; i++)
                            {
                                    //
動作切換
                                    publishProgress(i);
                                    //
0.05秒後繼續動作
                                    try { Thread.sleep(50);} catch (InterruptedException e) {}
                            }
                    }
                    else
                    {
                            //
滑動動作分成10個階段
                            for(int i = 10 ; i > -1 ; i--)
                            {
                                    //
動作切換
                                    publishProgress(i);
                                    //
0.05秒後繼續動作
                                    try { Thread.sleep(50);} catch (InterruptedException e) {}
                            }
                    }
       
                    return true;
            }

            @Override
            protected void onProgressUpdate(Integer... values)
            {
                    //Menu
每個階段位置
                    int y = values[0] * (((HEIGHT/4)*3)/10);
                    //
Menu每個位置帶入
                    mLayoutParams.topMargin = (mPhone.heightPixels - HEIGHT) + y;
                    mLayoutParams.bottomMargin = -y;
                    //
將設定放入Menu
                    mMenu.setLayoutParams(mLayoutParams);
            }
        }
}

這整段程式裡包含手機解析度讀取、滑動距離換算、選單上下滑動控制,整體看來還不會很複雜,小黑人這個範例分享主要是強調滑動效果的運作,如果還要更多控制的話,大家可以再繼續加入判斷,讓滑動選單的功能更多更流暢。

最後,小黑人範例實作的擷圖畫面如下 :







看似平凡的縮放抽屜效果,其實依不同需求與設計都會有不一樣的呈現方式,大家可以一起設計看看怎樣的滑動選單才是最貼切使用者的需求!

謝謝大家如有任何問題都可以和小黑人一起交流討論

☆小黑人☆

1 則留言:

  1. 請問像是晶鑽美甲這個app, 固定下方的選單, 但是icon可以無限增加延伸, 這種滑動的選單. 怎麼做? 要點是甚麼? 謝謝

    回覆刪除

謝謝大家支持,有任何問題都可以和小黑人一起討論!