LoadingBar - 如何更优雅的使用Loading

转载请注明出处:
http://blog.csdn.net/aa464971/article/details/70197394

 

已经迁移到新版,请移步

http://blog.csdn.net/aa464971/article/details/70197394

 

 

源码与例子下载地址:

https://github.com/xiandanin/LoadingBar

 

 

前言

我们平时在开发的时候,发起网络请求前,会需要显示一个Loading,一般的做法都是在xml布局上添加好Loading,然后在Activity中,setVisibility来控制Loading的显示和隐藏,这样使用起来就很不方便,因为每一个xml都得引入一个Loading布局。

而LoadingBar就更好的解决了这个问题

 

先来看看效果是怎么样的

 

 

使用方法

先在build.gradle中添加一个引入

 

compile 'com.dyhdyh.loadingbar:loadingbar:1.3'

 

 

再来看看这个页面的布局是怎么写的

其中的FrameLayout就是你要显示的内容,如果你把这个FrameLayout传给LoadingBar,LoadingBar会覆盖在内容上面,从而达到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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.dyhdyh.loadingbar.example.MainActivity">

    <Button
        android:onClick="showLoading"
        android:text="默认样式Loading"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:onClick="showCustomLoading"
        android:text="自定义样式Loading"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:onClick="showClickLoading"
        android:text="带有点击事件Loading"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:onClick="hideLoading"
        android:text="隐藏Loading"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:onClick="multiLoading"
        android:text="多页面显示Loading"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:onClick="listLoading"
        android:text="列表显示Loading"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </FrameLayout>
</LinearLayout>

 

 

 

再来看看Java里怎么来用它

 

 

 

你只需要调用LoadingBar.show(parent),这个parent是一个View,也就是你要显示的位置。

比如现在这个例子,xml中那个id为content的FrameLayout,就是要显示的内容,然后在网络请求前需要把Loading覆盖在内容上面,所以需要把这个FrameLayout传给LoadingBar,当然如果你把getWindow().getDecorView()传给了LoadingBar,Loading就会作用于整个屏幕。

 

package com.dyhdyh.loadingbar.example;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import com.dyhdyh.widget.loadingbar.LoadingBar;

public class MainActivity extends AppCompatActivity {
    View mParent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mParent = findViewById(R.id.content);
    }

    /**
     * 显示默认样式Loading
     *
     * @param v
     */
    public void showLoading(View v) {
        LoadingBar.show(mParent);
    }

    /**
     * 显示自定义样式Loading
     *
     * @param v
     */
    public void showCustomLoading(View v) {
        LoadingBar.show(mParent, View.inflate(this, R.layout.custom_loading, null), null);
    }

    /**
     * 带有点击事件Loading
     *
     * @param v
     */
    public void showClickLoading(View v) {
        LoadingBar.show(mParent, View.inflate(this, R.layout.custom_error, null), new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //在这里处理点击LoadingBar后的要做的操作
                Toast.makeText(MainActivity.this, "重新加载", Toast.LENGTH_SHORT).show();
                showLoading(v);
            }
        });
    }

    /**
     * 隐藏单个Loading
     *
     * @param v
     */
    public void hideLoading(View v) {
        LoadingBar.cancel(mParent);
    }

    /**
     * 取消所有Loading
     *
     */
    public void cancelAll() {
        LoadingBar.cancelAll();
    }

    /**
     * 多页面显示Loading
     *
     * @param v
     */
    public void multiLoading(View v) {
        startActivity(new Intent(this, MutiFragmentActivity.class));
    }


    /**
     * 显示列表的Loading
     *
     * @param v
     */
    public void listLoading(View v) {
        startActivity(new Intent(this, ListViewActivity.class));
    }

}

 

 

 

注意事项

 

 

 

show方法中传的parent,目前支持FrameLayout|RelativeLayout|DrawerLayout|CoordinatorLayout|CardView,这样才能覆盖在内容上面。

 

源码解析

LoadingBar的灵感来源于SnackBar,SnackBar的原理其实就是寻找最外层的CoordinatorLayout或者FrameLayout,然后添加到布局上,再通过动画显示出来。

LoadingBar的思路大致也是这样,唯一跟SnackBar的区别就是LoadingBar并不是找最外层的Layout,而是直接添加到show方法传过来的ViewGroup上,这样就可以将Loading显示在任意位置,我们先来看看show方法是怎么把Loading显示出来的。

1.show有个两个重载方法,一个参数的会使用默认样式的LoadingView,三个参数的会使用传过来的LoadingView并且设置点击事件。

 

    public static LoadingBar show(View parent) {
        return show(parent, null, null);
    }

    public static LoadingBar show(View parent, View loadingView, View.OnClickListener onClickListener) {
        //如果已经有Loading在显示了
        LoadingBar loadingBar;
        if (mLoadingBars.containsKey(parent)) {
            loadingBar = mLoadingBars.get(parent);
        } else {
            //如果没有就新建一个
            loadingBar = new LoadingBar(findSuitableParent(parent));
            mLoadingBars.put(parent, loadingBar);
        }
        //
        loadingBar.mParent.removeView(loadingBar.mView);
        if (loadingView == null) {
            loadingBar.mView = loadingBar.createDefaultLoadingView();
        } else {
            loadingBar.mView = loadingView;
        }
        loadingBar.mParent.addView(loadingBar.mView);
        if (onClickListener != null) {
            loadingBar.mView.setOnClickListener(onClickListener);
        }
        loadingBar.showView();
        return loadingBar;
    }

 

 

 

 

2.show方法中可以看见有调用findSuitableParent(parent),因为LoadingView是要覆盖在内容上面的,那父节点就必须是一个可覆盖的布局,所以在这里检查了一下是否能够让LoadingView遮住内容。

先检查一下parent是不是可覆盖的ViewGroup,如果是就能直接使用,如果不是,就需要循环寻找可用的ViewGroup。
 
private static ViewGroup findSuitableParent(View parent) { if (parent == null) { return null; } View suitableParent = parent; do { if (suitableParent instanceof FrameLayout || suitableParent instanceof RelativeLayout || "android.support.v4.widget.DrawerLayout".equals(suitableParent.getClass().getName()) || "android.support.design.widget.CoordinatorLayout".equals(suitableParent.getClass().getName()) || "android.support.v7.widget.CardView".equals(suitableParent.getClass().getName())) { return (ViewGroup) suitableParent; } else { final ViewParent viewParent = suitableParent.getParent(); suitableParent = viewParent instanceof View ? (View) viewParent : null; return (ViewGroup) suitableParent; } } while (suitableParent != null); }

 

3.show方法中还调用了showView,这里很简单,就是把传过来的LoadingView设为可见就行了。

 

 

final void showView() {
        mView.setVisibility(View.VISIBLE);
    }

 

 

4.有显示就会需要隐藏,隐藏的代码也很简单,就是把LoadingView设为不可见。

 

    /**
     * 取消所有loading
     */
    public static void cancelAll() {
        for (Map.Entry<View, LoadingBar> entry : mLoadingBars.entrySet()) {
            entry.getValue().cancel();
        }
    }

    /**
     * 根据父节点取消单个loading
     *
     * @param parent show传过来的父节点
     */
    public static void cancel(View parent) {
        mLoadingBars.get(parent).cancel();
    }


    /**
     * 取消loading
     */
    public void cancel() {
        if (mView != null) {
            hideView();
        }
    }

 

 

 

 

怎么样,实现起来是不是很简单,用起来也是一句代码,这种思路可以应用在很多别的场景上,所以不得不说Snackbar真的很强大。
 

对这个组件有不懂的地方可以进群问我:146262062

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值