Android Studio开发学习(三、侧滑界面)

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>

函数位置目录

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值