├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── CBPullRefresh ├── .gitignore ├── CBPullRefresh.iml ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── zhl │ │ └── CBPullRefresh │ │ ├── CBPullRefreshListView.java │ │ ├── CBRefreshFooter.java │ │ ├── CBRefreshHeader.java │ │ ├── CBRefreshHeaderView.java │ │ ├── CBRefreshState.java │ │ ├── CBRefreshTopSearchView.java │ │ ├── SwipeMenu │ │ ├── SwipeMenu.java │ │ ├── SwipeMenuAdapter.java │ │ ├── SwipeMenuCreator.java │ │ ├── SwipeMenuItem.java │ │ ├── SwipeMenuLayout.java │ │ └── SwipeMenuView.java │ │ ├── titanic │ │ ├── Titanic.java │ │ └── TitanicTextView.java │ │ └── utils │ │ ├── Blur.java │ │ ├── BlurUtil.java │ │ ├── TimeType.java │ │ └── Utils.java │ └── res │ ├── drawable-hdpi │ ├── top_search_bar.png │ └── top_search_bar_night.png │ ├── drawable-nodpi │ └── wave.png │ ├── drawable-xhdpi │ ├── icon_header_refresh.png │ ├── top_pull_refresh_arrow.png │ └── top_search_bar.png │ ├── drawable │ └── footer_bg_selector.xml │ ├── layout │ ├── cblistview_footer.xml │ ├── cblistview_header.xml │ └── cbpullrefrsh_topsearch.xml │ ├── menu │ └── menu_main.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ └── strings.xml ├── CBPullRefreshListView.iml ├── GIF1.gif ├── GIF2.gif ├── GIF3.gif ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zhl │ │ └── cbpullrefreshlistview │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── zhl │ │ └── cbpullrefreshlistview │ │ ├── BaseActivity.java │ │ ├── CustomRefreshHeaderActivity.java │ │ ├── CustomRefreshHeaderRippleActivity.java │ │ ├── DragBackLayout.java │ │ ├── DragbackActivity.java │ │ ├── MainActivity.java │ │ ├── MyCustomRrefreshHeader.java │ │ └── MyCustomRrefreshHeaderRippleColor.java │ └── res │ ├── drawable-hdpi │ ├── app_logo_icon.png │ └── item_icon_girl.png │ ├── drawable-xhdpi │ ├── app_logo_icon.png │ ├── icon_collection.png │ ├── icon_delete.png │ ├── icon_header_refresh.png │ ├── item_icon_girl.png │ ├── item_icon_girl2.png │ ├── item_icon_girl3.png │ └── top_header_bg.jpg │ ├── drawable │ └── swipeback_shadow.xml │ ├── layout │ ├── activity_custom_header_layout.xml │ ├── activity_custom_header_layout_ripple.xml │ ├── activity_main.xml │ ├── base.xml │ ├── item_listview.xml │ ├── item_listview2.xml │ ├── item_listview3.xml │ ├── my_custom_header.xml │ ├── my_custom_header_ripplecolor.xml │ └── mylistview_footer.xml │ ├── menu │ └── menu_main.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── custom_ripple.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | CBPullRefreshListView -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CBPullRefresh/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /CBPullRefresh/CBPullRefresh.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /CBPullRefresh/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | group='com.github.yilylong' 5 | android { 6 | compileSdkVersion 25 7 | buildToolsVersion "25.0.0" 8 | 9 | defaultConfig { 10 | minSdkVersion 14 11 | targetSdkVersion 23 12 | versionCode 1 13 | versionName "1.0.0" 14 | renderscriptTargetApi 20 15 | renderscriptSupportModeEnabled true 16 | ndk { 17 | abiFilters "armeabi", "armeabi-v7a", "x86", "mips" 18 | } 19 | } 20 | lintOptions { 21 | abortOnError false 22 | } 23 | buildTypes { 24 | release { 25 | minifyEnabled false 26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | } 30 | 31 | dependencies { 32 | compile fileTree(dir: 'libs', include: ['*.jar']) 33 | compile 'com.android.support:appcompat-v7:25.0.0' 34 | compile 'com.android.support:support-v4:25.0.0' 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /CBPullRefresh/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:\WORK\Android\AndroidSDK/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 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/CBPullRefreshListView.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.support.v4.view.GestureDetectorCompat; 7 | import android.util.AttributeSet; 8 | import android.util.Log; 9 | import android.view.GestureDetector; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | import android.view.ViewConfiguration; 13 | import android.view.ViewTreeObserver.OnGlobalLayoutListener; 14 | import android.view.animation.DecelerateInterpolator; 15 | import android.view.animation.Interpolator; 16 | import android.widget.AbsListView; 17 | import android.widget.AbsListView.OnScrollListener; 18 | import android.widget.AdapterView; 19 | import android.widget.ListAdapter; 20 | import android.widget.ListView; 21 | import android.widget.Scroller; 22 | 23 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenu; 24 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuAdapter; 25 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuCreator; 26 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuLayout; 27 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuView; 28 | import com.zhl.CBPullRefresh.utils.Utils; 29 | 30 | import java.text.SimpleDateFormat; 31 | import java.util.Date; 32 | 33 | 34 | public class CBPullRefreshListView extends ListView implements OnScrollListener { 35 | private static final int TOUCH_STATE_NONE = 0; 36 | private static final int TOUCH_STATE_X = 1; 37 | private static final int TOUCH_STATE_Y = 2; 38 | private float mLastY = -1; // save event y 39 | private Scroller mScroller; // used for scroll back 40 | private OnScrollListener mScrollListener; // user's scroll listener 41 | // the interface to trigger refresh and load more. 42 | private OnPullRefreshListener mPullRefreshListener; 43 | private int headersCount; 44 | // -- header view 45 | private CBRefreshHeaderView mHeaderView; 46 | // -- footer view 47 | private CBRefreshHeaderView mFooterView; 48 | private int mHeaderViewHeight; // header view's height 49 | private boolean mEnablePullRefresh = true; 50 | 51 | private boolean mPullRefreshing = false; // is refreashing. 52 | private boolean mEnablePullLoad; 53 | private boolean mPullLoading;// isLoading 54 | private boolean mIsFooterReady = false; 55 | // total list items, used to detect is at the bottom of listview. 56 | private int mTotalItemCount = 0; 57 | // for mScroller, scroll back from header or footer. 58 | private int mScrollBack; 59 | private final static int SCROLLBACK_HEADER = 0; 60 | private final static int SCROLLBACK_FOOTER = 1; 61 | private final static int SCROLL_DURATION = 200; // scroll back duration 62 | private final static int PULL_LOAD_MORE_DELTA = 150; // when pull up >= 150px 63 | private final static float OFFSET_RADIO = 2.3f; // support iOS like pull 64 | // feature. 65 | private boolean showTopSearchBar = false; 66 | private CBRefreshHeaderView topSearchView; 67 | private int topSearchBarHeight = 0; 68 | private OnSearchClickListener searchClickListener; 69 | private OnMenuItemClickListener mMenuItemClickListener; 70 | private SwipeMenuLayout mTouchView; 71 | private long refreshTime; 72 | private SwipeMenuCreator mMenuCreator; 73 | private Interpolator mSwipeInterpolator; 74 | private int mTouchPosition; 75 | private int mTouchState = TOUCH_STATE_NONE; 76 | private float mDownX; 77 | private float mDownY; 78 | private float disX, disY; 79 | private int MAX_Y = 5; 80 | private int MAX_X = 3; 81 | private OnSwipeListener mOnSwipeListener; 82 | private Context context; 83 | private boolean swipeEnable = false; 84 | private int touchSlop; 85 | private int MIN_FLING; 86 | private int MAX_VELOCITYX; 87 | private GestureDetectorCompat mGestureDetector; 88 | private GestureDetector.OnGestureListener mGestureListener; 89 | private boolean isFling; 90 | 91 | /** 92 | * @param context 93 | */ 94 | public CBPullRefreshListView(Context context) { 95 | super(context); 96 | initWithContext(context); 97 | } 98 | 99 | public CBPullRefreshListView(Context context, AttributeSet attrs) { 100 | super(context, attrs); 101 | initWithContext(context); 102 | } 103 | 104 | public CBPullRefreshListView(Context context, AttributeSet attrs, int defStyle) { 105 | super(context, attrs, defStyle); 106 | initWithContext(context); 107 | } 108 | 109 | private void initWithContext(Context context) { 110 | this.context = context; 111 | touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 112 | MIN_FLING = ViewConfiguration.get(context).getScaledMinimumFlingVelocity(); 113 | MAX_VELOCITYX = ViewConfiguration.get(context).getScaledMaximumFlingVelocity(); 114 | mScroller = new Scroller(context, new DecelerateInterpolator()); 115 | super.setOnScrollListener(this); 116 | // init header view 117 | mHeaderView = new CBRefreshHeader(context); 118 | addHeaderView(mHeaderView); 119 | 120 | // init header height 121 | initHeaderHeight(); 122 | 123 | topSearchView = new CBRefreshTopSearchView(context); 124 | topSearchView.setOnClickListener(new OnClickListener() { 125 | @Override 126 | public void onClick(View v) { 127 | if (searchClickListener != null) { 128 | searchClickListener.onSearchBarClick(); 129 | } 130 | } 131 | }); 132 | addHeaderView(topSearchView); 133 | initTopsearchViewHeight(); 134 | 135 | // init footer view 136 | mFooterView = new CBRefreshFooter(context); 137 | mFooterView.footerViewHide(); 138 | mFooterView.setOnClickListener(null); 139 | // headerview and footer divider 140 | setHeaderDividersEnabled(false); 141 | mGestureListener = new GestureDetector.SimpleOnGestureListener() { 142 | @Override 143 | public boolean onDown(MotionEvent e) { 144 | isFling = false; 145 | return true; 146 | } 147 | 148 | @Override 149 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 150 | if(e1==null){ 151 | return false; 152 | } 153 | if ((e1.getX() - e2.getX()) > MIN_FLING && velocityX < MAX_VELOCITYX) { 154 | isFling = true; 155 | } 156 | return super.onFling(e1, e2, velocityX, velocityY); 157 | } 158 | }; 159 | mGestureDetector = new GestureDetectorCompat(getContext(), mGestureListener); 160 | } 161 | 162 | @Override 163 | public void addHeaderView(View v, Object data, boolean isSelectable) { 164 | super.addHeaderView(v, data, isSelectable); 165 | headersCount++; 166 | } 167 | 168 | private void initTopsearchViewHeight() { 169 | topSearchView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 170 | @Override 171 | public void onGlobalLayout() { 172 | topSearchBarHeight = topSearchView.getRealHeaderContentHeight(); 173 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 174 | getViewTreeObserver().removeOnGlobalLayoutListener(this); 175 | } else { 176 | getViewTreeObserver().removeGlobalOnLayoutListener(this); 177 | } 178 | } 179 | }); 180 | } 181 | 182 | private void initHeaderHeight() { 183 | mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 184 | @Override 185 | public void onGlobalLayout() { 186 | mHeaderViewHeight = mHeaderView.getRealHeaderContentHeight(); 187 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 188 | getViewTreeObserver().removeOnGlobalLayoutListener(this); 189 | } else { 190 | getViewTreeObserver().removeGlobalOnLayoutListener(this); 191 | } 192 | } 193 | }); 194 | } 195 | 196 | @Override 197 | public void setAdapter(ListAdapter adapter) { 198 | // ensure footer view is the last child view 199 | if (mIsFooterReady == false) { 200 | mIsFooterReady = true; 201 | addFooterView(mFooterView); 202 | setFooterDividersEnabled(false); 203 | } 204 | setHeaderDividersEnabled(false); 205 | setRefreshTime(null); 206 | // super.setAdapter(adapter); 207 | super.setAdapter(new SwipeMenuAdapter(getContext(), adapter) { 208 | @Override 209 | public void createMenu(SwipeMenu menu) { 210 | if (mMenuCreator != null) { 211 | mMenuCreator.create(menu); 212 | } 213 | } 214 | 215 | @Override 216 | public void onItemClick(SwipeMenuView view, SwipeMenu menu, int index) { 217 | if (mMenuItemClickListener != null) { 218 | mMenuItemClickListener.onMenuItemClick(view.getPosition(), menu, index); 219 | } 220 | if (mTouchView != null) { 221 | mTouchView.smoothCloseMenu(); 222 | } 223 | } 224 | }); 225 | } 226 | 227 | /** 228 | * enable or disable pull down refresh feature. 229 | * 230 | * @param enable 231 | */ 232 | public void setPullRefreshEnable(boolean enable) { 233 | mEnablePullRefresh = enable; 234 | mHeaderView.setPullRefreshEnable(mEnablePullRefresh); 235 | } 236 | 237 | public void setStyleChange(int state) { 238 | mHeaderView.onStyleChange(state); 239 | mFooterView.onStyleChange(state); 240 | } 241 | 242 | /** 243 | * enable or disable pull up load more feature. 244 | * 245 | * @param enable 246 | */ 247 | public void setPullLoadMoreEnable(boolean enable) { 248 | mEnablePullLoad = enable; 249 | if (!mEnablePullLoad) { 250 | mFooterView.footerViewHide(); 251 | mFooterView.setOnClickListener(null); 252 | } else { 253 | mPullLoading = false; 254 | mFooterView.footerViewShow(); 255 | mFooterView.setState(CBRefreshState.STATE_PULL_UP_TO_LOADMORE); 256 | mFooterView.pullUpToLoadmore(); 257 | mFooterView.setOnClickListener(new OnClickListener() { 258 | @Override 259 | public void onClick(View v) { 260 | startLoadMore(); 261 | } 262 | }); 263 | } 264 | } 265 | 266 | /** 267 | * set Swipe enable 268 | * 269 | * @param swipeEnable 270 | */ 271 | public void setSwipeEnable(boolean swipeEnable) { 272 | this.swipeEnable = swipeEnable; 273 | } 274 | 275 | /** 276 | * stop refresh, reset header view. 277 | */ 278 | public void stopRefresh() { 279 | if (mPullRefreshing == true) { 280 | mPullRefreshing = false; 281 | resetHeaderHeight(); 282 | resetTopSearchBarHeight(); 283 | mHeaderView.setState(CBRefreshState.STATE_PULL_TO_REFRESH); 284 | } 285 | } 286 | 287 | 288 | /** 289 | * stop load more, reset footer view. 290 | */ 291 | public void stopLoadMore() { 292 | if (mPullLoading == true) { 293 | mPullLoading = false; 294 | mFooterView.pullUpToLoadmore(); 295 | mFooterView.setState(CBRefreshState.STATE_PULL_UP_TO_LOADMORE); 296 | } 297 | } 298 | 299 | /** 300 | * set last refresh time 301 | * 302 | * @param time 303 | */ 304 | @SuppressLint("SimpleDateFormat") 305 | public void setRefreshTime(String time) { 306 | if (null == time) { 307 | Date now = new Date(); 308 | SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); 309 | mHeaderView.setRefreshTime(dateFormat.format(now)); 310 | } else { 311 | mHeaderView.setRefreshTime(time); 312 | } 313 | } 314 | 315 | /** 316 | * set refreshTIme 317 | * 318 | * @param time 319 | */ 320 | public void setRefreshTime(long time) { 321 | if (time <= 0) { 322 | setRefreshTime(null); 323 | } else { 324 | refreshTime = time; 325 | setRefreshTime(Utils.getTimeDifferent(context, time)); 326 | } 327 | } 328 | 329 | private void invokeOnScrolling() { 330 | if (mScrollListener instanceof OnXScrollListener) { 331 | OnXScrollListener l = (OnXScrollListener) mScrollListener; 332 | l.onXScrolling(this); 333 | } 334 | } 335 | 336 | private void updateHeaderHeight(float delta) { 337 | mHeaderView.setVisiableHeight((int) delta + mHeaderView.getVisiableHeight()); 338 | if (mEnablePullRefresh && !mPullRefreshing) { 339 | if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) { 340 | mHeaderView.releaseToRefresh(); 341 | mHeaderView.setState(CBRefreshState.STATE_RELEASE_TO_REFRESH); 342 | } else { 343 | mHeaderView.pullToRefresh(); 344 | mHeaderView.setState(CBRefreshState.STATE_PULL_TO_REFRESH); 345 | } 346 | } 347 | setSelection(0); // scroll to top each time 348 | } 349 | 350 | /** 351 | * reset header view's height. 352 | */ 353 | private void resetHeaderHeight() { 354 | int height = mHeaderView.getVisiableHeight(); 355 | if (height == 0) // not visible. 356 | return; 357 | // refreshing and header isn't shown fully. do nothing. 358 | if (mPullRefreshing && height <= mHeaderViewHeight) { 359 | return; 360 | } 361 | int finalHeight = 0; // default: scroll back to dismiss header. 362 | // is refreshing, just scroll back to show all the header. 363 | if (mPullRefreshing && height > mHeaderViewHeight) { 364 | finalHeight = mHeaderViewHeight; 365 | } 366 | mScrollBack = SCROLLBACK_HEADER; 367 | mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION); 368 | // trigger computeScroll 369 | invalidate(); 370 | } 371 | 372 | private void updateFooterHeight(float delta) { 373 | if (!mEnablePullLoad) { 374 | return; 375 | } 376 | int height = mFooterView.getLoadMorePullUpDistance() + (int) delta; 377 | if (mEnablePullLoad && !mPullLoading) { 378 | if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load more. 379 | mFooterView.releaseToLoadmore(); 380 | mFooterView.setState(CBRefreshState.STATE_RELEASE_TO_LOADMORE); 381 | } else { 382 | mFooterView.pullUpToLoadmore(); 383 | mFooterView.setState(CBRefreshState.STATE_PULL_UP_TO_LOADMORE); 384 | } 385 | } 386 | mFooterView.setLoadMorePullUpDistance(height); 387 | 388 | // setSelection(mTotalItemCount - 1); // scroll to bottom 389 | } 390 | 391 | private void resetFooterHeight() { 392 | int bottomMargin = mFooterView.getLoadMorePullUpDistance(); 393 | if (bottomMargin > 0) { 394 | mScrollBack = SCROLLBACK_FOOTER; 395 | mScroller.startScroll(0, bottomMargin, 0, -bottomMargin, SCROLL_DURATION); 396 | invalidate(); 397 | } 398 | } 399 | 400 | private void startLoadMore() { 401 | mPullLoading = true; 402 | mFooterView.onLoading(); 403 | mFooterView.setState(CBRefreshState.STATE_REFRESHING); 404 | if (mPullRefreshListener != null) { 405 | mPullRefreshListener.onLoadMore(); 406 | } 407 | } 408 | 409 | @Override 410 | public boolean onTouchEvent(MotionEvent ev) { 411 | mGestureDetector.onTouchEvent(ev); 412 | if (mLastY == -1) { 413 | mLastY = ev.getRawY(); 414 | } 415 | 416 | switch (ev.getAction()) { 417 | case MotionEvent.ACTION_DOWN: 418 | Log.d("MyTag", "按下-x=" + ev.getX()); 419 | mLastY = ev.getRawY(); 420 | mDownX = ev.getX(); 421 | mDownY = ev.getY(); 422 | int oldPos = mTouchPosition; 423 | mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); 424 | View view = getChildAt(mTouchPosition - getFirstVisiblePosition()); 425 | if (swipeEnable && mTouchView != null && (mTouchView.isOpen() || mTouchView.isActive()) && oldPos != mTouchPosition) { 426 | mTouchView.smoothCloseMenu(); 427 | mTouchView = null; 428 | mTouchState = TOUCH_STATE_NONE; 429 | } 430 | if (view instanceof SwipeMenuLayout) { 431 | mTouchView = (SwipeMenuLayout) view; 432 | } 433 | break; 434 | case MotionEvent.ACTION_MOVE: 435 | Log.d("MyTag", "移动downx=" + mDownX); 436 | final float deltaY = ev.getRawY() - mLastY; 437 | mLastY = ev.getRawY(); 438 | disX = ev.getX() - mDownX; 439 | disY = ev.getY() - mDownY; 440 | 441 | if (Math.abs(disX) > touchSlop && Math.abs(disX) > Math.abs(disY)) {// 左右滑动 442 | mTouchState = TOUCH_STATE_X; 443 | if (swipeEnable && mTouchView != null) { 444 | Log.d("MyTag", "侧滑菜单移动=" + disX); 445 | mTouchView.swipeMenuSlide(-(int) disX); 446 | if (mTouchView.isActive()) { 447 | return true; 448 | } 449 | } 450 | } else if (Math.abs(disY) > touchSlop && Math.abs(disY) > Math.abs(disX)) {// 上下滑动 451 | if ((swipeEnable && mTouchView != null && mTouchView.isOpen()) || (swipeEnable && mTouchView != null && mTouchView.isActive())) { 452 | mTouchView.smoothCloseMenu(); 453 | mTouchView = null; 454 | mTouchState = TOUCH_STATE_NONE; 455 | } 456 | mTouchState = TOUCH_STATE_Y; 457 | if (getFirstVisiblePosition() == 0 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) { 458 | if (showTopSearchBar && topSearchView.getVisiableHeight() < topSearchBarHeight) { 459 | updateTopSearchBarHeight(deltaY); 460 | } else { 461 | updateHeaderHeight(deltaY / OFFSET_RADIO); 462 | mHeaderView.onDragSlide((float) mHeaderView.getVisiableHeight() + Math.abs(deltaY / OFFSET_RADIO)); 463 | invokeOnScrolling(); 464 | } 465 | 466 | } else if (getLastVisiblePosition() == mTotalItemCount - 1 && (mFooterView.getLoadMorePullUpDistance() > 0 || deltaY < 0)) {// 上拉 467 | // last item, already pulled up or want to pull up. 468 | updateFooterHeight(-deltaY / OFFSET_RADIO); 469 | mFooterView.onDragSlide((float) mFooterView.getLoadMorePullUpDistance() + (-deltaY / OFFSET_RADIO)); 470 | } 471 | } 472 | break; 473 | default: 474 | Log.d("MyTag", "抬起"); 475 | mLastY = -1; // reset 476 | switch (mTouchState) { 477 | case TOUCH_STATE_X: 478 | if (swipeEnable && mTouchView != null) { 479 | mTouchView.swipeMenuFling(isFling, -(int) disX); 480 | if (mTouchView.isActive()) { 481 | return true; 482 | } 483 | } 484 | break; 485 | case TOUCH_STATE_Y: 486 | if (getFirstVisiblePosition() == 0) { 487 | // invoke refresh 488 | if (mEnablePullRefresh && mHeaderView.getVisiableHeight() > mHeaderViewHeight) { 489 | mPullRefreshing = true; 490 | mHeaderView.onRefreshing(); 491 | mHeaderView.setState(CBRefreshState.STATE_REFRESHING); 492 | if (mPullRefreshListener != null) { 493 | mPullRefreshListener.onRefresh(); 494 | mPullRefreshListener.onUpdateRefreshTime(System.currentTimeMillis()); 495 | } 496 | setRefreshTime(System.currentTimeMillis()); 497 | } 498 | resetHeaderHeight(); 499 | } else if (getLastVisiblePosition() == mTotalItemCount - 1) { 500 | // invoke load more. 501 | if (mEnablePullLoad && mFooterView.getLoadMorePullUpDistance() > PULL_LOAD_MORE_DELTA) { 502 | startLoadMore(); 503 | } 504 | resetFooterHeight(); 505 | } else { 506 | resetTopSearchBarHeight(); 507 | } 508 | break; 509 | } 510 | mTouchState = TOUCH_STATE_NONE; 511 | break; 512 | } 513 | return super.onTouchEvent(ev); 514 | } 515 | 516 | 517 | private void resetTopSearchBarHeight() { 518 | if (showTopSearchBar && topSearchView != null) { 519 | topSearchView.setVisiableHeight(0); 520 | } 521 | } 522 | 523 | public void setTopSearchBarHeight() { 524 | if (topSearchView != null) { 525 | topSearchView.setVisiableHeight(0); 526 | } 527 | } 528 | 529 | private void updateTopSearchBarHeight(float deltaY) { 530 | if (deltaY > 20) { 531 | topSearchView.setVisiableHeight(topSearchBarHeight); 532 | } 533 | } 534 | 535 | @Override 536 | public void computeScroll() { 537 | if (mScroller.computeScrollOffset()) { 538 | if (mScrollBack == SCROLLBACK_HEADER) { 539 | mHeaderView.setVisiableHeight(mScroller.getCurrY()); 540 | mHeaderView.onDragSlide(mScroller.getCurrY()); 541 | } else { 542 | mFooterView.setLoadMorePullUpDistance(mScroller.getCurrY()); 543 | mFooterView.onDragSlide(mScroller.getCurrY()); 544 | } 545 | postInvalidate(); 546 | invokeOnScrolling(); 547 | } 548 | super.computeScroll(); 549 | } 550 | 551 | @Override 552 | public void setOnScrollListener(OnScrollListener l) { 553 | mScrollListener = l; 554 | } 555 | 556 | @Override 557 | public void onScrollStateChanged(AbsListView view, int scrollState) { 558 | if (mScrollListener != null) { 559 | mScrollListener.onScrollStateChanged(view, scrollState); 560 | } 561 | } 562 | 563 | @Override 564 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 565 | // send to user's listener 566 | mTotalItemCount = totalItemCount; 567 | if (mScrollListener != null) { 568 | mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); 569 | } 570 | } 571 | 572 | 573 | /** 574 | * set the refresh header icon 575 | * 576 | * @param resName 577 | */ 578 | public void setHeaderRefreshIcon(int resName) { 579 | if (mHeaderView != null) { 580 | mHeaderView.setHeaderIcon(resName); 581 | } 582 | } 583 | 584 | /** 585 | * set footer view background 586 | * 587 | * @param resName 588 | */ 589 | public void setFooterBg(int resName) { 590 | if (mFooterView != null) { 591 | ((CBRefreshFooter) mFooterView).setFooterBg(resName); 592 | } 593 | } 594 | 595 | /** 596 | * set topsearchbar show or not 597 | * 598 | * @param show 599 | */ 600 | public void showTopSearchBar(boolean show) { 601 | this.showTopSearchBar = show; 602 | } 603 | 604 | public void setOnPullRefreshListener(OnPullRefreshListener l) { 605 | mPullRefreshListener = l; 606 | } 607 | 608 | public void setOnItemClickListener(final OnItemClickListener listener) { 609 | this.setOnItemClickListener(new AbsListView.OnItemClickListener() { 610 | @Override 611 | public void onItemClick(AdapterView parent, View view, 612 | int position, long id) { 613 | if (listener != null) { 614 | //must subtract the headers count 615 | listener.onItemClick(parent, view, position - headersCount, id); 616 | } 617 | } 618 | }); 619 | } 620 | 621 | public void setOnSearchBarClickListener(OnSearchClickListener searchClickListener) { 622 | this.searchClickListener = searchClickListener; 623 | } 624 | 625 | /** 626 | * you can listen ListView.OnScrollListener or this one. it will invoke 627 | * onXScrolling when header/footer scroll back. 628 | */ 629 | public interface OnXScrollListener extends OnScrollListener { 630 | public void onXScrolling(View view); 631 | } 632 | 633 | public void setTopSearchDrawable(int resid) { 634 | topSearchView.setHeaderIcon(resid); 635 | } 636 | 637 | public void setRefreshHeader(T header) { 638 | if (header == null) { 639 | return; 640 | } 641 | removeHeaderView(mHeaderView); 642 | headersCount--; 643 | removeHeaderView(topSearchView); 644 | headersCount--; 645 | mHeaderView = header; 646 | addHeaderView(mHeaderView); 647 | addHeaderView(topSearchView); 648 | initHeaderHeight(); 649 | initTopsearchViewHeight(); 650 | } 651 | 652 | public void setLoadMoreFooter(T footer) { 653 | if (footer == null) { 654 | return; 655 | } 656 | this.removeFooterView(mFooterView); 657 | this.mFooterView = footer; 658 | addFooterView(mFooterView); 659 | mFooterView.footerViewHide(); 660 | mFooterView.setOnClickListener(null); 661 | } 662 | 663 | public void setTopSearchBar(T searchBar) { 664 | if (searchBar == null) { 665 | return; 666 | } 667 | this.removeFooterView(topSearchView); 668 | headersCount--; 669 | this.topSearchView = searchBar; 670 | addHeaderView(topSearchView); 671 | initTopsearchViewHeight(); 672 | } 673 | 674 | /** 675 | * 返回当前触摸的item view 676 | * 677 | * @return 678 | */ 679 | public SwipeMenuLayout getTouchView() { 680 | return mTouchView; 681 | } 682 | 683 | /** 684 | * swipe item is open? 685 | * 686 | * @return 687 | */ 688 | public boolean isSwipeMenuOpen() { 689 | return mTouchView == null ? false : mTouchView.isOpen() || mTouchView.isActive(); 690 | } 691 | 692 | public void setMenuCreator(SwipeMenuCreator menuCreator) { 693 | this.mMenuCreator = menuCreator; 694 | } 695 | 696 | public void setSwipeMenuInterpolator(Interpolator interpolator) { 697 | this.mSwipeInterpolator = interpolator; 698 | } 699 | 700 | public void setOnMenuItemClickListener(OnMenuItemClickListener itemClickListener) { 701 | this.mMenuItemClickListener = itemClickListener; 702 | } 703 | 704 | /** 705 | * the refresh listener 706 | */ 707 | public interface OnPullRefreshListener { 708 | public void onRefresh(); 709 | 710 | public void onLoadMore(); 711 | 712 | public void onUpdateRefreshTime(long time); 713 | } 714 | 715 | public interface OnItemClickListener { 716 | public void onItemClick(AdapterView parent, View view, 717 | int position, long id); 718 | } 719 | 720 | public interface OnSearchClickListener { 721 | public void onSearchBarClick(); 722 | } 723 | 724 | public static interface OnMenuItemClickListener { 725 | void onMenuItemClick(int position, SwipeMenu menu, int index); 726 | } 727 | 728 | public static interface OnSwipeListener { 729 | void onSwipeStart(int position); 730 | 731 | void onSwipeEnd(int position); 732 | } 733 | } 734 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/CBRefreshFooter.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.LinearLayout; 8 | import android.widget.TextView; 9 | 10 | 11 | 12 | public class CBRefreshFooter extends CBRefreshHeaderView { 13 | 14 | private Context mContext; 15 | private View mContentView; 16 | private View mProgressBar; 17 | private TextView mHintView; 18 | private int state; 19 | 20 | public CBRefreshFooter(Context context) { 21 | super(context); 22 | initView(context); 23 | } 24 | 25 | public CBRefreshFooter(Context context, AttributeSet attrs) { 26 | super(context, attrs); 27 | initView(context); 28 | } 29 | 30 | @Override 31 | public void setState(int state) { 32 | this.state = state; 33 | } 34 | 35 | private void initView(Context context) { 36 | mContext = context; 37 | LinearLayout moreView = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.cblistview_footer, null); 38 | addView(moreView); 39 | moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 40 | 41 | mContentView = moreView.findViewById(R.id.cbrefresh_footer_content); 42 | mProgressBar = moreView.findViewById(R.id.cbrefresh_footer_progressbar); 43 | mHintView = (TextView) moreView.findViewById(R.id.cbrefresh_footer_hint_textview); 44 | } 45 | 46 | /** 47 | * set the footer bg 48 | * 49 | * @param resName 50 | */ 51 | public void setFooterBg(int resName) { 52 | mContentView.setBackgroundResource(resName); 53 | } 54 | 55 | @Override 56 | public void pullUpToLoadmore() { 57 | mProgressBar.setVisibility(View.GONE); 58 | mHintView.setVisibility(View.VISIBLE); 59 | mHintView.setText(getString(R.string.refresh_footer_tip_pullup_loadmore)); 60 | } 61 | 62 | @Override 63 | public void releaseToLoadmore() { 64 | mProgressBar.setVisibility(View.GONE); 65 | mHintView.setVisibility(View.VISIBLE); 66 | mHintView.setText(getString(R.string.refresh_footer_tip_release_loadmore)); 67 | } 68 | 69 | @Override 70 | public void onLoading() { 71 | mProgressBar.setVisibility(View.VISIBLE); 72 | mHintView.setVisibility(View.VISIBLE); 73 | mHintView.setText(getString(R.string.refresh_footer_tip_loading)); 74 | } 75 | 76 | @Override 77 | public void onStyleChange(int state) { 78 | super.onStyleChange(state); 79 | } 80 | 81 | @Override 82 | public int getLoadMorePullUpDistance() { 83 | LayoutParams lp = (LayoutParams) mContentView.getLayoutParams(); 84 | return lp.bottomMargin; 85 | } 86 | 87 | @Override 88 | public void setLoadMorePullUpDistance(int deltaY) { 89 | if (deltaY < 0) 90 | return; 91 | LayoutParams lp = (LayoutParams) mContentView.getLayoutParams(); 92 | lp.bottomMargin = deltaY; 93 | mContentView.setLayoutParams(lp); 94 | } 95 | 96 | @Override 97 | public void footerViewShow() { 98 | LayoutParams lp = (LayoutParams) mContentView.getLayoutParams(); 99 | lp.height = LayoutParams.WRAP_CONTENT; 100 | mContentView.setLayoutParams(lp); 101 | } 102 | 103 | @Override 104 | public void footerViewHide() { 105 | LayoutParams lp = (LayoutParams) mContentView.getLayoutParams(); 106 | lp.height = 0; 107 | mContentView.setLayoutParams(lp); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/CBRefreshHeader.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.Gravity; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.animation.Animation; 9 | import android.view.animation.RotateAnimation; 10 | import android.widget.ImageView; 11 | import android.widget.LinearLayout; 12 | import android.widget.ProgressBar; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | import com.zhl.CBPullRefresh.titanic.Titanic; 17 | import com.zhl.CBPullRefresh.titanic.TitanicTextView; 18 | 19 | 20 | public class CBRefreshHeader extends CBRefreshHeaderView { 21 | private LinearLayout mContainer; 22 | private RelativeLayout mHeaderViewContent; 23 | private ImageView mArrowImageView; 24 | private ProgressBar mProgressBar; 25 | private TextView mHintTextView; 26 | private TextView mHeaderTimeView; 27 | // the curent state 28 | private int mState = STATE_PULL_TO_REFRESH; 29 | private Animation mRotateUpAnim; 30 | private Animation mRotateDownAnim; 31 | private final int ROTATE_ANIM_DURATION = 200; 32 | private TitanicTextView headrAnimView; 33 | private Titanic titanic; 34 | 35 | 36 | public CBRefreshHeader(Context context) { 37 | this(context, null); 38 | } 39 | 40 | /** 41 | * @param context 42 | * @param attrs 43 | */ 44 | public CBRefreshHeader(Context context, AttributeSet attrs) { 45 | super(context, attrs); 46 | initView(context); 47 | } 48 | 49 | private void initView(Context context) { 50 | // in the first set the Header height=0 51 | LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0); 52 | mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.cblistview_header, null); 53 | mHeaderViewContent = (RelativeLayout) mContainer.findViewById(R.id.cbrefresh_header_content); 54 | mHeaderTimeView = (TextView) mContainer.findViewById(R.id.cbrefresh_header_time); 55 | addView(mContainer, lp); 56 | setGravity(Gravity.BOTTOM); 57 | 58 | mArrowImageView = (ImageView) findViewById(R.id.cbrefresh_header_arrow); 59 | mHintTextView = (TextView) findViewById(R.id.cbrefresh_header_hint_textview); 60 | mProgressBar = (ProgressBar) findViewById(R.id.cbrefresh_header_progressbar); 61 | headrAnimView = (TitanicTextView) findViewById(R.id.cbrefresh_header_anim); 62 | titanic = new Titanic(); 63 | mRotateUpAnim = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 64 | mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION); 65 | mRotateUpAnim.setFillAfter(true); 66 | mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 67 | mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION); 68 | mRotateDownAnim.setFillAfter(true); 69 | } 70 | 71 | @Override 72 | public void setState(int state) { 73 | this.mState = state; 74 | } 75 | 76 | /** 77 | * @param resName 78 | */ 79 | @Override 80 | public void setHeaderIcon(int resName) { 81 | mArrowImageView.setBackgroundResource(resName); 82 | } 83 | 84 | @Override 85 | public void pullToRefresh() { 86 | mHintTextView.setText(getString(R.string.refresh_header_tip_pull2refresh)); 87 | mArrowImageView.setVisibility(View.VISIBLE); 88 | mProgressBar.setVisibility(View.INVISIBLE); 89 | if (mState == STATE_RELEASE_TO_REFRESH) { 90 | mArrowImageView.startAnimation(mRotateDownAnim); 91 | } 92 | if (mState == STATE_REFRESHING) { 93 | mArrowImageView.clearAnimation(); 94 | } 95 | } 96 | 97 | @Override 98 | public void releaseToRefresh() { 99 | mHintTextView.setText(getString(R.string.refresh_header_tip_release2refresh)); 100 | if (mState != STATE_RELEASE_TO_REFRESH) { 101 | mArrowImageView.clearAnimation(); 102 | mArrowImageView.startAnimation(mRotateUpAnim); 103 | } 104 | } 105 | 106 | @Override 107 | public void onRefreshing() { 108 | mHintTextView.setText(getString(R.string.refresh_header_tip_refreshing)); 109 | mArrowImageView.clearAnimation(); 110 | mArrowImageView.setVisibility(View.INVISIBLE); 111 | mProgressBar.setVisibility(View.VISIBLE); 112 | } 113 | 114 | @Override 115 | public void onStyleChange(int state) { 116 | super.onStyleChange(state); 117 | } 118 | 119 | @Override 120 | public void setVisiableHeight(int height) { 121 | if (height < 0) 122 | height = 0; 123 | LayoutParams lp = (LayoutParams) mContainer.getLayoutParams(); 124 | lp.height = height; 125 | mContainer.setLayoutParams(lp); 126 | } 127 | 128 | @Override 129 | public int getVisiableHeight() { 130 | return mContainer.getHeight(); 131 | } 132 | 133 | @Override 134 | public int getRealHeaderContentHeight() { 135 | // beacuse container height =0 at the first ,so return mHeaderViewContent height 136 | if (mHeaderViewContent != null) { 137 | return mHeaderViewContent.getHeight(); 138 | } 139 | return 0; 140 | } 141 | 142 | @Override 143 | public void setPullRefreshEnable(boolean enable) { 144 | if (!enable) { // disable, hide the content 145 | mHeaderViewContent.setVisibility(View.INVISIBLE); 146 | } else { 147 | mHeaderViewContent.setVisibility(View.VISIBLE); 148 | } 149 | } 150 | 151 | @Override 152 | public void setRefreshTime(String refreshTime) { 153 | mHeaderTimeView.setText(refreshTime); 154 | } 155 | } -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/CBRefreshHeaderView.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.LinearLayout; 6 | 7 | public class CBRefreshHeaderView extends LinearLayout implements CBRefreshState { 8 | private Context context; 9 | public CBRefreshHeaderView(Context context) { 10 | this(context, null); 11 | } 12 | 13 | public CBRefreshHeaderView(Context context, AttributeSet attrs) { 14 | this(context, attrs, -1); 15 | } 16 | 17 | public CBRefreshHeaderView(Context context, AttributeSet attrs, 18 | int defStyleAttr) { 19 | super(context, attrs, defStyleAttr); 20 | this.context = context; 21 | } 22 | 23 | /** 24 | * set the current state 25 | * @param state 26 | */ 27 | @Override 28 | public void setState(int state) { 29 | 30 | } 31 | 32 | /** 33 | * pull to refresh listener 34 | */ 35 | @Override 36 | public void pullToRefresh() { 37 | 38 | } 39 | 40 | /** 41 | * relase to fresh listener 42 | */ 43 | @Override 44 | public void releaseToRefresh() { 45 | 46 | } 47 | 48 | 49 | /** 50 | * pull up to loadmore 51 | */ 52 | @Override 53 | public void pullUpToLoadmore() { 54 | 55 | } 56 | 57 | /** 58 | * relase to loadmore 59 | */ 60 | @Override 61 | public void releaseToLoadmore() { 62 | 63 | } 64 | 65 | /** 66 | * onrefreshing 67 | */ 68 | @Override 69 | public void onRefreshing() { 70 | 71 | } 72 | 73 | /** 74 | * onloading 75 | */ 76 | @Override 77 | public void onLoading() { 78 | 79 | } 80 | 81 | /** 82 | * set the header height 83 | * @param height 84 | */ 85 | @Override 86 | public void setVisiableHeight(int height) { 87 | 88 | } 89 | 90 | /** 91 | * get the header visiable height 92 | * @return 93 | */ 94 | @Override 95 | public int getVisiableHeight() { 96 | return 0; 97 | } 98 | 99 | /** 100 | * on draging 101 | * @param deltaY 102 | */ 103 | @Override 104 | public void onDragSlide(float deltaY) { 105 | 106 | } 107 | /** 108 | * get the pull up(footer) height 109 | */ 110 | @Override 111 | public int getLoadMorePullUpDistance() { 112 | return 0; 113 | } 114 | /** 115 | * set the pull up(footer) heith 116 | */ 117 | @Override 118 | public void setLoadMorePullUpDistance(int deltaY) { 119 | 120 | } 121 | /** 122 | * show footerview 123 | */ 124 | @Override 125 | public void footerViewShow() { 126 | 127 | } 128 | /** 129 | * hidden footer view 130 | */ 131 | @Override 132 | public void footerViewHide() { 133 | 134 | } 135 | /** 136 | * get the header's real height 137 | */ 138 | @Override 139 | public int getRealHeaderContentHeight() { 140 | return 0; 141 | } 142 | /** 143 | * set pull refresh enable 144 | */ 145 | @Override 146 | public void setPullRefreshEnable(boolean enable) { 147 | 148 | } 149 | /** 150 | * set loadmore enable 151 | */ 152 | @Override 153 | public void setLoadMoreEnable(boolean enable) { 154 | 155 | } 156 | 157 | /** 158 | * set the refresh time 159 | * @param refreshTime 160 | */ 161 | @Override 162 | public void setRefreshTime(String refreshTime) { 163 | 164 | } 165 | 166 | /** 167 | * set the header icon 168 | * @param resId 169 | */ 170 | @Override 171 | public void setHeaderIcon(int resId) { 172 | 173 | } 174 | 175 | /** 176 | * on style change 177 | * @param state 178 | */ 179 | @Override 180 | public void onStyleChange(int state) { 181 | 182 | } 183 | 184 | protected String getString(int redID){ 185 | return context.getString(redID); 186 | } 187 | 188 | 189 | } 190 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/CBRefreshState.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh; 2 | 3 | /** 4 | * 描述:刷新状态的接口 5 | * Created by zhaohl on 2016-3-22. 6 | */ 7 | public interface CBRefreshState { 8 | /** 9 | * state pull to refresh 10 | */ 11 | public final static int STATE_PULL_TO_REFRESH = 0; 12 | /** 13 | * state relase to refresh 14 | */ 15 | public final static int STATE_RELEASE_TO_REFRESH = 1; 16 | /** 17 | * state on refreshing 18 | */ 19 | public final static int STATE_REFRESHING = 2; 20 | /** 21 | * state pull to loadmore 22 | */ 23 | public final static int STATE_PULL_UP_TO_LOADMORE = 3; 24 | /** 25 | * state relase to loadmore 26 | */ 27 | public final static int STATE_RELEASE_TO_LOADMORE = 4; 28 | 29 | /** 30 | * set the state 31 | */ 32 | public void setState(int state); 33 | public void pullToRefresh(); 34 | 35 | public void releaseToRefresh(); 36 | 37 | public void pullUpToLoadmore(); 38 | 39 | public void releaseToLoadmore(); 40 | 41 | public void onRefreshing(); 42 | 43 | public void onLoading(); 44 | 45 | public void setVisiableHeight(int height); 46 | 47 | public int getVisiableHeight(); 48 | 49 | public void onDragSlide(float deltaY); 50 | 51 | public int getLoadMorePullUpDistance(); 52 | 53 | public void setLoadMorePullUpDistance(int deltaY); 54 | 55 | public void footerViewShow(); 56 | 57 | public void footerViewHide(); 58 | 59 | public int getRealHeaderContentHeight(); 60 | 61 | public void setPullRefreshEnable(boolean enable); 62 | 63 | public void setLoadMoreEnable(boolean enable); 64 | 65 | public void setRefreshTime(String refreshTime); 66 | 67 | public void setHeaderIcon(int resId); 68 | 69 | public void onStyleChange(int state); 70 | } 71 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/CBRefreshTopSearchView.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.widget.ImageView; 7 | import android.widget.LinearLayout; 8 | 9 | 10 | public class CBRefreshTopSearchView extends CBRefreshHeaderView { 11 | private LinearLayout container; 12 | private ImageView searchImg; 13 | 14 | public CBRefreshTopSearchView(Context context) { 15 | super(context); 16 | initView(context); 17 | } 18 | 19 | /** 20 | * @param context 21 | * @param attrs 22 | */ 23 | public CBRefreshTopSearchView(Context context, AttributeSet attrs) { 24 | super(context, attrs); 25 | initView(context); 26 | } 27 | 28 | private void initView(Context context) { 29 | // in the first set the header's height = 0 30 | LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0); 31 | container = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.cbpullrefrsh_topsearch, null); 32 | searchImg = (ImageView) container.findViewById(R.id.pull2reresh_top_search); 33 | addView(container, lp); 34 | } 35 | 36 | 37 | @Override 38 | public void setVisiableHeight(int height) { 39 | if (height < 0) 40 | height = 0; 41 | LayoutParams lp = (LayoutParams) container.getLayoutParams(); 42 | lp.height = height; 43 | container.setLayoutParams(lp); 44 | } 45 | 46 | public int getVisiableHeight() { 47 | return container.getHeight(); 48 | } 49 | 50 | @Override 51 | public int getRealHeaderContentHeight() { 52 | return searchImg.getHeight(); 53 | } 54 | } -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/SwipeMenu/SwipeMenu.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.SwipeMenu; 2 | 3 | import android.content.Context; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class SwipeMenu { 9 | 10 | private Context mContext; 11 | private List mItems; 12 | private int mViewType; 13 | 14 | public SwipeMenu(Context context) { 15 | mContext = context; 16 | mItems = new ArrayList(); 17 | } 18 | 19 | public Context getContext() { 20 | return mContext; 21 | } 22 | 23 | public void addMenuItem(SwipeMenuItem item) { 24 | mItems.add(item); 25 | } 26 | 27 | public void removeMenuItem(SwipeMenuItem item) { 28 | mItems.remove(item); 29 | } 30 | 31 | public List getMenuItems() { 32 | return mItems; 33 | } 34 | 35 | public SwipeMenuItem getMenuItem(int index) { 36 | return mItems.get(index); 37 | } 38 | 39 | public int getViewType() { 40 | return mViewType; 41 | } 42 | 43 | public void setViewType(int viewType) { 44 | this.mViewType = viewType; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/SwipeMenu/SwipeMenuAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.SwipeMenu; 2 | 3 | import android.content.Context; 4 | import android.database.DataSetObserver; 5 | import android.graphics.Color; 6 | import android.graphics.drawable.ColorDrawable; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.animation.LinearInterpolator; 10 | import android.widget.ListAdapter; 11 | import android.widget.WrapperListAdapter; 12 | 13 | import com.zhl.CBPullRefresh.CBPullRefreshListView; 14 | 15 | 16 | public class SwipeMenuAdapter implements WrapperListAdapter, SwipeMenuView.OnSwipeItemClickListener { 17 | 18 | private ListAdapter mAdapter; 19 | private Context mContext; 20 | private CBPullRefreshListView.OnMenuItemClickListener onMenuItemClickListener; 21 | 22 | public SwipeMenuAdapter(Context context, ListAdapter adapter) { 23 | mAdapter = adapter; 24 | mContext = context; 25 | } 26 | 27 | @Override 28 | public int getCount() { 29 | return mAdapter.getCount(); 30 | } 31 | 32 | @Override 33 | public Object getItem(int position) { 34 | return mAdapter.getItem(position); 35 | } 36 | 37 | @Override 38 | public long getItemId(int position) { 39 | return mAdapter.getItemId(position); 40 | } 41 | 42 | @Override 43 | public View getView(int position, View convertView, ViewGroup parent) { 44 | SwipeMenuLayout layout = null; 45 | if (convertView == null) { 46 | View contentView = mAdapter.getView(position, convertView, parent); 47 | SwipeMenu menu = new SwipeMenu(mContext); 48 | menu.setViewType(mAdapter.getItemViewType(position)); 49 | createMenu(menu); 50 | SwipeMenuView menuView = new SwipeMenuView(menu); 51 | menuView.setOnSwipeItemClickListener(this); 52 | // CBPullRefreshListView listView = (CBPullRefreshListView) parent; 53 | layout = new SwipeMenuLayout(contentView, menuView, new LinearInterpolator(), 54 | new LinearInterpolator()); 55 | layout.setPosition(position); 56 | } else { 57 | layout = (SwipeMenuLayout) convertView; 58 | layout.closeMenu(); 59 | layout.setPosition(position); 60 | mAdapter.getView(position, layout.getContentView(), parent); 61 | } 62 | return layout; 63 | } 64 | 65 | public void createMenu(SwipeMenu menu) { 66 | // Test Code 67 | SwipeMenuItem item = new SwipeMenuItem(mContext); 68 | item.setTitle("Item 1"); 69 | item.setBackground(new ColorDrawable(Color.GRAY)); 70 | item.setWidth(300); 71 | menu.addMenuItem(item); 72 | 73 | item = new SwipeMenuItem(mContext); 74 | item.setTitle("Item 2"); 75 | item.setBackground(new ColorDrawable(Color.RED)); 76 | item.setWidth(300); 77 | menu.addMenuItem(item); 78 | } 79 | 80 | @Override 81 | public void onItemClick(SwipeMenuView view, SwipeMenu menu, int index) { 82 | if (onMenuItemClickListener != null) { 83 | onMenuItemClickListener.onMenuItemClick(view.getPosition(), menu, index); 84 | } 85 | } 86 | 87 | public void setOnMenuItemClickListener(CBPullRefreshListView.OnMenuItemClickListener onMenuItemClickListener) { 88 | this.onMenuItemClickListener = onMenuItemClickListener; 89 | } 90 | 91 | @Override 92 | public void registerDataSetObserver(DataSetObserver observer) { 93 | mAdapter.registerDataSetObserver(observer); 94 | } 95 | 96 | @Override 97 | public void unregisterDataSetObserver(DataSetObserver observer) { 98 | mAdapter.unregisterDataSetObserver(observer); 99 | } 100 | 101 | @Override 102 | public boolean areAllItemsEnabled() { 103 | return mAdapter.areAllItemsEnabled(); 104 | } 105 | 106 | @Override 107 | public boolean isEnabled(int position) { 108 | return mAdapter.isEnabled(position); 109 | } 110 | 111 | @Override 112 | public boolean hasStableIds() { 113 | return mAdapter.hasStableIds(); 114 | } 115 | 116 | @Override 117 | public int getItemViewType(int position) { 118 | return mAdapter.getItemViewType(position); 119 | } 120 | 121 | @Override 122 | public int getViewTypeCount() { 123 | return mAdapter.getViewTypeCount(); 124 | } 125 | 126 | @Override 127 | public boolean isEmpty() { 128 | return mAdapter.isEmpty(); 129 | } 130 | 131 | @Override 132 | public ListAdapter getWrappedAdapter() { 133 | return mAdapter; 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/SwipeMenu/SwipeMenuCreator.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.SwipeMenu; 2 | 3 | public interface SwipeMenuCreator { 4 | 5 | void create(SwipeMenu menu); 6 | } 7 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/SwipeMenu/SwipeMenuItem.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.SwipeMenu; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | 6 | public class SwipeMenuItem { 7 | 8 | private int id; 9 | private Context mContext; 10 | private String title; 11 | private Drawable icon; 12 | private Drawable background; 13 | private int titleColor; 14 | private int titleSize; 15 | private int width; 16 | 17 | public SwipeMenuItem(Context context) { 18 | mContext = context; 19 | } 20 | 21 | public int getId() { 22 | return id; 23 | } 24 | 25 | public void setId(int id) { 26 | this.id = id; 27 | } 28 | 29 | public int getTitleColor() { 30 | return titleColor; 31 | } 32 | 33 | public int getTitleSize() { 34 | return titleSize; 35 | } 36 | 37 | public void setTitleSize(int titleSize) { 38 | this.titleSize = titleSize; 39 | } 40 | 41 | public void setTitleColor(int titleColor) { 42 | this.titleColor = titleColor; 43 | } 44 | 45 | public String getTitle() { 46 | return title; 47 | } 48 | 49 | public void setTitle(String title) { 50 | this.title = title; 51 | } 52 | 53 | public void setTitle(int resId) { 54 | setTitle(mContext.getString(resId)); 55 | } 56 | 57 | public Drawable getIcon() { 58 | return icon; 59 | } 60 | 61 | public void setIcon(Drawable icon) { 62 | this.icon = icon; 63 | } 64 | 65 | public void setIcon(int resId) { 66 | this.icon = mContext.getResources().getDrawable(resId); 67 | } 68 | 69 | public Drawable getBackground() { 70 | return background; 71 | } 72 | 73 | public void setBackground(Drawable background) { 74 | this.background = background; 75 | } 76 | 77 | public void setBackground(int resId) { 78 | this.background = mContext.getResources().getDrawable(resId); 79 | } 80 | 81 | public int getWidth() { 82 | return width; 83 | } 84 | 85 | public void setWidth(int width) { 86 | this.width = width; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/SwipeMenu/SwipeMenuLayout.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.SwipeMenu; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.GestureDetectorCompat; 5 | import android.support.v4.widget.ScrollerCompat; 6 | import android.util.AttributeSet; 7 | import android.util.Log; 8 | import android.util.TypedValue; 9 | import android.view.GestureDetector; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | import android.view.animation.Interpolator; 13 | import android.widget.AbsListView; 14 | import android.widget.FrameLayout; 15 | import android.widget.Scroller; 16 | 17 | public class SwipeMenuLayout extends FrameLayout { 18 | 19 | private static final int CONTENT_VIEW_ID = 1; 20 | private static final int MENU_VIEW_ID = 2; 21 | 22 | private static final int STATE_CLOSE = 0; 23 | private static final int STATE_OPEN = 1; 24 | 25 | private View mContentView; 26 | private SwipeMenuView mMenuView; 27 | private int mDownX; 28 | private int state = STATE_CLOSE; 29 | private GestureDetectorCompat mGestureDetector; 30 | private GestureDetector.OnGestureListener mGestureListener; 31 | private boolean isFling; 32 | private int MIN_FLING = dp2px(15); 33 | private int MAX_VELOCITYX = -dp2px(500); 34 | private ScrollerCompat mOpenScroller; 35 | private ScrollerCompat mCloseScroller; 36 | private int mBaseX; 37 | private int position; 38 | private Interpolator mCloseInterpolator; 39 | private Interpolator mOpenInterpolator; 40 | 41 | public SwipeMenuLayout(View contentView, SwipeMenuView menuView) { 42 | this(contentView, menuView, null, null); 43 | } 44 | 45 | public SwipeMenuLayout(View contentView, SwipeMenuView menuView, Interpolator closeInterpolator, 46 | Interpolator openInterpolator) { 47 | super(contentView.getContext()); 48 | mCloseInterpolator = closeInterpolator; 49 | mOpenInterpolator = openInterpolator; 50 | mContentView = contentView; 51 | mMenuView = menuView; 52 | mMenuView.setLayout(this); 53 | init(); 54 | } 55 | 56 | private SwipeMenuLayout(Context context, AttributeSet attrs) { 57 | super(context, attrs); 58 | } 59 | 60 | private SwipeMenuLayout(Context context) { 61 | super(context); 62 | } 63 | 64 | public int getPosition() { 65 | return position; 66 | } 67 | 68 | public void setPosition(int position) { 69 | this.position = position; 70 | mMenuView.setPosition(position); 71 | } 72 | 73 | private void init() { 74 | setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 75 | mGestureListener = new GestureDetector.SimpleOnGestureListener() { 76 | @Override 77 | public boolean onDown(MotionEvent e) { 78 | isFling = false; 79 | return true; 80 | } 81 | 82 | @Override 83 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 84 | // TODO 85 | if ((e1.getX() - e2.getX()) > MIN_FLING && velocityX < MAX_VELOCITYX) { 86 | isFling = true; 87 | } 88 | // Log.i("byz", MAX_VELOCITYX + ", velocityX = " + velocityX); 89 | return super.onFling(e1, e2, velocityX, velocityY); 90 | } 91 | }; 92 | mGestureDetector = new GestureDetectorCompat(getContext(), mGestureListener); 93 | 94 | if (mCloseInterpolator != null) { 95 | mCloseScroller = ScrollerCompat.create(getContext(), mCloseInterpolator); 96 | } else { 97 | mCloseScroller = ScrollerCompat.create(getContext()); 98 | } 99 | if (mOpenInterpolator != null) { 100 | mOpenScroller = ScrollerCompat.create(getContext(), mOpenInterpolator); 101 | } else { 102 | mOpenScroller = ScrollerCompat.create(getContext()); 103 | } 104 | 105 | LayoutParams contentParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 106 | mContentView.setLayoutParams(contentParams); 107 | if (mContentView.getId() < 1) { 108 | mContentView.setId(CONTENT_VIEW_ID); 109 | } 110 | 111 | mMenuView.setId(MENU_VIEW_ID); 112 | mMenuView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); 113 | 114 | addView(mContentView); 115 | addView(mMenuView); 116 | 117 | } 118 | 119 | @Override 120 | protected void onAttachedToWindow() { 121 | super.onAttachedToWindow(); 122 | } 123 | 124 | @Override 125 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 126 | super.onSizeChanged(w, h, oldw, oldh); 127 | } 128 | 129 | public boolean onSwipe(MotionEvent event) { 130 | mGestureDetector.onTouchEvent(event); 131 | switch (event.getAction()) { 132 | case MotionEvent.ACTION_DOWN: 133 | mDownX = (int) event.getX(); 134 | isFling = false; 135 | break; 136 | case MotionEvent.ACTION_MOVE: 137 | // Log.i("byz", "downX = " + mDownX + ", moveX = " + event.getX()); 138 | int dis = (int) (mDownX - event.getX()); 139 | if (state == STATE_OPEN) { 140 | dis += mMenuView.getWidth(); 141 | } 142 | swipe(dis); 143 | break; 144 | case MotionEvent.ACTION_UP: 145 | if (isFling || (mDownX - event.getX()) > (mMenuView.getWidth() / 2)) { 146 | // open 147 | smoothOpenMenu(); 148 | } else { 149 | // close 150 | smoothCloseMenu(); 151 | return false; 152 | } 153 | break; 154 | } 155 | return false; 156 | } 157 | 158 | /** 159 | * 滑动侧滑菜单 160 | * @param dis 161 | */ 162 | public void swipeMenuSlide(int dis){ 163 | if (state == STATE_OPEN) { 164 | dis += mMenuView.getWidth(); 165 | } 166 | swipe(dis); 167 | } 168 | 169 | /** 170 | * 手指快速滑动的时候是打开还是关闭侧滑菜单 171 | * @param isFling 172 | * @param dix 173 | */ 174 | public void swipeMenuFling(boolean isFling,int dix){ 175 | if (isFling || dix > (mMenuView.getWidth() / 2)) { 176 | // open 177 | smoothOpenMenu(); 178 | } else { 179 | // close 180 | smoothCloseMenu(); 181 | } 182 | } 183 | 184 | 185 | public boolean isOpen() { 186 | return state == STATE_OPEN; 187 | } 188 | 189 | public boolean isActive() { 190 | if (mContentView != null) { 191 | return mContentView.getLeft() != 0; 192 | } 193 | return false; 194 | } 195 | 196 | @Override 197 | public boolean onTouchEvent(MotionEvent event) { 198 | return super.onTouchEvent(event); 199 | } 200 | 201 | private void swipe(int dis) { 202 | if (dis > mMenuView.getWidth()) { 203 | dis = mMenuView.getWidth(); 204 | } 205 | if (dis < 0) { 206 | dis = 0; 207 | } 208 | mContentView.layout(-dis, mContentView.getTop(), mContentView.getWidth() - dis, getMeasuredHeight()); 209 | mMenuView.layout(mContentView.getWidth() - dis, mMenuView.getTop(), 210 | mContentView.getWidth() + mMenuView.getWidth() - dis, getMeasuredHeight()); 211 | } 212 | 213 | @Override 214 | public void computeScroll() { 215 | if (state == STATE_OPEN) { 216 | if (mOpenScroller.computeScrollOffset()) { 217 | swipe(mOpenScroller.getCurrX()); 218 | postInvalidate(); 219 | } 220 | } else { 221 | if (mCloseScroller.computeScrollOffset()) { 222 | swipe(mBaseX - mCloseScroller.getCurrX()); 223 | postInvalidate(); 224 | } 225 | } 226 | } 227 | 228 | public void smoothCloseMenu() { 229 | state = STATE_CLOSE; 230 | mBaseX = -mContentView.getLeft(); 231 | mCloseScroller.startScroll(0, 0, mBaseX, 0, 350); 232 | postInvalidate(); 233 | } 234 | 235 | public void smoothOpenMenu() { 236 | state = STATE_OPEN; 237 | mOpenScroller.startScroll(-mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350); 238 | postInvalidate(); 239 | } 240 | 241 | public void closeMenu() { 242 | if (mCloseScroller.computeScrollOffset()) { 243 | mCloseScroller.abortAnimation(); 244 | } 245 | if (state == STATE_OPEN) { 246 | state = STATE_CLOSE; 247 | swipe(0); 248 | } 249 | } 250 | 251 | public void openMenu() { 252 | if (state == STATE_CLOSE) { 253 | state = STATE_OPEN; 254 | swipe(mMenuView.getWidth()); 255 | } 256 | } 257 | 258 | public View getContentView() { 259 | return mContentView; 260 | } 261 | 262 | public SwipeMenuView getMenuView() { 263 | return mMenuView; 264 | } 265 | 266 | private int dp2px(int dp) { 267 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources() 268 | .getDisplayMetrics()); 269 | } 270 | 271 | @Override 272 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 273 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 274 | mMenuView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 275 | MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); 276 | } 277 | 278 | @Override 279 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 280 | mContentView.layout(0, 0, getMeasuredWidth(), getMeasuredHeight()); 281 | mMenuView.layout(getMeasuredWidth(), 0, getMeasuredWidth() + mMenuView.getMeasuredWidth(), 282 | getMeasuredHeight()); 283 | } 284 | 285 | public void setMenuHeight(int measuredHeight) { 286 | Log.i("byz", "pos = " + position + ", height = " + measuredHeight); 287 | LayoutParams params = (LayoutParams) mMenuView.getLayoutParams(); 288 | if (params.height != measuredHeight) { 289 | params.height = measuredHeight; 290 | mMenuView.setLayoutParams(mMenuView.getLayoutParams()); 291 | } 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/SwipeMenu/SwipeMenuView.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.SwipeMenu; 2 | 3 | import android.text.TextUtils; 4 | import android.view.Gravity; 5 | import android.view.View; 6 | import android.view.View.OnClickListener; 7 | import android.widget.ImageView; 8 | import android.widget.LinearLayout; 9 | import android.widget.TextView; 10 | 11 | import java.util.List; 12 | 13 | public class SwipeMenuView extends LinearLayout implements OnClickListener { 14 | 15 | // private CBPullRefreshListView mListView; 16 | private SwipeMenuLayout mLayout; 17 | private SwipeMenu mMenu; 18 | private OnSwipeItemClickListener onItemClickListener; 19 | private int position; 20 | 21 | public int getPosition() { 22 | return position; 23 | } 24 | 25 | public void setPosition(int position) { 26 | this.position = position; 27 | } 28 | 29 | public SwipeMenuView(SwipeMenu menu) { 30 | super(menu.getContext()); 31 | mMenu = menu; 32 | List items = menu.getMenuItems(); 33 | int id = 0; 34 | for (SwipeMenuItem item : items) { 35 | addItem(item, id++); 36 | } 37 | } 38 | 39 | private void addItem(SwipeMenuItem item, int id) { 40 | LayoutParams params = new LayoutParams(item.getWidth(), LayoutParams.MATCH_PARENT); 41 | LinearLayout parent = new LinearLayout(getContext()); 42 | parent.setId(id); 43 | parent.setGravity(Gravity.CENTER); 44 | parent.setOrientation(LinearLayout.VERTICAL); 45 | parent.setLayoutParams(params); 46 | parent.setBackgroundDrawable(item.getBackground()); 47 | parent.setOnClickListener(this); 48 | if (item.getIcon() != null) { 49 | parent.addView(createIcon(item)); 50 | } 51 | if (!TextUtils.isEmpty(item.getTitle())) { 52 | parent.addView(createTitle(item)); 53 | } 54 | addView(parent); 55 | } 56 | 57 | private ImageView createIcon(SwipeMenuItem item) { 58 | ImageView iv = new ImageView(getContext()); 59 | iv.setImageDrawable(item.getIcon()); 60 | return iv; 61 | } 62 | 63 | private TextView createTitle(SwipeMenuItem item) { 64 | TextView tv = new TextView(getContext()); 65 | tv.setText(item.getTitle()); 66 | tv.setGravity(Gravity.CENTER); 67 | tv.setTextSize(item.getTitleSize()); 68 | tv.setTextColor(item.getTitleColor()); 69 | return tv; 70 | } 71 | 72 | @Override 73 | public void onClick(View v) { 74 | if (onItemClickListener != null && mLayout.isOpen()) { 75 | onItemClickListener.onItemClick(this, mMenu, v.getId()); 76 | } 77 | } 78 | 79 | public OnSwipeItemClickListener getOnSwipeItemClickListener() { 80 | return onItemClickListener; 81 | } 82 | 83 | public void setOnSwipeItemClickListener(OnSwipeItemClickListener onItemClickListener) { 84 | this.onItemClickListener = onItemClickListener; 85 | } 86 | 87 | public void setLayout(SwipeMenuLayout mLayout) { 88 | this.mLayout = mLayout; 89 | } 90 | 91 | public static interface OnSwipeItemClickListener { 92 | void onItemClick(SwipeMenuView view, SwipeMenu menu, int index); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/titanic/Titanic.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.titanic; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorSet; 5 | import android.animation.ObjectAnimator; 6 | import android.animation.ValueAnimator; 7 | import android.annotation.SuppressLint; 8 | import android.os.Build; 9 | import android.view.animation.LinearInterpolator; 10 | 11 | 12 | public class Titanic { 13 | 14 | private AnimatorSet animatorSet; 15 | private Animator.AnimatorListener animatorListener; 16 | 17 | public Animator.AnimatorListener getAnimatorListener() { 18 | return animatorListener; 19 | } 20 | 21 | public void setAnimatorListener(Animator.AnimatorListener animatorListener) { 22 | this.animatorListener = animatorListener; 23 | } 24 | 25 | public void start(final TitanicTextView textView) { 26 | 27 | final Runnable animate = new Runnable() { 28 | @Override 29 | public void run() { 30 | 31 | textView.setSinking(true); 32 | 33 | // horizontal animation. 200 = wave.png width 34 | ObjectAnimator maskXAnimator = ObjectAnimator.ofFloat(textView, "maskX", 0, 200); 35 | maskXAnimator.setRepeatCount(ValueAnimator.INFINITE); 36 | maskXAnimator.setDuration(1000); 37 | maskXAnimator.setStartDelay(0); 38 | 39 | int h = textView.getHeight(); 40 | 41 | // vertical animation 42 | // maskY = 0 -> wave vertically centered 43 | // repeat mode REVERSE to go back and forth 44 | ObjectAnimator maskYAnimator = ObjectAnimator.ofFloat(textView, "maskY", h/2, -h/2); 45 | maskYAnimator.setRepeatCount(ValueAnimator.INFINITE); 46 | maskYAnimator.setRepeatMode(ValueAnimator.REVERSE); 47 | maskYAnimator.setDuration(8000); 48 | maskYAnimator.setStartDelay(0); 49 | 50 | // now play both animations together 51 | animatorSet = new AnimatorSet(); 52 | animatorSet.playTogether(maskXAnimator, maskYAnimator); 53 | animatorSet.setInterpolator(new LinearInterpolator()); 54 | animatorSet.addListener(new Animator.AnimatorListener() { 55 | @Override 56 | public void onAnimationStart(Animator animation) { 57 | } 58 | 59 | @SuppressLint("NewApi") 60 | @Override 61 | public void onAnimationEnd(Animator animation) { 62 | textView.setSinking(false); 63 | 64 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 65 | textView.postInvalidate(); 66 | } else { 67 | textView.postInvalidateOnAnimation(); 68 | } 69 | 70 | animatorSet = null; 71 | } 72 | 73 | @Override 74 | public void onAnimationCancel(Animator animation) { 75 | 76 | } 77 | 78 | @Override 79 | public void onAnimationRepeat(Animator animation) { 80 | 81 | } 82 | }); 83 | 84 | 85 | if (animatorListener != null) { 86 | animatorSet.addListener(animatorListener); 87 | } 88 | 89 | animatorSet.start(); 90 | } 91 | }; 92 | 93 | if (!textView.isSetUp()) { 94 | textView.setAnimationSetupCallback(new TitanicTextView.AnimationSetupCallback() { 95 | @Override 96 | public void onSetupAnimation(final TitanicTextView target) { 97 | animate.run(); 98 | } 99 | }); 100 | } else { 101 | animate.run(); 102 | } 103 | } 104 | 105 | public void cancel() { 106 | if (animatorSet != null) { 107 | animatorSet.cancel(); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/titanic/TitanicTextView.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.titanic; 2 | 3 | 4 | import android.content.Context; 5 | import android.content.res.ColorStateList; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapShader; 8 | import android.graphics.Canvas; 9 | import android.graphics.Matrix; 10 | import android.graphics.Shader; 11 | import android.graphics.drawable.Drawable; 12 | import android.util.AttributeSet; 13 | import android.widget.TextView; 14 | 15 | import com.zhl.CBPullRefresh.R; 16 | 17 | 18 | public class TitanicTextView extends TextView { 19 | 20 | public interface AnimationSetupCallback { 21 | public void onSetupAnimation(TitanicTextView titanicTextView); 22 | } 23 | 24 | // callback fired at first onSizeChanged 25 | private AnimationSetupCallback animationSetupCallback; 26 | // wave shader coordinates 27 | private float maskX, maskY; 28 | // if true, the shader will display the wave 29 | private boolean sinking; 30 | // true after the first onSizeChanged 31 | private boolean setUp; 32 | 33 | // shader containing a repeated wave 34 | private BitmapShader shader; 35 | // shader matrix 36 | private Matrix shaderMatrix; 37 | // wave drawable 38 | private Drawable wave; 39 | // (getHeight() - waveHeight) / 2 40 | private float offsetY; 41 | 42 | public TitanicTextView(Context context) { 43 | super(context); 44 | init(); 45 | } 46 | 47 | public TitanicTextView(Context context, AttributeSet attrs) { 48 | super(context, attrs); 49 | init(); 50 | } 51 | 52 | public TitanicTextView(Context context, AttributeSet attrs, int defStyle) { 53 | super(context, attrs, defStyle); 54 | init(); 55 | } 56 | 57 | private void init() { 58 | shaderMatrix = new Matrix(); 59 | } 60 | 61 | public AnimationSetupCallback getAnimationSetupCallback() { 62 | return animationSetupCallback; 63 | } 64 | 65 | public void setAnimationSetupCallback(AnimationSetupCallback animationSetupCallback) { 66 | this.animationSetupCallback = animationSetupCallback; 67 | } 68 | 69 | public float getMaskX() { 70 | return maskX; 71 | } 72 | 73 | public void setMaskX(float maskX) { 74 | this.maskX = maskX; 75 | invalidate(); 76 | } 77 | 78 | public float getMaskY() { 79 | return maskY; 80 | } 81 | 82 | public void setMaskY(float maskY) { 83 | this.maskY = maskY; 84 | invalidate(); 85 | } 86 | 87 | public boolean isSinking() { 88 | return sinking; 89 | } 90 | 91 | public void setSinking(boolean sinking) { 92 | this.sinking = sinking; 93 | } 94 | 95 | public boolean isSetUp() { 96 | return setUp; 97 | } 98 | 99 | @Override 100 | public void setTextColor(int color) { 101 | super.setTextColor(color); 102 | createShader(); 103 | } 104 | 105 | @Override 106 | public void setTextColor(ColorStateList colors) { 107 | super.setTextColor(colors); 108 | createShader(); 109 | } 110 | 111 | @Override 112 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 113 | super.onSizeChanged(w, h, oldw, oldh); 114 | 115 | createShader(); 116 | 117 | if (!setUp) { 118 | setUp = true; 119 | if (animationSetupCallback != null) { 120 | animationSetupCallback.onSetupAnimation(TitanicTextView.this); 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * Create the shader 127 | * draw the wave with current color for a background 128 | * repeat the bitmap horizontally, and clamp colors vertically 129 | */ 130 | private void createShader() { 131 | 132 | if (wave == null) { 133 | wave = getResources().getDrawable(R.drawable.wave); 134 | } 135 | 136 | int waveW = wave.getIntrinsicWidth(); 137 | int waveH = wave.getIntrinsicHeight(); 138 | 139 | Bitmap b = Bitmap.createBitmap(waveW, waveH, Bitmap.Config.ARGB_8888); 140 | Canvas c = new Canvas(b); 141 | 142 | c.drawColor(getCurrentTextColor()); 143 | 144 | wave.setBounds(0, 0, waveW, waveH); 145 | wave.draw(c); 146 | 147 | shader = new BitmapShader(b, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); 148 | getPaint().setShader(shader); 149 | 150 | offsetY = (getHeight() - waveH) / 2; 151 | } 152 | 153 | @Override 154 | protected void onDraw(Canvas canvas) { 155 | 156 | // modify text paint shader according to sinking state 157 | if (sinking && shader != null) { 158 | 159 | // first call after sinking, assign it to our paint 160 | if (getPaint().getShader() == null) { 161 | getPaint().setShader(shader); 162 | } 163 | 164 | // translate shader accordingly to maskX maskY positions 165 | // maskY is affected by the offset to vertically center the wave 166 | shaderMatrix.setTranslate(maskX, maskY + offsetY); 167 | 168 | // assign matrix to invalidate the shader 169 | shader.setLocalMatrix(shaderMatrix); 170 | } else { 171 | getPaint().setShader(null); 172 | } 173 | 174 | super.onDraw(canvas); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/utils/Blur.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.support.v8.renderscript.Allocation; 6 | import android.support.v8.renderscript.Element; 7 | import android.support.v8.renderscript.RenderScript; 8 | import android.support.v8.renderscript.ScriptIntrinsicBlur; 9 | 10 | /** 11 | * Blur.java 12 | * 13 | * @author Manabu-GT on 6/12/14. 14 | */ 15 | public class Blur { 16 | 17 | private static final int DEFAULT_BLUR_RADIUS = 10; 18 | 19 | public static Bitmap apply(Context context, Bitmap sentBitmap) { 20 | return apply(context, sentBitmap, DEFAULT_BLUR_RADIUS); 21 | } 22 | 23 | public static Bitmap apply(Context context, Bitmap sentBitmap, int radius) { 24 | Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); 25 | final RenderScript rs = RenderScript.create(context); 26 | final Allocation input = Allocation.createFromBitmap(rs, sentBitmap, Allocation.MipmapControl.MIPMAP_NONE, 27 | Allocation.USAGE_SCRIPT); 28 | final Allocation output = Allocation.createTyped(rs, input.getType()); 29 | final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); 30 | script.setRadius(radius); 31 | script.setInput(input); 32 | script.forEach(output); 33 | output.copyTo(bitmap); 34 | 35 | // clean up renderscript resources 36 | rs.destroy(); 37 | input.destroy(); 38 | output.destroy(); 39 | script.destroy(); 40 | 41 | return bitmap; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/utils/BlurUtil.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.utils; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.annotation.TargetApi; 6 | import android.graphics.Bitmap; 7 | import android.graphics.Canvas; 8 | import android.os.Build; 9 | import android.os.Handler; 10 | import android.view.View; 11 | import android.view.ViewPropertyAnimator; 12 | import android.view.animation.AlphaAnimation; 13 | import android.view.animation.Animation; 14 | 15 | /** 16 | * BlurUtil.java 17 | * 18 | * @author Manabu-GT on 6/12/14. 19 | */ 20 | public class BlurUtil { 21 | 22 | public static Bitmap drawViewToBitmap(View view, int width, int height, int downSampling) { 23 | return drawViewToBitmap(view, width, height, 0f, 0f, downSampling); 24 | } 25 | 26 | public static Bitmap drawViewToBitmap(View view, int width, int height, float translateX, 27 | float translateY, int downSampling) { 28 | float scale = 1f / downSampling; 29 | int bmpWidth = (int) (width * scale - translateX / downSampling); 30 | int bmpHeight = (int) (height * scale - translateY / downSampling); 31 | Bitmap dest = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888); 32 | Canvas c = new Canvas(dest); 33 | c.translate(-translateX / downSampling, -translateY / downSampling); 34 | if (downSampling > 1) { 35 | c.scale(scale, scale); 36 | } 37 | view.draw(c); 38 | return dest; 39 | } 40 | 41 | public static boolean isPostHoneycomb() { 42 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1; 43 | } 44 | 45 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) 46 | public static void setAlpha(View view, float alpha) { 47 | if (isPostHoneycomb()) { 48 | view.setAlpha(alpha); 49 | } else { 50 | AlphaAnimation alphaAnimation = new AlphaAnimation(alpha, alpha); 51 | // make it instant 52 | alphaAnimation.setDuration(0); 53 | alphaAnimation.setFillAfter(true); 54 | view.startAnimation(alphaAnimation); 55 | } 56 | } 57 | 58 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) 59 | public static void animateAlpha(final View view, float fromAlpha, float toAlpha, int duration, final Runnable endAction) { 60 | if (isPostHoneycomb()) { 61 | ViewPropertyAnimator animator = view.animate().alpha(toAlpha).setDuration(duration); 62 | if (endAction != null) { 63 | animator.setListener(new AnimatorListenerAdapter() { 64 | public void onAnimationEnd(Animator animation) { 65 | endAction.run(); 66 | } 67 | }); 68 | } 69 | } else { 70 | AlphaAnimation alphaAnimation = new AlphaAnimation(fromAlpha, toAlpha); 71 | alphaAnimation.setDuration(duration); 72 | alphaAnimation.setFillAfter(true); 73 | if (endAction != null) { 74 | alphaAnimation.setAnimationListener(new Animation.AnimationListener() { 75 | @Override 76 | public void onAnimationEnd(Animation animation) { 77 | // fixes the crash bug while removing views 78 | Handler handler = new Handler(); 79 | handler.post(endAction); 80 | } 81 | @Override 82 | public void onAnimationStart(Animation animation) { } 83 | @Override 84 | public void onAnimationRepeat(Animation animation) { } 85 | }); 86 | } 87 | view.startAnimation(alphaAnimation); 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/utils/TimeType.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.utils; 2 | 3 | public enum TimeType { 4 | /** 5 | * yyyy-MM-dd hh:mm:ss 6 | */ 7 | DEFAULT, 8 | 9 | /** 10 | * yyyyMMdd hhmmss 11 | */ 12 | DEFAULT_CHINESS, 13 | 14 | /** 15 | * MM-dd HH:mm 16 | */ 17 | DEFAULT_SHORT, 18 | 19 | /** 20 | * MMddhhmm 21 | */ 22 | DEFAULT_CHINESS_SHORT, 23 | 24 | FROMNOW, 25 | 26 | DEFAULT_YEAR; 27 | } -------------------------------------------------------------------------------- /CBPullRefresh/src/main/java/com/zhl/CBPullRefresh/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package com.zhl.CBPullRefresh.utils; 2 | 3 | import android.content.Context; 4 | 5 | import com.zhl.CBPullRefresh.R; 6 | 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import java.util.Locale; 10 | 11 | /** 12 | * Created by zhaohl on 2016-3-24. 13 | */ 14 | public class Utils { 15 | public static String getTimeDifferent(Context context,long time) { 16 | String updateTime = ""; 17 | Date currentTime = new Date(System.currentTimeMillis()); 18 | Date inputTime = new Date(time); 19 | long interval = currentTime.getTime() - inputTime.getTime(); 20 | long days = interval / 86400000; 21 | long hours = (interval - days * 86400000) / 3600000; 22 | long minutes = (interval - days * 86400000 - hours * 3600000) / 60000; 23 | if (days >= 1) { 24 | updateTime = getPublishTime(context,TimeType.DEFAULT_YEAR, inputTime.getTime()); 25 | } else if (hours >= 1) { 26 | updateTime = hours +context.getString(R.string.util_hours_ago) ; 27 | } else { 28 | if (minutes <= 10) { 29 | updateTime = context.getString(R.string.util_a_moment_ago); 30 | } else if (minutes > 10 && minutes <= 20) { 31 | updateTime = context.getString(R.string.util_10_moment_ago); 32 | } else if (minutes > 20 && minutes <= 30) { 33 | updateTime = context.getString(R.string.util_20_moment_ago); 34 | } else if (minutes > 30 && minutes < 60) { 35 | updateTime = context.getString(R.string.util_30_moment_ago); 36 | } 37 | } 38 | return updateTime; 39 | } 40 | 41 | public static String getPublishTime(Context context ,TimeType type, long time) { 42 | if (time == 0) 43 | return ""; 44 | Date date = new Date(time); 45 | SimpleDateFormat dateFormat; 46 | String timeStr = null; 47 | switch (type) { 48 | case DEFAULT: 49 | dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA); 50 | timeStr = dateFormat.format(date); 51 | break; 52 | case DEFAULT_CHINESS: 53 | dateFormat = new SimpleDateFormat(context.getString(R.string.util_format_yyyymmdd_hhmmss), Locale.CHINA); 54 | timeStr = dateFormat.format(date); 55 | break; 56 | case DEFAULT_SHORT: 57 | dateFormat = new SimpleDateFormat("MM-dd HH:mm", Locale.CHINA); 58 | timeStr = dateFormat.format(date); 59 | break; 60 | case DEFAULT_CHINESS_SHORT: 61 | dateFormat = new SimpleDateFormat(context.getString(R.string.util_format_mmdd_hhmm), Locale.CHINA); 62 | timeStr = dateFormat.format(date); 63 | break; 64 | case FROMNOW: 65 | timeStr = getTimeFromNow(context,time); 66 | break; 67 | case DEFAULT_YEAR: 68 | dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA); 69 | timeStr = dateFormat.format(date); 70 | break; 71 | } 72 | return timeStr; 73 | } 74 | 75 | public static String getTimeFromNow(Context context,long time) { 76 | String updateTime = ""; 77 | long currentTime = System.currentTimeMillis(); 78 | long interval = currentTime - time; 79 | long minutes = interval / 60000; 80 | if (minutes < 60) { 81 | minutes = minutes == 0 ? 1 : minutes; 82 | updateTime = minutes + context.getString(R.string.util_miniutes_ago); 83 | } else { 84 | minutes = minutes / 60; 85 | minutes = minutes == 0 ? 1 : minutes; 86 | if (minutes < 24) { 87 | updateTime = minutes + context.getString(R.string.util_hours_ago); 88 | } else { 89 | minutes = minutes / 24; 90 | minutes = minutes == 0 ? 1 : minutes; 91 | updateTime = minutes + context.getString(R.string.util_day_ago); 92 | } 93 | } 94 | return updateTime; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/drawable-hdpi/top_search_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/CBPullRefresh/src/main/res/drawable-hdpi/top_search_bar.png -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/drawable-hdpi/top_search_bar_night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/CBPullRefresh/src/main/res/drawable-hdpi/top_search_bar_night.png -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/drawable-nodpi/wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/CBPullRefresh/src/main/res/drawable-nodpi/wave.png -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/drawable-xhdpi/icon_header_refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/CBPullRefresh/src/main/res/drawable-xhdpi/icon_header_refresh.png -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/drawable-xhdpi/top_pull_refresh_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/CBPullRefresh/src/main/res/drawable-xhdpi/top_pull_refresh_arrow.png -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/drawable-xhdpi/top_search_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/CBPullRefresh/src/main/res/drawable-xhdpi/top_search_bar.png -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/drawable/footer_bg_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/layout/cblistview_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 25 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/layout/cblistview_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 26 | 27 | 35 | 36 | 44 | 45 | 49 | 50 | 57 | 58 | 64 | 65 | 66 | 67 | 75 | 76 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/layout/cbpullrefrsh_topsearch.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 24 | 28 | 29 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | #ECEDED 5 | #3fbecc 6 | #f1494c 7 | #efefef 8 | #f1f1f1 9 | #a6a7a6 10 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /CBPullRefresh/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PullRefreshLibrary 3 | 4 | Hello world! 5 | Settings 6 | 下拉刷新 7 | 松开刷新数据 8 | 正在刷新... 9 | 正在加载... 10 | 上拉加载更多 11 | 松开载入更多 12 | 小时前 13 | 刚刚 14 | 10分钟前 15 | 20分钟前 16 | 30分钟前 17 | yyyy年MM月dd日 HH时mm分ss秒 18 | MM月dd日 HH时mm分 19 | 分钟前 20 | 日前 21 | 22 | -------------------------------------------------------------------------------- /CBPullRefreshListView.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /GIF1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/GIF1.gif -------------------------------------------------------------------------------- /GIF2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/GIF2.gif -------------------------------------------------------------------------------- /GIF3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/GIF3.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](https://jitpack.io/v/yilylong/CBPullRefreshListView.svg)](https://jitpack.io/#yilylong/CBPullRefreshListView) 2 | ## CBPullRefreshListView 3 | 4 | RecyclerView版本 [DragableRecyclerView](https://github.com/yilylong/DragableRecyclerView) 5 | 6 | 下拉刷新很常见,listview带侧滑功能的也很常见。github上将两者结合的也很多比如:[SwipeMenuListView](https://github.com/baoyongzhang/SwipeMenuListView)是带有侧滑功能的lisetview但是无法下拉刷新。而[Android-PullToRefresh-SwipeMenuListView-Sample](https://github.com/licaomeng/Android-PullToRefresh-SwipeMenuListView-Sample)是将几个功能完整结合。看了下他们的实现,是在以前的XListView基础上整合。但listview里面的下拉刷新和上拉加载的动作与刷新头耦合比较严重。如果想自定义自己的刷新头样式稍微麻烦点。于是就想把下拉刷新的功能和刷新头的展示样式抽离分开。listview只管将一些下拉上拉的事件传递出来。刷新头通过实现这些状态方法去做自己想要的刷新样式就可以了。
7 |
8 |
9 |
10 |
11 | 12 | 引入 13 | -- 14 | 15 | Step 1. Add the JitPack repository to your build file 16 | - 17 | 18 | allprojects { 19 | repositories { 20 | ... 21 | maven { url 'https://jitpack.io' } 22 | } 23 | } 24 | 25 | Step 2. Add the dependency 26 | - 27 | dependencies { 28 | compile 'com.github.yilylong:CBPullRefreshListView:1.0.0' 29 | } 30 | 31 | 32 | 33 | 34 | 自定义刷新头 35 | --- 36 | 继承CBRefreshHeaderView 实现几个状态下的回调的方法比如: 37 | 38 | /** 39 | * 设置当前状态 40 | * @param state 41 | */ 42 | @Override 43 | public void setState(int state) { 44 | 45 | } 46 | /** 47 | * 下拉刷新的回调 48 | */ 49 | @Override 50 | public void pullToRefresh() { 51 | 52 | } 53 | /** 54 | * 释放刷新的回调 55 | */ 56 | @Override 57 | public void releaseToRefresh() { 58 | 59 | } 60 | /** 61 | * 正在刷新 62 | */ 63 | @Override 64 | public void onRefreshing() { 65 | 66 | } 67 | /** 68 | * 设置头部或底部的可见高度 69 | * @param height 70 | */ 71 | @Override 72 | public void setVisiableHeight(int height) { 73 | 74 | } 75 | /** 76 | * 获取可见高度 77 | * @return 78 | */ 79 | @Override 80 | public int getVisiableHeight() { 81 | return 0; 82 | } 83 | /** 84 | * 正在拖动 85 | * @param deltaY 86 | */ 87 | @Override 88 | public void onDragSlide(float deltaY) { 89 | 90 | } 91 | 92 | 在这些方法中去改变刷新头不同状态下的表现形式。(下拉刷新是通过改变头部高度实现的)可以参考CBRefreshHeader MyCustomRrefreshHeader 有哪些状态回调可以查看 CBRefreshState 93 | 94 | CBPullRefreshListView一些其他方法: 95 | --- 96 | 设置自定义的刷新头 97 | - 98 | mListView.setRefreshHeader(myRefreshHeader); 99 | 100 | 设置是否显示顶部的搜索栏(可自定义) 101 | - 102 | mListView.showTobSearchBar(true); 103 | mListView.setTopSearchBar(myTopSearchBar); 104 | 105 | 设置swipe开关 106 | - 107 | 108 | mListView.setSwipeEnable(false) 109 | 110 | 设置下拉刷新的监听接口 111 | - 112 | mListView.setOnPullRefreshListener(new CBPullRefreshListView.OnPullRefreshListener() { 113 | @Override 114 | public void onRefresh() { 115 | mListView.postDelayed(new Runnable() { 116 | @Override 117 | public void run() { 118 | mListView.stopRefresh(); 119 | } 120 | }, 3000); 121 | } 122 | 123 | @Override 124 | public void onLoadMore() { 125 | mListView.postDelayed(new Runnable() { 126 | @Override 127 | public void run() { 128 | mListView.stopLoadMore(); 129 | } 130 | }, 3000); 131 | } 132 | 133 | @Override 134 | public void onUpdateRefreshTime(long time) { 135 | 136 | } 137 | 138 | }); 139 | 140 | 设置侧滑菜单项目 141 | - 142 | 143 | SwipeMenuCreator creator = new SwipeMenuCreator() { 144 | 145 | @Override 146 | public void create(SwipeMenu menu) { 147 | 148 | SwipeMenuItem collectionItem = new SwipeMenuItem(getApplicationContext()); 149 | collectionItem.setBackground(R.color.green); 150 | collectionItem.setWidth(dp2px(CustomRefreshHeaderActivity.this, 90)); 151 | collectionItem.setTitle("收藏"); 152 | collectionItem.setTitleSize(18); 153 | collectionItem.setTitleColor(Color.WHITE); 154 | collectionItem.setIcon(R.drawable.icon_collection); 155 | menu.addMenuItem(collectionItem); 156 | 157 | SwipeMenuItem deleteItem = new SwipeMenuItem(getApplicationContext()); 158 | deleteItem.setBackground(R.color.red); 159 | deleteItem.setWidth(dp2px(CustomRefreshHeaderActivity.this, 90)); 160 | deleteItem.setTitle("删除"); 161 | deleteItem.setIcon(R.drawable.icon_delete); 162 | deleteItem.setTitleSize(18); 163 | deleteItem.setTitleColor(Color.WHITE); 164 | menu.addMenuItem(deleteItem); 165 | } 166 | }; 167 | mListView.setMenuCreator(creator); 168 | 169 | 设置侧滑菜单项的点击添加和listview的item点击监听 170 | 171 | mListView.setOnMenuItemClickListener(new CBPullRefreshListView.OnMenuItemClickListener() { 172 | @Override 173 | public void onMenuItemClick(int position, SwipeMenu menu, int index) { 174 | Toast.makeText(CustomRefreshHeaderActivity.this, "点击了item swipe 菜单的第" + index, Toast.LENGTH_SHORT).show(); 175 | } 176 | }); 177 | mListView.setOnItemClickListener(new CBPullRefreshListView.OnItemClickListener() { 178 | @Override 179 | public void onItemClick(AdapterView parent, View view, int position, long id) { 180 | Toast.makeText(CustomRefreshHeaderActivity.this,"点击了"+position,Toast.LENGTH_SHORT).show(); 181 | } 182 | }); 183 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.zhl.cbpullrefreshlistview" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | renderscriptTargetApi 20 14 | renderscriptSupportModeEnabled true 15 | ndk { 16 | abiFilters "armeabi", "armeabi-v7a", "x86", "mips" 17 | } 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | } 26 | 27 | dependencies { 28 | compile fileTree(dir: 'libs', include: ['*.jar']) 29 | compile 'com.android.support:appcompat-v7:25.0.0' 30 | compile project(':CBPullRefresh') 31 | compile 'com.wang.avi:library:1.0.5' 32 | compile 'com.nineoldandroids:library:2.4.0' 33 | compile 'com.rodolfonavalon:ShapeRippleLibrary:0.2.0' 34 | } 35 | -------------------------------------------------------------------------------- /app/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:\WORK\Android\AndroidSDK/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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/zhl/cbpullrefreshlistview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.zhl.cbpullrefreshlistview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhl/cbpullrefreshlistview/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhl.cbpullrefreshlistview; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.FragmentActivity; 5 | import android.view.LayoutInflater; 6 | 7 | public class BaseActivity extends FragmentActivity{ 8 | protected DragBackLayout dragBacklayout; 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | dragBacklayout = (DragBackLayout) LayoutInflater.from(this).inflate(R.layout.base, null); 12 | dragBacklayout.attachToActivity(this); 13 | } 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhl/cbpullrefreshlistview/CustomRefreshHeaderActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhl.cbpullrefreshlistview; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.util.TypedValue; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.AdapterView; 14 | import android.widget.BaseAdapter; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | import android.widget.Toast; 18 | 19 | import com.zhl.CBPullRefresh.CBPullRefreshListView; 20 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenu; 21 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuCreator; 22 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuItem; 23 | 24 | import java.util.ArrayList; 25 | 26 | public class CustomRefreshHeaderActivity extends AppCompatActivity { 27 | private TestAdapter mAdatper; 28 | private ArrayList DataList = new ArrayList(); 29 | private CBPullRefreshListView mListView; 30 | private ImageView blurView,blurContentView; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_custom_header_layout); 36 | initData(); 37 | initView(); 38 | } 39 | 40 | private void initView() { 41 | blurView = (ImageView) findViewById(R.id.blur_view); 42 | blurContentView = (ImageView) findViewById(R.id.blur_orign); 43 | mListView = (CBPullRefreshListView) findViewById(R.id.listview); 44 | MyCustomRrefreshHeader myRefreshHeader = new MyCustomRrefreshHeader(this); 45 | myRefreshHeader.setBlurView(blurContentView,blurView); 46 | mListView.setRefreshHeader(myRefreshHeader); 47 | mListView.setAdapter(mAdatper = new TestAdapter()); 48 | mListView.setPullRefreshEnable(true); 49 | mListView.setPullLoadMoreEnable(true); 50 | mListView.setSwipeEnable(true); 51 | // mListView.showTobSearchBar(true); 52 | mListView.setOnPullRefreshListener(new CBPullRefreshListView.OnPullRefreshListener() { 53 | @Override 54 | public void onRefresh() { 55 | mListView.postDelayed(new Runnable() { 56 | @Override 57 | public void run() { 58 | mListView.stopRefresh(); 59 | } 60 | }, 3000); 61 | } 62 | 63 | @Override 64 | public void onLoadMore() { 65 | mListView.postDelayed(new Runnable() { 66 | @Override 67 | public void run() { 68 | mListView.stopLoadMore(); 69 | } 70 | }, 3000); 71 | } 72 | 73 | @Override 74 | public void onUpdateRefreshTime(long time) { 75 | 76 | } 77 | 78 | }); 79 | SwipeMenuCreator creator = new SwipeMenuCreator() { 80 | 81 | @Override 82 | public void create(SwipeMenu menu) { 83 | 84 | SwipeMenuItem collectionItem = new SwipeMenuItem(getApplicationContext()); 85 | collectionItem.setBackground(R.color.green); 86 | collectionItem.setWidth(dp2px(CustomRefreshHeaderActivity.this, 90)); 87 | collectionItem.setTitle("收藏"); 88 | collectionItem.setTitleSize(18); 89 | collectionItem.setTitleColor(Color.WHITE); 90 | // collectionItem.setIcon(R.drawable.icon_collection); 91 | menu.addMenuItem(collectionItem); 92 | 93 | SwipeMenuItem deleteItem = new SwipeMenuItem(getApplicationContext()); 94 | deleteItem.setBackground(R.color.red); 95 | deleteItem.setWidth(dp2px(CustomRefreshHeaderActivity.this, 90)); 96 | deleteItem.setTitle("删除"); 97 | // deleteItem.setIcon(R.drawable.icon_delete); 98 | deleteItem.setTitleSize(18); 99 | deleteItem.setTitleColor(Color.WHITE); 100 | menu.addMenuItem(deleteItem); 101 | } 102 | }; 103 | // set creator 104 | mListView.setMenuCreator(creator); 105 | mListView.setOnMenuItemClickListener(new CBPullRefreshListView.OnMenuItemClickListener() { 106 | @Override 107 | public void onMenuItemClick(int position, SwipeMenu menu, int index) { 108 | Toast.makeText(CustomRefreshHeaderActivity.this, "点击了item swipe 菜单的第" + index, Toast.LENGTH_SHORT).show(); 109 | } 110 | }); 111 | mListView.setOnItemClickListener(new CBPullRefreshListView.OnItemClickListener() { 112 | @Override 113 | public void onItemClick(AdapterView parent, View view, int position, long id) { 114 | Toast.makeText(CustomRefreshHeaderActivity.this,"点击了"+position,Toast.LENGTH_SHORT).show(); 115 | } 116 | }); 117 | } 118 | 119 | private void initData() { 120 | for (int i = 0; i < 30; i++) { 121 | DataList.add(new String("this is a cbpullrefreshlistview test" + i)); 122 | } 123 | } 124 | 125 | 126 | @Override 127 | public boolean onCreateOptionsMenu(Menu menu) { 128 | getMenuInflater().inflate(R.menu.menu_main, menu); 129 | return true; 130 | } 131 | 132 | @Override 133 | public boolean onOptionsItemSelected(MenuItem item) { 134 | switch (item.getItemId()){ 135 | case R.id.action_settings: 136 | Intent intent = new Intent(this,DragbackActivity.class); 137 | startActivity(intent); 138 | break; 139 | } 140 | return super.onOptionsItemSelected(item); 141 | } 142 | 143 | class TestAdapter extends BaseAdapter { 144 | 145 | 146 | @Override 147 | public int getCount() { 148 | return DataList == null ? 0 : DataList.size(); 149 | } 150 | 151 | @Override 152 | public Object getItem(int position) { 153 | return DataList.get(position); 154 | } 155 | 156 | @Override 157 | public long getItemId(int position) { 158 | return 0; 159 | } 160 | 161 | @Override 162 | public View getView(int position, View convertView, ViewGroup parent) { 163 | ViewHolder viewHolder = null; 164 | if (convertView == null) { 165 | viewHolder = new ViewHolder(); 166 | convertView = getLayoutInflater().inflate(R.layout.item_listview3, parent, false); 167 | viewHolder.title = (TextView) convertView.findViewById(R.id.item_title); 168 | convertView.setTag(viewHolder); 169 | } else { 170 | viewHolder = (ViewHolder) convertView.getTag(); 171 | } 172 | viewHolder.title.setText(DataList.get(position)); 173 | return convertView; 174 | } 175 | } 176 | 177 | class ViewHolder { 178 | TextView title; 179 | } 180 | 181 | public int dp2px(Context context,int dp) { 182 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhl/cbpullrefreshlistview/CustomRefreshHeaderRippleActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhl.cbpullrefreshlistview; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.util.TypedValue; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.AdapterView; 14 | import android.widget.BaseAdapter; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | import android.widget.Toast; 18 | 19 | import com.zhl.CBPullRefresh.CBPullRefreshListView; 20 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenu; 21 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuCreator; 22 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuItem; 23 | 24 | import java.util.ArrayList; 25 | 26 | public class CustomRefreshHeaderRippleActivity extends AppCompatActivity { 27 | private TestAdapter mAdatper; 28 | private ArrayList DataList = new ArrayList(); 29 | private CBPullRefreshListView mListView; 30 | private ImageView blurView,blurContentView; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_custom_header_layout_ripple); 36 | initData(); 37 | initView(); 38 | } 39 | 40 | private void initView() { 41 | blurView = (ImageView) findViewById(R.id.blur_view); 42 | blurContentView = (ImageView) findViewById(R.id.blur_orign); 43 | mListView = (CBPullRefreshListView) findViewById(R.id.listview); 44 | MyCustomRrefreshHeaderRippleColor myRefreshHeader = new MyCustomRrefreshHeaderRippleColor(this); 45 | mListView.setRefreshHeader(myRefreshHeader); 46 | mListView.setAdapter(mAdatper = new TestAdapter()); 47 | mListView.setSwipeEnable(true); 48 | mListView.setPullRefreshEnable(true); 49 | mListView.setPullLoadMoreEnable(true); 50 | // mListView.showTobSearchBar(true); 51 | mListView.setOnPullRefreshListener(new CBPullRefreshListView.OnPullRefreshListener() { 52 | @Override 53 | public void onRefresh() { 54 | mListView.postDelayed(new Runnable() { 55 | @Override 56 | public void run() { 57 | mListView.stopRefresh(); 58 | } 59 | }, 10000); 60 | } 61 | 62 | @Override 63 | public void onLoadMore() { 64 | mListView.postDelayed(new Runnable() { 65 | @Override 66 | public void run() { 67 | mListView.stopLoadMore(); 68 | } 69 | }, 10000); 70 | } 71 | 72 | @Override 73 | public void onUpdateRefreshTime(long time) { 74 | 75 | } 76 | 77 | }); 78 | SwipeMenuCreator creator = new SwipeMenuCreator() { 79 | 80 | @Override 81 | public void create(SwipeMenu menu) { 82 | 83 | SwipeMenuItem collectionItem = new SwipeMenuItem(getApplicationContext()); 84 | collectionItem.setBackground(R.color.green); 85 | collectionItem.setWidth(dp2px(CustomRefreshHeaderRippleActivity.this, 90)); 86 | collectionItem.setTitle("收藏"); 87 | collectionItem.setTitleSize(18); 88 | collectionItem.setTitleColor(Color.WHITE); 89 | // collectionItem.setIcon(R.drawable.icon_collection); 90 | menu.addMenuItem(collectionItem); 91 | 92 | SwipeMenuItem deleteItem = new SwipeMenuItem(getApplicationContext()); 93 | deleteItem.setBackground(R.color.red); 94 | deleteItem.setWidth(dp2px(CustomRefreshHeaderRippleActivity.this, 90)); 95 | deleteItem.setTitle("删除"); 96 | // deleteItem.setIcon(R.drawable.icon_delete); 97 | deleteItem.setTitleSize(18); 98 | deleteItem.setTitleColor(Color.WHITE); 99 | menu.addMenuItem(deleteItem); 100 | } 101 | }; 102 | // set creator 103 | mListView.setMenuCreator(creator); 104 | mListView.setOnMenuItemClickListener(new CBPullRefreshListView.OnMenuItemClickListener() { 105 | @Override 106 | public void onMenuItemClick(int position, SwipeMenu menu, int index) { 107 | Toast.makeText(CustomRefreshHeaderRippleActivity.this, "点击了item swipe 菜单的第" + index, Toast.LENGTH_SHORT).show(); 108 | } 109 | }); 110 | mListView.setOnItemClickListener(new CBPullRefreshListView.OnItemClickListener() { 111 | @Override 112 | public void onItemClick(AdapterView parent, View view, int position, long id) { 113 | Toast.makeText(CustomRefreshHeaderRippleActivity.this,"点击了"+position,Toast.LENGTH_SHORT).show(); 114 | } 115 | }); 116 | } 117 | 118 | private void initData() { 119 | for (int i = 0; i < 30; i++) { 120 | DataList.add(new String("this is a cbpullrefreshlistview test" + i)); 121 | } 122 | } 123 | 124 | 125 | @Override 126 | public boolean onCreateOptionsMenu(Menu menu) { 127 | getMenuInflater().inflate(R.menu.menu_main, menu); 128 | return true; 129 | } 130 | 131 | @Override 132 | public boolean onOptionsItemSelected(MenuItem item) { 133 | switch (item.getItemId()){ 134 | case R.id.action_settings: 135 | Intent intent = new Intent(this,DragbackActivity.class); 136 | startActivity(intent); 137 | break; 138 | } 139 | return super.onOptionsItemSelected(item); 140 | } 141 | 142 | class TestAdapter extends BaseAdapter { 143 | 144 | 145 | @Override 146 | public int getCount() { 147 | return DataList == null ? 0 : DataList.size(); 148 | } 149 | 150 | @Override 151 | public Object getItem(int position) { 152 | return DataList.get(position); 153 | } 154 | 155 | @Override 156 | public long getItemId(int position) { 157 | return 0; 158 | } 159 | 160 | @Override 161 | public View getView(int position, View convertView, ViewGroup parent) { 162 | ViewHolder viewHolder = null; 163 | if (convertView == null) { 164 | viewHolder = new ViewHolder(); 165 | convertView = getLayoutInflater().inflate(R.layout.item_listview3, parent, false); 166 | viewHolder.title = (TextView) convertView.findViewById(R.id.item_title); 167 | convertView.setTag(viewHolder); 168 | } else { 169 | viewHolder = (ViewHolder) convertView.getTag(); 170 | } 171 | viewHolder.title.setText(DataList.get(position)); 172 | return convertView; 173 | } 174 | } 175 | 176 | class ViewHolder { 177 | TextView title; 178 | } 179 | 180 | public int dp2px(Context context,int dp) { 181 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhl/cbpullrefreshlistview/DragBackLayout.java: -------------------------------------------------------------------------------- 1 | package com.zhl.cbpullrefreshlistview; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.graphics.Canvas; 7 | import android.graphics.Rect; 8 | import android.graphics.drawable.Drawable; 9 | import android.support.v4.view.ViewPager; 10 | import android.util.AttributeSet; 11 | import android.view.MotionEvent; 12 | import android.view.View; 13 | import android.view.ViewConfiguration; 14 | import android.view.ViewGroup; 15 | import android.widget.FrameLayout; 16 | import android.widget.GridView; 17 | import android.widget.Scroller; 18 | 19 | import com.zhl.CBPullRefresh.CBPullRefreshListView; 20 | 21 | import java.util.LinkedList; 22 | import java.util.List; 23 | 24 | // import android.util.Log; 25 | 26 | public class DragBackLayout extends FrameLayout { 27 | // private static final String TAG = DragBackLayout.class.getSimpleName(); 28 | private View mContentView; 29 | private int mTouchSlop; 30 | private int downX; 31 | private int downY; 32 | private int tempX; 33 | private Scroller mScroller; 34 | private int viewWidth; 35 | private boolean isSilding; 36 | private boolean isFinish; 37 | private boolean canDragBack = true; 38 | private Drawable mShadowDrawable; 39 | private Activity mActivity; 40 | private List mViewPagers = new LinkedList(); 41 | private List mGridViews = new LinkedList(); 42 | private List mCbPullRefreshListViews = new LinkedList(); 43 | 44 | public DragBackLayout(Context context, AttributeSet attrs) { 45 | this(context, attrs, 0); 46 | } 47 | 48 | public DragBackLayout(Context context, AttributeSet attrs, int defStyle) { 49 | super(context, attrs, defStyle); 50 | 51 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 52 | mScroller = new Scroller(context); 53 | 54 | mShadowDrawable = getResources().getDrawable(R.drawable.swipeback_shadow); 55 | } 56 | 57 | public void attachToActivity(Activity activity) { 58 | mActivity = activity; 59 | TypedArray a = activity.getTheme().obtainStyledAttributes(new int[]{android.R.attr.windowBackground}); 60 | int background = a.getResourceId(0, 0); 61 | a.recycle(); 62 | 63 | ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView(); 64 | ViewGroup decorChild = (ViewGroup) decor.getChildAt(0); 65 | decorChild.setBackgroundResource(background); 66 | decor.removeView(decorChild); 67 | addView(decorChild); 68 | setContentView(decorChild); 69 | decor.addView(this); 70 | } 71 | 72 | private void setContentView(View decorChild) { 73 | mContentView = (View) decorChild.getParent(); 74 | } 75 | 76 | public void setCanDragBack(boolean canDragBack) { 77 | this.canDragBack = canDragBack; 78 | } 79 | 80 | /** 81 | * 事件拦截操作 82 | */ 83 | @Override 84 | public boolean onInterceptTouchEvent(MotionEvent ev) { 85 | if (!canDragBack) { 86 | return super.onInterceptTouchEvent(ev); 87 | } 88 | 89 | // 处理ViewPager冲突问题 90 | ViewPager mViewPager = getTouchViewPager(mViewPagers, ev); 91 | // Log.i(TAG, "mViewPager = " + mViewPager); 92 | 93 | if (mViewPager != null && mViewPager.getCurrentItem() != 0) { 94 | return super.onInterceptTouchEvent(ev); 95 | } 96 | 97 | // 处理与cbpullrefreshlistview 的事件冲突 98 | CBPullRefreshListView cbPullRefreshListView = getTouchCBpullrefreshListView(mCbPullRefreshListViews,ev); 99 | if(cbPullRefreshListView!=null&&cbPullRefreshListView.isSwipeMenuOpen()){ 100 | return super.onInterceptTouchEvent(ev); 101 | } 102 | 103 | // 暂时不处理gridview 104 | // GridView mGridView = getTouchGridView(mGridViews, ev); 105 | // Log.i(TAG, "mGridView = " + mGridView); 106 | // if (mGridView != null) { 107 | // return super.onInterceptTouchEvent(ev); 108 | // } 109 | 110 | switch (ev.getAction()) { 111 | case MotionEvent.ACTION_DOWN: 112 | downX = tempX = (int) ev.getRawX(); 113 | downY = (int) ev.getRawY(); 114 | break; 115 | case MotionEvent.ACTION_MOVE: 116 | int moveX = (int) ev.getRawX(); 117 | // 满足此条件屏蔽SildingFinishLayout里面子类的touch事件 118 | if (moveX - downX > mTouchSlop && Math.abs((int) ev.getRawY() - downY) < mTouchSlop) { 119 | return true; 120 | } 121 | break; 122 | } 123 | 124 | return super.onInterceptTouchEvent(ev); 125 | } 126 | 127 | @Override 128 | public boolean onTouchEvent(MotionEvent event) { 129 | switch (event.getAction()) { 130 | case MotionEvent.ACTION_MOVE: 131 | int moveX = (int) event.getRawX(); 132 | int deltaX = tempX - moveX; 133 | tempX = moveX; 134 | if (moveX - downX > mTouchSlop && Math.abs((int) event.getRawY() - downY) < mTouchSlop) { 135 | isSilding = true; 136 | } 137 | 138 | if (moveX - downX >= 0 && isSilding) { 139 | mContentView.scrollBy(deltaX, 0); 140 | } 141 | break; 142 | case MotionEvent.ACTION_UP: 143 | isSilding = false; 144 | if (mContentView.getScrollX() <= -viewWidth / 2) { 145 | isFinish = true; 146 | scrollRight(); 147 | } else { 148 | scrollOrigin(); 149 | isFinish = false; 150 | } 151 | break; 152 | } 153 | 154 | return true; 155 | } 156 | 157 | /** 158 | * 获取SwipeBackLayout里面的ViewPager的集合 159 | * 160 | * @param mViewPagers 161 | * @param parent 162 | */ 163 | private void getAllViewPager(List mViewPagers, ViewGroup parent) { 164 | int childCount = parent.getChildCount(); 165 | for (int i = 0; i < childCount; i++) { 166 | View child = parent.getChildAt(i); 167 | if (child instanceof ViewPager) { 168 | mViewPagers.add((ViewPager) child); 169 | } else if (child instanceof ViewGroup) { 170 | getAllViewPager(mViewPagers, (ViewGroup) child); 171 | } 172 | } 173 | } 174 | 175 | private void getAllGridView(List mGridViews, ViewGroup parent) { 176 | int childCount = parent.getChildCount(); 177 | for (int i = 0; i < childCount; i++) { 178 | View child = parent.getChildAt(i); 179 | if (child instanceof GridView) { 180 | mGridViews.add((GridView) child); 181 | } else if (child instanceof ViewGroup) { 182 | getAllGridView(mGridViews, (ViewGroup) child); 183 | } 184 | } 185 | } 186 | 187 | private void getCBpullRefreshListView(ViewGroup parent) { 188 | int childCount = parent.getChildCount(); 189 | for (int i = 0; i < childCount; i++) { 190 | View child = parent.getChildAt(i); 191 | if (child instanceof CBPullRefreshListView) { 192 | mCbPullRefreshListViews.add((CBPullRefreshListView) child); 193 | } else if (child instanceof ViewGroup) { 194 | getCBpullRefreshListView((ViewGroup) child); 195 | } 196 | } 197 | } 198 | 199 | private CBPullRefreshListView getTouchCBpullrefreshListView(List cbPullRefreshListViews, MotionEvent ev) { 200 | if (cbPullRefreshListViews == null || cbPullRefreshListViews.size() == 0) { 201 | return null; 202 | } 203 | Rect rect = new Rect(); 204 | for (CBPullRefreshListView listview : cbPullRefreshListViews) { 205 | listview.getHitRect(rect); 206 | if (rect.contains((int) ev.getX(), (int) ev.getY())) { 207 | return listview; 208 | } 209 | } 210 | return null; 211 | } 212 | 213 | /** 214 | * 返回我们touch的ViewPager 215 | * 216 | * @param mViewPagers 217 | * @param ev 218 | * @return 219 | */ 220 | private ViewPager getTouchViewPager(List mViewPagers, MotionEvent ev) { 221 | if (mViewPagers == null || mViewPagers.size() == 0) { 222 | return null; 223 | } 224 | Rect mRect = new Rect(); 225 | for (ViewPager v : mViewPagers) { 226 | v.getHitRect(mRect); 227 | 228 | if (mRect.contains((int) ev.getX(), (int) ev.getY())) { 229 | return v; 230 | } 231 | } 232 | return null; 233 | } 234 | 235 | private GridView getTouchGridView(List mGridViews, MotionEvent ev) { 236 | if (mGridViews == null || mGridViews.size() == 0) { 237 | return null; 238 | } 239 | Rect mRect = new Rect(); 240 | for (GridView v : mGridViews) { 241 | v.getHitRect(mRect); 242 | 243 | if (mRect.contains((int) ev.getX(), (int) ev.getY())) { 244 | return v; 245 | } 246 | } 247 | return null; 248 | } 249 | 250 | @Override 251 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 252 | super.onLayout(changed, l, t, r, b); 253 | if (changed) { 254 | viewWidth = this.getWidth(); 255 | 256 | getAllViewPager(mViewPagers, this); 257 | // Log.i(TAG, "ViewPager size = " + mViewPagers.size()); 258 | 259 | getAllGridView(mGridViews, this); 260 | getCBpullRefreshListView(this); 261 | } 262 | } 263 | 264 | @Override 265 | protected void dispatchDraw(Canvas canvas) { 266 | super.dispatchDraw(canvas); 267 | if (mShadowDrawable != null && mContentView != null) { 268 | 269 | int left = mContentView.getLeft() - mShadowDrawable.getIntrinsicWidth(); 270 | int right = left + mShadowDrawable.getIntrinsicWidth(); 271 | int top = mContentView.getTop(); 272 | int bottom = mContentView.getBottom(); 273 | 274 | mShadowDrawable.setBounds(left, top, right, bottom); 275 | mShadowDrawable.draw(canvas); 276 | } 277 | 278 | } 279 | 280 | /** 281 | * 滚动出界面 282 | */ 283 | private void scrollRight() { 284 | final int delta = (viewWidth + mContentView.getScrollX()); 285 | // 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item 286 | mScroller.startScroll(mContentView.getScrollX(), 0, -delta + 1, 0, Math.abs(delta)); 287 | postInvalidate(); 288 | } 289 | 290 | /** 291 | * 滚动到起始位置 292 | */ 293 | private void scrollOrigin() { 294 | int delta = mContentView.getScrollX(); 295 | mScroller.startScroll(mContentView.getScrollX(), 0, -delta, 0, Math.abs(delta)); 296 | postInvalidate(); 297 | } 298 | 299 | @Override 300 | public void computeScroll() { 301 | // 调用startScroll的时候scroller.computeScrollOffset()返回true, 302 | if (mScroller.computeScrollOffset()) { 303 | mContentView.scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 304 | postInvalidate(); 305 | 306 | if (mScroller.isFinished() && isFinish) { 307 | mActivity.finish(); 308 | /* 309 | if (mActivity.getClass().equals(Content.class)) { 310 | Intent intent = new Intent(mActivity, Main.class); 311 | mActivity.startActivity(intent); 312 | }*/ 313 | } 314 | } 315 | } 316 | 317 | } 318 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhl/cbpullrefreshlistview/DragbackActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhl.cbpullrefreshlistview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.util.TypedValue; 7 | import android.view.Menu; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.AdapterView; 11 | import android.widget.BaseAdapter; 12 | import android.widget.TextView; 13 | import android.widget.Toast; 14 | 15 | import com.zhl.CBPullRefresh.CBPullRefreshListView; 16 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenu; 17 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuCreator; 18 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuItem; 19 | 20 | import java.util.ArrayList; 21 | 22 | /** 23 | * 描述: 24 | * Created by zhaohl on 2016-4-5. 25 | */ 26 | public class DragbackActivity extends BaseActivity { 27 | private TestAdapter mAdatper; 28 | private ArrayList DataList = new ArrayList(); 29 | private CBPullRefreshListView mListView; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_main); 35 | initData(); 36 | initView(); 37 | } 38 | 39 | private void initView() { 40 | mListView = (CBPullRefreshListView) findViewById(R.id.listview); 41 | // mListView.setRefreshHeader(new CBRefreshHeader(this)); 42 | mListView.setAdapter(mAdatper = new TestAdapter()); 43 | mListView.setPullRefreshEnable(true); 44 | mListView.setPullLoadMoreEnable(true); 45 | // mListView.showTobSearchBar(true); 46 | mListView.setOnPullRefreshListener(new CBPullRefreshListView.OnPullRefreshListener() { 47 | @Override 48 | public void onRefresh() { 49 | mListView.postDelayed(new Runnable() { 50 | @Override 51 | public void run() { 52 | mListView.stopRefresh(); 53 | } 54 | }, 3000); 55 | } 56 | 57 | @Override 58 | public void onLoadMore() { 59 | mListView.postDelayed(new Runnable() { 60 | @Override 61 | public void run() { 62 | mListView.stopLoadMore(); 63 | } 64 | }, 3000); 65 | } 66 | 67 | @Override 68 | public void onUpdateRefreshTime(long time) { 69 | 70 | } 71 | 72 | }); 73 | SwipeMenuCreator creator = new SwipeMenuCreator() { 74 | 75 | @Override 76 | public void create(SwipeMenu menu) { 77 | 78 | SwipeMenuItem collectionItem = new SwipeMenuItem(getApplicationContext()); 79 | collectionItem.setBackground(R.color.green); 80 | collectionItem.setWidth(dp2px(DragbackActivity.this, 90)); 81 | collectionItem.setTitle("收藏"); 82 | collectionItem.setTitleSize(18); 83 | collectionItem.setTitleColor(Color.WHITE); 84 | collectionItem.setIcon(R.drawable.icon_collection); 85 | menu.addMenuItem(collectionItem); 86 | 87 | SwipeMenuItem deleteItem = new SwipeMenuItem(getApplicationContext()); 88 | deleteItem.setBackground(R.color.red); 89 | deleteItem.setWidth(dp2px(DragbackActivity.this, 90)); 90 | deleteItem.setTitle("删除"); 91 | deleteItem.setIcon(R.drawable.icon_delete); 92 | deleteItem.setTitleSize(18); 93 | deleteItem.setTitleColor(Color.WHITE); 94 | menu.addMenuItem(deleteItem); 95 | } 96 | }; 97 | // set creator 98 | mListView.setMenuCreator(creator); 99 | mListView.setOnMenuItemClickListener(new CBPullRefreshListView.OnMenuItemClickListener() { 100 | @Override 101 | public void onMenuItemClick(int position, SwipeMenu menu, int index) { 102 | Toast.makeText(DragbackActivity.this, "点击了item swipe 菜单的第" + index, Toast.LENGTH_SHORT).show(); 103 | } 104 | }); 105 | mListView.setOnItemClickListener(new CBPullRefreshListView.OnItemClickListener() { 106 | @Override 107 | public void onItemClick(AdapterView parent, View view, int position, long id) { 108 | Toast.makeText(DragbackActivity.this,"点击了"+position,Toast.LENGTH_SHORT).show(); 109 | } 110 | }); 111 | } 112 | 113 | private void initData() { 114 | for (int i = 0; i < 30; i++) { 115 | DataList.add(new String("this is a cbpullrefreshlistview test" + i)); 116 | } 117 | } 118 | 119 | 120 | @Override 121 | public boolean onCreateOptionsMenu(Menu menu) { 122 | getMenuInflater().inflate(R.menu.menu_main, menu); 123 | return true; 124 | } 125 | 126 | class TestAdapter extends BaseAdapter { 127 | 128 | 129 | @Override 130 | public int getCount() { 131 | return DataList == null ? 0 : DataList.size(); 132 | } 133 | 134 | @Override 135 | public Object getItem(int position) { 136 | return DataList.get(position); 137 | } 138 | 139 | @Override 140 | public long getItemId(int position) { 141 | return 0; 142 | } 143 | 144 | @Override 145 | public View getView(int position, View convertView, ViewGroup parent) { 146 | ViewHolder viewHolder = null; 147 | if (convertView == null) { 148 | viewHolder = new ViewHolder(); 149 | convertView = getLayoutInflater().inflate(R.layout.item_listview2, parent, false); 150 | viewHolder.title = (TextView) convertView.findViewById(R.id.item_title); 151 | convertView.setTag(viewHolder); 152 | } else { 153 | viewHolder = (ViewHolder) convertView.getTag(); 154 | } 155 | viewHolder.title.setText(DataList.get(position)); 156 | return convertView; 157 | } 158 | } 159 | 160 | class ViewHolder { 161 | TextView title; 162 | } 163 | 164 | public int dp2px(Context context,int dp) { 165 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhl/cbpullrefreshlistview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhl.cbpullrefreshlistview; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.util.TypedValue; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.AdapterView; 14 | import android.widget.BaseAdapter; 15 | import android.widget.TextView; 16 | import android.widget.Toast; 17 | 18 | import com.zhl.CBPullRefresh.CBPullRefreshListView; 19 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenu; 20 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuCreator; 21 | import com.zhl.CBPullRefresh.SwipeMenu.SwipeMenuItem; 22 | 23 | import java.util.ArrayList; 24 | 25 | public class MainActivity extends AppCompatActivity { 26 | private TestAdapter mAdatper; 27 | private ArrayList DataList = new ArrayList(); 28 | private CBPullRefreshListView mListView; 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_main); 34 | initData(); 35 | initView(); 36 | } 37 | 38 | private void initView() { 39 | mListView = (CBPullRefreshListView) findViewById(R.id.listview); 40 | // mListView.setRefreshHeader(new CBRefreshHeader(this)); 41 | mListView.setAdapter(mAdatper = new TestAdapter()); 42 | mListView.setPullRefreshEnable(true); 43 | mListView.setPullLoadMoreEnable(true); 44 | mListView.setSwipeEnable(true); 45 | mListView.showTopSearchBar(true); 46 | mListView.setOnSearchBarClickListener(new CBPullRefreshListView.OnSearchClickListener() { 47 | @Override 48 | public void onSearchBarClick() { 49 | Toast.makeText(MainActivity.this, "点击了搜索栏", Toast.LENGTH_SHORT).show(); 50 | } 51 | }); 52 | mListView.setOnPullRefreshListener(new CBPullRefreshListView.OnPullRefreshListener() { 53 | @Override 54 | public void onRefresh() { 55 | mListView.postDelayed(new Runnable() { 56 | @Override 57 | public void run() { 58 | mListView.stopRefresh(); 59 | } 60 | }, 3000); 61 | } 62 | 63 | @Override 64 | public void onLoadMore() { 65 | mListView.postDelayed(new Runnable() { 66 | @Override 67 | public void run() { 68 | mListView.stopLoadMore(); 69 | } 70 | }, 3000); 71 | } 72 | 73 | @Override 74 | public void onUpdateRefreshTime(long time) { 75 | 76 | } 77 | 78 | }); 79 | SwipeMenuCreator creator = new SwipeMenuCreator() { 80 | 81 | @Override 82 | public void create(SwipeMenu menu) { 83 | 84 | SwipeMenuItem collectionItem = new SwipeMenuItem(getApplicationContext()); 85 | collectionItem.setBackground(R.color.green); 86 | collectionItem.setWidth(dp2px(MainActivity.this, 90)); 87 | collectionItem.setTitle("收藏"); 88 | collectionItem.setTitleSize(18); 89 | collectionItem.setTitleColor(Color.WHITE); 90 | collectionItem.setIcon(R.drawable.icon_collection); 91 | menu.addMenuItem(collectionItem); 92 | 93 | SwipeMenuItem deleteItem = new SwipeMenuItem(getApplicationContext()); 94 | deleteItem.setBackground(R.color.red); 95 | deleteItem.setWidth(dp2px(MainActivity.this, 90)); 96 | deleteItem.setTitle("删除"); 97 | deleteItem.setIcon(R.drawable.icon_delete); 98 | deleteItem.setTitleSize(18); 99 | deleteItem.setTitleColor(Color.WHITE); 100 | menu.addMenuItem(deleteItem); 101 | } 102 | }; 103 | // set creator 104 | mListView.setMenuCreator(creator); 105 | mListView.setOnMenuItemClickListener(new CBPullRefreshListView.OnMenuItemClickListener() { 106 | @Override 107 | public void onMenuItemClick(int position, SwipeMenu menu, int index) { 108 | Toast.makeText(MainActivity.this, "点击了item swipe 菜单的第" + index, Toast.LENGTH_SHORT).show(); 109 | } 110 | }); 111 | mListView.setOnItemClickListener(new CBPullRefreshListView.OnItemClickListener() { 112 | @Override 113 | public void onItemClick(AdapterView parent, View view, int position, long id) { 114 | Toast.makeText(MainActivity.this,"点击了"+position,Toast.LENGTH_SHORT).show(); 115 | } 116 | }); 117 | } 118 | 119 | private void initData() { 120 | for (int i = 0; i < 30; i++) { 121 | DataList.add(new String("this is a cbpullrefreshlistview test" + i)); 122 | } 123 | } 124 | 125 | 126 | @Override 127 | public boolean onCreateOptionsMenu(Menu menu) { 128 | getMenuInflater().inflate(R.menu.menu_main, menu); 129 | return true; 130 | } 131 | 132 | @Override 133 | public boolean onOptionsItemSelected(MenuItem item) { 134 | switch (item.getItemId()){ 135 | case R.id.action_settings: 136 | Intent intent = new Intent(this,DragbackActivity.class); 137 | startActivity(intent); 138 | break; 139 | case R.id.action_custom_header: 140 | Intent intent2 = new Intent(this,CustomRefreshHeaderActivity.class); 141 | startActivity(intent2); 142 | break; 143 | case R.id.action_custom_header2: 144 | Intent intent3 = new Intent(this,CustomRefreshHeaderRippleActivity.class); 145 | startActivity(intent3); 146 | break; 147 | } 148 | return super.onOptionsItemSelected(item); 149 | } 150 | 151 | class TestAdapter extends BaseAdapter { 152 | 153 | 154 | @Override 155 | public int getCount() { 156 | return DataList == null ? 0 : DataList.size(); 157 | } 158 | 159 | @Override 160 | public Object getItem(int position) { 161 | return DataList.get(position); 162 | } 163 | 164 | @Override 165 | public long getItemId(int position) { 166 | return 0; 167 | } 168 | 169 | @Override 170 | public View getView(int position, View convertView, ViewGroup parent) { 171 | ViewHolder viewHolder = null; 172 | if (convertView == null) { 173 | viewHolder = new ViewHolder(); 174 | convertView = getLayoutInflater().inflate(R.layout.item_listview, parent, false); 175 | viewHolder.title = (TextView) convertView.findViewById(R.id.item_title); 176 | convertView.setTag(viewHolder); 177 | } else { 178 | viewHolder = (ViewHolder) convertView.getTag(); 179 | } 180 | viewHolder.title.setText(DataList.get(position)); 181 | return convertView; 182 | } 183 | } 184 | 185 | class ViewHolder { 186 | TextView title; 187 | } 188 | 189 | public int dp2px(Context context,int dp) { 190 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhl/cbpullrefreshlistview/MyCustomRrefreshHeader.java: -------------------------------------------------------------------------------- 1 | package com.zhl.cbpullrefreshlistview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.util.AttributeSet; 6 | import android.util.DisplayMetrics; 7 | import android.util.Log; 8 | import android.view.Gravity; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.widget.ImageView; 12 | import android.widget.LinearLayout; 13 | import android.widget.RelativeLayout; 14 | 15 | import com.wang.avi.AVLoadingIndicatorView; 16 | import com.zhl.CBPullRefresh.CBRefreshHeaderView; 17 | import com.zhl.CBPullRefresh.CBRefreshState; 18 | import com.zhl.CBPullRefresh.utils.Blur; 19 | import com.zhl.CBPullRefresh.utils.BlurUtil; 20 | 21 | 22 | /** 23 | * 描述: 24 | * Created by zhaohl on 2016-4-6. 25 | */ 26 | public class MyCustomRrefreshHeader extends CBRefreshHeaderView { 27 | private LinearLayout mHeaderContanier; 28 | private RelativeLayout mHeaderContent; 29 | private ImageView blurView; 30 | private View blurContentView; 31 | private AVLoadingIndicatorView indicatorView; 32 | private ImageView rotateView; 33 | private int State; 34 | private Context context; 35 | private int mScreenW,mScreenH; 36 | 37 | 38 | public MyCustomRrefreshHeader(Context context) { 39 | this(context, null); 40 | } 41 | 42 | public MyCustomRrefreshHeader(Context context, AttributeSet attrs) { 43 | this(context, attrs, -1); 44 | } 45 | 46 | public MyCustomRrefreshHeader(Context context, AttributeSet attrs, int defStyleAttr) { 47 | super(context, attrs, defStyleAttr); 48 | init(context); 49 | } 50 | 51 | private void init(Context context) { 52 | this.context = context; 53 | DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 54 | mScreenW = metrics.widthPixels; 55 | mScreenH = metrics.heightPixels; 56 | // 初始情况,设置下拉刷新view高度为0 57 | LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0); 58 | mHeaderContanier = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.my_custom_header,null); 59 | mHeaderContent = (RelativeLayout) mHeaderContanier.findViewById(R.id.header_content); 60 | indicatorView = (AVLoadingIndicatorView) mHeaderContanier.findViewById(R.id.avloadingIndicatorView); 61 | rotateView = (ImageView) mHeaderContanier.findViewById(R.id.rotate_icon); 62 | startBlur(0); 63 | addView(mHeaderContanier,lp); 64 | setGravity(Gravity.BOTTOM); 65 | } 66 | 67 | @Override 68 | public void setState(int state) { 69 | this.State = state; 70 | } 71 | 72 | @Override 73 | public void onDragSlide(float deltaY) { 74 | Log.i("mytag", "--------deltaY===========" + deltaY); 75 | if(deltaY>0f){ 76 | if(State!= CBRefreshState.STATE_REFRESHING){ 77 | startRotae(deltaY); 78 | startBlur(deltaY/1000); 79 | } 80 | }else{ 81 | clearBlurImage(); 82 | } 83 | } 84 | 85 | private void startRotae(float deltaY) { 86 | rotateView.setRotation(deltaY); 87 | } 88 | 89 | @Override 90 | public void pullToRefresh() { 91 | rotateView.setVisibility(View.VISIBLE); 92 | indicatorView.setVisibility(View.INVISIBLE); 93 | } 94 | 95 | @Override 96 | public void releaseToRefresh() { 97 | super.releaseToRefresh(); 98 | } 99 | 100 | @Override 101 | public void onRefreshing() { 102 | rotateView.setVisibility(View.INVISIBLE); 103 | indicatorView.setVisibility(View.VISIBLE); 104 | } 105 | 106 | @Override 107 | public void setVisiableHeight(int height) { 108 | if(height<0){ 109 | height = 0; 110 | } 111 | LinearLayout.LayoutParams params = (LayoutParams) mHeaderContanier.getLayoutParams(); 112 | params.height = height; 113 | mHeaderContanier.setLayoutParams(params); 114 | } 115 | 116 | @Override 117 | public int getVisiableHeight() { 118 | return mHeaderContanier.getHeight(); 119 | } 120 | 121 | @Override 122 | public int getRealHeaderContentHeight() { 123 | // 因为container刚开始设置的高度为0所以这里要获取mHeaderContent的高度为真实高度 124 | if(mHeaderContent!=null){ 125 | return mHeaderContent.getHeight(); 126 | } 127 | return 0; 128 | } 129 | 130 | @Override 131 | public void setPullRefreshEnable(boolean enable) { 132 | if(enable){ 133 | mHeaderContanier.setVisibility(View.VISIBLE); 134 | }else{ 135 | mHeaderContanier.setVisibility(View.INVISIBLE); 136 | } 137 | } 138 | 139 | 140 | private void clearBlurImage() { 141 | if(blurView!=null){ 142 | blurView.setVisibility(View.GONE); 143 | blurView.setImageBitmap(null); 144 | } 145 | } 146 | 147 | private void startBlur(float slideOffset) { 148 | if(slideOffset>1){ 149 | return; 150 | } 151 | if(blurContentView==null||blurView==null){ 152 | return; 153 | } 154 | if (blurView.getVisibility() != View.VISIBLE) { 155 | blurView.setImageBitmap(null); 156 | blurView.setVisibility(View.VISIBLE); 157 | Bitmap downScaled = BlurUtil.drawViewToBitmap(blurContentView, 158 | mScreenW, mScreenH, 5); 159 | Bitmap blurred = Blur.apply(context, downScaled, 20); 160 | blurView.setImageBitmap(blurred); 161 | downScaled.recycle(); 162 | } 163 | BlurUtil.setAlpha(blurView, 1-slideOffset); 164 | } 165 | 166 | public void setBlurView(View contentView,ImageView BlurView){ 167 | this.blurContentView = contentView; 168 | this.blurView = BlurView; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhl/cbpullrefreshlistview/MyCustomRrefreshHeaderRippleColor.java: -------------------------------------------------------------------------------- 1 | package com.zhl.cbpullrefreshlistview; 2 | 3 | import android.animation.ArgbEvaluator; 4 | import android.animation.ObjectAnimator; 5 | import android.content.Context; 6 | import android.util.AttributeSet; 7 | import android.util.DisplayMetrics; 8 | import android.util.Log; 9 | import android.view.Gravity; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.widget.FrameLayout; 13 | import android.widget.ImageView; 14 | import android.widget.LinearLayout; 15 | 16 | import com.rodolfonavalon.shaperipplelibrary.ShapeRipple; 17 | import com.wang.avi.AVLoadingIndicatorView; 18 | import com.zhl.CBPullRefresh.CBRefreshHeaderView; 19 | import com.zhl.CBPullRefresh.CBRefreshState; 20 | 21 | 22 | /** 23 | * 描述: 24 | * Created by zhaohl on 2016-4-6. 25 | */ 26 | public class MyCustomRrefreshHeaderRippleColor extends CBRefreshHeaderView { 27 | private LinearLayout mHeaderContanier; 28 | private FrameLayout mHeaderContent; 29 | private AVLoadingIndicatorView indicatorView; 30 | private ShapeRipple shapeRipple; 31 | private ImageView rotateView; 32 | private int State; 33 | private Context context; 34 | private int mScreenW,mScreenH; 35 | private int duration = 1500; 36 | private ObjectAnimator colorAnimator; 37 | 38 | 39 | public MyCustomRrefreshHeaderRippleColor(Context context) { 40 | this(context, null); 41 | } 42 | 43 | public MyCustomRrefreshHeaderRippleColor(Context context, AttributeSet attrs) { 44 | this(context, attrs, -1); 45 | } 46 | 47 | public MyCustomRrefreshHeaderRippleColor(Context context, AttributeSet attrs, int defStyleAttr) { 48 | super(context, attrs, defStyleAttr); 49 | init(context); 50 | } 51 | 52 | private void init(Context context) { 53 | this.context = context; 54 | DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 55 | mScreenW = metrics.widthPixels; 56 | mScreenH = metrics.heightPixels; 57 | // 初始情况,设置下拉刷新view高度为0 58 | LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0); 59 | mHeaderContanier = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.my_custom_header_ripplecolor,null); 60 | mHeaderContent = (FrameLayout) mHeaderContanier.findViewById(R.id.header_content); 61 | indicatorView = (AVLoadingIndicatorView) mHeaderContanier.findViewById(R.id.avloadingIndicatorView); 62 | rotateView = (ImageView) mHeaderContanier.findViewById(R.id.rotate_icon); 63 | shapeRipple = (ShapeRipple) mHeaderContanier.findViewById(R.id.shape_ripple); 64 | shapeRipple.setEnableColorTransition(true); 65 | shapeRipple.setEnableRandomPosition(true); 66 | shapeRipple.setEnableRandomColor(true); 67 | // shapeRipple.setRippleShape(new Square()); 68 | shapeRipple.setRippleInterval(1); 69 | shapeRipple.setRippleDuration(duration); 70 | shapeRipple.stopRipple(); 71 | // initColorAnim(); 72 | addView(mHeaderContanier,lp); 73 | setGravity(Gravity.BOTTOM); 74 | } 75 | 76 | private void initColorAnim() { 77 | colorAnimator = ObjectAnimator.ofObject(mHeaderContent,"backgroundColor",new ArgbEvaluator(),0xEFFAFAFA,0x55DE8DAB); 78 | colorAnimator.setDuration(8000); 79 | colorAnimator.setRepeatMode(ObjectAnimator.REVERSE); 80 | colorAnimator.setRepeatCount(ObjectAnimator.INFINITE); 81 | } 82 | 83 | @Override 84 | public void setState(int state) { 85 | this.State = state; 86 | } 87 | 88 | @Override 89 | public void onDragSlide(float deltaY) { 90 | Log.i("MyTag", "--------deltaY===========" + deltaY); 91 | if(deltaY>0&&State!= CBRefreshState.STATE_REFRESHING){ 92 | startRotae(deltaY); 93 | } 94 | } 95 | 96 | private void startRotae(float deltaY) { 97 | rotateView.setRotation(deltaY); 98 | } 99 | 100 | @Override 101 | public void pullToRefresh() { 102 | rotateView.setVisibility(View.VISIBLE); 103 | indicatorView.setVisibility(View.INVISIBLE); 104 | shapeRipple.stopRipple(); 105 | } 106 | 107 | @Override 108 | public void releaseToRefresh() { 109 | shapeRipple.stopRipple(); 110 | } 111 | 112 | @Override 113 | public void onRefreshing() { 114 | rotateView.setVisibility(View.INVISIBLE); 115 | indicatorView.setVisibility(View.VISIBLE); 116 | shapeRipple.startRipple(); 117 | } 118 | 119 | @Override 120 | public void setVisiableHeight(int height) { 121 | if(height<0){ 122 | height = 0; 123 | } 124 | LayoutParams params = (LayoutParams) mHeaderContanier.getLayoutParams(); 125 | params.height = height; 126 | mHeaderContanier.setLayoutParams(params); 127 | } 128 | 129 | @Override 130 | public int getVisiableHeight() { 131 | return mHeaderContanier.getHeight(); 132 | } 133 | 134 | @Override 135 | public int getRealHeaderContentHeight() { 136 | // 因为container刚开始设置的高度为0所以这里要获取mHeaderContent的高度为真实高度 137 | if(mHeaderContent!=null){ 138 | return mHeaderContent.getHeight(); 139 | } 140 | return 0; 141 | } 142 | 143 | @Override 144 | public void setPullRefreshEnable(boolean enable) { 145 | if(enable){ 146 | mHeaderContanier.setVisibility(View.VISIBLE); 147 | }else{ 148 | mHeaderContanier.setVisibility(View.INVISIBLE); 149 | } 150 | } 151 | 152 | 153 | 154 | 155 | } 156 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/app_logo_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-hdpi/app_logo_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/item_icon_girl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-hdpi/item_icon_girl.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/app_logo_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-xhdpi/app_logo_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-xhdpi/icon_collection.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-xhdpi/icon_delete.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_header_refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-xhdpi/icon_header_refresh.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/item_icon_girl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-xhdpi/item_icon_girl.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/item_icon_girl2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-xhdpi/item_icon_girl2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/item_icon_girl3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-xhdpi/item_icon_girl3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/top_header_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/app/src/main/res/drawable-xhdpi/top_header_bg.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/swipeback_shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_custom_header_layout.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 21 | 22 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_custom_header_layout_ripple.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/base.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_listview.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_listview2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_listview3.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/my_custom_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 24 | 25 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/my_custom_header_ripplecolor.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 19 | 20 | 29 | 30 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/mylistview_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 16 | 22 | 23 | 30 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 15 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #4ea6ed 4 | #e8e8e8 5 | #33000001 6 | #00000000 7 | #19BF80 8 | #ffffff 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CBPullRefreshListView 3 | 4 | Hello world! 5 | 滑动返回的activity 6 | 自定义刷新头 7 | 自定义刷新头2 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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.3.3' 9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 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 | } 19 | } 20 | -------------------------------------------------------------------------------- /custom_ripple.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/custom_ripple.gif -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | android.useDeprecatedNdk=true 20 | #gradlew clean build bintrayUpload -PbintrayUser=yilylong -PbintrayKey=xxxxxx -PdryRun=false -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yilylong/CBPullRefreshListView/c5c4826df767c5d6c9b48f4480143e06e3c56069/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jun 26 14:43:52 CST 2017 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-3.3-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 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':CBPullRefresh' 2 | --------------------------------------------------------------------------------