├── .gitignore ├── BaseRecyclerAndAdapter ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── itheima │ │ └── recycler │ │ ├── L.java │ │ ├── adapter │ │ ├── BaseLoadMoreRecyclerAdapter.java │ │ └── BaseRecyclerAdapter.java │ │ ├── bean │ │ ├── BasePageBean.java │ │ └── SwipeRefreshBean.java │ │ ├── header │ │ └── RecyclerViewHeader.java │ │ ├── listener │ │ ├── ItemClickSupport.java │ │ └── PullToMoreListener.java │ │ ├── viewholder │ │ └── BaseRecyclerViewHolder.java │ │ └── widget │ │ ├── BaseSwipeRefreshHeaderRecyclerView.java │ │ ├── ItheimaHeaderRecyclerView.java │ │ ├── ItheimaRecyclerView.java │ │ ├── PullToLoadMoreRecyclerView.java │ │ ├── RecyclerViewHeader.java │ │ └── SwipeRefreshHeaderRecyclerView.java │ └── res │ ├── layout │ ├── itheima_header_recyclerview_layout.xml │ └── itheima_item_loadmore_layout.xml │ └── values │ ├── attrs.xml │ ├── color.xml │ └── ids.xml ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── jitpack.png ├── loadMoreAdapter.png └── recyclerViewHeader.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | /.idea 11 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'android-apt' 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "25.0.0" 6 | 7 | defaultConfig { 8 | minSdkVersion 11 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile 'com.android.support:appcompat-v7:24.2.1' 26 | compile 'com.android.support:recyclerview-v7:24.2.1' 27 | compile 'com.jakewharton:butterknife:8.4.0' 28 | apt 'com.jakewharton:butterknife-compiler:8.4.0' 29 | compile 'com.github.open-android:RetrofitUtils:0.4.13' 30 | } 31 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\_tools\_java\android\android-sdk\android-sdk-windows/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/L.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler; 2 | 3 | import android.util.Log; 4 | 5 | 6 | public class L { 7 | 8 | public static boolean isDebug = false; 9 | private static final String TAG = "TAG_ADAPTER"; 10 | 11 | public static void i(String tag, String message) { 12 | if (isDebug) { 13 | Log.i(tag, message); 14 | } 15 | } 16 | 17 | public static void i(String message) { 18 | i(TAG, message); 19 | } 20 | 21 | public static void e(String tag, String message) { 22 | if (isDebug) { 23 | Log.e(tag, message); 24 | } 25 | } 26 | 27 | public static void e(String message) { 28 | e(TAG, message); 29 | } 30 | 31 | public static void e(String tag, String message, Throwable e) { 32 | if (isDebug) { 33 | Log.e(tag, message, e); 34 | } 35 | 36 | 37 | } 38 | 39 | public static void e(String tag, Throwable e) { 40 | e(tag, "", e); 41 | } 42 | 43 | public static void e(Throwable e, String message) { 44 | e(TAG, message, e); 45 | } 46 | 47 | public static void e(Throwable e) { 48 | e(TAG, "", e); 49 | } 50 | 51 | 52 | public static void isDebug(boolean isDebug) { 53 | L.isDebug = isDebug; 54 | } 55 | 56 | 57 | 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/adapter/BaseLoadMoreRecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.adapter; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.text.TextUtils; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ProgressBar; 8 | import android.widget.TextView; 9 | 10 | import org.itheima.recycler.R; 11 | import org.itheima.recycler.listener.PullToMoreListener; 12 | import org.itheima.recycler.viewholder.BaseRecyclerViewHolder; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * Created by lyl on 2016/10/7. 18 | */ 19 | 20 | public class BaseLoadMoreRecyclerAdapter extends BaseRecyclerAdapter { 21 | //加载更多类型 22 | protected final int ITHEIMA_FOOT_TYPE = "ITHEIMA_FOOT_TYPE".hashCode(); 23 | 24 | protected PullToMoreListener mPullAndMoreListener; 25 | 26 | 27 | public BaseLoadMoreRecyclerAdapter(RecyclerView recyclerView, Class viewHolderClazz, int itemResId, List datas) { 28 | super(recyclerView, viewHolderClazz, itemResId, datas); 29 | 30 | } 31 | 32 | @Override 33 | public int getItemViewType(int position) { 34 | return (getItemCount() - 1 == position) ? ITHEIMA_FOOT_TYPE : super.getItemViewType(position); 35 | } 36 | 37 | @Override 38 | public int getItemCount() { 39 | int itemCount = super.getItemCount(); 40 | return itemCount == 0 ? 0 : itemCount + 1; 41 | } 42 | 43 | @Override 44 | public final BaseRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 45 | if (viewType == ITHEIMA_FOOT_TYPE) { 46 | return new LoadMoreViewHolder(parent, R.layout.itheima_item_loadmore_layout); 47 | } 48 | return super.onCreateViewHolder(parent, viewType); 49 | } 50 | 51 | @Override 52 | public void onBindViewHolder(BaseRecyclerViewHolder holder, int position) { 53 | if (position == mItemCount) { 54 | holder.onBindData(position, null); 55 | } else { 56 | super.onBindViewHolder(holder, position); 57 | } 58 | } 59 | 60 | public void setPullAndMoreListener(PullToMoreListener listener) { 61 | mPullAndMoreListener = listener; 62 | } 63 | 64 | 65 | public class LoadMoreViewHolder extends BaseRecyclerViewHolder { 66 | 67 | ProgressBar mProgressBar; 68 | 69 | TextView tvLoading; 70 | 71 | public LoadMoreViewHolder(ViewGroup parentView, int itemResId) { 72 | super(parentView, itemResId); 73 | mProgressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar); 74 | tvLoading = (TextView) itemView.findViewById(R.id.tv_loading); 75 | } 76 | 77 | @Override 78 | protected void onBindRealData() { 79 | if (mPullAndMoreListener != null) { 80 | mPullAndMoreListener.onRefreshLoadMore(this); 81 | } 82 | } 83 | 84 | public void loading(String txt) { 85 | mProgressBar.setVisibility(View.VISIBLE); 86 | tvLoading.setText(TextUtils.isEmpty(txt) ? "加载中..." : txt); 87 | } 88 | 89 | public void loadingFinish(String txt) { 90 | mProgressBar.setVisibility(View.GONE); 91 | tvLoading.setText(TextUtils.isEmpty(txt) ? "没有更多数据" : txt); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/adapter/BaseRecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.adapter; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.ViewGroup; 5 | 6 | import org.itheima.recycler.L; 7 | import org.itheima.recycler.viewholder.BaseRecyclerViewHolder; 8 | 9 | import java.lang.reflect.Constructor; 10 | import java.lang.reflect.ParameterizedType; 11 | import java.lang.reflect.Type; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * 通过反射创建viewHolder 17 | * Created by lyl on 2016/10/3. 18 | */ 19 | 20 | public class BaseRecyclerAdapter extends RecyclerView.Adapter { 21 | protected List mDatas; 22 | protected int mItemCount; 23 | protected int mItemResId; 24 | 25 | protected Class mViewHolderClazz; 26 | 27 | /** 28 | * @param recyclerView 29 | * @param viewHolderClazz 30 | * @param itemResId recyclerView条目的资源id 31 | * @param datas recyclerView展示的数据集合(可以传null) 32 | */ 33 | public BaseRecyclerAdapter(RecyclerView recyclerView, Class viewHolderClazz, int itemResId, List datas) { 34 | mDatas = datas != null ? datas : new ArrayList(); 35 | mItemResId = itemResId; 36 | if (recyclerView != null) { 37 | recyclerView.setAdapter(this); 38 | } 39 | mViewHolderClazz = viewHolderClazz; 40 | } 41 | 42 | @Override 43 | public BaseRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 44 | // return ViewHolderFactory.onCreateRealViewHolder(parent, mItemResId); 45 | try { 46 | Constructor con = mViewHolderClazz.getConstructor(ViewGroup.class, int.class); 47 | return con.newInstance(parent, mItemResId); 48 | } catch (Exception e) { 49 | L.e(e); 50 | return null; 51 | } 52 | 53 | } 54 | 55 | @Override 56 | public void onBindViewHolder(BaseRecyclerViewHolder holder, int position) { 57 | holder.onBindData(position, mDatas.get(position)); 58 | } 59 | 60 | /** 61 | * @param isLoadMore 数据是否累加 62 | * @param datas 数据 63 | */ 64 | public void addDatas(boolean isLoadMore, List datas) { 65 | if (!isLoadMore) { 66 | clearAllData(); 67 | } 68 | if (datas != null && datas.size() > 0) { 69 | mDatas.addAll(datas); 70 | notifyDataSetChanged(); 71 | } 72 | } 73 | 74 | public void clearAllData() { 75 | if (mDatas != null && !mDatas.isEmpty()) { 76 | mDatas.clear(); 77 | } 78 | } 79 | 80 | 81 | @Override 82 | public int getItemCount() { 83 | mItemCount = mDatas != null ? mDatas.size() : 0; 84 | return mItemCount; 85 | } 86 | 87 | public Class getClazz() { 88 | Type mySuperClass = getClass().getGenericSuperclass(); 89 | Type type = ((ParameterizedType) mySuperClass).getActualTypeArguments()[0]; 90 | return type.getClass(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/bean/BasePageBean.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.bean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 分页的基类bean 7 | * Created by lyl on 2016/10/7. 8 | */ 9 | 10 | public abstract class BasePageBean { 11 | //@SerializedName("totalCount") 12 | public int totalCount = 0; 13 | public int currentPage = 1; 14 | public int totalPage = 0; 15 | public int pageSize = 20; 16 | 17 | public abstract List getItemDatas(); 18 | 19 | public int getTotalCount() { 20 | return totalCount; 21 | } 22 | 23 | public int getCurrentPage() { 24 | return currentPage; 25 | } 26 | 27 | public int getTotalPage() { 28 | return totalPage; 29 | } 30 | 31 | public int getPageSize() { 32 | return pageSize; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/bean/SwipeRefreshBean.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.bean; 2 | 3 | import org.itheima.recycler.viewholder.BaseRecyclerViewHolder; 4 | 5 | /** 6 | * Created by lyl on 2016/11/21. 7 | */ 8 | 9 | public class SwipeRefreshBean { 10 | 11 | public int recyclerViewItemResId; 12 | 13 | public Class viewHolderClazz; 14 | 15 | 16 | public Class httpResponseBeanClazz; 17 | 18 | public String apiUrl; 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/header/RecyclerViewHeader.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.header; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.support.annotation.CallSuper; 6 | import android.support.annotation.IntDef; 7 | import android.support.annotation.NonNull; 8 | import android.support.annotation.Nullable; 9 | import android.support.v7.widget.GridLayoutManager; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.RecyclerView; 12 | import android.support.v7.widget.StaggeredGridLayoutManager; 13 | import android.util.AttributeSet; 14 | import android.view.MotionEvent; 15 | import android.view.View; 16 | import android.widget.RelativeLayout; 17 | 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | 21 | public class RecyclerViewHeader extends RelativeLayout { 22 | 23 | @Visibility 24 | private int intendedVisibility = VISIBLE; 25 | private int downTranslation; 26 | private boolean hidden = false; 27 | private boolean recyclerWantsTouch; 28 | private boolean isVertical; 29 | private boolean isAttachedToRecycler; 30 | private RecyclerViewDelegate recyclerView; 31 | private LayoutManagerDelegate layoutManager; 32 | 33 | public RecyclerViewHeader(Context context) { 34 | super(context); 35 | } 36 | 37 | public RecyclerViewHeader(Context context, AttributeSet attrs) { 38 | super(context, attrs); 39 | } 40 | 41 | public RecyclerViewHeader(Context context, AttributeSet attrs, int defStyle) { 42 | super(context, attrs, defStyle); 43 | } 44 | 45 | /** 46 | * Attaches RecyclerViewHeader to RecyclerView. 47 | * Be sure that setLayoutManager(...) has been called for RecyclerView before calling this method. 48 | * 49 | * @param recycler RecyclerView to attach RecyclerViewHeader to. 50 | */ 51 | public final void attachTo(@NonNull final RecyclerView recycler) { 52 | validate(recycler); 53 | this.recyclerView = RecyclerViewDelegate.with(recycler); 54 | this.layoutManager = LayoutManagerDelegate.with(recycler.getLayoutManager()); 55 | isVertical = layoutManager.isVertical(); 56 | isAttachedToRecycler = true; 57 | recyclerView.setHeaderDecoration(new HeaderItemDecoration()); 58 | recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 59 | @Override 60 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 61 | onScrollChanged(); 62 | } 63 | }); 64 | recyclerView.setOnChildAttachListener(new RecyclerView.OnChildAttachStateChangeListener() { 65 | @Override 66 | public void onChildViewAttachedToWindow(View view) { 67 | } 68 | 69 | @Override 70 | public void onChildViewDetachedFromWindow(View view) { 71 | recycler.post(new Runnable() { 72 | @Override 73 | public void run() { 74 | recyclerView.invalidateItemDecorations(); 75 | onScrollChanged(); 76 | } 77 | }); 78 | } 79 | }); 80 | } 81 | 82 | /** 83 | * Detaches RecyclerViewHeader from RecyclerView. 84 | */ 85 | public final void detach() { 86 | if (isAttachedToRecycler) { 87 | isAttachedToRecycler = false; 88 | recyclerWantsTouch = false; 89 | recyclerView.reset(); 90 | recyclerView = null; 91 | layoutManager = null; 92 | } 93 | } 94 | 95 | private void onScrollChanged() { 96 | hidden = recyclerView.hasItems() && !layoutManager.isFirstRowVisible(); 97 | RecyclerViewHeader.super.setVisibility(hidden ? INVISIBLE : intendedVisibility); 98 | if (!hidden) { 99 | final int translation = calculateTranslation(); 100 | if (isVertical) { 101 | setTranslationY(translation); 102 | } else { 103 | setTranslationX(translation); 104 | } 105 | } 106 | } 107 | 108 | private int calculateTranslation() { 109 | int offset = recyclerView.getScrollOffset(isVertical); 110 | int base = layoutManager.isReversed() ? recyclerView.getTranslationBase(isVertical) : 0; 111 | return base - offset; 112 | } 113 | 114 | @Override 115 | public final void setVisibility(@Visibility int visibility) { 116 | this.intendedVisibility = visibility; 117 | if (!hidden) { 118 | super.setVisibility(intendedVisibility); 119 | } 120 | } 121 | 122 | @Visibility 123 | @Override 124 | public final int getVisibility() { 125 | return intendedVisibility; 126 | } 127 | 128 | @Override 129 | protected final void onLayout(boolean changed, int l, int t, int r, int b) { 130 | super.onLayout(changed, l, t, r, b); 131 | if (changed && isAttachedToRecycler) { 132 | int verticalMargins = 0; 133 | int horizontalMargins = 0; 134 | if (getLayoutParams() instanceof MarginLayoutParams) { 135 | final MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams(); 136 | verticalMargins = layoutParams.topMargin + layoutParams.bottomMargin; 137 | horizontalMargins = layoutParams.leftMargin + layoutParams.rightMargin; 138 | } 139 | recyclerView.onHeaderSizeChanged(getHeight() + verticalMargins, getWidth() + horizontalMargins); 140 | onScrollChanged(); 141 | } 142 | } 143 | 144 | @Override 145 | @CallSuper 146 | public boolean onInterceptTouchEvent(MotionEvent ev) { 147 | recyclerWantsTouch = isAttachedToRecycler && recyclerView.onInterceptTouchEvent(ev); 148 | if (recyclerWantsTouch && ev.getAction() == MotionEvent.ACTION_MOVE) { 149 | downTranslation = calculateTranslation(); 150 | } 151 | return recyclerWantsTouch || super.onInterceptTouchEvent(ev); 152 | } 153 | 154 | @Override 155 | @CallSuper 156 | public boolean onTouchEvent(@NonNull MotionEvent event) { 157 | if (recyclerWantsTouch) { // this cannot be true if recycler is not attached 158 | int scrollDiff = downTranslation - calculateTranslation(); 159 | int verticalDiff = isVertical ? scrollDiff : 0; 160 | int horizontalDiff = isVertical ? 0 : scrollDiff; 161 | MotionEvent recyclerEvent = 162 | MotionEvent.obtain(event.getDownTime(), 163 | event.getEventTime(), 164 | event.getAction(), 165 | event.getX() - horizontalDiff, 166 | event.getY() - verticalDiff, 167 | event.getMetaState()); 168 | recyclerView.onTouchEvent(recyclerEvent); 169 | return false; 170 | } 171 | return super.onTouchEvent(event); 172 | } 173 | 174 | private void validate(RecyclerView recyclerView) { 175 | if (recyclerView.getLayoutManager() == null) { 176 | throw new IllegalStateException("Be sure to attach RecyclerViewHeader after setting your RecyclerView's LayoutManager."); 177 | } 178 | } 179 | 180 | private class HeaderItemDecoration extends RecyclerView.ItemDecoration { 181 | private int headerHeight; 182 | private int headerWidth; 183 | private int firstRowSpan; 184 | 185 | public HeaderItemDecoration() { 186 | firstRowSpan = layoutManager.getFirstRowSpan(); 187 | } 188 | 189 | public void setWidth(int width) { 190 | headerWidth = width; 191 | } 192 | 193 | public void setHeight(int height) { 194 | headerHeight = height; 195 | } 196 | 197 | @Override 198 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 199 | super.getItemOffsets(outRect, view, parent, state); 200 | final boolean headerRelatedPosition = parent.getChildLayoutPosition(view) < firstRowSpan; 201 | int heightOffset = headerRelatedPosition && isVertical ? headerHeight : 0; 202 | int widthOffset = headerRelatedPosition && !isVertical ? headerWidth : 0; 203 | if (layoutManager.isReversed()) { 204 | outRect.bottom = heightOffset; 205 | outRect.right = widthOffset; 206 | } else { 207 | outRect.top = heightOffset; 208 | outRect.left = widthOffset; 209 | } 210 | } 211 | } 212 | 213 | private static class RecyclerViewDelegate { 214 | 215 | @NonNull 216 | private final RecyclerView recyclerView; 217 | private HeaderItemDecoration decoration; 218 | private RecyclerView.OnScrollListener onScrollListener; 219 | private RecyclerView.OnChildAttachStateChangeListener onChildAttachListener; 220 | 221 | private RecyclerViewDelegate(final @NonNull RecyclerView recyclerView) { 222 | this.recyclerView = recyclerView; 223 | } 224 | 225 | public static RecyclerViewDelegate with(@NonNull RecyclerView recyclerView) { 226 | return new RecyclerViewDelegate(recyclerView); 227 | } 228 | 229 | public final void onHeaderSizeChanged(int height, int width) { 230 | if (decoration != null) { 231 | decoration.setHeight(height); 232 | decoration.setWidth(width); 233 | recyclerView.post(new Runnable() { 234 | @Override 235 | public void run() { 236 | invalidateItemDecorations(); 237 | } 238 | }); 239 | } 240 | } 241 | 242 | private void invalidateItemDecorations() { 243 | if (!recyclerView.isComputingLayout()) { 244 | recyclerView.invalidateItemDecorations(); 245 | } 246 | } 247 | 248 | public final int getScrollOffset(boolean isVertical) { 249 | return isVertical ? recyclerView.computeVerticalScrollOffset() : recyclerView.computeHorizontalScrollOffset(); 250 | } 251 | 252 | public final int getTranslationBase(boolean isVertical) { 253 | return isVertical ? 254 | recyclerView.computeVerticalScrollRange() - recyclerView.getHeight() : 255 | recyclerView.computeHorizontalScrollRange() - recyclerView.getWidth(); 256 | } 257 | 258 | public final boolean hasItems() { 259 | return recyclerView.getAdapter() != null && recyclerView.getAdapter().getItemCount() != 0; 260 | } 261 | 262 | public final void setHeaderDecoration(HeaderItemDecoration decoration) { 263 | clearHeaderDecoration(); 264 | this.decoration = decoration; 265 | recyclerView.addItemDecoration(this.decoration, 0); 266 | } 267 | 268 | public final void clearHeaderDecoration() { 269 | if (decoration != null) { 270 | recyclerView.removeItemDecoration(decoration); 271 | decoration = null; 272 | } 273 | } 274 | 275 | public final void setOnScrollListener(RecyclerView.OnScrollListener onScrollListener) { 276 | clearOnScrollListener(); 277 | this.onScrollListener = onScrollListener; 278 | recyclerView.addOnScrollListener(this.onScrollListener); 279 | } 280 | 281 | public final void clearOnScrollListener() { 282 | if (onScrollListener != null) { 283 | recyclerView.removeOnScrollListener(onScrollListener); 284 | onScrollListener = null; 285 | } 286 | } 287 | 288 | public final void setOnChildAttachListener(RecyclerView.OnChildAttachStateChangeListener onChildAttachListener) { 289 | clearOnChildAttachListener(); 290 | this.onChildAttachListener = onChildAttachListener; 291 | recyclerView.addOnChildAttachStateChangeListener(this.onChildAttachListener); 292 | } 293 | 294 | public final void clearOnChildAttachListener() { 295 | if (onChildAttachListener != null) { 296 | recyclerView.removeOnChildAttachStateChangeListener(onChildAttachListener); 297 | onChildAttachListener = null; 298 | } 299 | } 300 | 301 | public final void reset() { 302 | clearHeaderDecoration(); 303 | clearOnScrollListener(); 304 | clearOnChildAttachListener(); 305 | } 306 | 307 | public boolean onInterceptTouchEvent(MotionEvent ev) { 308 | return recyclerView.onInterceptTouchEvent(ev); 309 | } 310 | 311 | public boolean onTouchEvent(MotionEvent ev) { 312 | return recyclerView.onTouchEvent(ev); 313 | } 314 | 315 | } 316 | 317 | private static class LayoutManagerDelegate { 318 | @Nullable 319 | private final LinearLayoutManager linear; 320 | @Nullable 321 | private final GridLayoutManager grid; 322 | @Nullable 323 | private final StaggeredGridLayoutManager staggeredGrid; 324 | 325 | private LayoutManagerDelegate(@NonNull RecyclerView.LayoutManager manager) { 326 | final Class managerClass = manager.getClass(); 327 | if (managerClass == LinearLayoutManager.class) { //not using instanceof on purpose 328 | linear = (LinearLayoutManager) manager; 329 | grid = null; 330 | staggeredGrid = null; 331 | } else if (managerClass == GridLayoutManager.class) { 332 | linear = null; 333 | grid = (GridLayoutManager) manager; 334 | staggeredGrid = null; 335 | // } else if (manager instanceof StaggeredGridLayoutManager) { //TODO: 05.04.2016 implement staggered 336 | // linear = null; 337 | // grid = null; 338 | // staggeredGrid = (StaggeredGridLayoutManager) manager; 339 | } else { 340 | throw new IllegalArgumentException("Currently RecyclerViewHeader supports only LinearLayoutManager and GridLayoutManager."); 341 | } 342 | } 343 | 344 | public static LayoutManagerDelegate with(@NonNull RecyclerView.LayoutManager layoutManager) { 345 | return new LayoutManagerDelegate(layoutManager); 346 | } 347 | 348 | public final int getFirstRowSpan() { 349 | if (linear != null) { 350 | return 1; 351 | } else if (grid != null) { 352 | return grid.getSpanCount(); 353 | // } else if (staggeredGrid != null) { 354 | // return staggeredGrid.getSpanCount(); //TODO: 05.04.2016 implement staggered 355 | } 356 | return 0; //shouldn't get here 357 | } 358 | 359 | public final boolean isFirstRowVisible() { 360 | if (linear != null) { 361 | return linear.findFirstVisibleItemPosition() == 0; 362 | } else if (grid != null) { 363 | return grid.findFirstVisibleItemPosition() == 0; 364 | // } else if (staggeredGrid != null) { 365 | // return staggeredGrid.findFirstCompletelyVisibleItemPositions() //TODO: 05.04.2016 implement staggered 366 | } 367 | return false; //shouldn't get here 368 | } 369 | 370 | public final boolean isReversed() { 371 | if (linear != null) { 372 | return linear.getReverseLayout(); 373 | } else if (grid != null) { 374 | return grid.getReverseLayout(); 375 | // } else if (staggeredGrid != null) { 376 | // return ; //TODO: 05.04.2016 implement staggered 377 | } 378 | return false; //shouldn't get here 379 | } 380 | 381 | public final boolean isVertical() { 382 | if (linear != null) { 383 | return linear.getOrientation() == LinearLayoutManager.VERTICAL; 384 | } else if (grid != null) { 385 | return grid.getOrientation() == LinearLayoutManager.VERTICAL; 386 | // } else if (staggeredGrid != null) { 387 | // return ; //TODO: 05.04.2016 implement staggered 388 | } 389 | return false; //shouldn't get here 390 | } 391 | } 392 | 393 | @IntDef({VISIBLE, INVISIBLE, GONE}) 394 | @Retention(RetentionPolicy.SOURCE) 395 | private @interface Visibility { 396 | } 397 | 398 | } -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/listener/ItemClickSupport.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.listener; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | import org.itheima.recycler.R; 7 | 8 | /** 9 | * Created by mwqi on 2017/2/25. 10 | */ 11 | 12 | public class ItemClickSupport { 13 | private final RecyclerView mRecyclerView; 14 | private OnItemClickListener mOnItemClickListener; 15 | private OnItemLongClickListener mOnItemLongClickListener; 16 | private View.OnClickListener mOnClickListener = new View.OnClickListener() { 17 | @Override 18 | public void onClick(View v) { 19 | if (mOnItemClickListener != null) { 20 | RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v); 21 | mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v); 22 | } 23 | } 24 | }; 25 | private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() { 26 | @Override 27 | public boolean onLongClick(View v) { 28 | if (mOnItemLongClickListener != null) { 29 | RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v); 30 | return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v); 31 | } 32 | return false; 33 | } 34 | }; 35 | private RecyclerView.OnChildAttachStateChangeListener mAttachListener 36 | = new RecyclerView.OnChildAttachStateChangeListener() { 37 | @Override 38 | public void onChildViewAttachedToWindow(View view) { 39 | if (mOnItemClickListener != null) { 40 | view.setOnClickListener(mOnClickListener); 41 | } 42 | if (mOnItemLongClickListener != null) { 43 | view.setOnLongClickListener(mOnLongClickListener); 44 | } 45 | } 46 | 47 | @Override 48 | public void onChildViewDetachedFromWindow(View view) { 49 | 50 | } 51 | }; 52 | 53 | public ItemClickSupport(RecyclerView recyclerView) { 54 | mRecyclerView = recyclerView; 55 | mRecyclerView.setTag(R.id.item_click_support, this); 56 | mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener); 57 | } 58 | 59 | public static ItemClickSupport addTo(RecyclerView view) { 60 | ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support); 61 | if (support == null) { 62 | support = new ItemClickSupport(view); 63 | } 64 | return support; 65 | } 66 | 67 | public static ItemClickSupport removeFrom(RecyclerView view) { 68 | ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support); 69 | if (support != null) { 70 | support.detach(view); 71 | } 72 | return support; 73 | } 74 | 75 | public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) { 76 | mOnItemClickListener = listener; 77 | return this; 78 | } 79 | 80 | public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) { 81 | mOnItemLongClickListener = listener; 82 | return this; 83 | } 84 | 85 | private void detach(RecyclerView view) { 86 | view.removeOnChildAttachStateChangeListener(mAttachListener); 87 | view.setTag(R.id.item_click_support, null); 88 | } 89 | 90 | public interface OnItemClickListener { 91 | 92 | void onItemClicked(RecyclerView recyclerView, int position, View v); 93 | } 94 | 95 | public interface OnItemLongClickListener { 96 | 97 | boolean onItemLongClicked(RecyclerView recyclerView, int position, View v); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/listener/PullToMoreListener.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.listener; 2 | 3 | import android.support.v4.widget.SwipeRefreshLayout; 4 | 5 | import org.itheima.recycler.adapter.BaseLoadMoreRecyclerAdapter; 6 | 7 | /** 8 | * Created by lyl on 2016/10/7. 9 | */ 10 | 11 | public abstract class PullToMoreListener implements SwipeRefreshLayout.OnRefreshListener { 12 | /** 13 | * 加载更多 14 | */ 15 | public abstract void onRefreshLoadMore(BaseLoadMoreRecyclerAdapter.LoadMoreViewHolder holder); 16 | 17 | public void onRefresh() { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/viewholder/BaseRecyclerViewHolder.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.viewholder; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import butterknife.ButterKnife; 10 | 11 | 12 | /** 13 | * Created by lyl on 2016/10/3. 14 | */ 15 | 16 | public abstract class BaseRecyclerViewHolder extends RecyclerView.ViewHolder { 17 | protected Context mContext; 18 | protected int mPosition; 19 | protected T mData; 20 | 21 | public BaseRecyclerViewHolder(View itemView) { 22 | super(itemView); 23 | ButterKnife.bind(this, itemView); 24 | mContext = itemView.getContext().getApplicationContext(); 25 | } 26 | 27 | public BaseRecyclerViewHolder(ViewGroup parentView, int itemResId) { 28 | this(LayoutInflater.from(parentView.getContext()).inflate(itemResId, parentView, false)); 29 | } 30 | 31 | public final void onBindData(int position, T t) { 32 | this.mPosition = position; 33 | this.mData = t; 34 | onBindRealData(); 35 | } 36 | 37 | protected abstract void onBindRealData(); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/widget/BaseSwipeRefreshHeaderRecyclerView.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.support.annotation.AttrRes; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.widget.SwipeRefreshLayout; 9 | import android.util.AttributeSet; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | 13 | import org.itheima.recycler.R; 14 | 15 | /** 16 | * Created by lyl on 2016/11/20. 17 | */ 18 | 19 | public class BaseSwipeRefreshHeaderRecyclerView extends SwipeRefreshLayout { 20 | protected View mHeaderView; 21 | protected int mSpanCount; 22 | protected RecyclerViewHeader mRecyclerViewHeader; 23 | protected ItheimaRecyclerView mItheimaRecyclerView; 24 | 25 | public BaseSwipeRefreshHeaderRecyclerView(Context context) { 26 | this(context, null); 27 | } 28 | 29 | public BaseSwipeRefreshHeaderRecyclerView(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | initAttr(context, attrs, 0); 32 | initView(); 33 | 34 | } 35 | 36 | private void initAttr(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { 37 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.itheima_recyclerView, defStyleAttr, 0); 38 | if (typedArray != null) { 39 | mSpanCount = typedArray.getInt(R.styleable.itheima_recyclerView_spanCount, 0); 40 | typedArray.recycle(); 41 | } 42 | 43 | } 44 | 45 | private void initView() { 46 | mHeaderView = getChildAt(0); 47 | removeView(mHeaderView); 48 | addView(LayoutInflater.from(getContext()).inflate(R.layout.itheima_header_recyclerview_layout, this, false)); 49 | mRecyclerViewHeader = (RecyclerViewHeader) findViewById(R.id.itheima_recycerview_header); 50 | mItheimaRecyclerView = (ItheimaRecyclerView) findViewById(R.id.itheima_recyclerview); 51 | mRecyclerViewHeader.addView(mHeaderView); 52 | 53 | setSpanCount(mSpanCount); 54 | mRecyclerViewHeader.attachTo(mItheimaRecyclerView); 55 | } 56 | 57 | 58 | public void setSpanCount(int spanCount) { 59 | mItheimaRecyclerView.setSpanCount(spanCount); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/widget/ItheimaHeaderRecyclerView.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.support.annotation.AttrRes; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.util.AttributeSet; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.widget.FrameLayout; 12 | 13 | import org.itheima.recycler.R; 14 | import org.itheima.recycler.adapter.BaseRecyclerAdapter; 15 | 16 | /** 17 | * Created by lyl on 2016/11/20. 18 | */ 19 | 20 | public class ItheimaHeaderRecyclerView extends FrameLayout { 21 | 22 | private RecyclerViewHeader mRecyclerViewHeader; 23 | private ItheimaRecyclerView mItheimaRecyclerView; 24 | private int mSpanCount; 25 | 26 | private View mHeaderView; 27 | 28 | public ItheimaHeaderRecyclerView(@NonNull Context context) { 29 | this(context, null, 0); 30 | } 31 | 32 | public ItheimaHeaderRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { 33 | this(context, attrs, 0); 34 | } 35 | 36 | public ItheimaHeaderRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { 37 | super(context, attrs, defStyleAttr); 38 | initAttr(context, attrs, defStyleAttr); 39 | initView(); 40 | } 41 | 42 | private void initAttr(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { 43 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.itheima_recyclerView, defStyleAttr, 0); 44 | if (typedArray != null) { 45 | mSpanCount = typedArray.getInt(R.styleable.itheima_recyclerView_spanCount, 0); 46 | typedArray.recycle(); 47 | } 48 | 49 | } 50 | 51 | 52 | private void initView() { 53 | post(new Runnable() { 54 | @Override 55 | public void run() { 56 | mHeaderView = getChildAt(0); 57 | removeView(mHeaderView); 58 | 59 | View contentView = LayoutInflater.from(getContext()).inflate(R.layout.itheima_header_recyclerview_layout, ItheimaHeaderRecyclerView.this, false); 60 | mRecyclerViewHeader = (RecyclerViewHeader) contentView.findViewById(R.id.itheima_recycerview_header); 61 | mItheimaRecyclerView = (ItheimaRecyclerView) contentView.findViewById(R.id.itheima_recyclerview); 62 | mRecyclerViewHeader.addView(mHeaderView); 63 | addView(contentView); 64 | 65 | setSpanCount(mSpanCount); 66 | mRecyclerViewHeader.attachTo(mItheimaRecyclerView); 67 | } 68 | }); 69 | 70 | } 71 | 72 | public void setSpanCount(int spanCount) { 73 | mItheimaRecyclerView.setSpanCount(spanCount); 74 | } 75 | 76 | public void setAdapter(BaseRecyclerAdapter adapter) { 77 | mItheimaRecyclerView.setAdapter(adapter); 78 | 79 | } 80 | 81 | public ItheimaRecyclerView getRecycerView() { 82 | return mItheimaRecyclerView; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/widget/ItheimaRecyclerView.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.widget.GridLayoutManager; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.util.AttributeSet; 10 | 11 | import org.itheima.recycler.R; 12 | 13 | /** 14 | * Created by lyl on 2016/10/3. 15 | */ 16 | 17 | public class ItheimaRecyclerView extends RecyclerView { 18 | /** 19 | * 0:LinearLayoutManager.VERTICAL(默认) 20 | * 1:LinearLayoutManager.HORIZONTAL 21 | * [2,9]: 22 | */ 23 | private int mSpanCount; 24 | 25 | public ItheimaRecyclerView(Context context) { 26 | this(context, null); 27 | } 28 | 29 | public ItheimaRecyclerView(Context context, @Nullable AttributeSet attrs) { 30 | this(context, attrs, 0); 31 | } 32 | 33 | public ItheimaRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { 34 | super(context, attrs, defStyle); 35 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.itheima_recyclerView, defStyle, 0); 36 | if (typedArray != null) { 37 | mSpanCount = typedArray.getInt(R.styleable.itheima_recyclerView_spanCount, 0); 38 | typedArray.recycle(); 39 | } 40 | setSpanCount(mSpanCount); 41 | } 42 | 43 | public void setSpanCount(int spanCount) { 44 | mSpanCount = spanCount; 45 | setLayoutManagerType(); 46 | } 47 | 48 | public int getSpanCount() { 49 | return mSpanCount; 50 | } 51 | 52 | private void setLayoutManagerType() { 53 | LayoutManager layoutManager = null; 54 | if (getSpanCount() == 0) { 55 | layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); 56 | } else if (getSpanCount() == 1) {//1 57 | layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false); 58 | } else if (getSpanCount() <= 10) {//[2,10] 59 | layoutManager = new GridLayoutManager(getContext(), getSpanCount()); 60 | } else if (getSpanCount() > 10) {// >10 横向GridLayout,第二位代表行 61 | layoutManager = new GridLayoutManager(getContext(), getSpanCount() % 10, GridLayoutManager.HORIZONTAL, false); 62 | } 63 | setLayoutManager(layoutManager); 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/widget/PullToLoadMoreRecyclerView.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.widget; 2 | 3 | import android.support.v4.widget.SwipeRefreshLayout; 4 | 5 | import com.itheima.retrofitutils.ItheimaHttp; 6 | import com.itheima.retrofitutils.Request; 7 | import com.itheima.retrofitutils.listener.HttpResponseListener; 8 | 9 | import org.itheima.recycler.R; 10 | import org.itheima.recycler.adapter.BaseLoadMoreRecyclerAdapter; 11 | import org.itheima.recycler.bean.BasePageBean; 12 | import org.itheima.recycler.listener.PullToMoreListener; 13 | import org.itheima.recycler.viewholder.BaseRecyclerViewHolder; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | import okhttp3.Headers; 19 | import okhttp3.ResponseBody; 20 | import retrofit2.Call; 21 | 22 | /** 23 | * Created by lyl on 2016/10/7. 24 | */ 25 | 26 | public abstract class PullToLoadMoreRecyclerView extends PullToMoreListener { 27 | 28 | private SwipeRefreshLayout mSwipeRefreshLayout; 29 | private ItheimaRecyclerView mRecyclerView; 30 | private Class mViewHolderClazz; 31 | /** 32 | * 扩展字段 33 | */ 34 | public Object mMextendObject; 35 | 36 | private LoadingDataListener mLoadingDataListener; 37 | 38 | public PullToLoadMoreRecyclerView(SwipeRefreshLayout swipeRefreshLayout, ItheimaRecyclerView recyclerView, Class viewHolderClazz) { 39 | mSwipeRefreshLayout = swipeRefreshLayout; 40 | mRecyclerView = recyclerView; 41 | mViewHolderClazz = viewHolderClazz; 42 | initView(); 43 | initData(); 44 | } 45 | 46 | private void initView() { 47 | if (mSwipeRefreshLayout != null) { 48 | mSwipeRefreshLayout.setColorSchemeResources(getSwipeColorSchemeResources()); 49 | mSwipeRefreshLayout.setOnRefreshListener(this); 50 | } 51 | } 52 | 53 | public void setSpanCount(int spanCount) { 54 | mRecyclerView.setSpanCount(spanCount); 55 | } 56 | 57 | 58 | protected void initData() { 59 | mLoadMoreRecyclerViewAdapter = new BaseLoadMoreRecyclerAdapter(mRecyclerView, mViewHolderClazz, getItemResId(), null); 60 | mLoadMoreRecyclerViewAdapter.setPullAndMoreListener(this); 61 | } 62 | 63 | 64 | public int mCurPage = 1; 65 | public int mPageSize = 20; 66 | 67 | public int mTotalPage = 0; 68 | 69 | public Call mCall; 70 | 71 | 72 | public String mCurPageKey = "curPage"; 73 | public String mPageSizeKey = "pageSize"; 74 | 75 | public BaseLoadMoreRecyclerAdapter mLoadMoreRecyclerViewAdapter; 76 | 77 | public abstract int getItemResId(); 78 | 79 | public abstract String getApi(); 80 | 81 | public int[] getSwipeColorSchemeResources() { 82 | return new int[]{R.color.colorPrimary}; 83 | } 84 | 85 | Map mParamMap = new HashMap<>(); 86 | Map mHeaderMap = new HashMap<>(); 87 | 88 | public Map putParam(String key, Object value) { 89 | mParamMap.put(key, value); 90 | return mParamMap; 91 | } 92 | 93 | public Map putHeader(String key, Object value) { 94 | mHeaderMap.put(key, value); 95 | return mHeaderMap; 96 | } 97 | 98 | 99 | @Override 100 | public void onRefresh() { 101 | if (mLoadingDataListener != null) { 102 | mLoadingDataListener.onRefresh(); 103 | } 104 | requestData(); 105 | } 106 | 107 | @Override 108 | public void onRefreshLoadMore(BaseLoadMoreRecyclerAdapter.LoadMoreViewHolder holder) { 109 | if (isMoreData(holder)) { 110 | holder.loading(null); 111 | requestData(true); 112 | } else { 113 | holder.loadingFinish(null); 114 | pullLoadFinish(); 115 | } 116 | } 117 | 118 | 119 | public void requestData() { 120 | mCurPage = 1; 121 | requestData(false); 122 | } 123 | 124 | /** 125 | * 是否有更多数据(可以更具自己的分页条件重写) 126 | */ 127 | public boolean isMoreData(BaseLoadMoreRecyclerAdapter.LoadMoreViewHolder holder) { 128 | return mCurPage <= mTotalPage; 129 | } 130 | 131 | 132 | private void requestData(final boolean isLoadMore) { 133 | if (mLoadingDataListener != null) { 134 | mLoadingDataListener.onStart(); 135 | } 136 | mParamMap.put(mCurPageKey, mCurPage); 137 | mParamMap.put(mPageSizeKey, mPageSize); 138 | Request request = ItheimaHttp.newGetRequest(getApi()); 139 | request.putParamsMap(mParamMap); 140 | 141 | if (mHeaderMap != null && mHeaderMap.size() > 0) { 142 | request.putHeaderMap(mHeaderMap); 143 | } 144 | mCall = ItheimaHttp.send(request, new HttpResponseListener() { 145 | @Override 146 | public void onResponse(HttpResponseBean responseBean, Headers headers) { 147 | mTotalPage = responseBean.getTotalPage(); 148 | mCurPage++; 149 | mLoadMoreRecyclerViewAdapter.addDatas(isLoadMore, responseBean.getItemDatas()); 150 | pullLoadFinish(); 151 | /* if (mHttpResponseCall != null) { 152 | mHttpResponseCall.onResponse(responseBean); 153 | }*/ 154 | 155 | if (mLoadingDataListener != null) { 156 | mLoadingDataListener.onSuccess(responseBean, headers); 157 | } 158 | } 159 | 160 | @Override 161 | public void onFailure(Call call, Throwable e) { 162 | super.onFailure(call, e); 163 | pullLoadFinish(); 164 | /*if (mHttpResponseCall != null) { 165 | mHttpResponseCall.onFailure(call, e); 166 | }*/ 167 | if (mLoadingDataListener != null) { 168 | mLoadingDataListener.onFailure(); 169 | } 170 | 171 | } 172 | 173 | 174 | @Override 175 | public Class getClazz() { 176 | return PullToLoadMoreRecyclerView.this.getClass(); 177 | } 178 | }); 179 | 180 | } 181 | 182 | //private HttpResponseListener mHttpResponseCall; 183 | 184 | /*public void setHttpResponseListener(HttpResponseListener call) { 185 | mHttpResponseCall = call; 186 | }*/ 187 | 188 | public void pullLoadFinish() { 189 | if (mSwipeRefreshLayout != null) { 190 | mSwipeRefreshLayout.setRefreshing(false); 191 | } 192 | } 193 | 194 | public void free() { 195 | mRecyclerView = null; 196 | if (mSwipeRefreshLayout != null) { 197 | mSwipeRefreshLayout.setRefreshing(false); 198 | mSwipeRefreshLayout = null; 199 | 200 | } 201 | if (mCall != null) { 202 | mCall.cancel(); 203 | mCall = null; 204 | } 205 | 206 | if (mLoadMoreRecyclerViewAdapter != null) { 207 | mLoadMoreRecyclerViewAdapter.setPullAndMoreListener(null); 208 | mLoadMoreRecyclerViewAdapter = null; 209 | } 210 | 211 | //mHttpResponseCall = null; 212 | mLoadingDataListener = null; 213 | } 214 | /*|||||||||||||||||||||||||||||||||||||||||||||||||||||*/ 215 | 216 | public void setCurPage(int curPage) { 217 | mCurPage = curPage; 218 | } 219 | 220 | public void setPageSize(int pageSize) { 221 | mPageSize = pageSize; 222 | } 223 | 224 | public void setTotalPage(int totalPage) { 225 | mTotalPage = totalPage; 226 | } 227 | 228 | public void setCurPageKey(String curPageKey) { 229 | mCurPageKey = curPageKey; 230 | } 231 | 232 | public void setPageSizeKey(String pageSizeKey) { 233 | mPageSizeKey = pageSizeKey; 234 | } 235 | 236 | /*///////////////////////////////////////////////////*/ 237 | public void setLoadingDataListener(LoadingDataListener loadingDataListener) { 238 | mLoadingDataListener = loadingDataListener; 239 | } 240 | 241 | /** 242 | * 监听下啦刷新 & 上啦加载更多 243 | */ 244 | public static abstract class LoadingDataListener { 245 | /** 246 | * 下啦刷新回调 247 | */ 248 | public void onRefresh() { 249 | 250 | } 251 | 252 | /** 253 | * http请求开始 254 | */ 255 | public void onStart() { 256 | } 257 | 258 | /** 259 | * http请求数据成功 260 | * 261 | * @param t 262 | */ 263 | public void onSuccess(T t, Headers headers) { 264 | } 265 | 266 | public void onFailure() { 267 | 268 | } 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/widget/RecyclerViewHeader.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.support.annotation.CallSuper; 6 | import android.support.annotation.IntDef; 7 | import android.support.annotation.NonNull; 8 | import android.support.annotation.Nullable; 9 | import android.support.v7.widget.GridLayoutManager; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.RecyclerView; 12 | import android.support.v7.widget.StaggeredGridLayoutManager; 13 | import android.util.AttributeSet; 14 | import android.view.MotionEvent; 15 | import android.view.View; 16 | import android.widget.RelativeLayout; 17 | 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | 21 | public class RecyclerViewHeader extends RelativeLayout { 22 | 23 | @Visibility 24 | private int intendedVisibility = VISIBLE; 25 | private int downTranslation; 26 | private boolean hidden = false; 27 | private boolean recyclerWantsTouch; 28 | private boolean isVertical; 29 | private boolean isAttachedToRecycler; 30 | private RecyclerViewDelegate recyclerView; 31 | private LayoutManagerDelegate layoutManager; 32 | 33 | public RecyclerViewHeader(Context context) { 34 | super(context); 35 | } 36 | 37 | public RecyclerViewHeader(Context context, AttributeSet attrs) { 38 | super(context, attrs); 39 | } 40 | 41 | public RecyclerViewHeader(Context context, AttributeSet attrs, int defStyle) { 42 | super(context, attrs, defStyle); 43 | } 44 | 45 | /** 46 | * Attaches RecyclerViewHeader to RecyclerView. 47 | * Be sure that setLayoutManager(...) has been called for RecyclerView before calling this method. 48 | * 49 | * @param recycler RecyclerView to attach RecyclerViewHeader to. 50 | */ 51 | public final void attachTo(@NonNull final RecyclerView recycler) { 52 | validate(recycler); 53 | this.recyclerView = RecyclerViewDelegate.with(recycler); 54 | this.layoutManager = LayoutManagerDelegate.with(recycler.getLayoutManager()); 55 | isVertical = layoutManager.isVertical(); 56 | isAttachedToRecycler = true; 57 | recyclerView.setHeaderDecoration(new HeaderItemDecoration()); 58 | recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { 59 | @Override 60 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 61 | onScrollChanged(); 62 | } 63 | }); 64 | recyclerView.setOnChildAttachListener(new RecyclerView.OnChildAttachStateChangeListener() { 65 | @Override 66 | public void onChildViewAttachedToWindow(View view) { 67 | } 68 | 69 | @Override 70 | public void onChildViewDetachedFromWindow(View view) { 71 | recycler.post(new Runnable() { 72 | @Override 73 | public void run() { 74 | recyclerView.invalidateItemDecorations(); 75 | onScrollChanged(); 76 | } 77 | }); 78 | } 79 | }); 80 | } 81 | 82 | /** 83 | * Detaches RecyclerViewHeader from RecyclerView. 84 | */ 85 | public final void detach() { 86 | if (isAttachedToRecycler) { 87 | isAttachedToRecycler = false; 88 | recyclerWantsTouch = false; 89 | recyclerView.reset(); 90 | recyclerView = null; 91 | layoutManager = null; 92 | } 93 | } 94 | 95 | private void onScrollChanged() { 96 | hidden = recyclerView.hasItems() && !layoutManager.isFirstRowVisible(); 97 | RecyclerViewHeader.super.setVisibility(hidden ? INVISIBLE : intendedVisibility); 98 | if (!hidden) { 99 | final int translation = calculateTranslation(); 100 | if (isVertical) { 101 | setTranslationY(translation); 102 | } else { 103 | setTranslationX(translation); 104 | } 105 | } 106 | } 107 | 108 | private int calculateTranslation() { 109 | int offset = recyclerView.getScrollOffset(isVertical); 110 | int base = layoutManager.isReversed() ? recyclerView.getTranslationBase(isVertical) : 0; 111 | return base - offset; 112 | } 113 | 114 | @Override 115 | public final void setVisibility(@Visibility int visibility) { 116 | this.intendedVisibility = visibility; 117 | if (!hidden) { 118 | super.setVisibility(intendedVisibility); 119 | } 120 | } 121 | 122 | @Visibility 123 | @Override 124 | public final int getVisibility() { 125 | return intendedVisibility; 126 | } 127 | 128 | @Override 129 | protected final void onLayout(boolean changed, int l, int t, int r, int b) { 130 | super.onLayout(changed, l, t, r, b); 131 | if (changed && isAttachedToRecycler) { 132 | int verticalMargins = 0; 133 | int horizontalMargins = 0; 134 | if (getLayoutParams() instanceof MarginLayoutParams) { 135 | final MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams(); 136 | verticalMargins = layoutParams.topMargin + layoutParams.bottomMargin; 137 | horizontalMargins = layoutParams.leftMargin + layoutParams.rightMargin; 138 | } 139 | recyclerView.onHeaderSizeChanged(getHeight() + verticalMargins, getWidth() + horizontalMargins); 140 | onScrollChanged(); 141 | } 142 | } 143 | 144 | @Override 145 | @CallSuper 146 | public boolean onInterceptTouchEvent(MotionEvent ev) { 147 | recyclerWantsTouch = isAttachedToRecycler && recyclerView.onInterceptTouchEvent(ev); 148 | if (recyclerWantsTouch && ev.getAction() == MotionEvent.ACTION_MOVE) { 149 | downTranslation = calculateTranslation(); 150 | } 151 | return recyclerWantsTouch || super.onInterceptTouchEvent(ev); 152 | } 153 | 154 | @Override 155 | @CallSuper 156 | public boolean onTouchEvent(@NonNull MotionEvent event) { 157 | if (recyclerWantsTouch) { // this cannot be true if recycler is not attached 158 | int scrollDiff = downTranslation - calculateTranslation(); 159 | int verticalDiff = isVertical ? scrollDiff : 0; 160 | int horizontalDiff = isVertical ? 0 : scrollDiff; 161 | MotionEvent recyclerEvent = 162 | MotionEvent.obtain(event.getDownTime(), 163 | event.getEventTime(), 164 | event.getAction(), 165 | event.getX() - horizontalDiff, 166 | event.getY() - verticalDiff, 167 | event.getMetaState()); 168 | recyclerView.onTouchEvent(recyclerEvent); 169 | return false; 170 | } 171 | return super.onTouchEvent(event); 172 | } 173 | 174 | private void validate(RecyclerView recyclerView) { 175 | if (recyclerView.getLayoutManager() == null) { 176 | throw new IllegalStateException("Be sure to attach RecyclerViewHeader after setting your RecyclerView's LayoutManager."); 177 | } 178 | } 179 | 180 | private class HeaderItemDecoration extends RecyclerView.ItemDecoration { 181 | private int headerHeight; 182 | private int headerWidth; 183 | private int firstRowSpan; 184 | 185 | public HeaderItemDecoration() { 186 | firstRowSpan = layoutManager.getFirstRowSpan(); 187 | } 188 | 189 | public void setWidth(int width) { 190 | headerWidth = width; 191 | } 192 | 193 | public void setHeight(int height) { 194 | headerHeight = height; 195 | } 196 | 197 | @Override 198 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 199 | super.getItemOffsets(outRect, view, parent, state); 200 | final boolean headerRelatedPosition = parent.getChildLayoutPosition(view) < firstRowSpan; 201 | int heightOffset = headerRelatedPosition && isVertical ? headerHeight : 0; 202 | int widthOffset = headerRelatedPosition && !isVertical ? headerWidth : 0; 203 | if (layoutManager.isReversed()) { 204 | outRect.bottom = heightOffset; 205 | outRect.right = widthOffset; 206 | } else { 207 | outRect.top = heightOffset; 208 | outRect.left = widthOffset; 209 | } 210 | } 211 | } 212 | 213 | private static class RecyclerViewDelegate { 214 | 215 | @NonNull 216 | private final RecyclerView recyclerView; 217 | private HeaderItemDecoration decoration; 218 | private RecyclerView.OnScrollListener onScrollListener; 219 | private RecyclerView.OnChildAttachStateChangeListener onChildAttachListener; 220 | 221 | private RecyclerViewDelegate(final @NonNull RecyclerView recyclerView) { 222 | this.recyclerView = recyclerView; 223 | } 224 | 225 | public static RecyclerViewDelegate with(@NonNull RecyclerView recyclerView) { 226 | return new RecyclerViewDelegate(recyclerView); 227 | } 228 | 229 | public final void onHeaderSizeChanged(int height, int width) { 230 | if (decoration != null) { 231 | decoration.setHeight(height); 232 | decoration.setWidth(width); 233 | recyclerView.post(new Runnable() { 234 | @Override 235 | public void run() { 236 | invalidateItemDecorations(); 237 | } 238 | }); 239 | } 240 | } 241 | 242 | private void invalidateItemDecorations() { 243 | if (!recyclerView.isComputingLayout()) { 244 | recyclerView.invalidateItemDecorations(); 245 | } 246 | } 247 | 248 | public final int getScrollOffset(boolean isVertical) { 249 | return isVertical ? recyclerView.computeVerticalScrollOffset() : recyclerView.computeHorizontalScrollOffset(); 250 | } 251 | 252 | public final int getTranslationBase(boolean isVertical) { 253 | return isVertical ? 254 | recyclerView.computeVerticalScrollRange() - recyclerView.getHeight() : 255 | recyclerView.computeHorizontalScrollRange() - recyclerView.getWidth(); 256 | } 257 | 258 | public final boolean hasItems() { 259 | return recyclerView.getAdapter() != null && recyclerView.getAdapter().getItemCount() != 0; 260 | } 261 | 262 | public final void setHeaderDecoration(HeaderItemDecoration decoration) { 263 | clearHeaderDecoration(); 264 | this.decoration = decoration; 265 | recyclerView.addItemDecoration(this.decoration, 0); 266 | } 267 | 268 | public final void clearHeaderDecoration() { 269 | if (decoration != null) { 270 | recyclerView.removeItemDecoration(decoration); 271 | decoration = null; 272 | } 273 | } 274 | 275 | public final void setOnScrollListener(RecyclerView.OnScrollListener onScrollListener) { 276 | clearOnScrollListener(); 277 | this.onScrollListener = onScrollListener; 278 | recyclerView.addOnScrollListener(this.onScrollListener); 279 | } 280 | 281 | public final void clearOnScrollListener() { 282 | if (onScrollListener != null) { 283 | recyclerView.removeOnScrollListener(onScrollListener); 284 | onScrollListener = null; 285 | } 286 | } 287 | 288 | public final void setOnChildAttachListener(RecyclerView.OnChildAttachStateChangeListener onChildAttachListener) { 289 | clearOnChildAttachListener(); 290 | this.onChildAttachListener = onChildAttachListener; 291 | recyclerView.addOnChildAttachStateChangeListener(this.onChildAttachListener); 292 | } 293 | 294 | public final void clearOnChildAttachListener() { 295 | if (onChildAttachListener != null) { 296 | recyclerView.removeOnChildAttachStateChangeListener(onChildAttachListener); 297 | onChildAttachListener = null; 298 | } 299 | } 300 | 301 | public final void reset() { 302 | clearHeaderDecoration(); 303 | clearOnScrollListener(); 304 | clearOnChildAttachListener(); 305 | } 306 | 307 | public boolean onInterceptTouchEvent(MotionEvent ev) { 308 | return recyclerView.onInterceptTouchEvent(ev); 309 | } 310 | 311 | public boolean onTouchEvent(MotionEvent ev) { 312 | return recyclerView.onTouchEvent(ev); 313 | } 314 | 315 | } 316 | 317 | private static class LayoutManagerDelegate { 318 | @Nullable 319 | private final LinearLayoutManager linear; 320 | @Nullable 321 | private final GridLayoutManager grid; 322 | @Nullable 323 | private final StaggeredGridLayoutManager staggeredGrid; 324 | 325 | private LayoutManagerDelegate(@NonNull RecyclerView.LayoutManager manager) { 326 | final Class managerClass = manager.getClass(); 327 | if (managerClass == LinearLayoutManager.class) { //not using instanceof on purpose 328 | linear = (LinearLayoutManager) manager; 329 | grid = null; 330 | staggeredGrid = null; 331 | } else if (managerClass == GridLayoutManager.class) { 332 | linear = null; 333 | grid = (GridLayoutManager) manager; 334 | staggeredGrid = null; 335 | // } else if (manager instanceof StaggeredGridLayoutManager) { //TODO: 05.04.2016 implement staggered 336 | // linear = null; 337 | // grid = null; 338 | // staggeredGrid = (StaggeredGridLayoutManager) manager; 339 | } else { 340 | throw new IllegalArgumentException("Currently RecyclerViewHeader supports only LinearLayoutManager and GridLayoutManager."); 341 | } 342 | } 343 | 344 | public static LayoutManagerDelegate with(@NonNull RecyclerView.LayoutManager layoutManager) { 345 | return new LayoutManagerDelegate(layoutManager); 346 | } 347 | 348 | public final int getFirstRowSpan() { 349 | if (linear != null) { 350 | return 1; 351 | } else if (grid != null) { 352 | return grid.getSpanCount(); 353 | // } else if (staggeredGrid != null) { 354 | // return staggeredGrid.getSpanCount(); //TODO: 05.04.2016 implement staggered 355 | } 356 | return 0; //shouldn't get here 357 | } 358 | 359 | public final boolean isFirstRowVisible() { 360 | if (linear != null) { 361 | return linear.findFirstVisibleItemPosition() == 0; 362 | } else if (grid != null) { 363 | return grid.findFirstVisibleItemPosition() == 0; 364 | // } else if (staggeredGrid != null) { 365 | // return staggeredGrid.findFirstCompletelyVisibleItemPositions() //TODO: 05.04.2016 implement staggered 366 | } 367 | return false; //shouldn't get here 368 | } 369 | 370 | public final boolean isReversed() { 371 | if (linear != null) { 372 | return linear.getReverseLayout(); 373 | } else if (grid != null) { 374 | return grid.getReverseLayout(); 375 | // } else if (staggeredGrid != null) { 376 | // return ; //TODO: 05.04.2016 implement staggered 377 | } 378 | return false; //shouldn't get here 379 | } 380 | 381 | public final boolean isVertical() { 382 | if (linear != null) { 383 | return linear.getOrientation() == LinearLayoutManager.VERTICAL; 384 | } else if (grid != null) { 385 | return grid.getOrientation() == LinearLayoutManager.VERTICAL; 386 | // } else if (staggeredGrid != null) { 387 | // return ; //TODO: 05.04.2016 implement staggered 388 | } 389 | return false; //shouldn't get here 390 | } 391 | } 392 | 393 | @IntDef({VISIBLE, INVISIBLE, GONE}) 394 | @Retention(RetentionPolicy.SOURCE) 395 | private @interface Visibility { 396 | } 397 | 398 | } -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/java/org/itheima/recycler/widget/SwipeRefreshHeaderRecyclerView.java: -------------------------------------------------------------------------------- 1 | package org.itheima.recycler.widget; 2 | 3 | import android.content.Context; 4 | import android.support.v4.widget.SwipeRefreshLayout; 5 | import android.util.AttributeSet; 6 | 7 | import com.google.gson.annotations.SerializedName; 8 | import com.itheima.retrofitutils.ItheimaHttp; 9 | import com.itheima.retrofitutils.Request; 10 | import com.itheima.retrofitutils.RequestMethod; 11 | import com.itheima.retrofitutils.listener.HttpResponseListener; 12 | 13 | import org.itheima.recycler.L; 14 | import org.itheima.recycler.R; 15 | import org.itheima.recycler.adapter.BaseRecyclerAdapter; 16 | import org.itheima.recycler.bean.BasePageBean; 17 | import org.itheima.recycler.bean.SwipeRefreshBean; 18 | 19 | import java.lang.reflect.Field; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | import okhttp3.Headers; 24 | import okhttp3.ResponseBody; 25 | import retrofit2.Call; 26 | 27 | /** 28 | * Created by lyl on 2016/11/20. 29 | */ 30 | 31 | public class SwipeRefreshHeaderRecyclerView extends BaseSwipeRefreshHeaderRecyclerView implements SwipeRefreshLayout.OnRefreshListener { 32 | 33 | private SwipeRefreshBean mSwipeRefreshBean; 34 | 35 | public int mCurPage = 1; 36 | public int mPageSize = 20; 37 | public int mTotalPage = 0; 38 | public String mCurPageKey = "currentPage"; 39 | public String mPageSizeKey = "pageSize"; 40 | public String mTotalPageKey = "totalPage"; 41 | 42 | private RequestMethod mRequestMethod; 43 | 44 | public Call mCall; 45 | 46 | private BaseRecyclerAdapter mBaseRecyclerAdapter; 47 | 48 | private SwipeLoadingDataListener mSwipeLoadingDataListener; 49 | 50 | 51 | public SwipeRefreshHeaderRecyclerView(Context context) { 52 | this(context, null); 53 | } 54 | 55 | public SwipeRefreshHeaderRecyclerView(Context context, AttributeSet attrs) { 56 | super(context, attrs); 57 | setColorSchemeResources(R.color.colorPrimary); 58 | setOnRefreshListener(this); 59 | } 60 | 61 | @Override 62 | public void onRefresh() { 63 | if (mSwipeLoadingDataListener != null) { 64 | mSwipeLoadingDataListener.onRefresh(); 65 | } 66 | mCurPage = 1; 67 | mParamMap.put(mCurPageKey, mCurPage); 68 | requestData(false, mRequestMethod, mParamMap); 69 | } 70 | 71 | private Map mParamMap = new HashMap(); 72 | 73 | public void requestData(RequestMethod method, Map paramMap) { 74 | requestData(false, method, paramMap); 75 | 76 | } 77 | 78 | public void requestData(final boolean isLoadMore, RequestMethod method, Map paramMap) { 79 | if (mSwipeLoadingDataListener != null) { 80 | mSwipeLoadingDataListener.onStart(); 81 | } 82 | mRequestMethod = method; 83 | if (paramMap != null) { 84 | mParamMap.putAll(paramMap); 85 | } 86 | Request request = null; 87 | if (RequestMethod.GET.equals(method)) { 88 | request = ItheimaHttp.newGetRequest(mSwipeRefreshBean.apiUrl); 89 | } else { 90 | request = ItheimaHttp.newPostRequest(mSwipeRefreshBean.apiUrl); 91 | } 92 | request.putParamsMap(mParamMap); 93 | mCall = ItheimaHttp.send(request, new HttpResponseListener() { 94 | @Override 95 | public void onResponse(BasePageBean responseBean, Headers headers) { 96 | if (mSwipeLoadingDataListener != null) { 97 | mSwipeLoadingDataListener.onSuccess(responseBean, headers); 98 | } 99 | mTotalPage = responseBean.totalPage; 100 | mCurPage++; 101 | mBaseRecyclerAdapter.addDatas(isLoadMore, responseBean.getItemDatas()); 102 | } 103 | 104 | @Override 105 | public void onFailure(Call call, Throwable e) { 106 | super.onFailure(call, e); 107 | 108 | if (mSwipeLoadingDataListener != null) { 109 | mSwipeLoadingDataListener.onFailure(); 110 | } 111 | 112 | } 113 | 114 | 115 | @Override 116 | public Class getClazz() { 117 | return mSwipeRefreshBean.httpResponseBeanClazz; 118 | } 119 | }); 120 | 121 | 122 | } 123 | 124 | 125 | /* public void prepareData(SwipeRefreshBean swipeRefreshBean) { 126 | mSwipeRefreshBean = swipeRefreshBean; 127 | try { 128 | //反射获取有关于分页数据的值 129 | Field pageSizeField = mSwipeRefreshBean.httpResponseBeanClazz.getField("pageSize"); 130 | Field currentPageField = mSwipeRefreshBean.httpResponseBeanClazz.getField("currentPage"); 131 | Field totalPageField = mSwipeRefreshBean.httpResponseBeanClazz.getField("totalPage"); 132 | 133 | mPageSize = pageSizeField.getInt(20); 134 | mCurPage = currentPageField.getInt(1); 135 | //mTotalPage = totalPageField.getInt(0); 136 | 137 | SerializedName pageSizeAnnotation = pageSizeField.getAnnotation(SerializedName.class); 138 | SerializedName currentPageAnnotation = currentPageField.getAnnotation(SerializedName.class); 139 | SerializedName totalPageAnnotation = totalPageField.getAnnotation(SerializedName.class); 140 | if (pageSizeAnnotation != null) { 141 | mPageSizeKey = pageSizeAnnotation.value(); 142 | } 143 | if (currentPageAnnotation != null) { 144 | mCurPageKey = currentPageAnnotation.value(); 145 | } 146 | if (totalPageAnnotation != null) { 147 | mTotalPageKey = currentPageAnnotation.value(); 148 | } 149 | 150 | } catch (Exception e) { 151 | L.e(e); 152 | } 153 | 154 | }*/ 155 | 156 | 157 | public void setAdapter(BaseRecyclerAdapter adapter) { 158 | mBaseRecyclerAdapter = adapter; 159 | mItheimaRecyclerView.setAdapter(adapter); 160 | } 161 | 162 | public void setSwipeLoadingDataListener(SwipeLoadingDataListener swipeLoadingDataListener) { 163 | mSwipeLoadingDataListener = swipeLoadingDataListener; 164 | } 165 | 166 | /** 167 | * 监听下啦刷新 & 上啦加载更多 168 | * 169 | * @param 170 | */ 171 | public static abstract class SwipeLoadingDataListener { 172 | /** 173 | * 下啦刷新回调 174 | */ 175 | public void onRefresh() { 176 | 177 | } 178 | 179 | /** 180 | * http请求开始 181 | */ 182 | public void onStart() { 183 | } 184 | 185 | /** 186 | * http请求数据成功 187 | * 188 | * @param t 189 | */ 190 | public void onSuccess(T t, Headers headers) { 191 | } 192 | 193 | public void onFailure() { 194 | 195 | } 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/res/layout/itheima_header_recyclerview_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 17 | 18 | 19 | 24 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/res/layout/itheima_item_loadmore_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/res/values/color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #fff4511e 4 | 5 | -------------------------------------------------------------------------------- /BaseRecyclerAndAdapter/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | #RecyclerView & RecyclerView.Adapter封装 3 | 4 | 开源项目:[https://github.com/open-android/BaseRecyclerAndAdapter](https://github.com/open-android/BaseRecyclerAndAdapter "地址") 5 | 6 | * 爱生活,爱学习,更爱做代码的搬运工,分类查找更方便请下载黑马助手app 7 | 8 | 9 | ![黑马助手.png](http://upload-images.jianshu.io/upload_images/4037105-f777f1214328dcc4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 10 | 11 | 12 | ## 使用步骤 13 | ### 1. 在project的build.gradle添加如下代码(如下图) 14 | ```groovy 15 | allprojects { 16 | repositories { 17 | ... 18 | maven { url "https://jitpack.io" } 19 | } 20 | } 21 | ``` 22 | ![](http://oi5nqn6ce.bkt.clouddn.com/itheima/booster/code/jitpack.png) 23 | 24 | ### 2. 在Module的build.gradle添加依赖 25 | ```groovy 26 | compile 'com.github.open-android:BaseRecyclerAndAdapter:0.5.13' 27 | compile 'com.jakewharton:butterknife:8.4.0' 28 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' 29 | ``` 30 | 31 | ### 3. 添加权限 32 | ```groovy 33 | 34 | 35 | 36 | 37 | ``` 38 | ### ItheimaRecyclerView使用方式 39 | 40 | 41 | * 网格RecyclerView(app:spanCount="2",spanCount取值范围[1,10]) 42 | 43 | ```xml 44 | 49 | ``` 50 | * 垂直滚动RecyclerView 51 | ```xml 52 | 56 | ``` 57 | * 横向滚动RecyclerView(11:一行,12:二行.......,spanCount取值范围[11,19]) 58 | ```xml 59 | 64 | ``` 65 | 66 | ### ItheimaRecyclerView添加头 67 | 68 | ![](http://upload-images.jianshu.io/upload_images/4037105-63a59d3c9fe90c08.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 69 | 70 | * xml代码 71 | ```xml 72 | 75 | 76 | 80 | 81 | 86 | 87 | 91 | 92 | 93 | ``` 94 | 95 | * java代码 96 | 97 | ```java 98 | RecyclerViewHeader header = (RecyclerViewHeader) findViewById(R.id.header); 99 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview); 100 | header.attachTo(recyclerView); 101 | ``` 102 | 103 | ### 给RecyclerView的item添加点击事件和长按事件 104 | 105 | ```java 106 | ItemClickSupport itemClickSupport = new ItemClickSupport(mRecyclerView); 107 | //点击事件 108 | itemClickSupport.setOnItemClickListener(new ItemClickSupport.OnItemClickListener() { 109 | @Override 110 | public void onItemClicked(RecyclerView recyclerView, int position, View v) { 111 | Toast.makeText(recyclerView.getContext(), "我被点击了", Toast.LENGTH_SHORT).show(); 112 | } 113 | }); 114 | //长按事件 115 | itemClickSupport.setOnItemLongClickListener(new ItemClickSupport.OnItemLongClickListener() { 116 | @Override 117 | public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) { 118 | Toast.makeText(recyclerView.getContext(), "我被长按了", Toast.LENGTH_SHORT).show(); 119 | return false; 120 | } 121 | }); 122 | ``` 123 | 124 | ### BaseRecyclerAdapter使用方式 125 | 126 | ```java 127 | adapter = new BaseRecyclerAdapter(recyclerView 128 | , MyRecyclerViewHolder.class 129 | , R.layout.item_reyclerview 130 | , datas); 131 | 132 | //@param recyclerView 133 | //@param viewHolderClazz 134 | //@param itemResId recyclerView条目的资源id 135 | //@param datas recyclerView展示的数据集合(可以传null) 136 | ``` 137 | 138 | ### ViewHolder模板(ViewHolder如果是内部类必须加上static和public关键字) 139 | 140 | ```java 141 | public static class MyRecyclerViewHolder extends BaseRecyclerViewHolder { 142 | //换成你布局文件中的id 143 | @BindView(R.id.tv_title) 144 | TextView tvTitle; 145 | 146 | public MyRecyclerViewHolder(ViewGroup parentView, int itemResId) { 147 | super(parentView, itemResId); 148 | } 149 | 150 | /** 151 | * 绑定数据的方法,在mData获取数据(mData声明在基类中) 152 | */ 153 | @Override 154 | public void onBindRealData() { 155 | tvTitle.setText(mData.title); 156 | } 157 | 158 | 159 | /** 160 | * 给按钮添加点击事件(button改成你要添加点击事件的id) 161 | * @param v 162 | */ 163 | @OnClick(R.id.button) 164 | public void click(View v) { 165 | } 166 | } 167 | ``` 168 | 169 | ### 下啦刷新 & 加载更多组合控件(下啦刷新和加载更多内部实现,你只需要在对应的ViewHolder做数据绑定即可) 170 | * http请求初始化 171 | ```java 172 | ItheimaHttp.init(context, baseUrl);//使用前必须调用(如果调用过则不需要重复调用) 173 | ``` 174 | * xml布局 175 | ```xml 176 | 180 | 181 | 185 | 186 | ``` 187 | * java代码实现布局 188 | ```java 189 | pullToLoadMoreRecyclerView = new PullToLoadMoreRecyclerView(mSwipeRefreshLayout, mRecyclerView, MyRecyclerViewHolder.class) { 190 | @Override 191 | public int getItemResId() { 192 | //recylerview item资源id 193 | return R.layout.item_recylerview; 194 | } 195 | 196 | @Override 197 | public String getApi() { 198 | //接口 199 | return "order/list"; 200 | } 201 |             //是否加载更多的数据,根据业务逻辑自行判断,true表示有更多的数据,false表示没有更多的数据,如果不需要监听可以不重写该方法 202 |             @Override 203 | public boolean isMoreData(BaseLoadMoreRecyclerAdapter.LoadMoreViewHolder holder) { 204 | System.out.println("isMoreData" + holder); 205 | 206 | return true; 207 | } 208 | }; 209 | ``` 210 | 211 | * 设置监听 212 | ```java 213 | pullToLoadMoreRecyclerView.setLoadingDataListener(new PullToLoadMoreRecyclerView.LoadingDataListener() { 214 | 215 | @Override 216 | public void onRefresh() { 217 | //监听下啦刷新,如果不需要监听可以不重新该方法 218 | L.i("setLoadingDataListener onRefresh"); 219 | } 220 | 221 | @Override 222 | public void onStart() { 223 | //监听http请求开始,如果不需要监听可以不重新该方法 224 | L.i("setLoadingDataListener onStart"); 225 | } 226 | 227 | @Override 228 | public void onSuccess(Bean o ,,Headers headers) { 229 | //监听http请求成功,如果不需要监听可以不重新该方法 230 | L.i("setLoadingDataListener onSuccess: " + o); 231 | } 232 | 233 | @Override 234 | public void onFailure() { 235 | //监听http请求失败,如果不需要监听可以不重新该方法 236 | L.i("setLoadingDataListener onFailure"); 237 | } 238 | }); 239 | 240 | 241 | //添加头 242 | pullToLoadMoreRecyclerView.putHeader(key,value); 243 | //添加请求参数 244 | pullToLoadMoreRecyclerView.putParam(key, value); 245 | //开始请求 246 | pullToLoadMoreRecyclerView.requestData(); 247 | 248 | 249 | //控制加状态,可以在监听中处理 250 | loadMoreViewHolder.loading("加载中...");//默认文字:"加载中..." 251 | loadMoreViewHolder.loadingFinish("没有更多数据"); 252 | ``` 253 | 254 | ### 高级用法 255 | ```java 256 | //如果使用数字控制页数可以使用如下api 257 | //设置参数的key 258 | setCurPageKey("curPage");//当前页key 259 | setPageSizeKey("pageSize");//每一页数量的key 260 | //设置参数的值 261 | setPageSize(1);//设置每一页数量 262 | setTotalPage(20);//设置一共有多少页 263 | //如果使用其他方式分页 264 | 可以设置setLoadingDataListener在onSuccess(Bean o)回调中处理分页 265 | onSuccess回调在每一次加载数据成功后回调 266 | ``` 267 | 268 | 269 | 270 | ### RecyclerView多条目展示 271 | ```java 272 | class MyTypeAdapter extends BaseRecyclerAdapter { 273 | private final int ITEM_TYPE_1 = 0; 274 | private final int ITEM_TYPE_2 = 1; 275 | 276 | public MyTypeAdapter(RecyclerView recyclerView, List datas) { 277 | super(recyclerView, null, 0, datas); 278 | } 279 | 280 | @Override 281 | public BaseRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 282 | //选择类型 283 | if (viewType == ITEM_TYPE_2) { 284 | return new MyTypeHolder2(parent, R.layout.item_type2); 285 | } 286 | return new MyTypeHolder1(parent, R.layout.item_type1); 287 | } 288 | 289 | @Override 290 | public int getItemViewType(int position) { 291 | //根据position返回类型 292 | return position % 2 == 0 ? ITEM_TYPE_2 : ITEM_TYPE_1; 293 | } 294 | } 295 | ``` 296 | 297 | ### 动态向Adapter中添加数据 298 | 299 | ```java 300 | //@param isLoadMore 数据是否累加 301 | //@param datas List数据 302 | 303 | adapter.addDatas(true,datas); 304 | ``` 305 | ### 清空Adapter中所以数据(不推荐使用,使用adapter.addDatas(true,datas))可以实现相同的功能 306 | 307 | ```java 308 | adapter.clearAllData(); 309 | ``` 310 | 详细的使用方法在DEMO里面都演示啦,如果你觉得这个库还不错,请赏我一颗star吧~~~ 311 | 312 | 欢迎关注微信公众号 313 | 314 | ![](http://oi5nqn6ce.bkt.clouddn.com/itheima/booster/code/qrcode.png) 315 | 316 | 317 | 318 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | maven { url "https://jitpack.io" } 19 | } 20 | } 21 | 22 | task clean(type: Delete) { 23 | delete rootProject.buildDir 24 | } 25 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Sat Dec 24 09:18:22 CST 2016 16 | systemProp.http.proxyHost=127.0.0.1 17 | org.gradle.jvmargs=-Xmx1536m 18 | systemProp.http.proxyPort=1080 19 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-android/BaseRecyclerAndAdapter/e44fdcc204de3f36f9829c38cc88149ac3c57aa6/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /img/jitpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-android/BaseRecyclerAndAdapter/e44fdcc204de3f36f9829c38cc88149ac3c57aa6/img/jitpack.png -------------------------------------------------------------------------------- /img/loadMoreAdapter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-android/BaseRecyclerAndAdapter/e44fdcc204de3f36f9829c38cc88149ac3c57aa6/img/loadMoreAdapter.png -------------------------------------------------------------------------------- /img/recyclerViewHeader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-android/BaseRecyclerAndAdapter/e44fdcc204de3f36f9829c38cc88149ac3c57aa6/img/recyclerViewHeader.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':BaseRecyclerAndAdapter' --------------------------------------------------------------------------------