常用的自定义View例子三(MultiInterfaceView多界面处理)

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

最近在做项目的时候,刚开始没有考虑空界面,错误界面的处理,一开始是想为每个界面在布局文件中都天剑一个错误界面,空界面,但仔细一想,这样的工作量太大了,而且也不方便处理,于是我想能不能做出一个自定义控件出来,想了听就,终于做出来了,现在将其分享出来,有什么不足的请各位指点。

源码下载地址: 转载请注明原博客地址:

老规矩,废话不多说,大家先来看一下效果图

  • 图一是多个界面的展示的动画图 
  • 图二是空界面的展示图 
  • 图三是错误界面的展示图 

大家先来看一下源码

package com.szl.loadinngpagedemo.view;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.widget.Button;import android.widget.FrameLayout;import com.szl.loadinngpagedemo.R;/*** * 创建了自定义帧布局 把baseFragment 一部分代码 抽取到这个类中 * * @author itcast */public abstract class LoadingPage extends FrameLayout {    public static final int STATE_UNKOWN = 0;    public static final int STATE_LOADING = 1;    public static final int STATE_ERROR = 2;    public static final int STATE_EMPTY = 3;    public static final int STATE_SUCCESS = 4;    public int state = STATE_UNKOWN;    private Context mContext;    private View loadingView;// 加载中的界面    private View errorView;// 错误界面    private View emptyView;// 空界面    private View successView;// 加载成功的界面    public LoadingPage(Context context) {        this(context,null,0);    }    public LoadingPage(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public LoadingPage(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        mContext = context;        init();    }    private void init() {        loadingView = createLoadingView(); // 创建了加载中的界面        if (loadingView != null) {            this.addView(loadingView, new LayoutParams(                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));        }        errorView = createErrorView(); // 加载错误界面        if (errorView != null) {            this.addView(errorView, new LayoutParams(                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));        }        emptyView = createEmptyView(); // 加载空的界面        if (emptyView != null) {            this.addView(emptyView, new LayoutParams(                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));        }        /**         * 注意这里依赖是就初始化成功的界面,也可以在状态成功的时候才初始化成功的界面         */        successView = createSuccessView();        if(successView!=null){            this.addView(successView, new LayoutParams(                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));        }        showPage();// 根据不同的状态显示不同的界面    }    // 根据不同的状态显示不同的界面    private void showPage() {        if (loadingView != null) {            loadingView.setVisibility(state == STATE_UNKOWN                    || state == STATE_LOADING ? View.VISIBLE : View.INVISIBLE);        }        if (errorView != null) {            errorView.setVisibility(state == STATE_ERROR ? View.VISIBLE                    : View.INVISIBLE);        }        if (emptyView != null) {            emptyView.setVisibility(state == STATE_EMPTY ? View.VISIBLE                    : View.INVISIBLE);        }        if (state == STATE_SUCCESS) {            if (successView == null) {                successView = createSuccessView();                this.addView(successView, new LayoutParams(                        LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));            }            successView.setVisibility(View.VISIBLE);        } else {            if (successView != null) {                successView.setVisibility(View.INVISIBLE);            }        }    }    /* 创建了空的界面 */    private View createEmptyView() {        View view = View.inflate(mContext, R.layout.loadpage_empty,                null);        return view;    }    /* 创建了错误界面 */    private View createErrorView() {        View view = View.inflate(mContext, R.layout.loadpage_error,                null);        Button page_bt = (Button) view.findViewById(R.id.page_bt);        page_bt.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {            }        });        return view;    }    /* 创建加载中的界面 */    private View createLoadingView() {        View view = View.inflate(mContext,                R.layout.loadpage_loading, null);        return view;    }    /**     * 枚举类,对应相应的状态码,用来表示各种状态     */    public enum LoadResult {        loading(1),error(2), empty(3), success(4);        int value;        LoadResult(int value) {            this.value = value;        }        public int getValue() {            return value;        }    }    /**     * 注意请求成功后必须调用show方法,会根据这个压面显示相应的数据     * @param loadResult     */    public void show(LoadResult loadResult) {        state = loadResult.getValue();        showPage();    }    /***     * 创建成功的界面     *     * @return     */    public abstract View createSuccessView();}

思路解析

  1. 首先在构造方法里面调用init()方法初始化各个界面,包括加载中的界面,错误界面, 空界面,加载成功的界面
   private View loadingView;// 加载中的界面   private View errorView;// 错误界面   private View emptyView;// 空界面   private View successView;// 加载成功的界面  errorView = createErrorView(); // 加载错误界面   emptyView = createEmptyView(); // 加载空的界面   successView = createSuccessView();//加载成功的界面

注意在init()方法里面我们可以知道 createSuccessView()是一个抽象方法,因为每个Activity或Fragment的成功界面一般是变异羊的,我们交给子类自己去实现  2. 接着我们调用showPage()方法根据不同的状态显示不同的界面,默认显示的状态是STATE_UNKOWN,所以显示的状态是

 public int state = STATE_UNKOWN; loadingView.setVisibility(state == STATE_UNKOWN                    || state == STATE_LOADING ? View.VISIBLE : View.INVISIBLE); errorView.setVisibility(state == STATE_ERROR ? View.VISIBLE                    : View.INVISIBLE); -------

效果图如下: 

**当然我们只需调用void show(LoadResult loadResult)这个方法即可根据相应的状态显示相应的界面

LoadingPage的源码分析到此为止


下面我们来看一下我们是怎样结合Fragment来是用的,首先我们抽取一个BaseFragemnt,源码如下

public abstract class BaseFragment extends Fragment {    protected LoadingPage mLoadingPage;    Context mContext;    Activity mActivity;    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        mContext=getActivity();        mActivity=getActivity();        if (mLoadingPage == null) {  // 之前的frameLayout 已经记录了一个爹了  爹是之前的ViewPager            mLoadingPage = new LoadingPage(this.mContext) {                @Override                public View createSuccessView() {                    return BaseFragment.this.createSuccessView();                }            };        } else {            ViewUtils.removeParent(mLoadingPage);// 移除frameLayout之前的爹        }        return mLoadingPage;  //  拿到当前viewPager 添加这个framelayout    }    @Override    public void onActivityCreated(@Nullable Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        initData();    }    protected void initData() {    }    /***     * 创建成功的界面     *     * @return     */    public abstract View createSuccessView();    public void show(LoadResult loadResult) {        if (mLoadingPage != null) {            mLoadingPage.show(loadResult);        }    }    /**     * 校验数据     */    public LoadResult checkData(List datas) {        if (datas == null) {            return LoadResult.error;//  请求服务器失败        } else {            if (datas.size() == 0) {                return LoadingPage.LoadResult.empty;            } else {                return LoadingPage.LoadResult.success;            }        }    }}

BaseFragment的代码很简单,就是将我们的LoadPager这个自定义View设置为根布局,然后创建成功的界面由子类自己去实现

下面我们来看一下他的子类ErrorFragment的代码

public class ErrorFragment extends BaseFragment {    @Override    public View createSuccessView() {        return View.inflate(mContext,R.layout.fragemnt_test,null);    }    @Override    protected void initData() {        mLoadingPage.postDelayed(new Runnable() {            @Override            public void run() {               show(LoadingPage.LoadResult.error);            }        },2500);    }}

我们可以看到我们所做的就是创建自己的成功界面,如果想显示别的界面,就调用void show(LoadResult loadResult)这个方法,这个我们延时之后调用 show(LoadingPage.LoadResult.error);来显示错误界面

看了ErrorFragment的代码以后,我们可以轻易地向导我们的EmptyFragment是怎样操作的,没错就是调用 show(LoadingPage.LoadResult.empty);这个方法而已

public class EmptyFragment extends BaseFragment {    @Override    public View createSuccessView() {        return View.inflate(mContext,R.layout.fragemnt_test,null);    }    @Override    protected void initData() {        mLoadingPage.postDelayed(new Runnable() {            @Override            public void run() {               show(LoadingPage.LoadResult.empty);            }        },2500);    }}

同理SuccessFragemnt的代码你也能轻易的想象得到,这里就不贴出来了

下面我们来看一下BaseActivity的代码,下面只给出主要代码,详细的代码请点击 源码下载地址:

/** * 博客地址:http://blog.csdn.net/gdutxiaoxu * @author xujun * @time 2016-6-29 14:52. */public abstract class BaseActivity extends AppCompatActivity {    protected Context mContext;    protected ProgressDialog dialog;    protected LoadingPage mLoadingPage;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);        initWindows();        // base setup        mContext = this;        if (mLoadingPage == null) {            mLoadingPage = new LoadingPage(this) {                @Override                public View createSuccessView() {                    return BaseActivity.this.createSuccessView();                }            };        } else {            ViewUtils.removeParent(mLoadingPage);        }        setContentView(mLoadingPage);        dialog = new ProgressDialog(this);        initListener();        initData();    }    public void show(LoadingPage.LoadResult loadResult){        if(mLoadingPage!=null){            mLoadingPage.show(loadResult);        }    }    /**     * 创造成功的页面     *     * @return     */    protected abstract View createSuccessView();   ----

总结

思路其实很简单,一开始给LoadPager初始化各种布局,包括错误界面,加载中的界面,空界面,其中成功的界面交友子类自己去实现,如果我们想显示别的界面的话,我们只需要调用void show(LoadResult loadResult)这个方法而已

待改进的地方

  1. 由于时间关系,没有给错误界面和空界面统一集成一个自定义控件,这样我们可以利用自定义属性统一处理要显示界面的信息
  2. 没有提供更换空界面,错误界面的方法,这个很简单,大家需要的话就自己去实现就好,这里我就实现了,有时间的话会统一处理这些问题,大家有兴趣的话可以关注我github上面仓库的变化。

源码下载地址:

转载请注明原博客地址:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏何俊林

记一次重构:Android实践从MVC架构到MVP架构

一直以来,想分享MVP的实战,因为很多项目开始并不是就是mvp架构的,可能是从传统的mvc结构变迁过来的。今天呈详给大家分享的这篇从mvc重构到mvp,让大家既...

2595
来自专栏向治洪

ViewPagerIndicator+viewpager指示器详解

前几天学习了ViewPager作为引导页和Tab的使用方法。后来也有根据不同的使用情况改用Fragment作为Tab的情况,以及ViewPager结合Fragm...

9309
来自专栏封碎

Android自定义长按事件 博客分类: Android AndroidUP

    Android系统自带了长按事件,setOnLongClickListener即可监听。但是有时候,你不希望用系统的长按事件,比如当希望长按的时间更长一...

2342
来自专栏分享达人秀

RecyclerView数据动态更新

列表的数据往往会跟随业务逻辑不断刷新,所呈现出来的数据需要动态更新,那么RecyclerView是如何动态更新数据的呢? ? 之前在学习Lis...

1.4K5
来自专栏俞其荣的博客

Android Data Binding入门

1515
来自专栏郭耀华‘s Blog

Android中级教程之----Log详解(Log.v,Log.d,Log.i,Log.w,Log.e)

在Android群里,经常会有人问我,Android Log是怎么用的,今天我就把从网上以及SDK里东拼西凑过来,让大家先一睹为快,希望对大家入门Androi...

36610
来自专栏向治洪

Android listView异步下载和convertView复用产生的错位问题

1:Item图片显示重复 这个显示重复是指当前行Item显示了之前某行Item的图片。 比如ListView滑动到第2行会异步加载某个图片,但是加载很慢,...

2457
来自专栏Android点滴积累

Android Toast cancel和show 不踩中不会知道的坑

说到Android Toast,几乎都很熟悉吧,下面讲讲怎么实现下面几种场景: 1、连续点击一个按钮,每次都产生一个新的Toast并且调用show方法 问题:...

3336
来自专栏向治洪

开源库BaseRecyclerViewAdapterHelper

相信大家RecyclerView应该不会陌生,大多数开发者应该都使用上它了,它也是google推荐替换ListView的控件,但是用过它的同学应该都知道它在某些...

2906
来自专栏Android干货

浅谈DrawerLayout(抽屉效果)

3645

扫码关注云+社区

领取腾讯云代金券