StateTool 一种好用的"空页面 错误页面 等待页面 数据页面"切换工具

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/alcoholdi/article/details/53750619

先上图


如图所示,页面主要有三个模块.

空页面:表示联网成功,但是服务器没有数据可取的页面提示

错误页面:表示网络等错误的页面提示.

内容页面:就是我们正常流程显示的页面.





为了结构精简,你只需要引用一个类StateTool就行!!!!精简到没朋友..



开始讲解StateTool

package com.yao.statetooldemo;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;


/**
 * Created by Yao on 2016/9/28.
 */

public class StateTool {

    /**
     * 一大堆静态变量,根据项目需要可以随意修改.比如项目全部用同一张错误页面的图片.
     * 在一个项目中如果用好几张不同的错误页面图片,可以考虑改成成员变量.
     */
    //内容字体的大小,单位SP
    private static int CONTENT_TEXT_SIZE = 20;
    //提示字体的大小,单位SP
    private static int TIP_TEXT_SIZE = 12;

    //空页面图片,默认用的安卓sdk里面的图片,严重建议替换成一个256px左右的图片 默认使用android.R.drawable.ic_menu_close_clear_cancel
    private static  int emptyImageResId = R.mipmap.empty;
    //错误页面图片,默认用的安卓sdk里面的图片,严重建议替换成一个256px左右的图片 默认使用android.R.drawable.ic_menu_search
    private static  int errorImageResId = R.mipmap.error;

    //空页面文字
    private static String emptyText = "空页面";
    //错误页面文字
    private static String errorText = "错误页面";
    //加载页面文字
    private static String loadingText = "加载中...";
    //重载动作的文字提示
    private static String reloadText = "点击重载";

    //图片的宽和高 可以用ViewGroup.LayoutParams.WRAP_CONTENT
    private static int imageSidesLength = 128;
    //等待,错误,空页面提示的向上偏移
    private static int offset = 0;

    //使用淡入淡出动画
    private static boolean useAlphaAnimator = false;

    private ViewGroup root;
    private Context ctx;
    private View contentView;
    private RelativeLayout emptyView;
    private RelativeLayout errorView;
    private RelativeLayout progressView;
    private View currentView;

    private LinearLayout.LayoutParams paramsChildrenWrapContent;
    private LinearLayout.LayoutParams paramsChildrenImage;
    private LinearLayout.LayoutParams paramsChildrenMarginBottom50;

    /**
     * 一个孩子,调用此方法
     * @param root
     */
    public StateTool(ViewGroup root) {
        this.root = root;
        if (root.getChildCount() > 1) {
            throw new RuntimeException("root view's children more than 1");
        }
        contentView = root.getChildAt(0);

        init();
    }

    /**
     * 如果有多个孩子,调用此方法
     * @param root
     * @param index 传孩子的位置
     */
    public StateTool(ViewGroup root, int index) {
        this.root = root;
        if (root.getChildCount() < index + 1) {
            throw new RuntimeException("Invalid index " + index +", size is " + root.getChildCount());
        }
        contentView = root.getChildAt(index);

        init();
    }

    private void init() {
        ctx = root.getContext();
        currentView = contentView;

        paramsChildrenWrapContent =  new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        paramsChildrenImage =  new LinearLayout.LayoutParams(imageSidesLength, imageSidesLength);
        paramsChildrenMarginBottom50 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        paramsChildrenMarginBottom50.setMargins(0, 0, 0, offset);//不margin不居中

        initEmptyView();
        initErrorView();
        initProgressView();
    }

    public void setEmptyAndErrorImageResId(int emptyImageResId, int errorImageResId) {
        this.emptyImageResId = emptyImageResId;
        this.errorImageResId = errorImageResId;
    }

    public void setEmptyAndErrorTextResId(String emptyText, String errorText, String reloadText, String loadingText) {
        this.emptyText = emptyText;
        this.errorText = errorText;
        this.reloadText = reloadText;
        this.loadingText = loadingText;
    }

    public void showEmptyView(){
        if (useAlphaAnimator) {
            alphaHide(currentView);
            alphaShow(emptyView);
        } else {
            currentView.setVisibility(View.GONE);
            emptyView.setVisibility(View.VISIBLE);
        }
        currentView = emptyView;
    }

    public void showErrorView(){
        currentView.setVisibility(View.GONE);
        errorView.setVisibility(View.VISIBLE);
        currentView = errorView;
    }

    public void showProgressView(){
        currentView.setVisibility(View.GONE);
        progressView.setVisibility(View.VISIBLE);
        currentView = progressView;
    }

    public void showContentView(){
        currentView.setVisibility(View.GONE);
        contentView.setVisibility(View.VISIBLE);
        currentView = contentView;
    }

    public void setOnClickListener(View.OnClickListener onClickListener) {
        emptyView.setOnClickListener(onClickListener);
        errorView.setOnClickListener(onClickListener);
    }

