一、概述

Android中经常在有的app中可以见到“加载中”并不是以弹出对话框的形式显示的,而是占用整个屏幕,如果加载失败就会出现加载失败页面,点击加载失败页面中任意区域,都可以重新加载。今天就和大家一起学习如何通过自定义view的方式实现加载中、加载失败、无数据的效果。

二、实现代码

自定义属性文件

<declare-styleable name="LoadingLayout"><attr name="loadingView" format="reference" /><attr name="stateView" format="reference" /><attr name="emptyView" format="reference" />declare-styleable>

自定义view:www.hack95.com

package com.czhappy.effectdemo.loadinglayout;import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;import com.czhappy.effectdemo.R;public class LoadingLayout extends FrameLayout {/*** 空数据View*/private int mEmptyView;/*** 状态View*/private int mStateView;/*** 加载View*/private int mLoadingView;public LoadingLayout(Context context) {this(context, null);}public LoadingLayout(Context context, AttributeSet attrs) {this(context, attrs, -1);}public LoadingLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.LoadingLayout, 0, 0);try {mStateView = a.getResourceId(R.styleable.LoadingLayout_stateView, R.layout.loadstate_layout);mLoadingView = a.getResourceId(R.styleable.LoadingLayout_loadingView, R.layout.loading_layout);mEmptyView = a.getResourceId(R.styleable.LoadingLayout_emptyView, R.layout.empty_layout);LayoutInflater inflater = LayoutInflater.from(getContext());inflater.inflate(mStateView, this, true);inflater.inflate(mLoadingView, this, true);inflater.inflate(mEmptyView, this, true);} finally {a.recycle();}}/*** 布局加载完成后隐藏所有View*/@Overrideprotected void onFinishInflate() {super.onFinishInflate();for (int i = 0; i < getChildCount() - 1; i++) {getChildAt(i).setVisibility(GONE);}}/*** 设置Empty点击事件* @param listener*/public void setEmptyClickListener(final OnClickListener listener) {if( listener!=null )findViewById(R.id.state_retry2).setOnClickListener(listener);}/*** 设置State点击事件* @param listener*/public void setStateClickListener( OnClickListener listener ){if(listener!=null)findViewById(R.id.state_retry).setOnClickListener(listener);}/*** 设置自定义布局的点击事件* @param resoureId* @param listener*/public void setViewOncClickListener(int resoureId,OnClickListener listener) {findViewById(resoureId).setOnClickListener(listener);}/*** 设置自定义布局的view文本* @param resoureId* @param text*/public void setViewText(int resoureId,String text){((TextView)findViewById(resoureId)).setText(text);}/*** 设置自定义布局的image* @param resoureId* @param img*/public void setViewImage(int resoureId,int img ){((ImageView)findViewById(resoureId)).setImageResource(img);}/*** State View*/public void showState() {for (int i = 0; i < this.getChildCount(); i++) {View child = this.getChildAt(i);if (i == 0) {child.setVisibility(VISIBLE);} else {child.setVisibility(GONE);}}}/*** Empty view*/public void showEmpty() {for (int i = 0; i < this.getChildCount(); i++) {View child = this.getChildAt(i);if (i == 2) {child.setVisibility(VISIBLE);} else {child.setVisibility(GONE);}}}/*** Loading view*/public void showLoading() {for (int i = 0; i < this.getChildCount(); i++) {View child = this.getChildAt(i);if (i == 1) {child.setVisibility(VISIBLE);} else {child.setVisibility(GONE);}}}/**** @param text*/public void showLoading(String text) {for (int i = 0; i < this.getChildCount(); i++) {View child = this.getChildAt(i);if (i == 1) {child.setVisibility(VISIBLE);((TextView) child.findViewById(R.id.loading_text)).setText(text + "");} else {child.setVisibility(GONE);}}}/*** Empty view** @param text*/public void showEmpty(String text) {for (int i = 0; i < this.getChildCount(); i++) {View child = this.getChildAt(i);if (i == 2) {child.setVisibility(VISIBLE);((TextView) child.findViewById(R.id.empty_text)).setText(text + "");} else {child.setVisibility(GONE);}}}/**** @param tips*/public void showState(String tips) {for (int i = 0; i < this.getChildCount(); i++) {View child = this.getChildAt(i);if (i == 0) {child.setVisibility(VISIBLE);((TextView) child.findViewById(R.id.load_state_tv)).setText(tips + "");} else {child.setVisibility(GONE);}}}/*** @param stateId* @param tips*/public void showState(int stateId, String tips) {for (int i = 0; i < this.getChildCount(); i++) {View child = this.getChildAt(i);if (i == 0) {child.setVisibility(VISIBLE);((ImageView) child.findViewById(R.id.load_state_img)).setImageResource(stateId);((TextView) child.findViewById(R.id.load_state_tv)).setText(tips + "");} else {child.setVisibility(GONE);}}}/*** 展示内容*/public void showContent() {for (int i = 0; i < this.getChildCount(); i++) {View child = this.getChildAt(i);if (i > 2 ) {child.setVisibility(VISIBLE);} else {child.setVisibility(GONE);}}}
}

