1. 设计目标
因为最近做课设,需要实现水平滑动页面和侧滑打开侧边栏功能,于是把这两个功能合在一起写了个demo。
实现的功能主要有:水平滑动和点击底部按钮切换页面,侧滑菜单拉出与监听。
2. 思路简介
2.1 ViewPager + Fragment
ViewPager
对象具有内置滑动手势来切换页面,并且默认显示屏幕滑动动画,因此无需再额外实现手势识别和创建自己的动画,直接使用即可。ViewPager
使用 PagerAdapter
对象提供要显示的新页面,因此需要创建的 Fragment
类。在Fragment
类里加载页面的layout
,并返回View
。同时需要重写TabFragmentPagerAdapter
类对Frament
进行管理。在屏幕底部添加两个Button
监听点击事件进行Frament
切换。为了提高用户体验,在屏幕顶部增加了标题栏来告知用户当前所在页面,屏幕底部在Button
也有高亮的字体提示用户当前所在页面。
2.2 DrawableLayout + NavigationView
drawerLayout
是一个布局控件,跟LinearLayout
等控件是一样的,只是drawerLayout
带有滑动的功能。只要按照drawerLayout
的规定布局方式写完布局,就能有侧滑的效果。其中在编写过程需要注意:1.必须设置layout_gravity
属性,它表示侧滑菜单是在左边还是右边,这里选择了start
,表示跟随系统语言判断左右(汉语往左)。2.NavigationView
需要在布局文件的最下面,可能会被其他布局给覆盖到导致无法监听。
NavigationView
可以很方便的实现Drawable的菜单页面,只需要把它放在DrawerLayout
里,再通过它把需要跳转的页面设置进去即可。
3.实现方法
3.1 activity_main布局
- 为了能侧滑,应把
drawerLayout
放在最外层。 NavigationView
需要在布局文件的最下面,可能会被其他布局给覆盖到导致无法监听
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:custom="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="0dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@color/cpb_blue"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical">
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView_topTitle"
android:text="安卓课设"
android:textSize="25dp"
android:textColor="@color/white"
android:layout_gravity="center_vertical"
android:textAlignment="center"
custom:ignore="RtlCompat" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"></LinearLayout>
</LinearLayout>
</LinearLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/myViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="0dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/content"></FrameLayout>
</androidx.viewpager.widget.ViewPager>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="bottom"
android:background="@color/lightgrey">
<Button
android:id="@+id/button_manage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="40dp"
android:layout_weight="1"
android:background="@drawable/main_button_bg"
android:text="管理系统"
android:textAlignment="center"
android:textSize="15dp" />
<Button
android:id="@+id/button_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginRight="40dp"
android:layout_weight="1"
android:background="@drawable/main_button_bg"
android:text="状态查询"
android:textSize="15dp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_gravity="start"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/nav_header"/>
</androidx.drawerlayout.widget.DrawerLayout>
3.2两个Fragment子页面与侧滑菜单布局
activity_status:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="状态查询"
android:id="@+id/textView_status"
android:textSize="25dp"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_manage:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="管理系统"
android:id="@+id/textView_manage"
android:textSize="25dp"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
nav_header:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="180dp"
android:padding="10dp"
android:background="?attr/colorPrimary">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/icon_image"
android:layout_width="132dp"
android:layout_height="90dp"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:layout_marginTop="9dp"
android:src="@drawable/head" />
<TextView
android:id="@+id/username"
android:layout_width="307dp"
android:layout_height="35dp"
android:layout_below="@id/icon_image"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="30dp"
android:text="lan"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/mail"
android:layout_width="356dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:layout_marginEnd="53dp"
android:layout_marginRight="53dp"
android:layout_marginBottom="5dp"
android:text="androidstudio@gmail.com"
android:textColor="@color/black"
android:textSize="14sp" />
</RelativeLayout>
在res目录下新建一个menu文件夹,存放nav_menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_call"
android:icon="@drawable/nav_call"
android:title="Call" />
<item
android:id="@+id/nav_friends"
android:icon="@drawable/nav_friends"
android:title="Friends" />
<item
android:id="@+id/nav_location"
android:icon="@drawable/nav_location"
android:title="Location" />
<item
android:id="@+id/nav_mail"
android:icon="@drawable/nav_mail"
android:title="Mail" />
<item
android:id="@+id/nav_task"
android:icon="@drawable/nav_task"
android:title="Tasks" />
</group>
</menu>
3.3 建立两个Fragment类加载布局和建立TabFragmentPagerAdapter类管理Fragment
Fragment_Manage:
package com.example.test7;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class Fragment_Manage extends Fragment {
public View onCreateView(LayoutInflater inflater , ViewGroup container, Bundle savedInstanceState){
View view=inflater .inflate(R.layout.activity_manage ,container,false) ;
return view;
}
}
Fragment_status:
package com.example.test7;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class Fragment_Staus extends Fragment {
public View onCreateView(LayoutInflater inflater , ViewGroup container, Bundle savedInstanceState){
View view=inflater .inflate(R.layout.activity_status ,container,false) ;
return view;
}
}
TabFragmentPagerAdapter:
package com.example.test7;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.List;
public class TabFragmentPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> mlist;
public TabFragmentPagerAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
this.mlist = list;
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
}
@Override
public Fragment getItem(int arg0) {
return mlist.get(arg0);//显示第几个页面
}
@Override
public int getCount() {
return mlist.size();//有几个页面
}
}
3.4 MainActivity
package com.example.test7;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.navigation.NavigationView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<Fragment> list;
private ViewPager myViewPager;
private TabFragmentPagerAdapter adapter;
private TextView topTitle;
private Button bt_status;
private Button bt_manage;
private NavigationView navView;
private DrawerLayout myDrawerLayout;
private ColorStateList cl_blue;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView()
{
//绑定点击事件
bt_status=(Button) findViewById(R.id.button_status ) ;
bt_manage =(Button) findViewById(R.id.button_manage ) ;
topTitle =(TextView) findViewById(R.id.textView_topTitle ) ;
myViewPager = (ViewPager) findViewById(R.id.myViewPager);
myViewPager.setOnPageChangeListener(new MyPagerChangeListener()) ;
navView = findViewById(R.id.nav_view);
myDrawerLayout = findViewById(R.id.drawer_layout);
//颜色初始化
Resources resource = (Resources) getBaseContext().getResources();
cl_blue= (ColorStateList) resource.getColorStateList(R.color.cpb_blue);
//把Fragment添加到List集合里面
list = new ArrayList<>();
list.add(new Fragment_Manage() );
list.add(new Fragment_Staus() );
adapter = new TabFragmentPagerAdapter(getSupportFragmentManager(), list);
myViewPager.setAdapter(adapter);
//初始化显示第一个页面
myViewPager.setCurrentItem(0);
//button切换监听
bt_status.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myViewPager.setCurrentItem(1);
}
});
bt_manage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myViewPager.setCurrentItem(0);
}
});
//侧边栏item的监听
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.nav_call:
Toast.makeText(MainActivity.this, "You clicked Call", Toast.LENGTH_SHORT).show();
myDrawerLayout.closeDrawers();
break;
}
return false;
}
});
}
//ViewPager监听事件,当左右滑动ViewPager时菜单栏被选中状态跟着改变
public class MyPagerChangeListener implements ViewPager.OnPageChangeListener {
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int arg0) {
switch (arg0) {
case 0:
bt_manage.setTextColor(cl_blue );
bt_status.setTextColor(Color.BLACK );
topTitle .setText("管理系统") ;
break;
case 1:
bt_manage.setTextColor(Color.BLACK);
bt_status.setTextColor(cl_blue);
topTitle .setText("状态查询") ;
break;
}
}
}
}
4. 补充
- 有些颜色、shape、图片这里没有给出,需要更改。
- 项目源码链接