android客户端界面加载处理方法

来源:互联网 发布:数控火焰切割编程代码 编辑:程序博客网 时间:2024/06/05 04:52

Knowledge is a treasure but practice is the key to it.

在android的前端开发过程中,对于前端的加载效果,界面友好是很重要的。

需要在界面加载过程中的变化中友好的显示:

1:加载中
2:加载成功
3:加载失败
4:网络异常
5:请求数据接口暂时没有数据

etc,所以,需要我们自己书写相关的界面加载类,来做一个统一的整理

在刚开始遇到这样的问题时,就个人而言,用的最笨的办法也是最耗性能。在原有的正常UI界面中添加 include 标签,然后根据逻辑进行隐藏显示。很不自在。之后在优化中总结经验,创建自己的界面类。

正题:

step1:自定义View extends FrameLayout
step2:创建enum来确定相应的状态
step3:创建相应界面的layout

package com.welive.defineview;import ···/*** author:wedfrend* email:wedfrend@yeah.net* create:2017/8/29 11:11* desc: 在手机端加载过程中,会出现很多的状况 * *      1:加载中 *      2:数据出错 *      3:网络异常 *      4:重新加载 * *      为了方便的统一管理,所以自定义View来进行相应的加载状态方法 **/public class NavFrameLayout extends FrameLayout {    private FrameLayout wholeFrameLayout;    //布局中的子页面    private View mContentView;    private LayoutInflater layoutInflater;    //不同的状态    private View statusView;    private EnumContent.statusPage statusPage = EnumContent.statusPage.LOADING;    public EnumContent.statusPage getStatusPage() {        return statusPage;    }    public void setStatusPage(EnumContent.statusPage statusPage) {        this.statusPage = statusPage;    }/***  默认情况下的三种布局界面*/    private final int loadingLayoutId = R.layout.z_loading_layout;//加载中    private final int dateErrorLayoutId = R.layout.z_daterror_layout;//数据异常    private final int netErrorLayoutId = R.layout.z_neterror_layout;//网络异常    public NavFrameLayout(Context context) {        super(context,null);    }    public NavFrameLayout(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public NavFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        InitDefault(context, attrs, defStyleAttr);    }    //初始化    public void InitDefault(Context context, AttributeSet attrs, int defStyleAttr){        wholeFrameLayout = new FrameLayout(context);        layoutInflater = LayoutInflater.from(context);        wholeFrameLayout.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));        //该方法可以在父类中查看,是直接将该布局放置在子布局的第一个位置        addView(wholeFrameLayout);        //加载界面的显示        setViewLoading(loadingLayoutId);    }/**进行界面的判断,在layout下该自定义VIEW下必须有且只有一个子布局Ui,但是实际上我们在代码中添加一个View,layout中一个,所以判断必须为2*/    @Override    protected void onFinishInflate() {        super.onFinishInflate();        if(getChildCount() != 2){            //抛出运行时异常            throw new RuntimeException(NavFrameLayout.class.getSimpleName() + "必须有且只有一个子控件");        }        mContentView = getChildAt(1);        //完成之后将该View先进行隐藏        mContentView.setVisibility(View.GONE);    }    /**     * 正在加载     * @param layoutResID     */    protected SwipeRefreshLayout swipeRefreshLayout;    public void setViewLoading(@LayoutRes int layoutResID){    //赋值状态        statusPage = EnumContent.statusPage.LOADING;    //判断是否statusView是否已经存在,存在的话先做一次清除,因为没有必要一直存在        if (statusView != null && statusView.getParent() != null) {            ViewGroup parent = (ViewGroup) statusView.getParent();            parent.removeView(statusView);        }        //接下来做自己界面流程        statusView = layoutInflater.inflate(layoutResID,null);        if (statusView != null) {            statusView.setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));            wholeFrameLayout.addView(statusView);        }        statusView.setVisibility(View.VISIBLE);        swipeRefreshLayout = ((SwipeRefreshLayout) statusView.findViewById(R.id.refresh_loading));        swipeRefreshLayout.setProgressViewOffset(true, 50, 100);        //设置下拉圆圈的大小,两个值 LARGE, DEFAULT        swipeRefreshLayout.setSize(SwipeRefreshLayout.DEFAULT);        //下拉刷新调用的一个接口        swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary, R.color.colorPrimaryDark, R.color.colorPrimaryDarkContentActivity);        //这里直接调用swipeRefrehLayout的加载状态        swipeRefreshLayout.post(() -> swipeRefreshLayout.setRefreshing(true));    }    /**     * 设置界面正常加载的情况下,对于不同状态需要做的处理如下,在自己主逻辑程序中只需调用方法,相应的处理状态交给该方法执行     */    public void setNormal(){        if(statusView.getVisibility() == View.VISIBLE){            //异常界面隐藏            statusView.setVisibility(View.GONE);            //正常界面显示            mContentView.setVisibility(View.VISIBLE);        }        //处理不同的情况        if(statusPage.equals(EnumContent.statusPage.NONE)){        }        //正在加载中        if(statusPage.equals(EnumContent.statusPage.LOADING)){            //加载界面显示            swipeRefreshLayout.post(() -> swipeRefreshLayout.setRefreshing(false));            return;        }        //数据出现异常        if(statusPage.equals(EnumContent.statusPage.DATEERROR)){            return;        }        //网络出现异常        if(statusPage.equals(EnumContent.statusPage.NETERROR)){            return;        }        setStatusPage(EnumContent.statusPage.NONE);    }    /**     *     * @param status 异常状态     * @param imgId  图片ID     * @param StringId 提示字段ID     */    public void setException(EnumContent.statusPage status,int imgId,int StringId){        if(statusPage.equals(EnumContent.statusPage.NONE)){            T.show(R.string.NetError,0);        }        statusPage = status;        if(statusView.getVisibility() == View.GONE){            //正常界面隐藏            mContentView.setVisibility(View.GONE);            //异常界面显示            statusView.setVisibility(View.VISIBLE);        }        //处理不同的情况        if(status.equals(EnumContent.statusPage.NONE)){        }        //正在加载中        if(status.equals(EnumContent.statusPage.LOADING)){            //加载界面显示            setViewLoading(loadingLayoutId);            return;        }        //数据出现异常        if(status.equals(EnumContent.statusPage.DATEERROR)){            setViewDateError(dateErrorLayoutId);            return;        }        //网络出现异常        if(status.equals(EnumContent.statusPage.NETERROR)){            setViewNetError(netErrorLayoutId);            return;        }    }    /**     * 数据异常     * @param layoutResID     */    public void setViewDateError(@LayoutRes int layoutResID){        if (statusView != null && statusView.getParent() != null) {            ViewGroup parent = (ViewGroup) statusView.getParent();            parent.removeView(statusView);        }        statusView = layoutInflater.inflate(layoutResID,null);        if (statusView != null) {            statusView.setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));            wholeFrameLayout.addView(statusView);        }        //下面要做些事情    }    /**     * 网络异常     * @param layoutResID     */    public void setViewNetError(@LayoutRes int layoutResID){        if (statusView != null && statusView.getParent() != null) {            ViewGroup parent = (ViewGroup) statusView.getParent();            parent.removeView(statusView);        }        statusView = layoutInflater.inflate(layoutResID,null);        if (statusView != null) {            statusView.setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));            wholeFrameLayout.addView(statusView);        }        statusView.findViewById(R.id.tv_reloading).setOnClickListener(v ->        {            setException(EnumContent.statusPage.LOADING,0,0);            loadingListener.onLoading();        });    }    //这里还需要一个接口的触发时间,来证实界面的可行性    public interface LoadingListener{        void onLoading();    }    private LoadingListener loadingListener;    public LoadingListener getLoadingListener() {        return loadingListener;    }    public void setLoadingListener(LoadingListener loadingListener) {        this.loadingListener = loadingListener;    }}

知识要点:

1:该类中需要注意的就是一个onFinishInflate()方法的判断以及我们在原有布局中添加一个布局。
2:addView()方法调用父类的方法

/**     * <p>Adds a child view. If no layout parameters are already set on the child, the     * default parameters for this ViewGroup are set on the child.</p>     *     * <p><strong>Note:</strong> do not invoke this method from     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>     *     * @param child the child view to add     *     * @see #generateDefaultLayoutParams()     */    public void addView(View child) {        addView(child, -1);    }

所以此时getChildAt(int i)中,角标0表示我们添加的View,而角标为1的表示在layout中的View

debug模式下的流程分析

3:对于各种状态的布局以及状态发生变化的时候先清空之前的内容,在加载新的界面。

由于不同公司的定制,如果将该类作为aar文件来进行引用反而会带来更加复杂的封装,所以还是由每个开发自己去写一套适用于自己公司的类更为合适。

最终在界面绘制完成,跟布局中有两个子布局

跟布局下的子布局

相关实践代码请在Github中进行下载:

https://github.com/wedfrendwang/NavLayout


Everyone gets tired.No one can take the pain for you. You have to go through it and grow up.

心烦事比较多,激励一下自己。希望从事编程行业的同仁们加油。

原创粉丝点击