测试类www.hack95.com

package com.czhappy.effectdemo.activity;import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;import com.czhappy.effectdemo.R;
import com.czhappy.effectdemo.loadinglayout.LoadingLayout;/*** Description:* User: chenzheng* Date: 2017/2/17 0017* Time: 18:05*/
public class LoadingLayoutActivity extends AppCompatActivity implements View.OnClickListener{private Button btn1, btn2, btn3;private LoadingLayout mLoading;private Handler mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if(msg.what==1000){mLoading.showContent();}else if(msg.what==2000){mLoading.showState("加载失败,点击重试!");}else if(msg.what==3000){mLoading.showEmpty();}}};@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_loading_layout);initView();}private void initView() {mLoading = (LoadingLayout) findViewById(R.id.loading_layout);btn1 = (Button) findViewById(R.id.btn1);btn2 = (Button) findViewById(R.id.btn2);btn3 = (Button) findViewById(R.id.btn3);btn1.setOnClickListener(this);btn2.setOnClickListener(this);btn3.setOnClickListener(this);mLoading.showContent();mLoading.setStateClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mLoading.showLoading();mLoading.postDelayed(new Thread(){@Overridepublic void run() {super.run();//模拟网络请求mHandler.sendEmptyMessage(2000);}},1000);}});}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn1:mLoading.showLoading();mLoading.postDelayed(new Thread(){@Overridepublic void run() {super.run();//模拟网络请求mHandler.sendEmptyMessage(1000);}},2000);break;case R.id.btn2:mLoading.showLoading();mLoading.postDelayed(new Thread(){@Overridepublic void run() {super.run();//模拟网络请求mHandler.sendEmptyMessage(2000);}},2000);break;case R.id.btn3:mLoading.showLoading();mLoading.postDelayed(new Thread(){@Overridepublic void run() {super.run();//模拟网络请求mHandler.sendEmptyMessage(3000);}},2000);break;}}
}

正在加载的布局文件loading_layout.xml

至于empty_layout.xml和loadstate_layout.xml这些简单布局的代码就不贴出来了,根据需要自己定义。


<LinearLayout xmlns:android="http://www.hack95.com/apk/res/android"xmlns:wheel="http://www.hack95.com/apk/res-auto"android:id="@+id/loading_view"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><com.pnikosis.materialishprogress.ProgressWheel
        android:id="@+id/progress_wheel"android:layout_width="50dp"android:layout_height="50dp"android:layout_centerHorizontal="true"android:layout_centerVertical="true"wheel:matProg_barColor="#5588FF"wheel:matProg_progressIndeterminate="true" /><TextView
        android:id="@+id/loading_text"android:layout_width="wrap_content"android:padding="5dp"android:layout_height="wrap_content"android:text="  正在加载..."android:textColor="#999999"android:textSize="15sp" />
LinearLayout>

三、注意事项

项目中实现正在加载的material design风格的进度动画,用的是开源库
https://www.hack95.com/pnikosis/materialish-progress
如果你有其他需求,可以自己替换