複雜type頁面封裝庫,支持多種狀態切換和下拉刷新上拉加載

目錄介紹

  • 1.複雜頁面庫介紹
  • 2.本庫優點亮點
    • 2.1 支持多種狀態切換管理
    • 2.2 支持添加多個header和footer
    • 2.3 支持側滑功能和拖拽移動
    • 2.4 其餘亮點介紹
  • 3.如何使用介紹
    • 3.1 最基礎的使用
    • 3.2 添加下拉刷新和加載更多監聽
    • 3.3 添加header和footer操做
    • 3.4 設置數據和刷新
    • 3.5 設置adapter
    • 3.6 設置條目點擊事件
    • 3.7 設置側滑刪除功能[QQ側滑刪除]
    • 3.8 輕量級拖拽排序與滑動刪除
  • 4.關於狀態切換
    • 4.1 關於佈局內容
    • 4.2 關於實現思路
    • 4.3 關於狀態切換api調用
    • 4.4 關於自定義狀態佈局
    • 4.5 關於自定義佈局交互事件處理
  • 5.經常使用api介紹
    • 5.1 狀態切換方法說明
    • 5.2 viewHolder方法說明
    • 5.3 adapter方法說明
    • 5.4 分割線方法說明
    • 5.5 swipe側滑方法說明
    • 5.6 其餘api說明
  • 6.優化實現點
    • 6.1 viewHolder優化
    • 6.2 狀態管理器優化
    • 6.3 recyclerView滑動卡頓優化
    • 6.4 多線程下插入數據優化
    • 6.5 rv四級緩存
    • 6.6 異常狀況下保存狀態
  • 7.實現效果展現
  • 8.版本更新說明
  • 9.參考資料說明
  • 10.其餘內容介紹

開源庫地址:github.com/yangchong21…

  • 自定義支持上拉加載更多,下拉刷新,能夠自定義頭部和底部,能夠添加多個header,使用一個原生recyclerView就能夠搞定複雜界面。支持自由切換狀態【加載中,加載成功,加載失敗,沒網絡等狀態】的控件,能夠自定義狀態視圖View。拓展功能【支持長按拖拽,側滑刪除】,輕量級,能夠選擇性添加 。持續更新……

1.複雜頁面庫介紹

  • 自定義支持上拉加載更多【加載中,加載失敗[好比沒有更多數據],加載異常[無網絡],加載成功等多種狀態】,下拉刷新,能夠實現複雜的狀態頁面,支持自由切換狀態【加載中,加載成功,加載失敗,沒網絡等狀態】的控件,拓展功能[支持長按拖拽,側滑刪除]能夠選擇性添加。具體使用方法,能夠直接參考demo案例。
  • 支持複雜type頁面,例如添加自定義頭部HeaderView和底部佈局FooterView,支持橫向滑動list,還能夠支持粘貼頭部list[相似微信好友分組],支持不規則瀑布流效果,支持側滑刪除功能。

2.本庫優點亮點

2.1 支持多種狀態切換管理

  • 支持在佈局中或者代碼設置自定義不一樣狀態的view,一行代碼既能夠切換不一樣的狀態,十分方便。
  • 針對自定義狀態view或者layout,能夠實現交互功能,好比當切換到網絡異常的頁面,能夠點擊頁面控件取刷新數據或者跳轉設置網絡頁面

2.2 支持添加多個header和footer

  • 支持添加多個自定義header頭部佈局,能夠自定義footer底部佈局。十分方便實現複雜type的佈局頁面,結構上井井有條,便於維護。
  • 支持複雜界面使用,好比有的頁面包含有輪播圖,按鈕組合,橫向滑動list,還有複雜list,那麼用這個控件就能夠搞定。

2.3 支持側滑功能和拖拽移動

  • 輕量級側滑刪除菜單,直接嵌套item佈局便可使用,使用十分簡單
  • 經過自定義ItemTouchHelper實現RecyclerView條目Item拖拽排序,只是設置是否拖拽,設置拖拽item的背景顏色,優化了拖拽效果,好比在拖拽過程當中設置item的縮放和漸變效果

2.4 其餘亮點介紹

  • 支持上拉加載,下拉刷新。當上拉加載更多失敗或者異常時,能夠設置自定義加載更多失敗或者異常佈局(好比沒有網絡時的場景),同時點擊該異常或者失敗佈局能夠恢復加載更多數據;當上拉加載更多沒有更多數據時,能夠設置自定義加載更多無數據佈局。
  • 能夠設置上拉加載更多後自動加載下一頁數據,也能夠上拉加載更多後手動觸發加載下一頁數據。在上拉加載更多時,能夠設置加載更多的佈局,支持加載監聽。
  • 支持粘貼頭部的需求效果,這種效果相似微信好友分組的那種功能界面。
  • 支持插入【插入指定索引】,更新【更新指定索引或者data數據】或者刪除某條數據,支持刪除全部數據。同時在多線程條件下,添加了鎖機制避免數據錯亂!
  • 支持橫向滑動list效果,支持瀑布流的效果,還支持與CoordinatorLayout結合實現炫酷的效果。這種效果特別不錯……
  • 已經用於實際開發項目投資界,新芽,沙丘大學中……且通過近三年時間的迭代與維護,持續更新維護中!

3.如何使用介紹

3.1 最基礎的使用

  • 首先在集成:
    • implementation 'org.yczbj:YCRefreshViewLib:2.5.8'
  • 在佈局中
    <org.yczbj.ycrefreshviewlib.YCRefreshView
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_progress="@layout/view_custom_loading_data"
        app:layout_empty="@layout/view_custom_empty_data"
        app:layout_error="@layout/view_custom_data_error"/>
    複製代碼
  • 在代碼中,初始化recyclerView
    adapter = new PersonAdapter(this);
    recyclerView.setAdapter(adapter);
    final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(linearLayoutManager);
    adapter.addAll(data);
    複製代碼
  • 在代碼中,建立adapter實現RecyclerArrayAdapter
    public class PersonAdapter extends RecyclerArrayAdapter<PersonData> {
    
        public PersonAdapter(Context context) {
            super(context);
        }
    
        @Override
        public BaseViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) {
            return new PersonViewHolder(parent);
        }
    
        public class PersonViewHolder extends BaseViewHolder<PersonData> {
    
            private ImageView iv_news_image;
    
            PersonViewHolder(ViewGroup parent) {
                super(parent, R.layout.item_news);
                iv_news_image = getView(R.id.iv_news_image);
            }
    
            @Override
            public void setData(final PersonData person){
    
            }
        }
    }
    複製代碼

3.2 添加下拉刷新和加載更多監聽

  • 下拉刷新監聽操做
    //設置刷新listener
    recyclerView.setRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            //刷新操做
        }
    });
    //設置是否刷新
    recyclerView.setRefreshing(false);
    //設置刷新顏色
    recyclerView.setRefreshingColorResources(R.color.colorAccent);
    複製代碼
  • 上拉加載更多監聽操做
    • 第一種狀況,上拉加載更多後自動加載下一頁數據
    //設置上拉加載更多時佈局,以及監聽事件
    adapter.setMore(R.layout.view_more, new OnLoadMoreListener() {
        @Override
        public void onLoadMore() {
            //能夠作請求下一頁操做
        }
    });
    複製代碼
    • 第二種狀況,上拉加載更多後手動觸發加載下一頁數據
    adapter.setMore(R.layout.view_more2, new OnMoreListener() {
        @Override
        public void onMoreShow() {
            //不作處理
        }
    
        @Override
        public void onMoreClick() {
            //點擊觸發加載下一頁數據
        }
    });
    複製代碼
  • 在上拉加載更多時,可能出現沒有更多數據,或者上拉加載失敗,該如何處理呢?
    //設置上拉加載沒有更多數據監聽
    adapter.setNoMore(R.layout.view_no_more, new OnNoMoreListener() {
        @Override
        public void onNoMoreShow() {
            //上拉加載,沒有更多數據展現,這個方法能夠暫停或者中止加載數據
            adapter.pauseMore();
        }
    
        @Override
        public void onNoMoreClick() {
            //這個方法是點擊沒有更多數據展現佈局的操做,好比能夠作吐司等等
            Log.e("逗比","沒有更多數據了");
        }
    });
    //設置上拉加載更多異常監聽數據監聽
    adapter.setError(R.layout.view_error, new OnErrorListener() {
        @Override
        public void onErrorShow() {
            //上拉加載,加載更多數據異常展現,這個方法能夠暫停或者中止加載數據
            adapter.pauseMore();
        }
    
        @Override
        public void onErrorClick() {
            //這個方法是點擊加載更多數據異常展現佈局的操做,好比恢復加載更多等等
            adapter.resumeMore();
        }
    });
    複製代碼

3.3 添加header和footer操做

  • 添加headerView操做。至於添加footerView的操做,幾乎和添加header步驟是同樣的。
    • 添加普通的佈局【非listView或者RecyclerView佈局】
    adapter.addHeader(new InterItemView() {
        @Override
        public View onCreateView(ViewGroup parent) {
            View inflate = LayoutInflater.from(context).inflate(R.layout.header_view, null);
            return inflate;
        }
    
        @Override
        public void onBindView(View headerView) {
            TextView tvTitle = headerView.findViewById(R.id.tvTitle);
        }
    });
    複製代碼
    • 添加list佈局【以橫向recyclerView爲例子】
    adapter.addHeader(new InterItemView() {
        @Override
        public View onCreateView(ViewGroup parent) {
            RecyclerView recyclerView = new RecyclerView(parent.getContext()){
                //爲了避免打擾橫向RecyclerView的滑動操做,能夠這樣處理
                @SuppressLint("ClickableViewAccessibility")
                @Override
                public boolean onTouchEvent(MotionEvent event) {
                    super.onTouchEvent(event);
                    return true;
                }
            };
            return recyclerView;
        }
    
        @Override
        public void onBindView(View headerView) {
            //這裏的處理別忘了
            ((ViewGroup)headerView).requestDisallowInterceptTouchEvent(true);
        }
    });
    複製代碼
  • 注意要點
    • 若是添加了HeaderView,凡是經過ViewHolder拿到的position都要減掉HeaderView的數量才能獲得正確的position。

3.4 設置數據和刷新

  • 添加全部數據,能夠是集合,也能夠是數組
    //添加全部數據
    adapter.addAll(data);
    //添加單挑數據
    adapter.add(data);
    複製代碼
  • 插入,刷新和刪除數據
    //插入指定索引數據,單個數據
    adapter.insert(data, pos);
    //插入指定索引數據,多個數據
    adapter.insertAll(data, pos);
    //刷新指定索引數據
    adapter.update(data, pos);
    //刪除數據,指定數據
    adapter.remove(data);
    //刪除數據,指定索引
    adapter.remove(pos);
    //清空全部數據
    複製代碼

3.5 設置adapter

  • 注意自定義adapter須要實現RecyclerArrayAdapter,其中T是泛型,就是你要使用的bean數據類型
    public class PersonAdapter extends RecyclerArrayAdapter<PersonData> {
    
        public PersonAdapter(Context context) {
            super(context);
        }
    
        @Override
        public BaseViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) {
            return new PersonViewHolder(parent);
        }
    
        public class PersonViewHolder extends BaseViewHolder<PersonData> {
    
            private TextView tv_title;
            private ImageView iv_news_image;
    
            PersonViewHolder(ViewGroup parent) {
                super(parent, R.layout.item_news);
                iv_news_image = getView(R.id.iv_news_image);
                tv_title = getView(R.id.tv_title);
    
                //添加孩子的點擊事件
                addOnClickListener(R.id.iv_news_image);
                addOnClickListener(R.id.tv_title);
            }
    
            @Override
            public void setData(final PersonData person){
                Log.i("ViewHolder","position"+getDataPosition());
                tv_title.setText(person.getName());
            }
        }
    }
    複製代碼

