預覽圖
界面布局
傳統(tǒng)的抽屜菜單一般采取DrawerLayout+Toolbar+NavigationView的布局組合。而為了使菜單欄界面設計更加自由,這兒使用自定義布局來代替NavigationView韩肝。在設計布局之前测垛,先在styles.xml中將“DarkActionBar”改為“NoActionBar”磅废,刪去標題欄秉宿,然后待會我們用Toolbar替代隆豹。
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
接著開始寫我們的主界面先煎,采取Material Design的DrawerLayout布局贼涩。
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="0dp"
app:cardElevation="20dp">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/content_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar"/>
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
<fragment
android:id="@+id/nav_view"
android:name="com.example.yc.androidsrc.MenuFragment"
android:layout_gravity="start"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.DrawerLayout>
DrawerLayout布局下的第一個子視圖表示主內容視圖,我將其嵌套在一個CardView里面薯蝎,主要是為了當拉開菜單時遥倦,主內容視圖的邊緣能呈現(xiàn)出卡片式的圓角和陰影。主內容視圖主要包括Toolbar和FrameLayout占锯,其中FrameLayout用以動態(tài)加載各個菜單選項所對應的fragment袒哥。
DrawerLayout布局下的第二個子視圖表示菜單欄視圖,我們使用靜態(tài)加載fragment的方式來呈現(xiàn)界面內容消略,其中android:layout_gravity="start"
表示抽屜菜單是從左邊拉開堡称,而end
則表示右邊。
菜單布局不詳說了艺演。不過菜單選項的ListView Item布局左邊有個設置為透明的View却紧,當該項被選中時才顯示為黑色,充當“視覺標簽”的作用胎撤。
菜單側滑時的監(jiān)聽事件
我們主要實現(xiàn)的效果是:當滑動菜單時晓殊,主視圖逐漸縮小,移至界面右邊并呈現(xiàn)出卡片式的圓角與陰影伤提,菜單欄視圖逐漸放大并完整呈現(xiàn)在界面左邊巫俺。
因此我們需要監(jiān)聽DrawerLayout的滑動事件,代碼如下:
mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
View mContent = mDrawerLayout.getChildAt(0);
View mMenu = drawerView;
float scale = 1 - slideOffset;
float rightScale = 0.8f + scale * 0.2f;
float leftScale = 0.5f + slideOffset * 0.5f;
mMenu.setAlpha(leftScale);
mMenu.setScaleX(leftScale);
mMenu.setScaleY(leftScale);
mContent.setPivotX(0);
mContent.setPivotY(mContent.getHeight() * 1/2);
mContent.setScaleX(rightScale);
mContent.setScaleY(rightScale);
mContent.setTranslationX(mMenu.getWidth() * slideOffset);
}
@Override
public void onDrawerOpened(View drawerView) {
cardView.setRadius(20);
}
@Override
public void onDrawerClosed(View drawerView) {
cardView.setRadius(0);
}
@Override
public void onDrawerStateChanged(int newState) {
}
});
我們來分析一下:其中參數(shù)slideOffset代表此時菜單欄的滑動比例飘弧,數(shù)值為0~1识藤。而在這個過程中,我希望主內容視圖的尺寸從原本的1縮放至最后的0.8次伶,因此我們可以得到一個很簡單的線性函數(shù)痴昧,即主內容視圖的尺寸Scale=0.8+(1-slideOffset)x0.2。同樣的冠王,我設置在這個過程中赶撰,菜單欄的尺寸由0.5擴大到1,因此它的尺寸線性函數(shù)為0.5+slideOffset*0.5。而此時主內容視圖的右移尺寸剛好對應為菜單欄滑出來的寬度豪娜,因此設置為mContent.setTranslationX(mMenu.getWidth()xslideOffset)餐胀。另外關于主內容視圖要從以哪個坐標點為中心進行縮放,可通過setPivot進行設置瘤载,我覺得從左邊界的中間點進行縮放否灾,效果會比較好看些。當然鸣奔,以上這些數(shù)據你都可以自由設計墨技,不同的數(shù)據得到的界面動態(tài)效果各有千秋。
主要的代碼如下:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout;
private FrameLayout contentFrameLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerLayout.setScrimColor(Color.TRANSPARENT); // 菜單滑動時content不被陰影覆蓋
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(""); // 不顯示程序應用名
toolbar.setNavigationIcon(R.drawable.ic_menu_black_24dp); // 在toolbar最左邊添加icon
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDrawerLayout.openDrawer(GravityCompat.START);
}
});
final CardView cardView = (CardView) findViewById(R.id.card_view);
contentFrameLayout = (FrameLayout) findViewById(R.id.content_view);
replaceFragment(new TabFragment1());
// 監(jiān)聽抽屜的滑動事件
mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
View mContent = mDrawerLayout.getChildAt(0);
View mMenu = drawerView;
float scale = 1 - slideOffset;
float rightScale = 0.8f + scale * 0.2f;
float leftScale = 0.5f + slideOffset * 0.5f;
mMenu.setAlpha(leftScale);
mMenu.setScaleX(leftScale);
mMenu.setScaleY(leftScale);
mContent.setPivotX(0);
mContent.setPivotY(mContent.getHeight() * 1/2);
mContent.setScaleX(rightScale);
mContent.setScaleY(rightScale);
mContent.setTranslationX(mMenu.getWidth() * slideOffset);
}
@Override
public void onDrawerOpened(View drawerView) {
cardView.setRadius(20); // 拉開菜單時挎狸,主內容視圖的邊緣能呈現(xiàn)出卡片式的圓角和陰影
}
@Override
public void onDrawerClosed(View drawerView) {
cardView.setRadius(0); // 菜單關閉扣汪,圓角消失
}
@Override
public void onDrawerStateChanged(int newState) {
}
});
}
public void replaceFragment(Fragment fragment) { // 動態(tài)加載fragment
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_view, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
至于菜單欄視圖,主要是設置好每個選項的點擊事件锨匆。這里我通過getActivity()強行獲得MainActivity對象崭别,然后再直接通過上面寫好的replaceFragment()函數(shù)去動態(tài)加載對應的fragment,將所要的不同功能視圖呈現(xiàn)在主視圖中恐锣。
MenuFragment
public class MenuFragment extends Fragment {
private ListView mListView;
private List<MenuItem> menuItemList = new ArrayList<>();
private MenuItemAdapter adapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View navView = inflater.inflate(R.layout.activity_menu, container, false);
mListView = (ListView) navView.findViewById(R.id.menu_list_view);
mListView.setDivider(null); // 去掉分割線
initListView();
clickEvents();
return navView;
}
public void initListView() {
String[] data_zh = getResources().getStringArray(R.array.menu_zh);
String[] data_en = getResources().getStringArray(R.array.menu_en);
for (int i = 0; i < data_zh.length; i++) {
MenuItem menuItem = new MenuItem(data_zh[i], data_en[i]);
menuItemList.add(menuItem);
}
adapter = new MenuItemAdapter(getActivity(), R.layout.menu_list_item, menuItemList);
mListView.setAdapter(adapter);
}
public void clickEvents() {
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
adapter.changeSelected(position); // 先定義好樣式如何改變
MainActivity activity = (MainActivity) getActivity();
DrawerLayout mDrawerLayout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
mDrawerLayout.closeDrawer(Gravity.START);
switch (position) {
case 0:
activity.replaceFragment(new TabFragment1());
break;
case 1:
activity.replaceFragment(new TabFragment2());
break;
case 2:
activity.replaceFragment(new TabFragment3());
break;
case 3:
activity.replaceFragment(new TabFragment4());
break;
case 4:
activity.replaceFragment(new TabFragment5());
break;
default:
break;
}
}
});
}
}
沉浸式狀態(tài)欄
可以看到效果圖上的頂部狀態(tài)欄為沉浸式茅主,背景色與Toolbar一致并且字體為黑色(一般為白色)。
首先土榴,應該明白各個版本的區(qū)別:要修改狀態(tài)欄暗膜,Android版本至少要在4.4以上,并且在4.4是不能讓狀態(tài)欄透明的鞭衩,只能達到一種半透明的陰影背景,而在5.x的版本中娃善,是可以修改背景顏色但無法修改字體顏色的论衍,只有在6.0以上是可以隨意修改的。但是在魅族和小米第三方ROM在4.4版本以上的手機都提供了修改的接口聚磺。
這里就不詳細展開了坯台,具體怎么做,我覺得這兩篇博客總結得比較好瘫寝,放上地址: