Repository: mylhyl/Android-CommonRefreshLayout Branch: master Commit: aae4f4a3304c Files: 70 Total size: 115.5 KB Directory structure: gitextract_bdxoz3li/ ├── .gitignore ├── README.md ├── build.gradle ├── commonrefreshlayout/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── mylhyl/ │ │ └── crlayout/ │ │ └── ApplicationTest.java │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── mylhyl/ │ │ └── crlayout/ │ │ ├── BaseSwipeRefresh.java │ │ ├── MultiSwipeRefreshLayout.java │ │ ├── SwipeRefreshAbsListView.java │ │ ├── SwipeRefreshAdapterView.java │ │ ├── SwipeRefreshExpandableListView.java │ │ ├── SwipeRefreshGridView.java │ │ ├── SwipeRefreshListView.java │ │ ├── SwipeRefreshRecyclerView.java │ │ ├── SwipeRefreshWebView.java │ │ ├── app/ │ │ │ ├── BaseSwipeRefreshFragment.java │ │ │ ├── SwipeRefreshAbsListFragment.java │ │ │ ├── SwipeRefreshAdapterFragment.java │ │ │ ├── SwipeRefreshExpandableListFragment.java │ │ │ └── SwipeRefreshListFragment.java │ │ └── internal/ │ │ ├── ILoadSwipeRefresh.java │ │ ├── ISwipeRefresh.java │ │ ├── LoadConfig.java │ │ ├── LoadLayout.java │ │ ├── LoadLayoutBase.java │ │ └── LoadLayoutConvert.java │ └── res/ │ └── values/ │ └── attrs.xml ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── preview/ │ └── sample-debug.apk ├── sample/ │ ├── .gitignore │ ├── build.gradle │ ├── libs/ │ │ └── lite-http-3.0.0.jar │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── mylhyl/ │ │ └── crlayout/ │ │ └── sample/ │ │ └── ApplicationTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── mylhyl/ │ │ │ └── crlayout/ │ │ │ └── sample/ │ │ │ ├── APP.java │ │ │ ├── MainActivity.java │ │ │ ├── TypesFragment.java │ │ │ ├── app/ │ │ │ │ ├── AppExpandableListFragment.java │ │ │ │ ├── AppListFragment.java │ │ │ │ ├── GridViewFragment.java │ │ │ │ ├── ListViewFragment.java │ │ │ │ ├── RecyclerViewFragment.java │ │ │ │ └── WebViewFragment.java │ │ │ └── widget/ │ │ │ └── MySwipeRefreshGridView.java │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── footer_progressbar.xml │ │ │ └── selector_list.xml │ │ ├── layout/ │ │ │ ├── fragment_grid_view.xml │ │ │ ├── fragment_list_view.xml │ │ │ ├── fragment_recycler_view.xml │ │ │ ├── fragment_recycler_view_item.xml │ │ │ ├── fragment_types.xml │ │ │ ├── fragment_web_view.xml │ │ │ ├── image_item.xml │ │ │ └── swipe_refresh_footer.xml │ │ ├── menu/ │ │ │ └── menu.xml │ │ ├── values/ │ │ │ ├── array.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ └── test/ │ └── java/ │ └── com/ │ └── mylhyl/ │ └── crlayout/ │ └── sample/ │ └── ExampleUnitTest.java └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml .gradle .idea /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures ================================================ FILE: README.md ================================================ #### Android-CommonRefreshLayout 基于`SwipeRefreshLayout`下拉刷新、上拉加载。支持的`AbsListView`、`RecycleView`、`WebView` ####特点 * 在布局`layout`中使用,支持`xml`属性 * 支持自动下拉刷新,什么用呢?比如进入界面时,只需要调用`autoRefresh()`方法即可,显示上拉动画同时刷新回调`onRefresh`将会被调用 * 上拉加载支持自定义`View`或设置加载文字、动画、加载完成 * 轻松设置`Adapter`空数据视图,默认为`TextView`支持更文字,也可自定义`View` * 对于简单的界面,例如只有`ListView`可以继承 [SwipeRefreshListFragment](commonrefreshlayout/src/main/java/com/mylhyl/crlayout/app/SwipeRefreshListFragment.java) 轻松搞定 ####效果图 ####使用 仔细看`listSelector`属性,我们是支持的,效果见`sample` ```xml ``` 设置上拉加载,更多方法见 [LoadConfig](commonrefreshlayout/src/main/java/com/mylhyl/crlayout/internal/LoadConfig.java) ```java LoadConfig loadConfig = swipeRefreshListView.getLoadConfig(); loadConfig.setLoadText("set自定义加载"); loadConfig.setIndeterminateDrawable(getResources().getDrawable(R.drawable.footer_progressbar)); ``` 或 xml属性配置,更多属生见[attrs](commonrefreshlayout/src/main/res/values/attrs.xml) ```xml crl:load_text="数据正在加载中" crl:load_indeterminate_drawable="@drawable/footer_progressbar" ``` 自定义上拉加载 * 方式一:代码配置 ```java getSwipeRefreshLayout().setLoadLayoutResource(R.layout.swipe_refresh_footer); ``` * 方式二:xml属性配置 ```xml crl:load_layout="@layout/swipe_refresh_footer" ``` * 方式三:继承重写`getLoadLayoutResource()`方法 ```java public class MySwipeRefreshGridView extends SwipeRefreshGridView { @Override protected int getLoadLayoutResource() { return R.layout.swipe_refresh_footer; } } ``` 设置adapter空数据视图文字 ```java swipeRefreshListView.setEmptyText("数据呢?"); ``` 自定义adapter空数据视图 ```java ImageView emptyView = new ImageView(getContext()); emptyView.setImageResource(R.mipmap.empty); swipeRefreshGridView.setEmptyView(emptyView); ``` 注册`ListView`长按事件怎么办?好说好说提供了方法`getScrollView()`,既然能获取`ListView`那`SwipeRefreshLayout`是不是也可以获取到呢?答案是肯定的,方法`getSwipeRefreshLayout`,你可以随心所欲设置下拉圆圈的颜色、大小等。 关于更多公开方法见 [ISwipeRefresh](commonrefreshlayout/src/main/java/com/mylhyl/crlayout/internal/ISwipeRefresh.java)、[ILoadSwipeRefresh](commonrefreshlayout/src/main/java/com/mylhyl/crlayout/internal/ILoadSwipeRefresh.java) #### 注意事项 `setLoadAnimator`、`setLoadLayoutResource`方法须在`setOnListLoadListener`之前调用 #### 使用Gradle构建时添加一下依赖即可: ```javascript compile 'com.mylhyl:commonrefreshlayout:2.4' ``` #### 如果使用eclipse 只能`clone`源码,然后在 eclipse 中用`library`方式引用 #### [下载APK体验](preview/sample-debug.apk) #### 更新日志 > 2.4 修复第二次setAdapter崩溃的问题,修改已知BUG > 2.1 修复空数据视图不显示 > 2.0 UI编辑支持预览 > 1.9 优化代码 > 1.8 优化加载更多显示效果 > 1.7 新增`setEnabled`禁用下拉刷新 > 1.6 新增加载完成,命名`footer`修改为`load` > 1.5 优化`SwipeRefreshWebView`的`autoRefresh`方法 > 1.4 优化`SwipeRefreshWebView`显示下拉动画 > 1.3 增加`autoRefresh(@ColorRes int... colorResIds)`方法,指定动画颜色 > 1.2 修复滑动到底部会上拉加载多次 > 1.1 修改为`recyclerview-v7:23.4.0` > 1.0 初始版本 ================================================ FILE: build.gradle ================================================ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.2.3' classpath 'com.novoda:bintray-release:0.3.4' } } allprojects { repositories { jcenter() } tasks.withType(Javadoc) { options { encoding "UTF-8" charSet 'UTF-8' links "http://docs.oracle.com/javase/7/docs/api" failOnError false } } } ================================================ FILE: commonrefreshlayout/.gitignore ================================================ /build ================================================ FILE: commonrefreshlayout/build.gradle ================================================ apply plugin: 'com.android.library' apply plugin: 'maven' apply plugin: 'com.novoda.bintray-release' android { compileSdkVersion 23 buildToolsVersion "23.0.3" defaultConfig { minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "2017.5.26" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } lintOptions { abortOnError false checkReleaseBuilds false } } dependencies { compile 'com.android.support:recyclerview-v7:23.4.0' } publish { userOrg = 'mylhyl' groupId = 'com.mylhyl' artifactId = 'commonrefreshlayout' version = '2.4' description = 'android pull refresh layout' website = "https://github.com/mylhyl/Android-CommonRefreshLayout" } ================================================ FILE: commonrefreshlayout/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in E:\android\android-sdk-windows/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: commonrefreshlayout/src/androidTest/java/com/mylhyl/crlayout/ApplicationTest.java ================================================ package com.mylhyl.crlayout; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: commonrefreshlayout/src/main/AndroidManifest.xml ================================================ ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/BaseSwipeRefresh.java ================================================ package com.mylhyl.crlayout; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.os.Build; import android.support.annotation.ColorRes; import android.support.v4.widget.SwipeRefreshLayout; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import com.mylhyl.crlayout.internal.ISwipeRefresh; /** * android v4 兼容包 中 SwipeRefreshLayout 刷新控件,支持上拉加载 *

*

 * 此处主要封装以下几点:
 * 1.手动刷新 {@link #autoRefresh() autoRefresh}
 * 2.支持上拉加载,并可自定义
 * 3.解决 SwipeRefreshLayout 与可滑动控件使用过程中冲突的问题
 * 
* Created by hupei on 2016/5/12. */ public abstract class BaseSwipeRefresh extends FrameLayout implements ISwipeRefresh { /** * 创建可滑动 View,子类实现 * * @param context * @param attrs * @return */ protected abstract T createScrollView(Context context, AttributeSet attrs); private FrameLayout mRefreshLayoutWrapper; protected MultiSwipeRefreshLayout mLoadSwipeRefresh; private T mScrollView; private View mEmptyView; private String mEmptyViewText = ""; private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener; protected boolean isLoadCompleted; public BaseSwipeRefresh(Context context) { this(context, null); } public BaseSwipeRefresh(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BaseSwipeRefresh(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); if (!isInEditMode()) init(context, attrs, defStyleAttr, 0); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public BaseSwipeRefresh(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); if (!isInEditMode()) init(context, attrs, defStyleAttr, defStyleRes); } private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { int[] crLayout = R.styleable.crLayout; if (crLayout != null && crLayout.length > 0) { final TypedArray a = context.obtainStyledAttributes(attrs, crLayout, defStyleAttr, defStyleRes); if (a != null) { mEmptyViewText = a.getString(R.styleable.crLayout_empty_text); a.recycle(); } } mLoadSwipeRefresh = new MultiSwipeRefreshLayout(context, attrs); mScrollView = createScrollView(context, attrs); mEmptyView = createEmptyView(context); addSwipeRefreshView(context, mLoadSwipeRefresh, mScrollView, mEmptyView); } @SuppressWarnings("ResourceType") private View createEmptyView(Context context) { TextView emptyView = new TextView(context); emptyView.setId(android.R.id.empty); emptyView.setTextAppearance(context, android.R.attr.textAppearanceSmall); emptyView.setGravity(Gravity.CENTER); emptyView.setVisibility(View.GONE); emptyView.setText(mEmptyViewText); return emptyView; } private void addSwipeRefreshView(Context context, MultiSwipeRefreshLayout loadSwipeRefresh, T scrollView, View emptyView) { mRefreshLayoutWrapper = new FrameLayout(context); mRefreshLayoutWrapper.addView(scrollView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); mRefreshLayoutWrapper.addView(emptyView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); loadSwipeRefresh.addView(mRefreshLayoutWrapper, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); addView(loadSwipeRefresh, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1)); loadSwipeRefresh.setSwipeableChildren(scrollView, emptyView); } @Override public void autoRefresh() { mLoadSwipeRefresh.showProgressView(); this.setRefreshing(true); } @Override public void autoRefresh(@ColorRes int... colorResIds) { mLoadSwipeRefresh.showProgressView(colorResIds); this.setRefreshing(true); } @Override public final void autoRefresh(boolean scale, int start, int end, @ColorRes int... colorResIds) { mLoadSwipeRefresh.showProgressView(scale, start, end, colorResIds); this.setRefreshing(true); } @Override public final void setEmptyText(int resId) { setEmptyText(getContext().getString(resId)); } @Override public final void setEmptyText(CharSequence text) { if (mEmptyView != null && mEmptyView instanceof TextView) { TextView textView = (TextView) mEmptyView; textView.setText(text); } } @Override public final void setEmptyView(View newEmptyView) { if (null != newEmptyView) { if (mEmptyView != null && mRefreshLayoutWrapper != null) { mRefreshLayoutWrapper.removeView(mEmptyView); } newEmptyView.setVisibility(GONE); mEmptyView = newEmptyView; newEmptyView.setClickable(true); ViewParent newEmptyViewParent = newEmptyView.getParent(); if (null != newEmptyViewParent && newEmptyViewParent instanceof ViewGroup) { ((ViewGroup) newEmptyViewParent).removeView(newEmptyView); } FrameLayout.LayoutParams lp = convertEmptyViewLayoutParams(newEmptyView.getLayoutParams()); if (null != lp) { mRefreshLayoutWrapper.addView(newEmptyView, lp); } else { mRefreshLayoutWrapper.addView(newEmptyView); } } } private static FrameLayout.LayoutParams convertEmptyViewLayoutParams(ViewGroup.LayoutParams lp) { FrameLayout.LayoutParams newLp = null; if (null != lp) { newLp = new FrameLayout.LayoutParams(lp); if (lp instanceof LinearLayout.LayoutParams) newLp.gravity = ((LinearLayout.LayoutParams) lp).gravity; else newLp.gravity = Gravity.CENTER; } return newLp; } @Override public final View getEmptyView() { return mEmptyView; } final void updateEmptyViewShown(boolean shown) { /* * ListView不能设置隐藏,否则下拉刷新动画无法跟随手势,因为 SwipeRefreshLayout 必须有滚动的view。 * mListView.setVisibility(!shown ? View.VISIBLE : View.GONE); */ if (mEmptyView != null) mEmptyView.setVisibility(shown ? View.VISIBLE : View.GONE); } @Override public final void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener) { mOnRefreshListener = listener; mLoadSwipeRefresh.setOnRefreshListener(listener); } @Override public final void setRefreshing(boolean refreshing) { isLoadCompleted = false; mLoadSwipeRefresh.setRefreshing(refreshing); // 下拉刷新中,此处目的是为了手动调用 setRefreshing(true)时,响应下拉刷新事件 if (mLoadSwipeRefresh.isRefreshing() && mOnRefreshListener != null) mOnRefreshListener.onRefresh(); } @Override public void setEnabled(boolean enabled) { getSwipeRefreshLayout().setEnabled(enabled); } @Override public final T getScrollView() { return mScrollView; } @Override public final SwipeRefreshLayout getSwipeRefreshLayout() { return mLoadSwipeRefresh; } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/MultiSwipeRefreshLayout.java ================================================ package com.mylhyl.crlayout; import android.content.Context; import android.support.annotation.ColorRes; import android.support.v4.view.ViewCompat; import android.support.v4.widget.SwipeRefreshLayout; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.AbsListView; public final class MultiSwipeRefreshLayout extends SwipeRefreshLayout { // Default offset in dips from the top of the view to where the progress spinner should stop private static final int DEFAULT_CIRCLE_TARGET = 64; private float mSpinnerFinalOffset; private static final int[] DEFAULT_COLOR_RES = new int[]{android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light}; private int mTouchSlop; private float mPrevX;// 上一次触摸时的X坐标 private View[] mSwipeableChildren; private int[] mColorResIds; public MultiSwipeRefreshLayout(Context context) { this(context, null); } public MultiSwipeRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); final DisplayMetrics metrics = getResources().getDisplayMetrics(); mSpinnerFinalOffset = DEFAULT_CIRCLE_TARGET * metrics.density; // 触发移动事件的最短距离,如果小于这个距离就不触发移动控件 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } public final void showProgressView() { if (mColorResIds == null) mColorResIds = DEFAULT_COLOR_RES; showProgressView(mColorResIds); } public final void showProgressView(@ColorRes int... colorResIds) { showProgressView(false, 0, (int) mSpinnerFinalOffset, colorResIds); } public final void showProgressView(boolean scale, int start, int end, @ColorRes int... colorResIds) { this.mColorResIds = colorResIds; setColorSchemeResources(colorResIds); // 显示下拉动画,关键在于源码中的 mUsingCustomStart = true //有二种方法显示动画,我的文章:http://blog.csdn.net/hupei/article/details/51953370 setProgressViewOffset(scale, start, end); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPrevX = event.getX(); break; case MotionEvent.ACTION_MOVE: final float eventX = event.getX(); float xDiff = Math.abs(eventX - mPrevX); // 增加容差,让下拉刷新在竖直滑动时就可以触发 if (xDiff > mTouchSlop + DEFAULT_CIRCLE_TARGET) { return false; } } return super.onInterceptTouchEvent(event); } final void setSwipeableChildren(final View... views) { assert views != null; mSwipeableChildren = views; } @Override public boolean canChildScrollUp() { if (mSwipeableChildren != null && mSwipeableChildren.length > 0) { for (View view : mSwipeableChildren) { if (view != null && view.isShown() && !canViewScrollUp(view)) { return false; } } } return true; } private static boolean canViewScrollUp(View target) { if (android.os.Build.VERSION.SDK_INT < 14) { if (target instanceof AbsListView) { final AbsListView absListView = (AbsListView) target; return absListView.getChildCount() > 0 && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0).getTop() < absListView.getPaddingTop()); } else { return ViewCompat.canScrollVertically(target, -1) || target.getScrollY() > 0; } } else { return ViewCompat.canScrollVertically(target, -1); } } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/SwipeRefreshAbsListView.java ================================================ package com.mylhyl.crlayout; import android.content.Context; import android.database.DataSetObserver; import android.util.AttributeSet; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ListAdapter; import com.mylhyl.crlayout.internal.ILoadSwipeRefresh; /** * SwipeRefreshLayout 加 AbsListView 布局
* 子类必须实现 {@linkplain BaseSwipeRefresh#createScrollView(Context, AttributeSet)} createScrollView}方法 *

Created by hupei on 2016/5/12. */ public abstract class SwipeRefreshAbsListView extends SwipeRefreshAdapterView { private ListAdapter mEmptyDataSetAdapter; private EmptyDataSetObserver mDataSetObserver; public SwipeRefreshAbsListView(Context context) { super(context); } public SwipeRefreshAbsListView(Context context, AttributeSet attrs) { super(context, attrs); } public final void setOnItemClickListener(AdapterView.OnItemClickListener listener) { getScrollView().setOnItemClickListener(listener); } /** * 为 AbsListView 设置适配器 * * @param adapter */ public final void setAdapter(ListAdapter adapter) { if (adapter == null) throw new NullPointerException("mAdapter is null please call SwipeRefreshAbsListView" + ".setAdapter"); getScrollView().setOnScrollListener(new OnScrollAbsListListener(this)); getScrollView().setAdapter(adapter); registerDataSetObserver(adapter); } final void registerDataSetObserver(ListAdapter adapter) { if (mEmptyDataSetAdapter != null && mDataSetObserver != null) mEmptyDataSetAdapter.unregisterDataSetObserver(mDataSetObserver); mEmptyDataSetAdapter = adapter; if (mEmptyDataSetAdapter != null) { mDataSetObserver = new EmptyDataSetObserver(); mEmptyDataSetAdapter.registerDataSetObserver(mDataSetObserver); mDataSetObserver.onChanged(); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mEmptyDataSetAdapter != null && mDataSetObserver != null) { mEmptyDataSetAdapter.unregisterDataSetObserver(mDataSetObserver); mDataSetObserver = null; } } public static class OnScrollAbsListListener implements AbsListView.OnScrollListener { private ILoadSwipeRefresh mILoadSwipeRefresh; private AbsListView.OnScrollListener mOnScrollListener; public OnScrollAbsListListener(ILoadSwipeRefresh loadSwipeRefresh) { mILoadSwipeRefresh = loadSwipeRefresh; } public OnScrollAbsListListener(ILoadSwipeRefresh loadSwipeRefresh, AbsListView .OnScrollListener onScrollListener) { mILoadSwipeRefresh = loadSwipeRefresh; mOnScrollListener = onScrollListener; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // 只有在闲置状态情况下检查 if (scrollState == SCROLL_STATE_IDLE) { // 如果满足允许上拉加载、非加载状态中、最后一个显示的 item 与数据源的大小一样,则表示滑动入底部 if (mILoadSwipeRefresh.isEnabledLoad() && !mILoadSwipeRefresh.isLoading() && view.getLastVisiblePosition() == (view.getCount() - 1)) { mILoadSwipeRefresh.loadData();// 执行上拉加载数据 } } if (null != mOnScrollListener) mOnScrollListener.onScrollStateChanged(view, scrollState); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (null != mOnScrollListener) mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } } private class EmptyDataSetObserver extends DataSetObserver { @Override public void onChanged() { updateEmptyViewShown(mEmptyDataSetAdapter == null || mEmptyDataSetAdapter.isEmpty()); } } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/SwipeRefreshAdapterView.java ================================================ package com.mylhyl.crlayout; import android.animation.Animator; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Build; import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import com.mylhyl.crlayout.internal.ILoadSwipeRefresh; import com.mylhyl.crlayout.internal.LoadConfig; import com.mylhyl.crlayout.internal.LoadLayout; import com.mylhyl.crlayout.internal.LoadLayoutBase; import com.mylhyl.crlayout.internal.LoadLayoutConvert; public abstract class SwipeRefreshAdapterView extends BaseSwipeRefresh implements ILoadSwipeRefresh { private static final String DEFAULT_FOOTER_TEXT = "加载数据中..."; private static final String DEFAULT_FOOTER_COMPLETED_TEXT = "没有更多了"; private static final int mLoadAnimatorDuration = 300; private boolean mLoading;// 是否处于上拉加载状态中 private boolean mEnabledLoad;// 是否允许上拉加载 private LoadLayoutBase mLoadLayout; private int mLoadResource; private String mLoadText; private String mCompletedText; private Drawable mLoadIndeterminateDrawable; private OnListLoadListener mOnListLoadListener; private ValueAnimator mShowLoadAnimator; private ValueAnimator mHideLoadAnimator; private int mLoadLayoutHeight; private boolean isLoadAnimator; public SwipeRefreshAdapterView(Context context) { this(context, null); } public SwipeRefreshAdapterView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SwipeRefreshAdapterView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr, 0); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public SwipeRefreshAdapterView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context, attrs, defStyleAttr, defStyleRes); } private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { int[] crLayout = R.styleable.crLayout; if (crLayout != null && crLayout.length > 0) { final TypedArray a = context.obtainStyledAttributes(attrs, crLayout, defStyleAttr, defStyleRes); if (a != null) { mLoadResource = a.getResourceId(R.styleable.crLayout_load_layout, 0); mLoadText = a.getString(R.styleable.crLayout_load_text); mLoadIndeterminateDrawable = a.getDrawable(R.styleable .crLayout_load_indeterminate_drawable); mCompletedText = a.getString(R.styleable.crLayout_load_completed_text); isLoadAnimator = a.getBoolean(R.styleable.crLayout_load_animator, false); a.recycle(); } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (isLoadAnimator && mLoadLayout != null && mLoadLayoutHeight == 0) { mLoadLayoutHeight = mLoadLayout.getMeasuredHeight(); if (mLoadLayoutHeight > 0) { mLoadLayout.setVisibility(GONE); initShowLoadAnimator(); initHideLoadAnimator(); } } } private void initShowLoadAnimator() { mShowLoadAnimator = ValueAnimator.ofFloat(0, mLoadLayoutHeight); mShowLoadAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { LayoutParams lp = (LayoutParams) mLoadLayout.getLayoutParams(); lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue(); mLoadLayout.setLayoutParams(lp); getScrollView().setTranslationY(-lp.height); } }); mShowLoadAnimator.addListener(new SimpleAnimatorListener() { @Override public void onAnimationEnd(Animator animation) { if (mOnListLoadListener != null && !isLoadCompleted) { mOnListLoadListener.onListLoad(); } } }); mShowLoadAnimator.setDuration(mLoadAnimatorDuration); } private void initHideLoadAnimator() { mHideLoadAnimator = ValueAnimator.ofFloat(mLoadLayoutHeight, 0); mHideLoadAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { LayoutParams lp = (LayoutParams) mLoadLayout.getLayoutParams(); lp.height = (int) ((Float) animation.getAnimatedValue()).floatValue(); mLoadLayout.setLayoutParams(lp); getScrollView().setTranslationY(-lp.height); } }); mHideLoadAnimator.setDuration(mLoadAnimatorDuration); } @Override public final void setOnListLoadListener(OnListLoadListener onListLoadListener) { this.mOnListLoadListener = onListLoadListener; setEnabledLoad(mOnListLoadListener != null); if (mEnabledLoad) addLoadLayout(); } private void addLoadLayout() { if (mLoadLayout == null) { createLoadLayout();//创建上拉加载 View LayoutParams layoutParams = new LayoutParams(mLoadLayout.getLayoutParams()); layoutParams.gravity = Gravity.BOTTOM; //永远处于第二节点,防止 mLoadLayout 遮挡其它控件 addView(mLoadLayout, 1, layoutParams); } } private void createLoadLayout() { if ((mLoadResource = getLoadLayoutResource()) > 0) { View view = LayoutInflater.from(getContext()).inflate(mLoadResource, this, false); mLoadLayout = new LoadLayoutConvert(getContext(), view); } else { LoadLayout footerLayout = new LoadLayout(getContext()); mLoadLayout = footerLayout; } if (mLoadLayout == null) throw new NullPointerException("mLoadLayout is null"); if (!isLoadAnimator) mLoadLayout.setVisibility(GONE); if (TextUtils.isEmpty(mCompletedText)) mCompletedText = DEFAULT_FOOTER_COMPLETED_TEXT; mLoadLayout.setLoadCompletedText(mCompletedText); if (TextUtils.isEmpty(mLoadText)) mLoadText = DEFAULT_FOOTER_TEXT; mLoadLayout.setLoadText(mLoadText); if (mLoadIndeterminateDrawable != null) mLoadLayout.setIndeterminateDrawable(mLoadIndeterminateDrawable); } @Override public final void setLoadLayoutResource(int resource) { mLoadResource = resource; if (mLoadLayout != null) throw new RuntimeException("please call setLoadLayoutResource before " + "setOnListLoadListener"); } /** * 获取自定义上拉加载 layoutResource,子类可重写 * * @return */ protected int getLoadLayoutResource() { return mLoadResource; } @Override public final void loadData() { setLoading(true); } @Override public final void setLoading(boolean loading) { if (mLoading == loading) return; this.mLoading = loading; if (mLoading) showLoadLayout(); else hideLoadLayout(); } private void showLoadLayout() { if (mLoadLayout != null) { LoadConfig footerLayout = getLoadConfig(); if (isLoadCompleted) { footerLayout.setLoadCompletedText(mLoadLayout.getCompletedText()); footerLayout.setProgressBarVisibility(View.GONE); mLoadLayout.postDelayed(new Runnable() { @Override public void run() { setLoading(false); } }, 1000); } else { footerLayout.setLoadText(mLoadLayout.getFooterText()); footerLayout.setProgressBarVisibility(View.VISIBLE); } mLoadLayout.setVisibility(View.VISIBLE); if (isLoadAnimator && mShowLoadAnimator != null) mShowLoadAnimator.start(); else if (!isLoadAnimator && !isLoadCompleted && mOnListLoadListener != null) mOnListLoadListener.onListLoad(); } } private void hideLoadLayout() { if (isLoadAnimator && mHideLoadAnimator != null) mHideLoadAnimator.start(); else mLoadLayout.setVisibility(GONE); } @Override public final void setEnabledLoad(boolean enabled) { mEnabledLoad = enabled; } @Override public final boolean isLoading() { return mLoading; } @Override public final boolean isEnabledLoad() { return mEnabledLoad; } @Override public void setLoadCompleted(boolean loadCompleted) { isLoadCompleted = loadCompleted; } @Override public LoadConfig getLoadConfig() { if (mLoadLayout == null) addLoadLayout(); return mLoadLayout; } @Override public void setLoadAnimator(boolean loadAnimator) { isLoadAnimator = loadAnimator; if (mLoadLayout != null) throw new RuntimeException("please call setLoadAnimator before setOnListLoadListener"); } public interface OnListLoadListener { /** * 当上拉加载时,此方法将被调用 */ void onListLoad(); } static class SimpleAnimatorListener implements Animator.AnimatorListener { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/SwipeRefreshExpandableListView.java ================================================ package com.mylhyl.crlayout; import android.content.Context; import android.database.DataSetObserver; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; /** * SwipeRefreshLayout 包含 ExpandableListView 布局
* 如须自定义加载框,可继承此类重写 {@link #getLoadLayoutResource()} getLoadLayoutResource} *

Created by hupei on 2016/5/16. */ public class SwipeRefreshExpandableListView extends SwipeRefreshAbsListView { private ExpandableListAdapter mAdapter; public SwipeRefreshExpandableListView(Context context) { super(context); } public SwipeRefreshExpandableListView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 为 ExpandableListView 设置适配器 * * @param adapter */ public final void setAdapter(ExpandableListAdapter adapter) { mAdapter = adapter; if (mAdapter == null) throw new NullPointerException("mAdapter is null please call SwipeRefreshExpandableListView.setAdapter"); getScrollView().setOnScrollListener(new OnScrollAbsListListener(this)); getScrollView().setAdapter(mAdapter); registerDataSetObserver(new ExpandableListConnector(mAdapter)); } @Override protected ExpandableListView createScrollView(Context context, AttributeSet attrs) { ExpandableListView expandableListView = new ExpandableListView(context, attrs); expandableListView.setId(android.R.id.list); return expandableListView; } private class ExpandableListConnector extends BaseAdapter { private ExpandableListAdapter mExpandableListAdapter; public ExpandableListConnector(ExpandableListAdapter expandableListAdapter) { this.mExpandableListAdapter = expandableListAdapter; } @Override public int getCount() { if (mExpandableListAdapter == null) return 0; return mExpandableListAdapter.getGroupCount(); } @Override public void registerDataSetObserver(DataSetObserver observer) { mExpandableListAdapter.registerDataSetObserver(observer); } @Override public void unregisterDataSetObserver(DataSetObserver observer) { mExpandableListAdapter.unregisterDataSetObserver(observer); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { return null; } } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/SwipeRefreshGridView.java ================================================ package com.mylhyl.crlayout; import android.content.Context; import android.util.AttributeSet; import android.widget.GridView; /** * SwipeRefreshLayout 包含 HeaderGridView 布局
* 如须自定义加载框,可继承此类重写 {@link #getLoadLayoutResource()} getLoadLayoutResource}方法 *

Created by hupei on 2016/5/17. */ public class SwipeRefreshGridView extends SwipeRefreshAbsListView { @Override protected GridView createScrollView(Context context, AttributeSet attrs) { GridView gridView = new GridView(context, attrs); gridView.setId(android.R.id.list); return gridView; } public SwipeRefreshGridView(Context context) { super(context); } public SwipeRefreshGridView(Context context, AttributeSet attrs) { super(context, attrs); } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/SwipeRefreshListView.java ================================================ package com.mylhyl.crlayout; import android.content.Context; import android.util.AttributeSet; import android.widget.ListView; /** * SwipeRefreshLayout 包含 ListView 布局
* 如须自定义加载框,可继承此类重写 {@link #getLoadLayoutResource()} getLoadLayoutResource}方法 *

Created by hupei on 2016/5/12. */ public class SwipeRefreshListView extends SwipeRefreshAbsListView { public SwipeRefreshListView(Context context) { super(context); } public SwipeRefreshListView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected ListView createScrollView(Context context, AttributeSet attrs) { ListView listView = new ListView(context, attrs); listView.setId(android.R.id.list); return listView; } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/SwipeRefreshRecyclerView.java ================================================ package com.mylhyl.crlayout; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.View; import com.mylhyl.crlayout.internal.ILoadSwipeRefresh; /** * SwipeRefreshLayout 加 RecyclerView 布局
* 如须自定义加载框,可继承此类重写 {@link #getLoadLayoutResource()} getLoadLayoutResource}方法 *

Created by hupei on 2016/5/12. */ public class SwipeRefreshRecyclerView extends SwipeRefreshAdapterView { private RecyclerView.Adapter mEmptyDataSetAdapter; private EmptyDataSetObserver mDataSetObserver; public SwipeRefreshRecyclerView(Context context) { super(context); } public SwipeRefreshRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 为 RecyclerView 设置适配器 * * @param adapter */ public final void setAdapter(RecyclerView.Adapter adapter) { if (adapter == null) throw new NullPointerException("mAdapter is null please call CygSwipeRefreshLayout" + ".setAdapter"); getScrollView().setOnScrollListener(new OnScrollRecyclerViewListener(this)); getScrollView().setAdapter(adapter); registerAdapterDataObserver(adapter); } public void setLayoutManager(RecyclerView.LayoutManager layout) { getScrollView().setLayoutManager(layout); } @Override protected RecyclerView createScrollView(Context context, AttributeSet attrs) { RecyclerView recyclerView = new RecyclerView(context, attrs); recyclerView.setId(android.R.id.list); return recyclerView; } private void registerAdapterDataObserver(RecyclerView.Adapter adapter) { if (mEmptyDataSetAdapter != null && mDataSetObserver != null) mEmptyDataSetAdapter.unregisterAdapterDataObserver(mDataSetObserver); mEmptyDataSetAdapter = adapter; if (mEmptyDataSetAdapter != null){ mDataSetObserver = new EmptyDataSetObserver(); mEmptyDataSetAdapter.registerAdapterDataObserver(mDataSetObserver); mDataSetObserver.onChanged(); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mEmptyDataSetAdapter != null && mDataSetObserver != null) { mEmptyDataSetAdapter.unregisterAdapterDataObserver(mDataSetObserver); mDataSetObserver = null; } } public static class OnScrollRecyclerViewListener extends RecyclerView.OnScrollListener { private ILoadSwipeRefresh mILoadSwipeRefresh; private RecyclerView.OnScrollListener mOnScrollListener; public OnScrollRecyclerViewListener(ILoadSwipeRefresh loadSwipeRefresh) { mILoadSwipeRefresh = loadSwipeRefresh; } public OnScrollRecyclerViewListener(ILoadSwipeRefresh loadSwipeRefresh, RecyclerView .OnScrollListener onScrollListener) { mILoadSwipeRefresh = loadSwipeRefresh; mOnScrollListener = onScrollListener; } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); // 只有在闲置状态情况下检查 if (newState == RecyclerView.SCROLL_STATE_IDLE) { // 如果满足允许上拉加载、非加载状态中、最后一个显示的 item 与数据源的大小一样,则表示滑动入底部 if (!isFirstItemVisible(recyclerView) && mILoadSwipeRefresh.isEnabledLoad() && !mILoadSwipeRefresh.isLoading() && isLastItemVisible(recyclerView)) { mILoadSwipeRefresh.loadData();// 执行上拉加载数据 } } if (null != mOnScrollListener) mOnScrollListener.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (null != mOnScrollListener) mOnScrollListener.onScrolled(recyclerView, dx, dy); } /** * 判断第一个条目是否完全可见 * * @param recyclerView * @return */ private boolean isFirstItemVisible(RecyclerView recyclerView) { final RecyclerView.Adapter adapter = recyclerView.getAdapter(); // 如果未设置Adapter或者Adapter没有数据可以下拉刷新 if (null == adapter || adapter.getItemCount() == 0) { return true; } // 第一个条目完全展示,可以刷新 if (getFirstVisiblePosition(recyclerView) == 0) { return recyclerView.getChildAt(0).getTop() >= recyclerView.getTop(); } return false; } /** * 获取第一个可见子View的位置下标 * * @param recyclerView * @return */ private int getFirstVisiblePosition(RecyclerView recyclerView) { View firstVisibleChild = recyclerView.getChildAt(0); return firstVisibleChild != null ? recyclerView.getChildAdapterPosition(firstVisibleChild) : -1; } /** * 判断最后一个条目是否完全可见 * * @param recyclerView * @return */ private boolean isLastItemVisible(RecyclerView recyclerView) { final RecyclerView.Adapter adapter = recyclerView.getAdapter(); // 如果未设置Adapter或者Adapter没有数据可以上拉刷新 if (null == adapter || adapter.getItemCount() == 0) { return true; } // 最后一个条目View完全展示,可以刷新 int lastVisiblePosition = getLastVisiblePosition(recyclerView); if (lastVisiblePosition >= recyclerView.getAdapter().getItemCount() - 1) { return recyclerView.getChildAt(recyclerView.getChildCount() - 1).getBottom() <= recyclerView.getBottom(); } return false; } /** * 获取最后一个可见子View的位置下标 * * @param recyclerView * @return */ private int getLastVisiblePosition(RecyclerView recyclerView) { View lastVisibleChild = recyclerView.getChildAt(recyclerView.getChildCount() - 1); return lastVisibleChild != null ? recyclerView.getChildAdapterPosition (lastVisibleChild) : -1; } } private class EmptyDataSetObserver extends RecyclerView.AdapterDataObserver { @Override public void onChanged() { updateEmptyViewShown(mEmptyDataSetAdapter == null || mEmptyDataSetAdapter .getItemCount() == 0); } @Override public void onItemRangeChanged(int positionStart, int itemCount) { onChanged(); } @Override public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { onChanged(); } @Override public void onItemRangeInserted(int positionStart, int itemCount) { onChanged(); } @Override public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { onChanged(); } @Override public void onItemRangeRemoved(int positionStart, int itemCount) { onChanged(); } } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/SwipeRefreshWebView.java ================================================ package com.mylhyl.crlayout; import android.content.Context; import android.support.annotation.ColorRes; import android.support.v4.widget.SwipeRefreshLayout; import android.util.AttributeSet; import android.webkit.WebChromeClient; import android.webkit.WebView; /** * SwipeRefreshLayout 加 WebView 布局
*

Created by hupei on 2016/5/12. */ public class SwipeRefreshWebView extends BaseSwipeRefresh { private final SwipeRefreshLayout.OnRefreshListener refreshListener = new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { getScrollView().reload(); } }; private final WebChromeClient defaultWebChromeClient = new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress == 100) { setRefreshing(false); } } }; public SwipeRefreshWebView(Context context) { this(context, null); } public SwipeRefreshWebView(Context context, AttributeSet attrs) { super(context, attrs); if (!isInEditMode()) { setOnRefreshListener(refreshListener); getScrollView().setWebChromeClient(defaultWebChromeClient); } } @Override public final void autoRefresh() { mLoadSwipeRefresh.showProgressView(); mLoadSwipeRefresh.setRefreshing(true); } @Override public final void autoRefresh(@ColorRes int... colorResIds) { //重写主要是为了显示动画时,不响应 onRefresh() 方法 mLoadSwipeRefresh.showProgressView(colorResIds); mLoadSwipeRefresh.setRefreshing(true); } @Override protected WebView createScrollView(Context context, AttributeSet attrs) { WebView webView = new WebView(context, attrs); webView.setId(android.R.id.list); return webView; } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/app/BaseSwipeRefreshFragment.java ================================================ package com.mylhyl.crlayout.app; import android.os.Bundle; import android.support.annotation.ColorRes; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.mylhyl.crlayout.BaseSwipeRefresh; import com.mylhyl.crlayout.internal.ISwipeRefresh; /** * Google自家下拉刷新 SwipeRefreshLayout
*

* 注:SwipeRefreshLayout 只能有一个 childView,childView自身必须是可滚动的view
* 或 childView 必须包含可滚动的view,如ScrollView或者AbsListView
* 子类继承重写 onCreateView 必须 super */ abstract class BaseSwipeRefreshFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { /** * 创建下拉刷新控件子类重写 * * @return */ public abstract T createSwipeRefreshLayout(); protected T mSwipeRefresh; @Override public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return mSwipeRefresh = createSwipeRefreshLayout(); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 注册下拉刷新 mSwipeRefresh.setOnRefreshListener(this); } public final void autoRefresh() { getSwipeRefreshLayout().autoRefresh(); } public final void autoRefresh(@ColorRes int... colorResIds) { getSwipeRefreshLayout().autoRefresh(colorResIds); } /** * {@link ISwipeRefresh#setRefreshing(boolean)} */ public final void setRefreshing(boolean refreshing) { getSwipeRefreshLayout().setRefreshing(refreshing); } public final void setEmptyText(int resId) { setEmptyText(getString(resId)); } public final void setEmptyText(CharSequence text) { getSwipeRefreshLayout().setEmptyText(text); } public final void setEmptyView(View emptyView) { getSwipeRefreshLayout().setEmptyView(emptyView); } public final T getSwipeRefreshLayout() { return mSwipeRefresh; } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/app/SwipeRefreshAbsListFragment.java ================================================ package com.mylhyl.crlayout.app; import android.view.View; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ExpandableListView; import android.widget.ListAdapter; import com.mylhyl.crlayout.SwipeRefreshAbsListView; abstract class SwipeRefreshAbsListFragment extends SwipeRefreshAdapterFragment { private final AdapterView.OnItemClickListener mOnItemClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { /** * ListView or GridView 单点事件 */ onListItemClick(parent, view, position, id); } }; /** * Item 点击时此方法调用,子类可重写 * * @param parent * @param view * @param position * @param id */ public void onListItemClick(AdapterView parent, View view, int position, long id) { } /** * 适配器设置数据源 * * @param adapter * @author hupei * @date 2015年7月31日 上午9:06:14 */ public final void setListAdapter(ListAdapter adapter) { AbsListView absListView = (AbsListView) getSwipeRefreshLayout().getScrollView(); if (absListView instanceof ExpandableListView) { new RuntimeException("please call SwipeRefreshExpandableListFragment.setListAdapter()"); } T swipeRefreshLayout = getSwipeRefreshLayout(); if (swipeRefreshLayout != null && swipeRefreshLayout instanceof SwipeRefreshAbsListView) { absListView.setVisibility(View.VISIBLE); absListView.setOnItemClickListener(mOnItemClickListener); swipeRefreshLayout.setAdapter(adapter); } } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/app/SwipeRefreshAdapterFragment.java ================================================ package com.mylhyl.crlayout.app; import com.mylhyl.crlayout.SwipeRefreshAdapterView; import com.mylhyl.crlayout.SwipeRefreshListView; /** * 如果开启{@linkplain SwipeRefreshAdapterFragment#setEnabledLoad(boolean) 上拉加载}功能 * 必须重写 {@linkplain SwipeRefreshAdapterFragment#onListLoad() onListLoad()}方法
*/ abstract class SwipeRefreshAdapterFragment extends BaseSwipeRefreshFragment implements SwipeRefreshAdapterView.OnListLoadListener { /** * 设置允许上拉加载,重写{@link #onListLoad() onListLoad 方法实现上拉加载数据} * * @param enabled * @see SwipeRefreshListView#setEnabledLoad(boolean) * @see SwipeRefreshListView#setOnListLoadListener(SwipeRefreshAdapterView.OnListLoadListener) */ public final void setEnabledLoad(boolean enabled) { if (enabled) mSwipeRefresh.setOnListLoadListener(this); mSwipeRefresh.setEnabledLoad(enabled); } /** * {@link SwipeRefreshAdapterView#setLoading(boolean)} */ public final void setLoading(boolean loading) { getSwipeRefreshLayout().setLoading(loading); } @Override public void onListLoad() { } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/app/SwipeRefreshExpandableListFragment.java ================================================ package com.mylhyl.crlayout.app; import android.view.View; import android.widget.AdapterView; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; import com.mylhyl.crlayout.SwipeRefreshExpandableListView; /** * Created by hupei on 2016/5/16. */ public abstract class SwipeRefreshExpandableListFragment extends SwipeRefreshAbsListFragment { private final ExpandableListView.OnGroupClickListener mOnGroupClickListener = new ExpandableListView.OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { return onListGroupClick(parent, v, groupPosition, id); } }; private final ExpandableListView.OnChildClickListener mOnChildClickListener = new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { return onListChildClick(parent, v, groupPosition, childPosition, id); } }; public boolean onListChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { return false; } public boolean onListGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { return false; } @Override public final void onListItemClick(AdapterView parent, View view, int position, long id) { //子类不允许重写 super.onListItemClick(parent, view, position, id); } @Override public SwipeRefreshExpandableListView createSwipeRefreshLayout() { return new SwipeRefreshExpandableListView(getActivity()); } public final void setListAdapter(ExpandableListAdapter adapter) { ExpandableListView expandableListView = getSwipeRefreshLayout().getScrollView(); SwipeRefreshExpandableListView swipeRefreshExpandableListView = getSwipeRefreshLayout(); if (expandableListView != null && swipeRefreshExpandableListView != null) { expandableListView.setVisibility(View.VISIBLE); expandableListView.setOnGroupClickListener(mOnGroupClickListener); expandableListView.setOnChildClickListener(mOnChildClickListener); swipeRefreshExpandableListView.setAdapter(adapter); } } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/app/SwipeRefreshListFragment.java ================================================ package com.mylhyl.crlayout.app; import com.mylhyl.crlayout.SwipeRefreshListView; public abstract class SwipeRefreshListFragment extends SwipeRefreshAbsListFragment { @Override public SwipeRefreshListView createSwipeRefreshLayout() { return new SwipeRefreshListView(getActivity()); } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/internal/ILoadSwipeRefresh.java ================================================ package com.mylhyl.crlayout.internal; import com.mylhyl.crlayout.SwipeRefreshAdapterView; /** * Created by hupei on 2016/5/18. */ public interface ILoadSwipeRefresh { void setOnListLoadListener(SwipeRefreshAdapterView.OnListLoadListener onListLoadListener); void setLoadLayoutResource(int resource); void loadData(); /** * 设置是否处于上拉加载状态 * * @param loading 为true加载状态,false结束加载 */ void setLoading(boolean loading); /** * 允许上拉加载 * * @param enabled */ void setEnabledLoad(boolean enabled); /** * 是否在上拉加载中 * * @return */ boolean isLoading(); /** * 是否允许上拉加载 * * @return */ boolean isEnabledLoad(); /** * 设置加载完成 * * @param loadCompleted */ void setLoadCompleted(boolean loadCompleted); LoadConfig getLoadConfig(); /** * 设置加载Layout有动画显示效果,默认false * * @param isLoadAnimator true 启用动画 */ void setLoadAnimator(boolean isLoadAnimator); } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/internal/ISwipeRefresh.java ================================================ package com.mylhyl.crlayout.internal; import android.support.annotation.ColorRes; import android.support.v4.widget.SwipeRefreshLayout; import android.view.View; /** * Created by hupei on 2016/5/18. */ public interface ISwipeRefresh { /** * 显示刷新动画,颜色随系统 */ void autoRefresh(); /** * 显示刷新动画,可指定颜色 * * @param colorResIds 动画颜色 */ void autoRefresh(@ColorRes int... colorResIds); void autoRefresh(boolean scale, int start, int end, @ColorRes int... colorResIds); void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener); void setEmptyText(CharSequence text); void setEmptyText(int resId); void setEmptyView(View emptyView); View getEmptyView(); /** * 设置下拉刷新状态 * * @param refreshing true=刷新中;false=刷新完成 */ void setRefreshing(boolean refreshing); /** * 禁用下拉刷新 * * @param enabled */ void setEnabled(boolean enabled); /** * 获取可滑动的 ListView、ExpandableListView、GridView、RecyclerView * * @return */ T getScrollView(); SwipeRefreshLayout getSwipeRefreshLayout(); } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/internal/LoadConfig.java ================================================ package com.mylhyl.crlayout.internal; import android.graphics.drawable.Drawable; /** * Created by hupei on 2016/5/19. */ public interface LoadConfig { /** * 设置加载文字 * * @param label */ void setLoadText(String label); /** * 设置加载文字大小 * * @param size */ void setLoadTextSize(float size); /** * 设置加载文字颜色 * * @param color */ void setLoadTextColor(int color); /** * 设置菊花显示或隐藏 * * @param v */ void setProgressBarVisibility(int v); /** * 设置菊花样式 * * @param d */ void setIndeterminateDrawable(Drawable d); /** * 设置加载完成文字 * * @param text */ void setLoadCompletedText(String text); /** * 设置加载更多 Layout 高度 * * @param height */ void setLoadViewHeight(int height); /** * 设置加载更多 Layout 资源背景 * * @param resId */ void setLoadViewBackgroundResource(int resId); /** * 设置加载更多 Layout 颜色背景 * * @param color */ void setLoadViewBackgroundColor(int color); } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/internal/LoadLayout.java ================================================ package com.mylhyl.crlayout.internal; import android.content.Context; import android.graphics.Color; import android.view.Gravity; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; /** * 上拉加载 layout 包含 ProgressBar 与 TextView * Created by hupei on 2016/5/19. */ public final class LoadLayout extends LoadLayoutBase { public LoadLayout(Context context) { super(context); } @Override void createFooter(ViewGroup v) { LinearLayout root = (LinearLayout) v; root.setOrientation(HORIZONTAL); root.setGravity(Gravity.CENTER); root.setBackgroundColor(Color.WHITE); root.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, pxTdp(50))); mProgressBar = new ProgressBar(getContext(), null, android.R.attr.progressBarStyleSmallInverse); root.addView(mProgressBar, new AbsListView.LayoutParams( AbsListView.LayoutParams.WRAP_CONTENT, AbsListView.LayoutParams.WRAP_CONTENT)); mTextView = new TextView(getContext()); mTextView.setTextAppearance(getContext(), android.R.attr.textAppearanceMedium); root.addView(mTextView, new LayoutParams( AbsListView.LayoutParams.WRAP_CONTENT, AbsListView.LayoutParams.WRAP_CONTENT)); } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/internal/LoadLayoutBase.java ================================================ package com.mylhyl.crlayout.internal; import android.content.Context; import android.graphics.drawable.Drawable; import android.support.annotation.ColorInt; import android.support.annotation.DrawableRes; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; /** * 上拉加载 layout 基类 * Created by hupei on 2016/5/19. */ public abstract class LoadLayoutBase extends LinearLayout implements LoadConfig { private String mFooterText; private String mCompletedText; protected ProgressBar mProgressBar; protected TextView mTextView; abstract void createFooter(ViewGroup v); public LoadLayoutBase(Context context) { super(context); createFooter(this); } public LoadLayoutBase(Context context, View v) { super(context); createFooter((ViewGroup) v); } protected int pxTdp(int size) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, getResources().getDisplayMetrics()); } @Override public void setLoadViewHeight(int height) { ViewGroup.LayoutParams params = getLayoutParams(); params.height = pxTdp(height); setLayoutParams(params); } @Override public void setLoadText(String text) { mFooterText = text; if (mTextView != null) mTextView.setText(text); } @Override public void setLoadTextSize(float size) { if (mTextView != null) mTextView.setTextSize(size); } @Override public void setLoadTextColor(@ColorInt int color) { if (mTextView != null) mTextView.setTextColor(color); } @Override public void setLoadViewBackgroundResource(@DrawableRes int resId) { setBackgroundResource(resId); } @Override public void setLoadViewBackgroundColor(@ColorInt int color) { setBackgroundColor(color); } @Override public void setProgressBarVisibility(int v) { if (mProgressBar != null) mProgressBar.setVisibility(v); } @Override public void setIndeterminateDrawable(Drawable d) { if (mProgressBar != null) mProgressBar.setIndeterminateDrawable(d); } @Override public void setLoadCompletedText(String text) { mCompletedText = text; if (mTextView != null) mTextView.setText(text); } public String getFooterText() { return mFooterText; } public String getCompletedText() { return mCompletedText; } } ================================================ FILE: commonrefreshlayout/src/main/java/com/mylhyl/crlayout/internal/LoadLayoutConvert.java ================================================ package com.mylhyl.crlayout.internal; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.TextView; /** * 转换自定义上拉加载 View * Created by hupei on 2016/5/19. */ public final class LoadLayoutConvert extends LoadLayoutBase { public LoadLayoutConvert(Context context, View v) { super(context, v); } @Override void createFooter(ViewGroup v) { //查找 mProgressBar 与 mTextView int count = v.getChildCount(); for (int i = 0; i < count; i++) { View childAt = v.getChildAt(i); if (childAt instanceof ProgressBar) mProgressBar = (ProgressBar) childAt; else if (childAt instanceof TextView) mTextView = (TextView) childAt; } setLayoutParams(v.getLayoutParams()); addView(v); } } ================================================ FILE: commonrefreshlayout/src/main/res/values/attrs.xml ================================================ ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ #Fri May 26 15:10:51 CST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip ================================================ FILE: gradle.properties ================================================ # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx10248m -XX:MaxPermSize=256m # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true ================================================ FILE: gradlew ================================================ #!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: sample/.gitignore ================================================ /build ================================================ FILE: sample/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 23 buildToolsVersion "23.0.3" defaultConfig { applicationId "com.mylhyl.prlayout.sample" minSdkVersion 15 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } lintOptions { abortOnError false } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile project(':commonrefreshlayout') compile 'com.android.support:appcompat-v7:23.3.0' compile 'com.android.support:support-v4:23.3.0' compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.mylhyl:cygadapter:1.0.0' compile files('libs/lite-http-3.0.0.jar') compile 'com.android.support:cardview-v7:23.3.0' } ================================================ FILE: sample/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in E:\android\android-sdk-windows/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: sample/src/androidTest/java/com/mylhyl/crlayout/sample/ApplicationTest.java ================================================ package com.mylhyl.crlayout.sample; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: sample/src/main/AndroidManifest.xml ================================================ ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/APP.java ================================================ package com.mylhyl.crlayout.sample; import android.app.Application; import com.bumptech.glide.request.target.ViewTarget; public class APP extends Application { @Override public void onCreate() { super.onCreate(); //因为Glide加载图片的源码中也使用了setTag和getTag模式而 //https://github.com/bumptech/glide/issues/370 ViewTarget.setTagId(R.string.app_name); } } ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/MainActivity.java ================================================ package com.mylhyl.crlayout.sample; import android.content.ContentUris; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.app.AppCompatActivity; import com.mylhyl.crlayout.sample.app.AppExpandableListFragment; import com.mylhyl.crlayout.sample.app.AppListFragment; import com.mylhyl.crlayout.sample.app.GridViewFragment; import com.mylhyl.crlayout.sample.app.ListViewFragment; import com.mylhyl.crlayout.sample.app.RecyclerViewFragment; import com.mylhyl.crlayout.sample.app.WebViewFragment; public class MainActivity extends AppCompatActivity implements TypesFragment.OnFragmentInteractionListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .add(android.R.id.content, TypesFragment.newInstance()) .commitAllowingStateLoss(); } } @Override public void onFragmentInteraction(Uri uri) { Fragment fragment = null; int typeId = (int) ContentUris.parseId(uri); switch (typeId) { case 0: fragment = ListViewFragment.newInstance(); break; case 1: fragment = GridViewFragment.newInstance(); break; case 2: fragment = RecyclerViewFragment.newInstance(); break; case 3: fragment = WebViewFragment.newInstance(); break; case 4: fragment = AppListFragment.newInstance(); break; case 5: fragment = AppExpandableListFragment.newInstance(); break; } if (fragment != null) getSupportFragmentManager().beginTransaction() .replace(android.R.id.content, fragment) .addToBackStack(null) .commitAllowingStateLoss(); } } ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/TypesFragment.java ================================================ package com.mylhyl.crlayout.sample; import android.content.ContentUris; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; public class TypesFragment extends Fragment implements AdapterView.OnItemClickListener { private OnFragmentInteractionListener mListener; private Uri mUri = Uri.parse("content://com.mylhyl.crlayout.sample/types"); public TypesFragment() { } public static TypesFragment newInstance() { return new TypesFragment(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_types, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ListView listView = (ListView) view.findViewById(R.id.listView); listView.setOnItemClickListener(this); listView.setAdapter(new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, getResources().getStringArray(R.array.types))); } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onDetach() { super.onDetach(); mListener = null; } @Override public void onItemClick(AdapterView parent, View view, int position, long id) { Uri uri = ContentUris.withAppendedId(mUri, position); onButtonPressed(uri); } public void onButtonPressed(Uri uri) { if (mListener != null) { mListener.onFragmentInteraction(uri); } } public interface OnFragmentInteractionListener { void onFragmentInteraction(Uri uri); } } ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/app/AppExpandableListFragment.java ================================================ package com.mylhyl.crlayout.sample.app; import android.content.Context; import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.TextView; import android.widget.Toast; import com.mylhyl.crlayout.SwipeRefreshExpandableListView; import com.mylhyl.crlayout.app.SwipeRefreshExpandableListFragment; import com.mylhyl.crlayout.sample.R; import java.util.ArrayList; import java.util.List; /** * Created by hupei on 2016/5/13. */ public class AppExpandableListFragment extends SwipeRefreshExpandableListFragment { private MyExpandableListAdapter adapter; private List groups = new ArrayList<>(); private List> childs = new ArrayList<>(); private int index; private int footerIndex = 20; public static AppExpandableListFragment newInstance() { return new AppExpandableListFragment(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); setEnabledLoad(true); for (int i = 0; i < footerIndex; i++) { groups.add("group = " + i); List child = new ArrayList<>(); for (int j = 0; j < 3; j++) { child.add("child = " + i + ":" + j); } childs.add(child); } adapter = new MyExpandableListAdapter(this.getContext()); setListAdapter(adapter); setEmptyText("什么也没有!"); } @Override public SwipeRefreshExpandableListView createSwipeRefreshLayout() { return new SwipeRefreshExpandableListView(getActivity()); } @Override public boolean onListGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { Toast.makeText(getContext(), "groupPosition:" + groupPosition, Toast.LENGTH_SHORT).show(); return false; } @Override public boolean onListChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { Toast.makeText(getContext(), "groupPosition:" + groupPosition + " | childPosition:" + childPosition, Toast.LENGTH_SHORT).show(); return true; } @Override public void onRefresh() { getSwipeRefreshLayout().getScrollView().postDelayed(new Runnable() { @Override public void run() { int count = --index; groups.add(0, "下拉group = " + count); List child = new ArrayList<>(); for (int j = 0; j < 3; j++) { child.add("下拉child = " + count + ":" + j); } childs.add(child); adapter.notifyDataSetChanged(); setRefreshing(false); } }, 1000); } @Override public void onListLoad() { getSwipeRefreshLayout().getScrollView().postDelayed(new Runnable() { @Override public void run() { int count = footerIndex + 3; for (int i = footerIndex; i < count; i++) { groups.add("上拉group = " + count); List child = new ArrayList<>(); for (int j = 0; j < 3; j++) { child.add("上拉child = " + count + ":" + j); } childs.add(0, child); } footerIndex = count; adapter.notifyDataSetChanged(); setLoading(false); } }, 2000); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { groups.clear(); childs.clear(); adapter.notifyDataSetChanged(); return super.onOptionsItemSelected(item); } class MyExpandableListAdapter extends BaseExpandableListAdapter { private LayoutInflater inflater; public MyExpandableListAdapter(Context context) { inflater = LayoutInflater.from(context); } @Override public int getGroupCount() { return groups.size(); } @Override public int getChildrenCount(int groupPosition) { return childs.get(groupPosition).size(); } @Override public String getGroup(int groupPosition) { return groups.get(groupPosition); } @Override public String getChild(int groupPosition, int childPosition) { return childs.get(groupPosition).get(childPosition); } @Override public long getGroupId(int groupPosition) { return 0; } @Override public long getChildId(int groupPosition, int childPosition) { return 0; } @Override public boolean hasStableIds() { return false; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { View view = inflater.inflate(android.R.layout.simple_expandable_list_item_1, parent, false); TextView tv = (TextView) view.findViewById(android.R.id.text1); tv.setText(getGroup(groupPosition)); return view; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { View view = inflater.inflate(android.R.layout.simple_expandable_list_item_2, parent, false); TextView tv = (TextView) view.findViewById(android.R.id.text1); tv.setText(getChild(groupPosition, childPosition)); tv.setTextColor(Color.RED); return view; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } } } ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/app/AppListFragment.java ================================================ package com.mylhyl.crlayout.sample.app; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.Toast; import com.bumptech.glide.Glide; import com.litesuits.http.LiteHttp; import com.litesuits.http.listener.HttpListener; import com.litesuits.http.request.AbstractRequest; import com.litesuits.http.request.StringRequest; import com.litesuits.http.request.param.HttpMethods; import com.litesuits.http.response.Response; import com.mylhyl.crlayout.internal.LoadConfig; import com.mylhyl.crlayout.app.SwipeRefreshListFragment; import com.mylhyl.crlayout.sample.R; import com.mylhyl.cygadapter.CygAdapter; import com.mylhyl.cygadapter.CygViewHolder; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by hupei on 2016/5/13. */ public class AppListFragment extends SwipeRefreshListFragment { private static final String URL = "http://image.baidu.com/"; private static final String REGEX_IMG = " adapter; private List objects = new ArrayList<>(); private LiteHttp liteHttp; private int index; public static AppListFragment newInstance() { return new AppListFragment(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); getSwipeRefreshLayout().setLoadAnimator(true); setEnabledLoad(true); adapter = new CygAdapter(getContext(), R.layout.image_item, objects) { @Override public void onBindData(CygViewHolder viewHolder, String item, int position) { ImageView imageView = viewHolder.findViewById(R.id.img_item); Glide.with(mContext) .load(item.toString()) .into(imageView); } }; setListAdapter(adapter); setEmptyText("无数据"); LoadConfig loadConfig = getSwipeRefreshLayout().getLoadConfig(); loadConfig.setLoadCompletedText("亲,数据加载完了!"); if (liteHttp == null) { liteHttp = LiteHttp.build(getContext()) .setSocketTimeout(5000) .setConnectTimeout(5000) .create(); } else { liteHttp.getConfig() .setSocketTimeout(5000) .setConnectTimeout(5000); } autoRefresh(R.color.colorPrimary); } @Override public void onListItemClick(AdapterView parent, View view, int position, long id) { super.onListItemClick(parent, view, position, id); Toast.makeText(getContext(), "" + position, Toast.LENGTH_SHORT).show(); } @Override public void onRefresh() { index = 0; adapter.clear(true); executeAsync(URL); getSwipeRefreshLayout().postDelayed(new Runnable() { @Override public void run() { setRefreshing(false); } }, 1000); } @Override public void onListLoad() { executeAsync(URL); getSwipeRefreshLayout().postDelayed(new Runnable() { @Override public void run() { setLoading(false); ++index; if (index == 1) { getSwipeRefreshLayout().setLoadCompleted(true); } } }, 1000); } private void executeAsync(String url) { StringRequest stringRequest = new StringRequest(url).setMethod(HttpMethods.Get) .setHttpListener(new HttpListener() { @Override public void onLoading(AbstractRequest request, long total, long len) { super.onLoading(request, total, len); } @Override public void onSuccess(String s, Response response) { String result = response.getResult(); List imgSrcList = getImgSrcList(result); adapter.addAll(imgSrcList); } @Override public void onStart(AbstractRequest request) { super.onStart(request); } @Override public void onUploading(AbstractRequest request, long total, long len) { super.onUploading(request, total, len); } }); liteHttp.executeAsync(stringRequest); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { objects.clear(); adapter.notifyDataSetChanged(); return super.onOptionsItemSelected(item); } private static List getImgSrcList(String htmlStr) { List pics = new ArrayList<>(); Pattern pImage = Pattern.compile(REGEX_IMG, Pattern.CASE_INSENSITIVE); Matcher mImage = pImage.matcher(htmlStr); while (mImage.find()) { String src = mImage.group(1); if (src.length() < 100) { pics.add("http://" + src + ".jpg"); } } return pics; } } ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/app/GridViewFragment.java ================================================ package com.mylhyl.crlayout.sample.app; import android.graphics.Color; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.Toast; import com.mylhyl.crlayout.internal.LoadConfig; import com.mylhyl.crlayout.SwipeRefreshAdapterView; import com.mylhyl.crlayout.SwipeRefreshGridView; import com.mylhyl.crlayout.sample.R; import java.util.ArrayList; import java.util.List; public class GridViewFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, SwipeRefreshAdapterView.OnListLoadListener, AdapterView.OnItemClickListener { private SwipeRefreshGridView swipeRefreshGridView; private ArrayAdapter adapter; private List objects = new ArrayList<>(); private int index; private int footerIndex = 38; public GridViewFragment() { } public static GridViewFragment newInstance() { GridViewFragment fragment = new GridViewFragment(); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_grid_view, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); swipeRefreshGridView = (SwipeRefreshGridView) view.findViewById(R.id.swipeRefresh); ImageView emptyView = new ImageView(getContext()); emptyView.setImageResource(R.mipmap.empty); swipeRefreshGridView.setEmptyView(emptyView); swipeRefreshGridView.setLoadAnimator(true); swipeRefreshGridView.setLoadLayoutResource(R.layout.swipe_refresh_footer); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); swipeRefreshGridView.setOnItemClickListener(this); swipeRefreshGridView.setOnListLoadListener(this); swipeRefreshGridView.setOnRefreshListener(this); LoadConfig loadConfig = swipeRefreshGridView.getLoadConfig(); loadConfig.setLoadText("加载更多数据..."); loadConfig.setLoadTextSize(18); loadConfig.setLoadTextColor(Color.GREEN); for (int i = 0; i < footerIndex; i++) { objects.add("Grid数据 = " + i); } adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, objects); swipeRefreshGridView.setAdapter(adapter); } @Override public void onRefresh() { index = 0; swipeRefreshGridView.postDelayed(new Runnable() { @Override public void run() { objects.add(0, "下拉 = " + (--index)); adapter.notifyDataSetChanged(); swipeRefreshGridView.setRefreshing(false); } }, 1000); } @Override public void onListLoad() { ++index; swipeRefreshGridView.postDelayed(new Runnable() { @Override public void run() { int count = footerIndex + 15; for (int i = footerIndex; i < count; i++) { objects.add("上拉 = " + i); } footerIndex = count; adapter.notifyDataSetChanged(); swipeRefreshGridView.setLoading(false); if (index == 1) { swipeRefreshGridView.setLoadCompleted(true); } } }, 2000); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { objects.clear(); adapter.notifyDataSetChanged(); return super.onOptionsItemSelected(item); } @Override public void onItemClick(AdapterView parent, View view, int position, long id) { Toast.makeText(getContext(), "" + position, Toast.LENGTH_SHORT).show(); } } ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/app/ListViewFragment.java ================================================ package com.mylhyl.crlayout.sample.app; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.widget.SwipeRefreshLayout; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.TextView; import android.widget.Toast; import com.mylhyl.crlayout.SwipeRefreshAdapterView; import com.mylhyl.crlayout.SwipeRefreshListView; import com.mylhyl.crlayout.internal.LoadConfig; import com.mylhyl.crlayout.sample.R; import java.util.ArrayList; import java.util.List; public class ListViewFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, SwipeRefreshAdapterView.OnListLoadListener, AdapterView.OnItemClickListener { private SwipeRefreshListView swipeRefreshListView; private ArrayAdapter adapter; private List objects = new ArrayList<>(); private int index; private int pagerSize = 20; public ListViewFragment() { } public static ListViewFragment newInstance() { ListViewFragment fragment = new ListViewFragment(); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_list_view, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); swipeRefreshListView = (SwipeRefreshListView) view.findViewById(R.id.swipeRefresh); swipeRefreshListView.getSwipeRefreshLayout().setColorSchemeResources(R.color.colorPrimary); swipeRefreshListView.setEnabled(false); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); swipeRefreshListView.setOnItemClickListener(this); swipeRefreshListView.setOnListLoadListener(this); swipeRefreshListView.setOnRefreshListener(this); initListViewHead(); LoadConfig loadConfig = swipeRefreshListView.getLoadConfig(); loadConfig.setLoadViewBackgroundColor(getResources().getColor(android.R.color.darker_gray)); // swipeRefreshListView.setEmptyText("数据呢?"); for (int i = 0; i < pagerSize; i++) { objects.add("数据 = " + i); } adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, objects); swipeRefreshListView.setAdapter(adapter); } private int mCurrentPosition; private ViewPager mViewPager; private final Handler mAutoPlayHandler = new Handler() { @Override public void handleMessage(Message msg) { mCurrentPosition++; if (mViewPager != null) mViewPager.setCurrentItem(mCurrentPosition); mAutoPlayHandler.sendEmptyMessageDelayed(1000, 3000); } }; private void initListViewHead() { if (mViewPager == null) { mViewPager = new ViewPager(getContext()); mViewPager.setLayoutParams(new AbsListView.LayoutParams( AbsListView.LayoutParams.MATCH_PARENT, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics()))); } mViewPager.setAdapter(new PagerAdapter() { @Override public int getCount() { return 4 + 2; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public void destroyItem(ViewGroup container, int position, Object object) { } @Override public Object instantiateItem(ViewGroup container, int position) { int toRealPosition = toRealPosition(position); TextView textView = (TextView) container.getChildAt(toRealPosition); if (textView == null) { textView = new TextView(getContext()); textView.setTextColor(Color.RED); textView.setTextSize(18); textView.setGravity(Gravity.CENTER); container.addView(textView); } textView.setText("position=" + toRealPosition); return textView; } }); mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { mCurrentPosition = position % (4 + 2); } @Override public void onPageScrollStateChanged(int state) { if (state == ViewPager.SCROLL_STATE_IDLE) { int current = mViewPager.getCurrentItem(); int last = mViewPager.getAdapter().getCount() - 2; if (current == 0) { mViewPager.setCurrentItem(last, false); } else if (current == last + 1) { mViewPager.setCurrentItem(1, false); } } } }); mViewPager.setCurrentItem(1, false); swipeRefreshListView.getScrollView().addHeaderView(mViewPager); mAutoPlayHandler.sendEmptyMessageDelayed(1000, 3000); } private int toRealPosition(int position) { int realPosition = (position - 1) % 4; if (realPosition < 0) realPosition += 4; return realPosition; } @Override public void onDestroyView() { if (mAutoPlayHandler != null) mAutoPlayHandler.removeMessages(1000); super.onDestroyView(); } @Override public void onRefresh() { index = 0; swipeRefreshListView.postDelayed(new Runnable() { @Override public void run() { objects.add(0, "下拉 = " + (--index)); adapter.notifyDataSetChanged(); swipeRefreshListView.setRefreshing(false); } }, 1000); } @Override public void onListLoad() { ++index; swipeRefreshListView.postDelayed(new Runnable() { @Override public void run() { int count = pagerSize + 10; for (int i = pagerSize; i < count; i++) { objects.add("上拉 = " + i); } pagerSize = count; adapter.notifyDataSetChanged(); swipeRefreshListView.setLoading(false); if (index == 1) { swipeRefreshListView.setLoadCompleted(true); } } }, 1000); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { objects.clear(); adapter.notifyDataSetChanged(); return super.onOptionsItemSelected(item); } @Override public void onItemClick(AdapterView parent, View view, int position, long id) { //有head,position-1才是真实item Toast.makeText(getContext(), "" + (position - 1), Toast.LENGTH_SHORT).show(); } } ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/app/RecyclerViewFragment.java ================================================ package com.mylhyl.crlayout.sample.app; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.mylhyl.crlayout.SwipeRefreshAdapterView; import com.mylhyl.crlayout.SwipeRefreshRecyclerView; import com.mylhyl.crlayout.sample.R; import java.util.ArrayList; import java.util.List; public class RecyclerViewFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, SwipeRefreshAdapterView.OnListLoadListener { private SwipeRefreshRecyclerView swipeRefreshRecyclerView; private RecyclerViewAdapter adapter; private List objects = new ArrayList<>(); private int index; private int footerIndex = 10; public RecyclerViewFragment() { } public static RecyclerViewFragment newInstance() { RecyclerViewFragment fragment = new RecyclerViewFragment(); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_recycler_view, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); swipeRefreshRecyclerView = (SwipeRefreshRecyclerView) view.findViewById(R.id.swipeRefresh); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); swipeRefreshRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); swipeRefreshRecyclerView.setOnListLoadListener(this); swipeRefreshRecyclerView.setOnRefreshListener(this); for (int i = 0; i < footerIndex; i++) { objects.add("数据 = " + i); } adapter = new RecyclerViewAdapter(); swipeRefreshRecyclerView.setAdapter(adapter); swipeRefreshRecyclerView.setEmptyText("数据又没有了!"); } @Override public void onRefresh() { index = 0; swipeRefreshRecyclerView.postDelayed(new Runnable() { @Override public void run() { objects.add(0, "下拉 = " + (--index)); adapter.notifyDataSetChanged(); swipeRefreshRecyclerView.setRefreshing(false); } }, 1000); } @Override public void onListLoad() { ++index; // swipeRefreshRecyclerView.postDelayed(new Runnable() { // @Override // public void run() { int count = footerIndex + 5; for (int i = footerIndex; i < count; i++) { objects.add("上拉 = " + i); } footerIndex = count; adapter.notifyDataSetChanged(); swipeRefreshRecyclerView.setLoading(false); // if (index == 1) { // swipeRefreshRecyclerView.setLoadCompleted(true); // } // } // }, 2000); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.menu) { objects.clear(); adapter.notifyDataSetChanged(); } else if (item.getItemId() == R.id.menu_reset) { objects.clear(); for (int i = 0; i < 5; i++) { objects.add("重置数据 = " + i); } adapter = new RecyclerViewAdapter(); swipeRefreshRecyclerView.setAdapter(adapter); } return super.onOptionsItemSelected(item); } class RecyclerViewAdapter extends RecyclerView.Adapter { @Override public int getItemCount() { return objects.size(); } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { MyViewHolder holder = new MyViewHolder(LayoutInflater.from( getContext()).inflate(R.layout.fragment_recycler_view_item, parent, false)); return holder; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ((MyViewHolder) holder).tv.setText(objects.get(position)); } class MyViewHolder extends RecyclerView.ViewHolder { TextView tv; public MyViewHolder(View view) { super(view); tv = (TextView) view.findViewById(android.R.id.text1); } } } } ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/app/WebViewFragment.java ================================================ package com.mylhyl.crlayout.sample.app; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.webkit.WebView; import android.webkit.WebViewClient; import com.mylhyl.crlayout.SwipeRefreshWebView; import com.mylhyl.crlayout.sample.R; public class WebViewFragment extends Fragment { private SwipeRefreshWebView swipeRefreshWebView; public WebViewFragment() { } public static WebViewFragment newInstance() { WebViewFragment fragment = new WebViewFragment(); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_web_view, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); swipeRefreshWebView = (SwipeRefreshWebView) view.findViewById(R.id.swipeRefresh); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); swipeRefreshWebView.autoRefresh(R.color.colorPrimary); WebView scrollView = swipeRefreshWebView.getScrollView(); scrollView.loadUrl("https://github.com/mylhyl"); scrollView.setWebViewClient(new SampleWebViewClient()); } private class SampleWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { swipeRefreshWebView.autoRefresh(); view.loadUrl(url); return true; } } } ================================================ FILE: sample/src/main/java/com/mylhyl/crlayout/sample/widget/MySwipeRefreshGridView.java ================================================ package com.mylhyl.crlayout.sample.widget; import android.content.Context; import android.util.AttributeSet; import com.mylhyl.crlayout.SwipeRefreshGridView; import com.mylhyl.crlayout.sample.R; /** * Created by hupei on 2016/5/16. */ public class MySwipeRefreshGridView extends SwipeRefreshGridView { public MySwipeRefreshGridView(Context context) { super(context); } public MySwipeRefreshGridView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected int getLoadLayoutResource() { return R.layout.swipe_refresh_footer; } } ================================================ FILE: sample/src/main/res/drawable/footer_progressbar.xml ================================================ ================================================ FILE: sample/src/main/res/drawable/selector_list.xml ================================================ ================================================ FILE: sample/src/main/res/layout/fragment_grid_view.xml ================================================ ================================================ FILE: sample/src/main/res/layout/fragment_list_view.xml ================================================ ================================================ FILE: sample/src/main/res/layout/fragment_recycler_view.xml ================================================ ================================================ FILE: sample/src/main/res/layout/fragment_recycler_view_item.xml ================================================ ================================================ FILE: sample/src/main/res/layout/fragment_types.xml ================================================ ================================================ FILE: sample/src/main/res/layout/fragment_web_view.xml ================================================ ================================================ FILE: sample/src/main/res/layout/image_item.xml ================================================ ================================================ FILE: sample/src/main/res/layout/swipe_refresh_footer.xml ================================================ ================================================ FILE: sample/src/main/res/menu/menu.xml ================================================

================================================ FILE: sample/src/main/res/values/array.xml ================================================ ListView GridView RecyclerView WebView AppListFragment AppExpandableListFragment ================================================ FILE: sample/src/main/res/values/colors.xml ================================================ #3F51B5 #303F9F #FF4081 ================================================ FILE: sample/src/main/res/values/dimens.xml ================================================ 16dp 16dp ================================================ FILE: sample/src/main/res/values/strings.xml ================================================ CommonRefreshLayout Hello blank fragment ================================================ FILE: sample/src/main/res/values/styles.xml ================================================ ================================================ FILE: sample/src/main/res/values-w820dp/dimens.xml ================================================ 64dp ================================================ FILE: sample/src/test/java/com/mylhyl/crlayout/sample/ExampleUnitTest.java ================================================ package com.mylhyl.crlayout.sample; import org.junit.Test; import static org.junit.Assert.*; /** * To work on unit tests, switch the Test Artifact in the Build Variants view. */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } } ================================================ FILE: settings.gradle ================================================ include ':sample', ':commonrefreshlayout'