3.6 設置條目點擊事件

  • 條目單擊點擊事件,長按事件[省略,能夠本身看代碼]
    adapter.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(int position) {
            if (adapter.getAllData().size()>position && position>=0){
                //處理點擊事件邏輯
            }
        }
    });
    複製代碼
  • 條目中孩子的點擊事件
    //添加孩子的點擊事件,能夠看3.5設置adapter
    addOnClickListener(R.id.iv_news_image);
    addOnClickListener(R.id.tv_title);
    
    //設置孩子的點擊事件
    adapter.setOnItemChildClickListener(new OnItemChildClickListener() {
        @Override
        public void onItemChildClick(View view, int position) {
            switch (view.getId()){
                case R.id.iv_news_image:
                    Toast.makeText(HeaderFooterActivity.this,
                            "點擊圖片了",Toast.LENGTH_SHORT).show();
                    break;
                case R.id.tv_title:
                    Toast.makeText(HeaderFooterActivity.this,
                            "點擊標題",Toast.LENGTH_SHORT).show();
                    break;
                default:
                    break;
            }
        }
    });
    複製代碼

3.7 設置側滑刪除功能[QQ側滑刪除]

  • 在佈局文件中,這裏省略部分代碼
    <org.yczbj.ycrefreshviewlib.swipeMenu.YCSwipeMenu
        android:orientation="horizontal">
        <!--item內容-->
        <RelativeLayout
        </RelativeLayout>
    
        <!-- 側滑菜單 -->
        <Button
            android:id="@+id/btn_del"/>
        <Button
            android:id="@+id/btn_top"/>
    </org.yczbj.ycrefreshviewlib.swipeMenu.YCSwipeMenu>
    複製代碼
  • 在代碼中設置
    • 在adapter中定義接口
    private OnSwipeMenuListener listener;
    public void setOnSwipeMenuListener(OnSwipeMenuListener listener) {
        this.listener = listener;
    }
    複製代碼
    • 在adapter設置點擊事件
    View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.btn_del:
                    if (null != listener) {
                        listener.toDelete(getAdapterPosition());
                    }
                    break;
                case R.id.btn_top:
                    if (null != listener) {
                        listener.toTop(getAdapterPosition());
                    }
                    break;
            }
        }
    };
    btn_del.setOnClickListener(clickListener);
    btn_top.setOnClickListener(clickListener);
    複製代碼
  • 處理置頂或者刪除的功能
    adapter.setOnSwipeMenuListener(new OnSwipeMenuListener() {
        //刪除功能
        @Override
        public void toDelete(int position) {
    
        }
    
        //置頂功能
        @Override
        public void toTop(int position) {
    
        }
    });
    複製代碼

3.8 輕量級拖拽排序與滑動刪除

  • 處理長按拖拽,滑動刪除的功能。輕量級,自由選擇是否實現。
    mCallback = new DefaultItemTouchHelpCallback(new DefaultItemTouchHelpCallback
                            .OnItemTouchCallbackListener() {
        @Override
        public void onSwiped(int adapterPosition) {
            // 滑動刪除的時候,從數據庫、數據源移除,並刷新UI
        }
    
        @Override
        public boolean onMove(int srcPosition, int targetPosition) {
            return false;
        }
    });
    mCallback.setDragEnable(true);
    mCallback.setSwipeEnable(true);
    mCallback.setColor(this.getResources().getColor(R.color.colorAccent));
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView);
    複製代碼

4.關於狀態切換

4.1 關於佈局內容

  • YCRecyclerView是一個組合自定義控件,其佈局以下所示
    <!--刷新控件    省略部分代碼-->
    <android.support.v4.widget.SwipeRefreshLayout>
        <FrameLayout>
            <!--RecyclerView控件-->
            <android.support.v7.widget.RecyclerView/>
            <!--加載數據爲空時的佈局-->
            <FrameLayout/>
            <!--正在加載數據中的佈局-->
            <FrameLayout/>
            <!--加載錯誤時的佈局:網絡錯誤或者請求數據錯誤-->
            <FrameLayout/>
        </FrameLayout>
    </android.support.v4.widget.SwipeRefreshLayout>
    複製代碼