    private void alphaShow(final View v){
        ObjectAnimator oa = ObjectAnimator.ofFloat(v, "alpha", 0, 1);
        oa.setDuration(500);
        oa.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animator) {
                v.setVisibility(View.VISIBLE);
            }
        });
        oa.start();
    }

    private void alphaHide(final View v){
        ObjectAnimator oa = ObjectAnimator.ofFloat(v, "alpha", 1, 0);
        oa.setDuration(500);
        oa.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animator) {
                v.setVisibility(View.GONE);
            }
        });
        oa.start();
    }

    private void initEmptyView() {
        emptyView = new RelativeLayout(ctx);

        LinearLayout linearLayout = new LinearLayout(ctx);
        linearLayout.setOrientation(LinearLayout.VERTICAL);

        ImageView iv = new ImageView(ctx);
        iv.setImageResource(emptyImageResId);
        linearLayout.addView(iv, paramsChildrenImage);

        TextView tvContent = new TextView(ctx);
        tvContent.setTextSize(TypedValue.COMPLEX_UNIT_SP, CONTENT_TEXT_SIZE);
        tvContent.setText(emptyText);
        linearLayout.addView(tvContent, paramsChildrenWrapContent);

        TextView tvTip = new TextView(ctx);
        tvTip.setTextSize(TypedValue.COMPLEX_UNIT_SP, TIP_TEXT_SIZE);
        tvTip.setText(reloadText);
        linearLayout.addView(tvTip, paramsChildrenMarginBottom50);

        RelativeLayout.LayoutParams paramsLinearLayout = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        paramsLinearLayout.addRule(RelativeLayout.CENTER_IN_PARENT);//这个是RelativeLayout的layout_centerInParent属性
        linearLayout.setGravity(Gravity.CENTER);//这个是LinearLayout的gravity属性
        emptyView.addView(linearLayout, paramsLinearLayout);

        root.addView(emptyView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

        emptyView.setVisibility(View.GONE);
    }

    private void initErrorView() {
        errorView = new RelativeLayout(ctx);

        LinearLayout linearLayout = new LinearLayout(ctx);
        linearLayout.setOrientation(LinearLayout.VERTICAL);

        ImageView iv = new ImageView(ctx);
        iv.setImageResource(errorImageResId);
        linearLayout.addView(iv, paramsChildrenImage);

        TextView tvContent = new TextView(ctx);
        tvContent.setTextSize(TypedValue.COMPLEX_UNIT_SP, CONTENT_TEXT_SIZE);
        tvContent.setText(errorText);
        linearLayout.addView(tvContent, paramsChildrenWrapContent);

        TextView tvTip = new TextView(ctx);
        tvTip.setTextSize(TypedValue.COMPLEX_UNIT_SP, TIP_TEXT_SIZE);
        tvTip.setText(reloadText);
        linearLayout.addView(tvTip, paramsChildrenMarginBottom50);

        RelativeLayout.LayoutParams paramsLinearLayout = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        paramsLinearLayout.addRule(RelativeLayout.CENTER_IN_PARENT);//这个是RelativeLayout的layout_centerInParent属性
        linearLayout.setGravity(Gravity.CENTER);//这个是LinearLayout的gravity属性
        errorView.addView(linearLayout, paramsLinearLayout);

        root.addView(errorView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

        errorView.setVisibility(View.GONE);
    }

    private void initProgressView() {
        progressView = new RelativeLayout(ctx);

        LinearLayout linearLayout = new LinearLayout(ctx);
        linearLayout.setOrientation(LinearLayout.VERTICAL);

        ProgressBar pb = new ProgressBar(ctx);
        linearLayout.addView(pb, paramsChildrenWrapContent);

        TextView tvContent = new TextView(ctx);
        tvContent.setTextSize(TypedValue.COMPLEX_UNIT_SP, CONTENT_TEXT_SIZE);
        tvContent.setText(loadingText);
        linearLayout.addView(tvContent, paramsChildrenMarginBottom50);

        RelativeLayout.LayoutParams paramsLinearLayout = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        paramsLinearLayout.addRule(RelativeLayout.CENTER_IN_PARENT);//这个是RelativeLayout的layout_centerInParent属性
        linearLayout.setGravity(Gravity.CENTER);//这个是LinearLayout的gravity属性
        progressView.addView(linearLayout, paramsLinearLayout);

        root.addView(progressView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    }

}

这个类本质是传入一个布局的主ViewGroup,然后里面有3+1种页面可以切换.分别是空页面,错误页面,等待页面和我们的主要内容页面.

这3个页面为了简直,直接用Java代码写布局嵌入了,对外提供showEmptyView(), showErrorView, showProgressView(), showContentView()方法使用


1.为了方便修改.我把可以自定义的文字提醒,大小,图片高宽等都放到开头,拿回去即可修改成项目需要的样式.

2.图片可以找UI切换,随意一点直接用android自带的android.R.drawable.ic_menu_close_clear_cancel和android.R.drawable.ic_menu_search.我随便选的.



使用

package com.yao.statetooldemo;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    private StateTool stateTool;

    private LinearLayout linearLayout;

    private int counter;//演示用的计数器

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

        stateTool = new StateTool(linearLayout);
        //如果处于错误或者空页面,点击后的事件
        stateTool.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stateTool.showProgressView();//让页面处于progress
                doSomeNetwork();//模拟联网操作
            }
        });

        stateTool.showProgressView();//让页面处于progress
        doSomeNetwork();//模拟联网操作
    }

    private void doSomeNetwork(){
        AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() {
            //耗时的操作
            @Override
            protected Void doInBackground(Void... params) {
                SystemClock.sleep(1500L);
                return null;
            }
            //耗时操作完成之后,调用这个方法,更新UI
            @Override
            protected void onPostExecute(Void aVoid) {
                if (counter == 0) {
                    stateTool.showEmptyView();
                } else if (counter == 1) {
                    stateTool.showErrorView();
                } else {
                    stateTool.showContentView();
                }
                counter++;
            }
        };
        asyncTask.execute();
    }
}


使用就简单了,构造函数new StateTool(linearLayout)传主ViewGroup进去.如果主ViewGroup有多个孩子,需要用new StateToo(linearLayout, index)传内容孩子位置的方法.

在你需要联网操作前,调一下stateTool.showProgressView();让它进入等待页面

然后出结果了,调一下相应的空, 错误, 内容页面的方法就行.

StateTool有个点击回调事件,当处于空页面和错误页面点击时,会回调里面的方法.处于正确的内容就当然不会了.



猜你喜欢

转载自blog.csdn.net/alcoholdi/article/details/53750619