├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── heihei │ │ └── hehe │ │ └── recyclerview_demo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── heihei │ │ │ └── hehe │ │ │ └── recyclerview_demo │ │ │ ├── MainActivity.java │ │ │ ├── divider │ │ │ ├── Area.java │ │ │ ├── GridManagerActivity.java │ │ │ ├── LinearManagerActivity.java │ │ │ ├── StickyActivity.java │ │ │ └── widgt │ │ │ │ ├── ItemDivider.java │ │ │ │ └── StickyRecyclerView.java │ │ │ ├── drag │ │ │ ├── DragActivity.java │ │ │ ├── MyItemTouchHandler.java │ │ │ └── SwipeActivity.java │ │ │ └── spansize │ │ │ ├── RefreshActivity.java │ │ │ ├── SpanSizeActivity.java │ │ │ └── widgt │ │ │ └── SuperRefreshLayout.java │ └── res │ │ ├── layout │ │ ├── activity_grid_manager.xml │ │ ├── activity_main.xml │ │ ├── activity_recycler.xml │ │ ├── activity_refresh.xml │ │ ├── activity_span_size.xml │ │ ├── activity_sticky.xml │ │ ├── activity_swipe.xml │ │ ├── grid_item.xml │ │ ├── item.xml │ │ ├── item_drag.xml │ │ ├── item_swipe.xml │ │ └── loadmore_default_footer.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── sticky_attrs.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── heihei │ └── hehe │ └── recyclerview_demo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/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 | 17 | 18 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "com.heihei.hehe.recyclerview_demo" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.0.0' 28 | testCompile 'junit:junit:4.12' 29 | compile 'com.android.support:recyclerview-v7:25.0.0' 30 | compile 'com.google.code.gson:gson:2.7' 31 | } 32 | -------------------------------------------------------------------------------- /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:\ide\sdk/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/heihei/hehe/recyclerview_demo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.heihei.hehe.recyclerview_demo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo; 2 | 3 | 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | 9 | import com.heihei.hehe.recyclerview_demo.divider.GridManagerActivity; 10 | import com.heihei.hehe.recyclerview_demo.divider.LinearManagerActivity; 11 | import com.heihei.hehe.recyclerview_demo.divider.StickyActivity; 12 | import com.heihei.hehe.recyclerview_demo.drag.DragActivity; 13 | import com.heihei.hehe.recyclerview_demo.drag.SwipeActivity; 14 | import com.heihei.hehe.recyclerview_demo.spansize.RefreshActivity; 15 | import com.heihei.hehe.recyclerview_demo.spansize.SpanSizeActivity; 16 | 17 | public class MainActivity extends AppCompatActivity { 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | 24 | } 25 | 26 | public void linear(View v){ 27 | startActivity(new Intent(this, LinearManagerActivity.class)); 28 | } 29 | 30 | public void grid(View v){ 31 | startActivity(new Intent(this, GridManagerActivity.class)); 32 | } 33 | 34 | public void sticky(View v){ 35 | startActivity(new Intent(this, StickyActivity.class)); 36 | } 37 | 38 | public void spanSize(View v){ 39 | startActivity(new Intent(this, SpanSizeActivity.class)); 40 | } 41 | 42 | public void refresh(View v){ 43 | startActivity(new Intent(this, RefreshActivity.class)); 44 | } 45 | 46 | public void drag(View v){ 47 | startActivity(new Intent(this, DragActivity.class)); 48 | } 49 | 50 | public void swip(View v){ 51 | startActivity(new Intent(this, SwipeActivity.class)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/divider/Area.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.divider; 2 | 3 | /** 4 | * Describe the function of the class 5 | * 6 | * @author zhujinlong@ichoice.com 7 | * @date 2016/10/28 8 | * @time 15:55 9 | * @description Describe the place where the class needs to pay attention. 10 | */ 11 | public class Area { 12 | 13 | /** 14 | * area_code : 330183 15 | * area_name : 富阳 16 | * city_code : null 17 | * city : null 18 | * province : 330100 19 | * medical_join_code : null 20 | * XINGZHENGJB : 3 21 | * quyubh : 100000000000000001 22 | * pingtaibh : 10001 23 | * ZHUANGTAI : null 24 | * shuruma : FYS 25 | * zhuangtai : 1 26 | * IncreasingSort : true 27 | */ 28 | 29 | public String area_code; 30 | public String area_name; 31 | public String city_code; 32 | public String city; 33 | public String province; 34 | public String medical_join_code; 35 | public String XINGZHENGJB; 36 | public String quyubh; 37 | public String pingtaibh; 38 | public String ZHUANGTAI; 39 | public String shuruma; 40 | public String zhuangtai; 41 | public boolean IncreasingSort; 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/divider/GridManagerActivity.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.divider; 2 | 3 | import android.graphics.Color; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.support.v7.widget.GridLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.heihei.hehe.recyclerview_demo.R; 13 | import com.heihei.hehe.recyclerview_demo.divider.widgt.ItemDivider; 14 | 15 | public class GridManagerActivity extends AppCompatActivity { 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_grid_manager); 21 | RecyclerView re = (RecyclerView) findViewById(R.id.re); 22 | re.setLayoutManager(new GridLayoutManager(this,4,GridLayoutManager.VERTICAL,false)); 23 | re.addItemDecoration(new ItemDivider().setDividerWith(2).setDividerColor(Color.MAGENTA)); 24 | re.setAdapter(new MyAdapter()); 25 | } 26 | 27 | private class MyAdapter extends RecyclerView.Adapter{ 28 | 29 | @Override 30 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 31 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item,parent,false)) { 32 | }; 33 | } 34 | 35 | @Override 36 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 37 | TextView tv = (TextView) holder.itemView.findViewById(R.id.text1); 38 | tv.setText(String.valueOf(position)); 39 | // holder.itemView.setBackgroundColor(Color.BLUE); 40 | } 41 | 42 | @Override 43 | public int getItemCount() { 44 | return 100; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/divider/LinearManagerActivity.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.divider; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | 13 | import com.heihei.hehe.recyclerview_demo.R; 14 | import com.heihei.hehe.recyclerview_demo.divider.widgt.ItemDivider; 15 | 16 | /** 17 | * Describe the function of the class 18 | * 19 | * @author zhujinlong@ichoice.com 20 | * @date 2016/10/28 21 | * @time 15:31 22 | * @description Describe the place where the class needs to pay attention. 23 | */ 24 | public class LinearManagerActivity extends AppCompatActivity { 25 | 26 | @Override 27 | protected void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_recycler); 30 | RecyclerView re = (RecyclerView) findViewById(R.id.re); 31 | re.setLayoutManager(new LinearLayoutManager(this)); 32 | re.addItemDecoration(new ItemDivider().setDividerWith(2).setDividerColor(Color.MAGENTA)); 33 | re.setAdapter(new MyAdapter()); 34 | } 35 | 36 | private class MyAdapter extends RecyclerView.Adapter{ 37 | 38 | @Override 39 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 40 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1,parent,false)) { 41 | }; 42 | } 43 | 44 | @Override 45 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 46 | TextView tv = (TextView) holder.itemView.findViewById(android.R.id.text1); 47 | tv.setText(String.valueOf(position)); 48 | // holder.itemView.setBackgroundColor(Color.BLUE); 49 | } 50 | 51 | @Override 52 | public int getItemCount() { 53 | return 100; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/divider/StickyActivity.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.divider; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | import com.google.gson.Gson; 10 | import com.heihei.hehe.recyclerview_demo.R; 11 | import com.heihei.hehe.recyclerview_demo.divider.widgt.StickyRecyclerView; 12 | import java.util.ArrayList; 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | public class StickyActivity extends AppCompatActivity { 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_sticky); 22 | StickyRecyclerView stickyRecyclerView = (StickyRecyclerView) findViewById(R.id.re); 23 | MyAdapter stickyAdapter = new MyAdapter(); 24 | stickyRecyclerView.setAdapter(stickyAdapter); 25 | List areas = Arrays.asList(new Gson().fromJson(a, Area[].class)); 26 | stickyAdapter.setDatas(areas); 27 | } 28 | 29 | private class MyAdapter extends StickyRecyclerView.StickyAdapter { 30 | 31 | List datas = new ArrayList<>(); 32 | 33 | public void setDatas(List datas) { 34 | this.datas.clear(); 35 | if (datas != null) { 36 | this.datas.addAll(datas); 37 | } 38 | notifyDataSetChanged(); 39 | } 40 | 41 | @Override 42 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 43 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false)) { 44 | }; 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 49 | TextView textView = (TextView) holder.itemView.findViewById(android.R.id.text1); 50 | textView.setText(datas.get(position).area_name); 51 | } 52 | 53 | @Override 54 | public int getItemCount() { 55 | return datas.size(); 56 | } 57 | 58 | @Override 59 | public String getItemViewTitle(int position) { 60 | return String.valueOf(datas.get(position).shuruma.charAt(0)); 61 | } 62 | } 63 | 64 | private String a = "[{\"area_code\":\"330522\",\"area_name\":\"长兴\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000960098\",\"pingtaibh\":\"910500000000960097\",\"ZHUANGTAI\":null,\"shuruma\":\"ZXS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330183\",\"area_name\":\"富阳\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"100000000000000001\",\"pingtaibh\":\"10001\",\"ZHUANGTAI\":null,\"shuruma\":\"FYS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"360201\",\"area_name\":\"景德镇\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040015\",\"pingtaibh\":\"10007\",\"ZHUANGTAI\":null,\"shuruma\":\"JDZ\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"331081\",\"area_name\":\"温岭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000008710874\",\"pingtaibh\":\"10006\",\"ZHUANGTAI\":null,\"shuruma\":\"WL\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"430321\",\"area_name\":\"湘潭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000006000665\",\"pingtaibh\":\"900500000005995269\",\"ZHUANGTAI\":null,\"shuruma\":\"XTS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"320582\",\"area_name\":\"张家港\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040013\",\"pingtaibh\":\"10004\",\"ZHUANGTAI\":null,\"shuruma\":\"ZJG\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330522\",\"area_name\":\"长兴\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000960098\",\"pingtaibh\":\"910500000000960097\",\"ZHUANGTAI\":null,\"shuruma\":\"ZXS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330183\",\"area_name\":\"富阳\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"100000000000000001\",\"pingtaibh\":\"10001\",\"ZHUANGTAI\":null,\"shuruma\":\"FYS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"360201\",\"area_name\":\"景德镇\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040015\",\"pingtaibh\":\"10007\",\"ZHUANGTAI\":null,\"shuruma\":\"JDZ\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"331081\",\"area_name\":\"温岭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000008710874\",\"pingtaibh\":\"10006\",\"ZHUANGTAI\":null,\"shuruma\":\"WL\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"430321\",\"area_name\":\"湘潭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000006000665\",\"pingtaibh\":\"900500000005995269\",\"ZHUANGTAI\":null,\"shuruma\":\"XTS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"320582\",\"area_name\":\"张家港\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040013\",\"pingtaibh\":\"10004\",\"ZHUANGTAI\":null,\"shuruma\":\"ZJG\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330522\",\"area_name\":\"长兴\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000960098\",\"pingtaibh\":\"910500000000960097\",\"ZHUANGTAI\":null,\"shuruma\":\"ZXS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330183\",\"area_name\":\"富阳\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"100000000000000001\",\"pingtaibh\":\"10001\",\"ZHUANGTAI\":null,\"shuruma\":\"FYS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"360201\",\"area_name\":\"景德镇\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040015\",\"pingtaibh\":\"10007\",\"ZHUANGTAI\":null,\"shuruma\":\"JDZ\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"331081\",\"area_name\":\"温岭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000008710874\",\"pingtaibh\":\"10006\",\"ZHUANGTAI\":null,\"shuruma\":\"WL\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"430321\",\"area_name\":\"湘潭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000006000665\",\"pingtaibh\":\"900500000005995269\",\"ZHUANGTAI\":null,\"shuruma\":\"XTS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"320582\",\"area_name\":\"张家港\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040013\",\"pingtaibh\":\"10004\",\"ZHUANGTAI\":null,\"shuruma\":\"ZJG\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330522\",\"area_name\":\"长兴\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000960098\",\"pingtaibh\":\"910500000000960097\",\"ZHUANGTAI\":null,\"shuruma\":\"ZXS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330183\",\"area_name\":\"富阳\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"100000000000000001\",\"pingtaibh\":\"10001\",\"ZHUANGTAI\":null,\"shuruma\":\"FYS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"360201\",\"area_name\":\"景德镇\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040015\",\"pingtaibh\":\"10007\",\"ZHUANGTAI\":null,\"shuruma\":\"JDZ\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"331081\",\"area_name\":\"温岭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000008710874\",\"pingtaibh\":\"10006\",\"ZHUANGTAI\":null,\"shuruma\":\"WL\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"430321\",\"area_name\":\"湘潭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000006000665\",\"pingtaibh\":\"900500000005995269\",\"ZHUANGTAI\":null,\"shuruma\":\"XTS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"320582\",\"area_name\":\"张家港\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040013\",\"pingtaibh\":\"10004\",\"ZHUANGTAI\":null,\"shuruma\":\"ZJG\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330522\",\"area_name\":\"长兴\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000960098\",\"pingtaibh\":\"910500000000960097\",\"ZHUANGTAI\":null,\"shuruma\":\"ZXS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330183\",\"area_name\":\"富阳\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"100000000000000001\",\"pingtaibh\":\"10001\",\"ZHUANGTAI\":null,\"shuruma\":\"FYS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"360201\",\"area_name\":\"景德镇\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040015\",\"pingtaibh\":\"10007\",\"ZHUANGTAI\":null,\"shuruma\":\"JDZ\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"331081\",\"area_name\":\"温岭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000008710874\",\"pingtaibh\":\"10006\",\"ZHUANGTAI\":null,\"shuruma\":\"WL\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"430321\",\"area_name\":\"湘潭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000006000665\",\"pingtaibh\":\"900500000005995269\",\"ZHUANGTAI\":null,\"shuruma\":\"XTS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"320582\",\"area_name\":\"张家港\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040013\",\"pingtaibh\":\"10004\",\"ZHUANGTAI\":null,\"shuruma\":\"ZJG\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330522\",\"area_name\":\"长兴\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000960098\",\"pingtaibh\":\"910500000000960097\",\"ZHUANGTAI\":null,\"shuruma\":\"ZXS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330183\",\"area_name\":\"富阳\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"100000000000000001\",\"pingtaibh\":\"10001\",\"ZHUANGTAI\":null,\"shuruma\":\"FYS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"360201\",\"area_name\":\"景德镇\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040015\",\"pingtaibh\":\"10007\",\"ZHUANGTAI\":null,\"shuruma\":\"JDZ\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"331081\",\"area_name\":\"温岭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000008710874\",\"pingtaibh\":\"10006\",\"ZHUANGTAI\":null,\"shuruma\":\"WL\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"430321\",\"area_name\":\"湘潭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000006000665\",\"pingtaibh\":\"900500000005995269\",\"ZHUANGTAI\":null,\"shuruma\":\"XTS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"320582\",\"area_name\":\"张家港\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040013\",\"pingtaibh\":\"10004\",\"ZHUANGTAI\":null,\"shuruma\":\"ZJG\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330522\",\"area_name\":\"长兴\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000960098\",\"pingtaibh\":\"910500000000960097\",\"ZHUANGTAI\":null,\"shuruma\":\"ZXS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"330183\",\"area_name\":\"富阳\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"100000000000000001\",\"pingtaibh\":\"10001\",\"ZHUANGTAI\":null,\"shuruma\":\"FYS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"360201\",\"area_name\":\"景德镇\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040015\",\"pingtaibh\":\"10007\",\"ZHUANGTAI\":null,\"shuruma\":\"JDZ\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"331081\",\"area_name\":\"温岭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000008710874\",\"pingtaibh\":\"10006\",\"ZHUANGTAI\":null,\"shuruma\":\"WL\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"430321\",\"area_name\":\"湘潭\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"900500000006000665\",\"pingtaibh\":\"900500000005995269\",\"ZHUANGTAI\":null,\"shuruma\":\"XTS\",\"zhuangtai\":\"1\",\"IncreasingSort\":true},{\"area_code\":\"320582\",\"area_name\":\"张家港\",\"city_code\":null,\"city\":null,\"province\":\"100000\",\"medical_join_code\":null,\"XINGZHENGJB\":\"2\",\"quyubh\":\"910500000000040013\",\"pingtaibh\":\"10004\",\"ZHUANGTAI\":null,\"shuruma\":\"ZJG\",\"zhuangtai\":\"1\",\"IncreasingSort\":true}]"; 65 | } -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/divider/widgt/ItemDivider.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.divider.widgt; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Rect; 6 | import android.support.v7.widget.GridLayoutManager; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.View; 10 | 11 | /** 12 | * Describe the function of the class 13 | * 14 | * @author zhujinlong@ichoice.com 15 | * @date 2016/10/28 16 | * @time 10:27 17 | * @description Describe the place where the class needs to pay attention. 18 | */ 19 | public class ItemDivider extends RecyclerView.ItemDecoration { 20 | 21 | private int dividerWith = 1; 22 | private Paint paint; 23 | private RecyclerView.LayoutManager layoutManager; 24 | 25 | public ItemDivider() { 26 | initPaint(); 27 | paint.setColor(0xfff0f0f0); 28 | } 29 | 30 | private void initPaint() { 31 | if (paint == null) { 32 | paint = new Paint(Paint.ANTI_ALIAS_FLAG); 33 | paint.setStyle(Paint.Style.FILL); 34 | } 35 | } 36 | 37 | public ItemDivider setDividerWith(int dividerWith) { 38 | this.dividerWith = dividerWith; 39 | return this; 40 | } 41 | 42 | public ItemDivider setDividerColor(int color) { 43 | initPaint(); 44 | paint.setColor(color); 45 | return this; 46 | } 47 | 48 | /** 49 | * 指定item之间的距离(就是指定分割线的宽度) 调用顺序 1 50 | * @param outRect Rect to receive the output. 51 | * @param view The child view to decorate 52 | * @param parent RecyclerView this ItemDecoration is decorating 53 | * @param state The current state of RecyclerView. 54 | */ 55 | @Override 56 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 57 | super.getItemOffsets(outRect, view, parent, state); 58 | if (layoutManager == null) { 59 | layoutManager = parent.getLayoutManager(); 60 | } 61 | // 适用 LinearLayoutManager 和 GridLayoutManager 62 | if (layoutManager instanceof LinearLayoutManager) { 63 | int orientation = ((LinearLayoutManager) layoutManager).getOrientation(); 64 | if (orientation == LinearLayoutManager.VERTICAL) { 65 | // 水平分割线将绘制在item底部 66 | outRect.bottom = dividerWith; 67 | } else if (orientation == LinearLayoutManager.HORIZONTAL) { 68 | // 垂直分割线将绘制在item右侧 69 | outRect.right = dividerWith; 70 | } 71 | if (layoutManager instanceof GridLayoutManager) { 72 | GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) view.getLayoutParams(); 73 | // 如果是 GridLayoutManager 则需要绘制另一个方向上的分割线 74 | if (orientation == LinearLayoutManager.VERTICAL && lp != null && lp.getSpanIndex() > 0) { 75 | // 如果列表是垂直方向,则最左边的一列略过 76 | outRect.left = dividerWith; 77 | } else if (orientation == LinearLayoutManager.HORIZONTAL && lp != null && lp.getSpanIndex() > 0) { 78 | // 如果列表是水平方向,则最上边的一列略过 79 | outRect.top = dividerWith; 80 | } 81 | } 82 | } 83 | } 84 | 85 | /** 86 | * 在item 绘制之前调用(就是绘制在 item 的下层) 调用顺序 2 87 | * 一般分割线在这里绘制 88 | * @param c Canvas to draw into 89 | * @param parent RecyclerView this ItemDecoration is drawing into 90 | * @param state The current state of RecyclerView 91 | */ 92 | @Override 93 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 94 | super.onDraw(c, parent, state); 95 | // 这个值是为了补偿横竖方向上分割线交叉处间隙 96 | int offSet = (int) Math.ceil(dividerWith * 1f / 2); 97 | for (int i = 0; i < parent.getChildCount(); i++) { 98 | View child = parent.getChildAt(i); 99 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); 100 | int left1 = child.getRight() + params.rightMargin; 101 | int right1 = left1 + dividerWith; 102 | int top1 = child.getTop() - offSet - params.topMargin; 103 | int bottom1 = child.getBottom() + offSet + params.bottomMargin; 104 | //绘制分割线(矩形) 105 | c.drawRect(left1, top1, right1, bottom1, paint); 106 | int left2 = child.getLeft() - offSet - params.leftMargin; 107 | int right2 = child.getRight() + offSet + params.rightMargin; 108 | int top2 = child.getBottom() + params.bottomMargin; 109 | int bottom2 = top2 + dividerWith; 110 | //绘制分割线(矩形) 111 | c.drawRect(left2, top2, right2, bottom2, paint); 112 | } 113 | } 114 | 115 | /** 116 | * 在item 绘制之后调用(就是绘制在 item 的上层) 调用顺序 3 117 | * 也可以在这里绘制分割线,和上面的方法 二选一 118 | * @param c Canvas to draw into 119 | * @param parent RecyclerView this ItemDecoration is drawing into 120 | * @param state The current state of RecyclerView 121 | */ 122 | @Override 123 | public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { 124 | super.onDrawOver(c, parent, state); 125 | } 126 | } -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/divider/widgt/StickyRecyclerView.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.divider.widgt; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Rect; 9 | import android.support.annotation.NonNull; 10 | import android.support.annotation.Nullable; 11 | import android.support.v7.widget.LinearLayoutManager; 12 | import android.support.v7.widget.RecyclerView; 13 | import android.text.TextUtils; 14 | import android.util.AttributeSet; 15 | import android.view.View; 16 | import com.heihei.hehe.recyclerview_demo.R; 17 | 18 | /** 19 | * Describe the function of the class 20 | * 21 | * @author zhujinlong@ichoice.com 22 | * @date 2016/9/19 23 | * @time 17:54 24 | * @description Describe the place where the class needs to pay attention. 25 | */ 26 | public class StickyRecyclerView extends RecyclerView { 27 | 28 | private int lineHeight,titleHeight; 29 | private int lineColor,titleColor,titleTextColor; 30 | 31 | public StickyRecyclerView(Context context) { 32 | this(context,null); 33 | } 34 | 35 | public StickyRecyclerView(Context context, @Nullable AttributeSet attrs) { 36 | this(context, attrs,0); 37 | } 38 | 39 | public StickyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { 40 | super(context, attrs, defStyle); 41 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.StickyRecyclerView); 42 | // 分割线的高度 43 | lineHeight = array.getDimensionPixelOffset(R.styleable.StickyRecyclerView_dividerHeight,1); 44 | // 分栏的高度 45 | titleHeight = array.getDimensionPixelOffset(R.styleable.StickyRecyclerView_titleHeight,dip2px(context,35)); 46 | // 分割线颜色 47 | lineColor = array.getColor(R.styleable.StickyRecyclerView_dividerColor,Color.LTGRAY); 48 | // 分栏背景色 49 | titleColor = array.getColor(R.styleable.StickyRecyclerView_titleColor,Color.LTGRAY); 50 | // 分栏文字颜色 51 | titleTextColor = array.getColor(R.styleable.StickyRecyclerView_titleTextColor,Color.BLUE); 52 | array.recycle(); 53 | // 不用说,肯定是线性布局了,默认就实现 54 | setLayoutManager(new LinearLayoutManager(context)); 55 | } 56 | 57 | @Deprecated 58 | @Override 59 | public void setAdapter(Adapter adapter) { 60 | super.setAdapter(adapter); 61 | } 62 | 63 | // 让 adapter 必须继承 StickyAdapter 64 | public void setAdapter(@NonNull StickyAdapter stickyAdapter){ 65 | addItemDecoration(new StickyDivider(stickyAdapter)); 66 | super.setAdapter(stickyAdapter); 67 | } 68 | 69 | /** 70 | * 自定义分割线,通过分割线绘制title 71 | */ 72 | private class StickyDivider extends ItemDecoration{ 73 | 74 | private StickyAdapter adapter; 75 | private Paint paint; 76 | 77 | StickyDivider(@NonNull StickyAdapter adapter) { 78 | super(); 79 | this.adapter = adapter; 80 | paint = new Paint(Paint.ANTI_ALIAS_FLAG); 81 | paint.setStyle(Paint.Style.FILL); 82 | paint.setTextSize(titleHeight * 0.5f); 83 | } 84 | 85 | /** 86 | * 计算 item间间隙(是普通分割线 ,还是title) 87 | */ 88 | @Override 89 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { 90 | super.getItemOffsets(outRect, view, parent, state); 91 | if(!adapter.needTitle(((LayoutParams) view.getLayoutParams()).getViewLayoutPosition())){ 92 | outRect.top = lineHeight; 93 | }else { 94 | outRect.top = titleHeight; 95 | } 96 | } 97 | 98 | /** 99 | * 底层绘制,绘制分栏title 100 | */ 101 | @Override 102 | public void onDraw(Canvas c, RecyclerView parent, State state) { 103 | super.onDraw(c, parent, state); 104 | int left = parent.getPaddingLeft(); 105 | int right = parent.getMeasuredWidth() - parent.getPaddingRight(); 106 | final int childCount = parent.getChildCount(); 107 | for (int i = 0; i < childCount; i++) { 108 | final View child = parent.getChildAt(i); 109 | int position = ((LayoutParams) child.getLayoutParams()).getViewLayoutPosition(); 110 | int bottom = child.getTop() - ((LayoutParams) child.getLayoutParams()).topMargin; 111 | if(!adapter.needTitle(position)){ 112 | // 画分割线 113 | int top = bottom - lineHeight; 114 | paint.setColor(lineColor); 115 | c.drawRect(left, top, right, bottom, paint); 116 | }else { 117 | //画TITLE 118 | int top = bottom - titleHeight; 119 | paint.setColor(titleColor); 120 | c.drawRect(left, top, right, bottom, paint); 121 | drawText(c,adapter.getItemViewTitle(position),left + titleHeight * 0.25f,bottom - titleHeight * 0.25f); 122 | } 123 | } 124 | } 125 | 126 | /** 127 | * 上层绘制,绘制顶部悬停title 128 | */ 129 | @Override 130 | public void onDrawOver(Canvas c, RecyclerView parent, State state) { 131 | super.onDrawOver(c, parent, state); 132 | // 悬停title 133 | int left = parent.getPaddingLeft(); 134 | int right = parent.getMeasuredWidth() - parent.getPaddingRight(); 135 | int top = parent.getPaddingTop(); 136 | int bottom = top + titleHeight; 137 | paint.setColor(titleColor); 138 | c.drawRect(left,top,right,bottom,paint); 139 | int pos = ((LinearLayoutManager)(parent.getLayoutManager())).findFirstVisibleItemPosition(); 140 | drawText(c,adapter.getItemViewTitle(pos),left + titleHeight * 0.25f,bottom - titleHeight * 0.25f); 141 | } 142 | 143 | void drawText(Canvas c, String itemViewTitle, float x, float y){ 144 | if(!TextUtils.isEmpty(itemViewTitle)){ 145 | paint.setColor(titleTextColor); 146 | //paint.getTextBounds(itemViewTitle, 0, itemViewTitle.length(), mBounds); 147 | c.drawText(itemViewTitle, x,y, paint); 148 | } 149 | } 150 | } 151 | 152 | public static abstract class StickyAdapter extends Adapter{ 153 | 154 | // 获取当前 item 的标题 155 | public abstract String getItemViewTitle(int position); 156 | 157 | // 如果标题和前面的item的标题一样,就不需要绘制 158 | boolean needTitle(int position){ 159 | return position > -1 && (position == 0 || !getItemViewTitle(position).equals(getItemViewTitle(position - 1))); 160 | } 161 | } 162 | 163 | public int dip2px(Context context, float dpValue) { 164 | final float scale = context.getResources().getDisplayMetrics().density; 165 | return (int) (dpValue * scale + 0.5f); 166 | } 167 | } -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/drag/DragActivity.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.drag; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.support.v7.widget.GridLayoutManager; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.support.v7.widget.helper.ItemTouchHelper; 9 | import android.view.LayoutInflater; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | 13 | import com.heihei.hehe.recyclerview_demo.R; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Collections; 17 | import java.util.List; 18 | 19 | public class DragActivity extends AppCompatActivity { 20 | 21 | RecyclerView recyclerView; 22 | List str = new ArrayList<>(); 23 | private MyAdapter myAdapter; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_swipe); 29 | for (int i = 0; i < 50; i++) { 30 | str.add("data: " + i); 31 | } 32 | recyclerView = (RecyclerView) findViewById(R.id.re); 33 | recyclerView.setLayoutManager(new GridLayoutManager(this,4,GridLayoutManager.VERTICAL,false)); 34 | myAdapter = new MyAdapter(); 35 | recyclerView.setAdapter(myAdapter); 36 | new ItemTouchHelper(new MyItemTouchHandler(myAdapter)).attachToRecyclerView(recyclerView); 37 | } 38 | 39 | private class MyAdapter extends MyItemTouchHandler.ItemTouchAdapterImpl{ 40 | 41 | @Override 42 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 43 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_drag,parent,false)) { 44 | }; 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 49 | TextView tv = (TextView) holder.itemView.findViewById(R.id.text1); 50 | tv.setText(str.get(position)); 51 | } 52 | 53 | @Override 54 | public int getItemCount() { 55 | return str.size(); 56 | } 57 | 58 | @Override 59 | public void onItemMove(int fromPosition, int toPosition) { 60 | // 拖动排序的回调,这里交换集合中数据的位置 61 | Collections.swap(str, fromPosition, toPosition); 62 | } 63 | 64 | @Override 65 | public void onItemRemove(int position) { 66 | // 滑动删除的回调,这里删除指定的数据 67 | } 68 | 69 | @Override 70 | protected boolean autoOpenSwipe() { 71 | return false; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/drag/MyItemTouchHandler.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.drag; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.support.annotation.NonNull; 6 | import android.support.v7.widget.GridLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.support.v7.widget.StaggeredGridLayoutManager; 9 | import android.support.v7.widget.helper.ItemTouchHelper; 10 | import android.util.Log; 11 | 12 | /** 13 | * Describe the function of the class 14 | * 15 | * @author zhujinlong@ichoice.com 16 | * @date 2016/10/28 17 | * @time 16:50 18 | * @description Describe the place where the class needs to pay attention. 19 | */ 20 | public class MyItemTouchHandler extends ItemTouchHelper.Callback { 21 | 22 | ItemTouchAdapterImpl adapter; 23 | 24 | public MyItemTouchHandler(@NonNull ItemTouchAdapterImpl adapter) { 25 | this.adapter = adapter; 26 | } 27 | 28 | /** 29 | * 设置 允许拖拽和滑动删除的方向 30 | */ 31 | @Override 32 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 33 | // 指定可 拖拽方向 和 滑动消失的方向 34 | int dragFlags, swipeFlags; 35 | RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); 36 | if (manager instanceof GridLayoutManager || manager instanceof StaggeredGridLayoutManager) { 37 | // 上下左右都可以拖动 38 | dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; 39 | } else { 40 | // 可以上下拖动 41 | dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; 42 | } 43 | // 可以左右方向滑动消失 44 | swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; 45 | // 如果某个值传 0 , 表示不支持该功能 46 | return makeMovementFlags(dragFlags, swipeFlags); 47 | } 48 | 49 | /** 50 | * 拖拽后回调,一般通过接口暴露给adapter, 让adapter去处理数据的交换 51 | */ 52 | @Override 53 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 54 | // 相同 viewType 之间才能拖动交换 55 | if (viewHolder.getItemViewType() == target.getItemViewType()) { 56 | int fromPosition = viewHolder.getAdapterPosition(); 57 | int toPosition = target.getAdapterPosition(); 58 | if (fromPosition < toPosition) { 59 | //途中所有的item位置都要移动 60 | for (int i = fromPosition; i < toPosition; i++) { 61 | adapter.onItemMove(i, i + 1); 62 | } 63 | } else { 64 | for (int i = fromPosition; i > toPosition; i--) { 65 | adapter.onItemMove(i, i - 1); 66 | } 67 | } 68 | adapter.notifyItemMoved(fromPosition, toPosition); 69 | return true; 70 | } 71 | return false; 72 | } 73 | 74 | /** 75 | * 滑动删除后回调,一般通过接口暴露给adapter, 让adapter去删除该条数据 76 | */ 77 | @Override 78 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 79 | int position = viewHolder.getAdapterPosition(); 80 | // 删除数据 81 | adapter.onItemRemove(position); 82 | // adapter 刷新 83 | adapter.notifyItemRemoved(position); 84 | } 85 | 86 | @Override 87 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { 88 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 89 | if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { 90 | //滑动时改变Item的透明度 91 | final float alpha = 1 - Math.abs(dX) / (float) viewHolder.itemView.getWidth(); 92 | viewHolder.itemView.setAlpha(alpha); 93 | viewHolder.itemView.setTranslationX(dX); 94 | } 95 | } 96 | 97 | /** 98 | * item被选中(长按) 99 | * 这里改变了 item的背景色, 也可以通过接口暴露, 让adapter去处理逻辑 100 | */ 101 | @Override 102 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { 103 | if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) { 104 | // 拖拽状态 105 | viewHolder.itemView.setBackgroundColor(Color.BLUE); 106 | } else if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { 107 | // 滑动删除状态 108 | viewHolder.itemView.setBackgroundColor(Color.RED); 109 | } 110 | super.onSelectedChanged(viewHolder, actionState); 111 | } 112 | 113 | /** 114 | * item取消选中(取消长按) 115 | * 这里改变了 item的背景色, 也可以通过接口暴露, 让adapter去处理逻辑 116 | */ 117 | @Override 118 | public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 119 | viewHolder.itemView.setBackgroundColor(Color.WHITE); 120 | super.clearView(recyclerView, viewHolder); 121 | } 122 | 123 | /** 124 | * 是否支持长按开始拖拽,默认开启 125 | * 可以不开启,然后在长按 item 的时候,手动 调用 mItemTouchHelper.startDrag(myHolder) 开启,更加灵活 126 | */ 127 | @Override 128 | public boolean isLongPressDragEnabled() { 129 | return adapter.autoOpenDrag(); 130 | } 131 | 132 | /** 133 | * 是否支持滑动删除,默认开启 134 | * 可以不开启,然后在长按 item 的时候,手动 调用 mItemTouchHelper.startSwipe(myHolder) 开启,更加灵活 135 | */ 136 | @Override 137 | public boolean isItemViewSwipeEnabled() { 138 | return adapter.autoOpenSwipe(); 139 | } 140 | 141 | // 建议让 adapter 实现该接口 142 | public static abstract class ItemTouchAdapterImpl extends RecyclerView.Adapter { 143 | 144 | public abstract void onItemMove(int fromPosition, int toPosition); 145 | 146 | public abstract void onItemRemove(int position); 147 | 148 | // 是否自动开启拖拽 149 | protected boolean autoOpenDrag() { 150 | return true; 151 | } 152 | 153 | // 是否自动开启滑动删除 154 | protected boolean autoOpenSwipe() { 155 | return true; 156 | } 157 | } 158 | } -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/drag/SwipeActivity.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.drag; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.helper.ItemTouchHelper; 8 | import android.view.LayoutInflater; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | import com.heihei.hehe.recyclerview_demo.R; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class SwipeActivity extends AppCompatActivity { 16 | 17 | RecyclerView recyclerView; 18 | List str = new ArrayList<>(); 19 | private MyAdapter myAdapter; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_swipe); 25 | for (int i = 0; i < 11; i++) { 26 | str.add("data: " + i); 27 | } 28 | recyclerView = (RecyclerView) findViewById(R.id.re); 29 | recyclerView.setLayoutManager(new LinearLayoutManager(this)); 30 | myAdapter = new MyAdapter(); 31 | recyclerView.setAdapter(myAdapter); 32 | new ItemTouchHelper(new MyItemTouchHandler(myAdapter)).attachToRecyclerView(recyclerView); 33 | } 34 | 35 | private class MyAdapter extends MyItemTouchHandler.ItemTouchAdapterImpl{ 36 | 37 | @Override 38 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 39 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_swipe,parent,false)) { 40 | }; 41 | } 42 | 43 | @Override 44 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 45 | TextView tv = (TextView) holder.itemView.findViewById(R.id.text1); 46 | tv.setText(str.get(position)); 47 | } 48 | 49 | @Override 50 | public int getItemCount() { 51 | return str.size(); 52 | } 53 | 54 | @Override 55 | public void onItemMove(int fromPosition, int toPosition) { 56 | 57 | } 58 | 59 | @Override 60 | public void onItemRemove(int position) { 61 | str.remove(position); 62 | } 63 | 64 | @Override 65 | protected boolean autoOpenDrag() { 66 | return false; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/spansize/RefreshActivity.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.spansize; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.support.v7.widget.GridLayoutManager; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | import com.heihei.hehe.recyclerview_demo.R; 12 | import com.heihei.hehe.recyclerview_demo.divider.widgt.ItemDivider; 13 | import com.heihei.hehe.recyclerview_demo.spansize.widgt.SuperRefreshLayout; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public class RefreshActivity extends AppCompatActivity { 18 | 19 | SuperRefreshLayout refreshLayout; 20 | RecyclerView recyclerView; 21 | MyAdapter adapter; 22 | int flag; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_refresh); 28 | refreshLayout = (SuperRefreshLayout) findViewById(R.id.refresh); 29 | recyclerView = (RecyclerView) findViewById(R.id.re); 30 | //recyclerView.setLayoutManager(new LinearLayoutManager(this)); 31 | recyclerView.setLayoutManager(new GridLayoutManager(this,3,GridLayoutManager.VERTICAL,false)); 32 | recyclerView.addItemDecoration(new ItemDivider()); 33 | adapter = new MyAdapter(); 34 | refreshLayout.setAdapter(recyclerView,adapter); 35 | refreshLayout.setOnRefreshHandler(new SuperRefreshLayout.OnRefreshHandler() { 36 | @Override 37 | public void refresh() { 38 | flag = 0; 39 | refreshLayout.postDelayed(new Runnable() { 40 | @Override 41 | public void run() { 42 | List datas = new ArrayList<>(); 43 | for (int i = 0; i < 30; i++) { 44 | datas.add("DATA: " + i); 45 | } 46 | adapter.setDatas(datas); 47 | refreshLayout.setRefreshing(false); 48 | } 49 | },1500); 50 | 51 | } 52 | 53 | @Override 54 | public void loadMore() { 55 | super.loadMore(); 56 | flag ++; 57 | refreshLayout.postDelayed(new Runnable() { 58 | @Override 59 | public void run() { 60 | if(flag % 3 == 2){ 61 | refreshLayout.loadError(); 62 | }else if(flag % 3 == 1){ 63 | List datas = new ArrayList<>(); 64 | for (int i = 0; i < 10; i++) { 65 | datas.add("ADD: " + i); 66 | } 67 | adapter.addDatas(datas); 68 | refreshLayout.loadComplete(true); 69 | }else { 70 | refreshLayout.loadComplete(false); 71 | } 72 | } 73 | },1000); 74 | 75 | 76 | } 77 | }); 78 | refreshLayout.autoRefresh(); 79 | } 80 | 81 | private class MyAdapter extends SuperRefreshLayout.Adapter { 82 | 83 | List datas = new ArrayList<>(); 84 | 85 | public void setDatas(List datas) { 86 | this.datas = datas; 87 | notifyDataSetChanged(); 88 | } 89 | 90 | public void addDatas(List datas) { 91 | this.datas.addAll(datas); 92 | notifyDataSetChanged(); 93 | } 94 | 95 | @Override 96 | public RecyclerView.ViewHolder onCreateItemHolder(ViewGroup parent, int viewType) { 97 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item, parent, false)) { 98 | }; 99 | } 100 | 101 | @Override 102 | public void onBindItemHolder(final RecyclerView.ViewHolder holder, int position) { 103 | TextView tv = (TextView) holder.itemView.findViewById(R.id.text1); 104 | tv.setText(datas.get(position)); 105 | } 106 | 107 | @Override 108 | public int getCount() { 109 | return datas.size(); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/spansize/SpanSizeActivity.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.spansize; 2 | 3 | import android.graphics.Color; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.support.v7.widget.GridLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.heihei.hehe.recyclerview_demo.R; 13 | import com.heihei.hehe.recyclerview_demo.divider.widgt.ItemDivider; 14 | 15 | public class SpanSizeActivity extends AppCompatActivity { 16 | 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_span_size); 22 | RecyclerView re = (RecyclerView) findViewById(R.id.re); 23 | GridLayoutManager layoutManager = new GridLayoutManager(this, 4, GridLayoutManager.VERTICAL, false); 24 | layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 25 | @Override 26 | public int getSpanSize(int position) { 27 | if(position % 5 == 0){ 28 | return 4; 29 | }else if(position % 5 == 1){ 30 | return 3; 31 | }else if(position % 5 == 2){ 32 | return 1; 33 | }else{ 34 | return 2; 35 | } 36 | } 37 | }); 38 | re.setLayoutManager(layoutManager); 39 | re.addItemDecoration(new ItemDivider().setDividerWith(2).setDividerColor(Color.BLUE)); 40 | MyAdapter myAdapter = new MyAdapter(); 41 | re.setAdapter(myAdapter); 42 | } 43 | 44 | private class MyAdapter extends RecyclerView.Adapter{ 45 | 46 | @Override 47 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 48 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item, parent, false)) { 49 | }; 50 | } 51 | 52 | @Override 53 | public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { 54 | TextView tv = (TextView) holder.itemView.findViewById(R.id.text1); 55 | tv.setText(String.valueOf(position)); 56 | // holder.itemView.setBackgroundColor(Color.RED); 57 | 58 | // tv.setOnLongClickListener(new View.OnLongClickListener() { 59 | // @Override 60 | // public boolean onLongClick(View view) { 61 | // //itemTouchHelper.startDrag(holder); 62 | // //itemTouchHelper.startSwipe(holder); 63 | // return false; 64 | // } 65 | // }); 66 | } 67 | 68 | @Override 69 | public int getItemCount() { 70 | return 100; 71 | } 72 | 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/heihei/hehe/recyclerview_demo/spansize/widgt/SuperRefreshLayout.java: -------------------------------------------------------------------------------- 1 | package com.heihei.hehe.recyclerview_demo.spansize.widgt; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.support.v4.view.ViewCompat; 6 | import android.support.v4.widget.SwipeRefreshLayout; 7 | import android.support.v7.widget.GridLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.support.v7.widget.StaggeredGridLayoutManager; 10 | import android.util.AttributeSet; 11 | import android.view.LayoutInflater; 12 | import android.view.MotionEvent; 13 | import android.view.View; 14 | import android.view.ViewConfiguration; 15 | import android.view.ViewGroup; 16 | import android.widget.ProgressBar; 17 | import android.widget.TextView; 18 | import com.heihei.hehe.recyclerview_demo.R; 19 | import java.lang.reflect.Field; 20 | 21 | /** 22 | * Describe the function of the class 23 | * 24 | * @author zhujinlong@ichoice.com 25 | * @date 2016/10/12 26 | * @time 12:45 27 | * @description Describe the place where the class needs to pay attention. 28 | */ 29 | public class SuperRefreshLayout extends SwipeRefreshLayout { 30 | 31 | private static OnRefreshHandler onRefreshHandler; 32 | private static boolean isRefresh = false; 33 | private Adapter adapter; 34 | private int mTouchSlop; 35 | private float mPrevX; 36 | 37 | public SuperRefreshLayout(Context context) { 38 | this(context, null); 39 | } 40 | 41 | public SuperRefreshLayout(Context context, AttributeSet attrs) { 42 | super(context, attrs); 43 | setColorSchemeColors(0xff3b93eb); 44 | setProgressBackgroundColorSchemeColor(0xffffffff); 45 | float scale = context.getResources().getDisplayMetrics().density; 46 | setProgressViewEndTarget(true, (int) (64 * scale + 0.5f)); 47 | //refreshLayout.setProgressViewOffset(false,dip2px(this,-40),dip2px(this,64)); 48 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 49 | } 50 | 51 | /** 52 | * 监听器 53 | */ 54 | public void setOnRefreshHandler(OnRefreshHandler handler) { 55 | onRefreshHandler = handler; 56 | super.setOnRefreshListener(new OnRefreshCallBack()); 57 | } 58 | 59 | /** 60 | * 自动刷新,原生不支持,通过反射修改字段属性 61 | */ 62 | public void autoRefresh() { 63 | try { 64 | setRefreshing(true); 65 | Field field = SwipeRefreshLayout.class.getDeclaredField("mNotify"); 66 | field.setAccessible(true); 67 | field.set(this, true); 68 | } catch (Exception e) { 69 | if(onRefreshHandler != null){ 70 | onRefreshHandler.refresh(); 71 | } 72 | } 73 | } 74 | 75 | @Override 76 | public void setRefreshing(boolean refreshing) { 77 | super.setRefreshing(refreshing); 78 | isRefresh = isRefreshing(); 79 | } 80 | 81 | /** 82 | * 加载完毕 83 | * @param hasMore 是否还有下一页 84 | */ 85 | public void loadComplete(boolean hasMore){ 86 | if(adapter == null){ 87 | throw new RuntimeException("must call method setAdapter to bind data"); 88 | } 89 | adapter.setState(hasMore ? Adapter.STATE_MORE : Adapter.STATE_END); 90 | } 91 | 92 | /** 93 | * 加载出错 94 | */ 95 | public void loadError(){ 96 | if(adapter == null){ 97 | throw new RuntimeException("must call method setAdapter to bind data"); 98 | } 99 | adapter.setState(Adapter.STATE_ERROR); 100 | } 101 | 102 | /** 103 | * 只支持 RecyclerView 加载更多,且需要通过此方法设置适配器 104 | */ 105 | public void setAdapter(@NonNull RecyclerView recyclerView,@NonNull SuperRefreshLayout.Adapter mAdapter) { 106 | adapter = mAdapter; 107 | recyclerView.setAdapter(adapter); 108 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 109 | @Override 110 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 111 | super.onScrollStateChanged(recyclerView, newState); 112 | if (onRefreshHandler != null 113 | && !isRefreshing() 114 | && (adapter.getState() == Adapter.STATE_MORE || adapter.getState() == Adapter.STATE_ERROR) 115 | && newState == RecyclerView.SCROLL_STATE_IDLE 116 | && !ViewCompat.canScrollVertically(recyclerView, 1) 117 | ) { 118 | adapter.setState(Adapter.STATE_LOAIND); 119 | onRefreshHandler.loadMore(); 120 | } 121 | } 122 | }); 123 | } 124 | 125 | /** 126 | * 如果滑动控件嵌套过深,可通过该方法控制是否可以下拉 127 | */ 128 | public void setRefreshEnable(boolean enable){ 129 | // boolean e = !ViewCompat.canScrollVertically(scrollView,-1); 130 | if(isEnabled() && !enable){ 131 | setEnabled(false); 132 | }else if(!isEnabled() && enable){ 133 | setEnabled(true); 134 | } 135 | } 136 | 137 | /** 138 | * 解决水平滑动冲突 139 | */ 140 | @Override 141 | public boolean onInterceptTouchEvent(MotionEvent event) { 142 | switch (event.getAction()) { 143 | case MotionEvent.ACTION_DOWN: 144 | mPrevX = MotionEvent.obtain(event).getX(); 145 | break; 146 | 147 | case MotionEvent.ACTION_MOVE: 148 | final float eventX = event.getX(); 149 | float xDiff = Math.abs(eventX - mPrevX); 150 | 151 | if (xDiff > mTouchSlop) { 152 | return false; 153 | } 154 | } 155 | return super.onInterceptTouchEvent(event); 156 | } 157 | 158 | /** 159 | * 代理回调(底层回调) 160 | */ 161 | private class OnRefreshCallBack implements OnRefreshListener { 162 | 163 | @Override 164 | public void onRefresh() { 165 | if(adapter != null && adapter.getState() != Adapter.STATE_MORE){ 166 | adapter.setState(Adapter.STATE_MORE); 167 | } 168 | if(onRefreshHandler != null){ 169 | onRefreshHandler.refresh(); 170 | } 171 | } 172 | } 173 | 174 | /** 175 | * 对方开放的回调 176 | */ 177 | public static abstract class OnRefreshHandler{ 178 | 179 | public abstract void refresh(); 180 | 181 | public void loadMore() { 182 | 183 | } 184 | } 185 | 186 | /** 187 | * 支持加载更多的代理适配器 188 | */ 189 | public static abstract class Adapter extends RecyclerView.Adapter { 190 | 191 | static final int STATE_MORE = 0, STATE_LOAIND = 1, STATE_END = 2, STATE_ERROR = 3; 192 | int state = STATE_MORE; 193 | 194 | public void setState(int state) { 195 | if (this.state != state) { 196 | this.state = state; 197 | notifyItemChanged(getItemCount() - 1); 198 | } 199 | } 200 | 201 | public int getState() { 202 | return state; 203 | } 204 | 205 | @Override 206 | public int getItemViewType(int position) { 207 | if (position == getItemCount() - 1) { 208 | return -99; 209 | } 210 | return getItemType(position); 211 | } 212 | 213 | @Override 214 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 215 | if (viewType == -99) { 216 | return new RecyclerView.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.loadmore_default_footer, parent, false)) { 217 | }; 218 | } else { 219 | return onCreateItemHolder(parent, viewType); 220 | } 221 | } 222 | 223 | @Override 224 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 225 | if (getItemViewType(position) == -99) { 226 | ProgressBar progressBar = (ProgressBar) holder.itemView.findViewById(R.id.loadmore_default_footer_progressbar); 227 | TextView textView = (TextView) holder.itemView.findViewById(R.id.loadmore_default_footer_tv); 228 | if (state == STATE_END) { 229 | progressBar.setVisibility(View.GONE); 230 | textView.setText("没有更多了"); 231 | } else if (state == STATE_MORE) { 232 | progressBar.setVisibility(View.GONE); 233 | textView.setText("点击加载"); 234 | } else if (state == STATE_LOAIND) { 235 | progressBar.setVisibility(View.VISIBLE); 236 | textView.setText("加载中..."); 237 | } else if (state == STATE_ERROR) { 238 | progressBar.setVisibility(View.GONE); 239 | textView.setText("加载失败,点击重新加载"); 240 | } 241 | holder.itemView.setOnClickListener(new OnClickListener() { 242 | @Override 243 | public void onClick(View view) { 244 | if (onRefreshHandler != null && !isRefresh && (state == STATE_MORE || state == STATE_ERROR)) { 245 | setState(STATE_LOAIND); 246 | onRefreshHandler.loadMore(); 247 | } 248 | } 249 | }); 250 | } else { 251 | onBindItemHolder(holder,position); 252 | } 253 | } 254 | 255 | @Override 256 | public int getItemCount() { 257 | return getCount() == 0 ? 0 : getCount() + 1; 258 | } 259 | 260 | public int getItemType(int position){ 261 | return super.getItemViewType(position); 262 | } 263 | 264 | public abstract RecyclerView.ViewHolder onCreateItemHolder(ViewGroup parent, int viewType); 265 | 266 | public abstract void onBindItemHolder(RecyclerView.ViewHolder holder, int position); 267 | 268 | public abstract int getCount(); 269 | 270 | @Override 271 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { 272 | // 处理瀑布流模式 最后的 item 占整行 273 | if (holder.getLayoutPosition() == getItemCount() - 1) { 274 | LayoutParams lp = holder.itemView.getLayoutParams(); 275 | if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) { 276 | StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; 277 | p.setFullSpan(true); 278 | } 279 | } 280 | } 281 | 282 | @Override 283 | public void onAttachedToRecyclerView(RecyclerView recyclerView) { 284 | // 处理网格布局模式 最后的 item 占整行 285 | final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 286 | if (layoutManager instanceof GridLayoutManager) { 287 | GridLayoutManager gridManager = ((GridLayoutManager) layoutManager); 288 | final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridManager.getSpanSizeLookup(); 289 | final int lastSpanCount = gridManager.getSpanCount(); 290 | gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 291 | @Override 292 | public int getSpanSize(int position) { 293 | return position == getItemCount() - 1 ? lastSpanCount : 294 | (spanSizeLookup == null ? 1 : spanSizeLookup.getSpanSize(position)); 295 | } 296 | }); 297 | } 298 | } 299 | } 300 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_grid_manager.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 |