4.2 關於實現思路

  • 關於頁面狀態切換的思路
    • 第一種方式:直接把這些界面include到main界面中,而後動態去切換界面,後來發現這樣處理不容易複用到其餘項目中,並且在activity中處理這些狀態的顯示和隱藏比較亂
    • 第二種方式:利用子類繼承父類特性,在父類中寫切換狀態,但有些界面若是沒有繼承父類,又該如何處理
  • 而本庫採用的作法思路
    • 一個幀佈局FrameLayout裏寫上4種不一樣類型佈局,正常佈局,空佈局,加載loading佈局,錯誤佈局[網絡異常,加載數據異常]
    • 固然也能夠自定義這些狀態的佈局,經過addView的形式,將不一樣狀態佈局添加到對應的FrameLayout中。而切換狀態,只須要設置佈局展現或者隱藏便可。

4.3 關於狀態切換api調用

  • 以下所示
    //設置加載數據完畢狀態
    recyclerView.showRecycler();
    //設置加載數據爲空狀態
    recyclerView.showEmpty();
    //設置加載錯誤狀態
    recyclerView.showError();
    //設置加載數據中狀態
    recyclerView.showProgress();
    複製代碼

4.4 關於自定義狀態佈局

  • 以下所示
    //設置空狀態頁面自定義佈局
    recyclerView.setEmptyView(R.layout.view_custom_empty_data);
    recyclerView.setEmptyView(view);
    //獲取空頁面自定義佈局
    View emptyView = recyclerView.getEmptyView();
    
    //設置異常狀態頁面自定義佈局
    recyclerView.setErrorView(R.layout.view_custom_data_error);
    recyclerView.setErrorView(view);
    
    //設置加載loading狀態頁面自定義佈局
    recyclerView.setProgressView(R.layout.view_progress_loading);
    recyclerView.setProgressView(view);
    複製代碼

4.5 關於自定義佈局交互事件處理

  • 有時候,加載頁面出現異常狀況,好比沒有網絡會顯示自定義的網絡異常頁面。如今須要點擊異常頁面按鈕等等操做,那麼該如何作呢?
    //注意須要
    LinearLayout ll_error_view = (LinearLayout) recyclerView.findViewById(R.id.ll_error_view);
    ll_error_view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //好比,跳轉到網絡設置頁面,或者再次刷新數據,或者其餘操做等等
        }
    });
    複製代碼

