1. 引言
欢迎大家来到第三部分的学习,我们还是延续上面注册登录界面继续进行,上两篇博客,我们成功登录后跳转界面为 dataActivity,为了功能对应,方便阅读理解,这里将 java 和 xml 的名称分别修改为 SideActivity 和 activity_side。(也可以直接删除旧的,重新创建)
MainActivity 中记得修改对应名称
2. 侧滑布局
首先我们知道,侧滑意味着他有两个界面即主界面和滑动界面,当我们在主界面进行屏幕滑动时,对应会出现滑动界面(比如 QQ 界面滑动),所以我们需要先设计主界面 layout_sidemain 和滑动界面 layout_sidemenu,然后将他们显示结果共同呈现在 activity_side 中。
先来看一下大致布局:(随便画的)
主界面( layout_sidemain )
开始之前,我们先介绍一下今天使用的新布局 ImageView :
ImageView 用于在界面上显示图片,它继承自 View 类,并且实现了 Drawable.Callback 接口,这允许它处理与可绘制对象(如位图、图标等)相关的回调。在 XML 布局文件中,可以通过以下方式添加:
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/your_image"
android:scaleType="fitCenter" />
我们重点看主界面上方的LinearLayout,用来展示一个头像和一个文本标签,下方按钮按需求添加即可。android: scaleType="centerCrop" 属性使图片在保持宽高比的同时,填充整个 ImageView。layout_marginTop 和 layout_marginLeft 顾名思义就是顶部距离和左端距离。
滑动界面( layout_sidemenu )
滑动界面就非常简单了,上方文本提示和按钮添加即可,这里只是一个简单的设计添加,有兴趣的小伙伴还可以设计更加复杂的界面。(这里先添加一个按钮,后续博客再做补充)
activity_side界面显示
创建一个侧边栏菜单,当用户触发某个动作时(如滑动或点击),侧边栏会从屏幕的一侧滑出,并显示在主内容旁边或覆盖在主内容之上。< include > 标签用于在布局文件中包含另一个布局文件。
3. 侧滑函数
侧滑功能函数实现
!!!重点来了,如何实现侧滑功能!
自定义视图类 SideMenu,该类继承自 FrameLayout,实现一个侧边菜单功能
FrameLayout 是一种布局容器类,继承自 ViewGroup 。它主要用于简单地布局子视图,通常用于在布局中显示单个子视图或重叠多个子视图。
onFinishInflate:当所有子视图加载完毕后调用,可用于初始化子视图引用。这里,第一个子视图(sidemenu)和第二个子视图(sidemain)被初始化,并得到菜单视图的宽度。
onInterceptTouchEvent:决定是否截获触摸事件。如果水平移动超过阈值(8 像素),它将拦截触摸事件以进行自定义处理。
设置两个子视图在页面上的布局。
onTouchEvent:处理用于滑动菜单的触摸事件。
- ACTION_DOWN:记录初始 X 位置。
- ACTION_MOVE:计算水平移动并相应地滚动视图,确保其保持在边界内。
- ACTION_UP:根据最终位置决定是打开还是关闭菜单。
计算滚动:在计算滚动偏移量的同时连续滚动视图,确保动画流畅。
根据菜单的当前位置在打开和关闭状态之间切换菜单
侧滑基础函数实现
和之前一样声明找到控件,增加侧滑功能调用(这里为了方便增加点击功能,把他们包装成函数,然后用switch-case方法,后续完整代码中大家可以查看)
4. 实机演示
完整代码
SideActivity.java
package com.example.login;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import com.example.login.Function.AddActivity;
import com.example.login.Function.QueryActivity;
import com.example.login.Function.RecordActivity;
public class SideActivity extends AppCompatActivity {
//声明控件
private ImageView mIvHead; // 头像
private com.example.login.SideMenu sideMenu; // 侧滑界面
private Button mBtnAdd;
private Button mBtnQuery;
private Button mBtnRecord;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_side);
//找到控件
mIvHead = findViewById(R.id.IV_head);
sideMenu = findViewById(R.id.sideMenu);
mBtnAdd = findViewById(R.id.btn_main_1);
mBtnQuery = findViewById(R.id.btn_main_2);
mBtnRecord = findViewById(R.id.btn_main_3);
//实现侧滑部分
mIvHead.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sideMenu.toggleMenu();
}
});
setListener();
}
//实现功能(7个)
private void setListener(){
OnClick onClick = new OnClick();
mBtnAdd.setOnClickListener(onClick);
mBtnQuery.setOnClickListener(onClick);
mBtnRecord.setOnClickListener(onClick);
}
private class OnClick implements View.OnClickListener{
public void onClick(View v) {
Intent intent = null;
switch (v.getId()){
case R.id.btn_main_1:
intent = new Intent(SideActivity.this, AddActivity.class);
break;
case R.id.btn_main_2:
intent = new Intent(SideActivity.this, QueryActivity.class);
break;
case R.id.btn_main_3:
intent = new Intent(SideActivity.this, RecordActivity.class);
break;
}
startActivity(intent);
}
}
}
activity_side.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:padding="5dp"
tools:context=".SideActivity">
<com.example.login.SideMenu
android:id="@+id/sideMenu"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 滑动界面布局-->
<include layout="@layout/layout_sidemenu"/>
<!-- 主界面布局-->
<include layout="@layout/layout_sidemain"/>
</com.example.login.SideMenu>
</RelativeLayout>
SideMenu.java
package com.example.login;
import android.content.Context;
import android.content.Intent;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Scroller;
public class SideMenu extends FrameLayout {
private View sidemenu, sidemain; // 引用侧边菜单和内容视图
private int sideMenuWidth; // 存储菜单的宽度
private Scroller smoothScroller; // 平滑滚动对象
private int startX; // 开始触摸时的X坐标
public SideMenu(Context context) {
super(context);
initialize();
}
public SideMenu(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
private void initialize() {
smoothScroller = new Scroller(getContext());
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
sidemenu = getChildAt(0);
sidemain = getChildAt(1);
sideMenuWidth = sidemenu.getLayoutParams().width;
}
// 使菜单也具有滑动功能
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) ev.getX();
break;
case MotionEvent.ACTION_MOVE:
int deltaX = (int) (ev.getX() - startX);
if (Math.abs(deltaX) > 8) {
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
sidemenu.layout(-sideMenuWidth, 0, 0, b);
sidemain.layout(0, 0, r, b);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getX();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getX();
int deltaX = moveX - startX;
int scrollX = getScrollX() - deltaX;
if (scrollX < -sideMenuWidth) scrollX = -sideMenuWidth;
if (scrollX > 0) scrollX = 0;
scrollTo(scrollX, 0);
startX = moveX;
break;
case MotionEvent.ACTION_UP:
if (getScrollX() > -sideMenuWidth / 2) {
closeSideMenu();
} else {
openSideMenu();
}
break;
}
return true;
}
// 关闭菜单
private void closeSideMenu() {
smoothScroller.startScroll(getScrollX(), 0, -getScrollX(), 0, 400);
invalidate();
}
// 打开菜单
private void openSideMenu() {
smoothScroller.startScroll(getScrollX(), 0, -sideMenuWidth - getScrollX(), 0, 400);
invalidate();
}
@Override
public void computeScroll() {
super.computeScroll();
if (smoothScroller.computeScrollOffset()) {
// 返回 true 表示动画还未结束
scrollTo(smoothScroller.getCurrX(), 0);
invalidate();
}
}
public void toggleMenu() {
if (getScrollX() == 0) {
openSideMenu();
} else {
closeSideMenu();
}
}
}
layout_sidemenu.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="270dp"
android:layout_height="match_parent">
<TextView
android:layout_marginTop="50dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="侧滑界面"
android:textSize="30dp" />
<Button
android:id="@+id/bluetooth_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="蓝牙"
android:gravity="center"
android:layout_marginTop="50dp"
android:onClick="onBluetoothButtonClick"
/>
</LinearLayout>
layout_sidemain.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="200dp"
android:background="@drawable/background1"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="40dp">
<ImageView
android:id="@+id/IV_head"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/jingliu1"
android:layout_marginLeft="10dp"
android:scaleType="centerCrop"/>
<TextView
android:layout_width="65dp"
android:layout_height="match_parent"
android:layout_marginLeft="20dp"
android:gravity="center"
android:text="明空"
android:textColor="@color/colorBlack"
android:textSize="22sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:layout_marginTop="180dp"
android:background="#00000000"
android:orientation="vertical">
<Button
android:id="@+id/btn_main_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="增加"
android:background="#00000000"
android:textColor="@color/colorBlack"/>
<Button
android:id="@+id/btn_main_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查询"
android:background="#00000000"
android:textColor="@color/colorBlack"/>
<Button
android:id="@+id/btn_main_3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="记录"
android:background="#00000000"
android:textColor="@color/colorBlack"/>
</LinearLayout>
</LinearLayout>