Android:借助addContentView()封装易用的通用加载loading,并防止页面按钮重复点击

O、前言

在应用开发中,由于访问网络是一个相当耗时的操作,当页面加载数据或进行提交数据时,一般我们会在页面上展示一个loading加载图,提示用户进行片刻等待。实现loading加载图的方式多种多样,比如有些刷新框架在用户进行下拉刷新时自带的loading图,或者使用Dialog自定义加载弹框,当需要显示时showDialog当需要隐藏时dismiss即可。

但在实际使用过程中刷新框架自带的下拉loading往往无法在提交数据时使用,而自定义的Dialog在使用过程中可能出现窗体泄露的异常,对此本篇文章要介绍一种不同于以上方法的loading实现方式:借助Activity的addContentView()方法在Activity的基类封装一个通用的加载loading,子类可以直接使用,并对此进行优化实现防止页面按钮多次重复点击的作用。

一、在Activity的基类封装一个通用的加载loading

Android项目一般都会有一个Activity基类BaseActivity,直接在BaseActivity中添加如下代码:

    /**
     * mliuxb:通用的Loading加载图
     * 使用方法:在需要显示Loading的地方调用showCenterLoading(),在需要隐藏loading的地方调用hideCenterLoading()即可
     * 若需修改Loading底部的文字提示则调用重载方法showCenterLoading(String text)
     * 注意:以下三个方法在本类中没有调用,而是在子类中调用,所以不影响本基类的任何逻辑
     */
    private LinearLayout llLoading;
    private TextView tvLoading;

    /**
     * 显示Loading
     */
    public void showCenterLoading() {
        showCenterLoading("数据加载中...");
    }

    /**
     * 显示Loading
     */
    public void showCenterLoading(String text) {
        addLoadingView();
        if (llLoading != null && tvLoading != null) {
            tvLoading.setText(text);
            llLoading.setVisibility(View.VISIBLE);
        }
    }

    /**
     * 隐藏Loading
     */
    public void hideCenterLoading() {
        if (llLoading != null) {
            llLoading.setVisibility(View.GONE);
        }
    }

    /**
     * 添加Loading布局
     */
    private void addLoadingView() {
        if (llLoading == null || tvLoading == null) {
            final View loadingView = View.inflate(this, R.layout.layout_global_center_loading, null);
            final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
            params.gravity = Gravity.CENTER;
            addContentView(loadingView, params);//核心方法
            llLoading = findViewById(R.id.ll_global_center_loading);
            tvLoading = findViewById(R.id.tv_global_center_loading);
        }
    }

其中布局文件 layout_global_center_loading 如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/ll_global_center_loading"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="@drawable/shape_global_center_loading_bg"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="20dp"
    android:visibility="gone">

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateDrawable="@drawable/anim_global_rotate_loading" />

    <TextView
        android:id="@+id/tv_global_center_loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:textColor="@android:color/black"
        android:textSize="14sp"
        tools:text="数据加载中..." />
</LinearLayout>

布局文件中 shape_global_center_loading_bg 如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">

    <!--颜色-->
    <solid android:color="#CCCCCCCC"/>

    <!--给矩形加圆角-->
    <corners android:radius="10dp"/>

    <!--边框-->
    <!--<stroke android:width="5dp" android:color="@color/blue_base"/>-->

</shape>

布局文件中 anim_global_rotate_loading 如下:

<?xml version="1.0" encoding="utf-8"?>
<rotate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/icon_global_center_loading"
    android:fromDegrees="0"
    android:toDegrees="1800">

</rotate>

以上即在Activity的基类封装一个通用的加载loading,正如注释中所述在子类中进行调用,在需要显示Loading的地方调用showCenterLoading(),在需要隐藏loading的地方调用hideCenterLoading()即可。

两个方法随处可用并且避免了自定义Dialog出现的窗体泄露的风险,一般情况下在网络访问发送请求前调用showCenterLoading()方法,在收到响应后调用hideCenterLoading()。

二、优化loading实现防止页面按钮多次重复点击的作用

在应用的实际使用过程中,由于网络卡顿或功能过于耗时,用户难免着急进行多次重复操作,如果是提交数据的情况(即数据库进行写数据操作),就可能造成多次提交,从而数据库可能多次写入数据,形成脏数据。此时服务端进行校验是必须的,当然在前端添加第一道防线也是必要的。

当前端与服务端交互时,此时我们的loading加载图是展示的,这个时间段恰好是应该避免用户重复操作的时间,所以修改loading图为全屏,并设置根布局为 android:clickable="true" ,此时底层正常页面的布局就被盖住且不能响应点击等操作,很好的避免了用户重复点击。

修改BaseActivity基类中的代码如下:

    /**
	 * mliuxb更新:通用的Loading加载图
	 * 使用方法:在需要显示Loading的地方调用showCenterLoading(),在需要隐藏loading的地方调用hideCenterLoading()即可
	 * 若需修改Loading底部的文字提示则调用重载方法showCenterLoading(String text)
	 * 注意:以下三个方法在本类中没有调用,而是在子类中调用,所以不影响本类的任何逻辑
	 */
	private FrameLayout flLoading;
	private TextView tvLoading;

	/**
	 * 显示Loading
	 */
	public void showCenterLoading() {
		showCenterLoading("数据加载中...");
	}

	/**
	 * 显示Loading
	 */
	public void showCenterLoading(String text) {
		addLoadingView();
		if (flLoading != null && tvLoading != null) {
			tvLoading.setText(text);
			flLoading.setVisibility(View.VISIBLE);
		}
	}

	/**
	 * 隐藏Loading
	 */
	public void hideCenterLoading() {
		if (flLoading != null) {
			flLoading.setVisibility(View.GONE);
		}
	}

	/**
	 * 添加Loading布局
	 */
	private void addLoadingView() {
		if (flLoading == null || tvLoading == null) {
			final View loadingView = View.inflate(this, R.layout.layout_global_center_loading, null);
			final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
			params.gravity = Gravity.CENTER;
			addContentView(loadingView, params);//核心方法
			flLoading = findViewById(R.id.fl_global_center_loading);
			tvLoading = findViewById(R.id.tv_global_center_loading);
		}
	}

主要是布局参数从 FrameLayout.LayoutParams.WRAP_CONTENT 改为 FrameLayout.LayoutParams.MATCH_PARENT,保证loading布局全屏。

对应的布局文件 layout_global_center_loading 修改如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fl_global_center_loading"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:clickable="true"
    android:focusable="true"
    android:visibility="gone">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="@drawable/shape_global_center_loading_bg"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="20dp">

        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:indeterminateDrawable="@drawable/anim_global_rotate_loading" />

        <TextView
            android:id="@+id/tv_global_center_loading"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:textColor="@android:color/black"
            android:textSize="14sp"
            tools:text="数据加载中..." />
    </LinearLayout>
</FrameLayout>

如上,首先增加了一层FrameLayout嵌套,让根布局FrameLayout为match_parent,保证原loading的大小不变,然后设置根布局 android:clickable="true" ,此时底层的布局就被盖住且不能响应点击等操作。

其中 shape_global_center_loading_bg 和 anim_global_rotate_loading 保持不变,与上面相同。

猜你喜欢

转载自blog.csdn.net/beita08/article/details/115028939