5.經常使用api介紹

  • 狀態切換方法說明
    //設置加載數據完畢狀態
    recyclerView.showRecycler();
    //設置加載數據爲空狀態
    recyclerView.showEmpty();
    //設置加載錯誤狀態
    recyclerView.showError();
    //設置加載數據中狀態
    recyclerView.showProgress();
    //設置自定義佈局,其餘幾個方法同理
    recyclerView.setEmptyView(R.layout.view_custom_empty_data);
    複製代碼
  • viewHolder方法說明
    //子類設置數據方法
    setData方法
    //findViewById方式
    iv_news_image = getView(R.id.iv_news_image);
    //獲取上下文
    Context context = getContext();
    //獲取數據索引的位置
    int dataPosition = getDataPosition();
    //添加item中子控件的點擊事件
    addOnClickListener(R.id.tv_title);
    複製代碼
  • adapter方法說明
    //刪除索引處的數據
    adapter.remove(0);
    //觸發清空全部數據
    adapter.removeAll();
    //添加數據,注意這個是在最後索引處添加
    adapter.add(new PersonData());
    //添加全部數據
    adapter.addAll(DataProvider.getPersonList(0));
    //插入數據
    adapter.insert(data,3);
    //在某個索引處插入集合數據
    adapter.insertAll(data,3);
    //獲取item索引位置
    adapter.getPosition(data);
    //觸發清空全部的數據
    adapter.clear();
    //獲取全部的數據
    adapter.getAllData();
    
    //清除全部footer
    adapter.removeAllFooter();
    //清除全部header
    adapter.removeAllHeader();
    //添加footerView
    adapter.addFooter(view);
    //添加headerView
    adapter.addHeader(view);
    //移除某個headerView
    adapter.removeHeader(view);
    //移除某個footerView
    adapter.removeFooter(view);
    //獲取某個索引處的headerView
    adapter.getHeader(0);
    //獲取某個索引處的footerView
    adapter.getFooter(0);
    //獲取footer的數量
    adapter.getFooterCount();
    //獲取header的數量
    adapter.getHeaderCount();
    
    //設置上拉加載更多的自定義佈局和監聽
    adapter.setMore(R.layout.view_more,listener);
    //設置上拉加載更多的自定義佈局和監聽
    adapter.setMore(view,listener);
    //設置上拉加載沒有更多數據佈局
    adapter.setNoMore(R.layout.view_nomore);
    //設置上拉加載沒有更多數據佈局
    adapter.setNoMore(view);
    //設置上拉加載沒有更多數據監聽
    adapter.setNoMore(R.layout.view_nomore,listener);
    //設置上拉加載異常的佈局
    adapter.setError(R.layout.view_error);
    //設置上拉加載異常的佈局
    adapter.setError(view);
    //設置上拉加載異常的佈局和異常監聽
    adapter.setError(R.layout.view_error,listener);
    //暫停上拉加載更多
    adapter.pauseMore();
    //中止上拉加載更多
    adapter.stopMore();
    //恢復上拉加載更多
    adapter.resumeMore();
    
    //獲取上下文
    adapter.getContext();
    //應該使用這個獲取item個數
    adapter.getCount();
    //設置操做數據[增刪改查]後,是否刷新adapter
    adapter.setNotifyOnChange(true);
    
    //設置孩子點擊事件
    adapter.setOnItemChildClickListener(listener);
    //設置條目點擊事件
    adapter.setOnItemClickListener(listener);
    //設置條目長按事件
    adapter.setOnItemLongClickListener(listener);
    複製代碼
  • 分割線方法說明
    //能夠設置線條顏色和寬度的分割線
    //四個參數,上下文,方向,線寬,顏色
    final RecycleViewItemLine line = new RecycleViewItemLine(this, LinearLayout.HORIZONTAL,
            (int)AppUtils.convertDpToPixel(1,this),
            this.getResources().getColor(R.color.color_f9f9f9));
    recyclerView.addItemDecoration(line);
    
    //適用於瀑布流中的間距設置
    SpaceViewItemLine itemDecoration = new SpaceViewItemLine(
            (int) AppUtils.convertDpToPixel(8,this));
    itemDecoration.setPaddingEdgeSide(true);
    itemDecoration.setPaddingStart(true);
    itemDecoration.setPaddingHeaderFooter(true);
    recyclerView.addItemDecoration(itemDecoration);
    
    //能夠設置線條顏色和寬度,而且能夠設置距離左右的間距
    DividerViewItemLine itemDecoration = new
            DividerViewItemLine( this.getResources().getColor(R.color.color_f9f9f9)
            , LibUtils.dip2px(this, 1f),
            LibUtils.dip2px(this, 72), 0);
    itemDecoration.setDrawLastItem(false);
    recyclerView.addItemDecoration(itemDecoration);
    複製代碼
  • 其餘api說明

7.實現效果展現

7.1 使用過YCRefreshView庫的案例代碼

7.2 圖片展現效果

1.jpg
2.jpg
3.jpg
4.jpg
5.jpg
6.jpg
7.jpg
8.jpg
9.jpg
10.jpg
11.jpg
12.jpg

7.3 部分案例圖展現[部分案例圖能夠參考7.1]

image
image

8.版本更新說明

  • v1.0 更新於2016年11月2日
  • v1.1 更新於2017年3月13日
  • v1.3 更新於2017年8月9日
  • v1.…… 更新於2018年1月5日
  • v2.2 更新於2018年1月17日
  • v2.3 更新於2018年2月9日
  • v2.4 更新於2018年3月19日
  • v2.5.6 更新於2018年8月6日
  • v2.5.7 更新於2019年3月3日
  • v2.5.8 更新於2019年3月4日

9.參考資料說明

10.其餘內容介紹

01.關於博客彙總連接

02.關於個人博客

03.勘誤及提問

  • 若是有疑問或者發現錯誤,能夠在相應的 issues 進行提問或勘誤。若是喜歡或者有所啓發,歡迎star,對做者也是一種鼓勵。

04.關於LICENSE

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
複製代碼

關於開源庫地址:github.com/yangchong21…

相關文章
相關標籤/搜索