show code block

2017年7月4日 星期二

Android實作(DrawerLayout) — 自製抽屜

 前言:

 前幾天想實作一下側邊欄的抽屜。
找了原廠的 drawerLayout,感覺效果不如預期。不夠彈性。
於是我實作了一個抽屜效果。





實作:

今日要實作的地方

程式碼有點多,讓我們先從動畫著手吧。

一、側邊欄動畫效果

二、首頁和側邊欄的製作

三、MainActivity程式的串接




一、側邊欄動畫效果
先在res下創建一個anim 



開兩個檔案,menu_push_in  and menu_push_out

 menu_push_in.xml
  <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="250"
        android:fillAfter="true"
        android:fromXDelta="0.0"
        android:toXDelta="+85%p" />
</set>
 
menu_push_out.xml
  
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
    android:duration="250"
    android:fromXDelta="85.0%"
    android:toXDelta="0.0"
    />
</set>
 
/**
*duration 動畫持續時間
*fromXDelta 依賴x軸,動畫起始的地方百分比
*toXDelta 依賴x軸,動畫結束的地方百分比
*/


接下來製作MenuController來實作動畫的效果。
MenuController.java
public class MenuController {


    public static void pushRight(final Context context, final RelativeLayout layout) {
        Animation mAnimIn = AnimationUtils.loadAnimation(context, R.anim.menu_push_in);
        layout.startAnimation(mAnimIn);
        mAnimIn.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                //動畫結束後,Hold住畫面
                TranslateAnimation anim = new TranslateAnimation(0.0f, 0.0f, 0.0f, 0.0f);
                anim.setDuration(1);
                layout.startAnimation(anim);
                int realWidth = (context.getResources().getDisplayMetrics().widthPixels);
                int left = (int) (realWidth * 0.85);
                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(layout.getLayoutParams());
                params.setMargins(left, 0, -(realWidth + left), 0);
                layout.setLayoutParams(params);

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
    }

    public static void pushLeft(final Context context, RelativeLayout layout) {
        Animation mAnimOut = AnimationUtils.loadAnimation(context, R.anim.menu_push_out);
        layout.startAnimation(mAnimOut);
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) layout.getLayoutParams();
        params.setMargins(0, 0, 0, 0);
        layout.setLayoutParams(params);

    }
} 
 


二、首頁和側邊欄的製作


直接在畫一個Menu和真正要放內容的Content的Layout。

我的作法是直接把Menu壓在最底部,最上層再用一層ContentLayout蓋著它。

先來製作側邊欄。

menu_main_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_blue_bright"
    tools:context="com.hello.kaiser.drawer.MenuMainLayout">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我是側邊欄"
        android:textSize="50dp" />
</android.support.constraint.ConstraintLayout>



讓我們來寫menu_main_layout的java部分吧
MenuMainLayout.java
/**
 * Menu內的東西可以實作在這裡
 * */
public class MenuMainLayout extends RelativeLayout {


    public MenuMainLayout(Context context) {
        super(context);
        View view = LayoutInflater.from(context).inflate(R.layout.menu_main_layout, this, false);
        addView(view);
    }
}

 

接著製作首頁內的內容,我是直接在頂端自己寫了ToolBar來呼叫側邊欄。

首頁內容

main_content_layout.xml
 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    tools:context="com.hello.kaiser.drawer.MainContentLayout">

    <include layout="@layout/activity_tool_bar" />

</RelativeLayout>


MainContentLayout.java
/***
 *
 * 內容內的東西可以實作在這裏
 *
 * */
public class MainContentLayout extends RelativeLayout {


    public MainContentLayout(Context context) {
        super(context);
        View view = LayoutInflater.from(context).inflate(R.layout.main_content_layout, this, false);
        addView(view);
    }
}

 

三、MainActivity程式的串接

 接著來實作MainActivity吧,來到步驟的最後一步,把上面的東西全部串起來的MagicTime!
MainActivity基本上就只是給一個id,我們要在上面疊入menu和主要content畫面

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.hello.kaiser.drawer.MainActivity">


</RelativeLayout>

 
MainActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.hello.kaiser.drawer.anim.MenuController;

public class MainActivity extends AppCompatActivity {

    private RelativeLayout main_layout;
    private int RealWidth = 0;
    private TextView mMenuClick;//打開menu的效果
    private boolean MenuOpen = false;//控制menu開啟與否

    RelativeLayout mContent;//主要內容layout
    RelativeLayout mBlack;//menu彈出的黑幕

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //獲取裝置的真正寬度
        RealWidth = getResources().getDisplayMetrics().widthPixels;
        
        initView();
        initListener();
    }


    private void initView() {
        main_layout = (RelativeLayout) findViewById(R.id.main_layout);
        //側邊欄
        MenuMainLayout mMenu = new MenuMainLayout(this);
        //讓側邊欄開啟整個畫面的85%
        main_layout.addView(mMenu, new RelativeLayout.LayoutParams(RealWidth * 85 / 100, ViewGroup.LayoutParams.MATCH_PARENT));

        //主畫面內容
        mContent = new MainContentLayout(this);
        main_layout.addView(mContent, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

        //黑幕
        mBlack = new RelativeLayout(this);
        mContent.addView(mBlack, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        mBlack.setBackgroundColor(0x7F000000);
        mBlack.setVisibility(View.GONE);

        mMenuClick = (TextView) mContent.findViewById(R.id.menu);

    }

    private void initListener() {
        mBlack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                menuControl();
            }
        });
        mMenuClick.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                menuControl();
            }
        });
    }

    private void menuControl() {
        if (!MenuOpen) {
            MenuOpen = true;
            mBlack.setVisibility(View.VISIBLE);
            MenuController.pushRight(this, mContent);
        } else {
            MenuOpen = false;
            mBlack.setVisibility(View.GONE);
            MenuController.pushLeft(this, mContent);
        }
    }


}

 

不講解什麼了,其實沒有很難,只是東西有點多,有問題再下發問囉。



Demo:

https://drive.google.com/open?id=0Byk75IYx-dKXa0tWY3RzZkxZYTA

沒有留言:

張貼留言

協程(coroutine) - 協程為什麼要學它?

 Coroutine 協程 再強調一次 協程就是由kotlin官方所提供的線程api //Thread Thread { }.start() //Executor val execu...