├── .gitignore ├── .idea ├── compiler.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── cn │ │ └── xmrk │ │ └── Itemdecoration │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── cn │ │ │ └── xmrk │ │ │ └── Itemdecoration │ │ │ ├── activity │ │ │ ├── MainActivity.java │ │ │ └── RecyclerViewActivity.java │ │ │ ├── adapter │ │ │ └── RecyclerAdapter.java │ │ │ ├── decoration │ │ │ ├── GridEntrust.java │ │ │ ├── LinearEntrust.java │ │ │ ├── SpacesItemDecoration.java │ │ │ ├── SpacesItemDecorationEntrust.java │ │ │ └── StaggeredGridEntrust.java │ │ │ └── pojo │ │ │ └── AdapterInfo.java │ └── res │ │ ├── drawable │ │ └── bg_item_press.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_recycler.xml │ │ └── item_recycler.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 │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── cn │ └── xmrk │ └── Itemdecoration │ └── 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 | -------------------------------------------------------------------------------- /.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 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | Android 36 | 37 | 38 | Android > Lint > Accessibility 39 | 40 | 41 | Android > Lint > Correctness 42 | 43 | 44 | Android > Lint > Correctness > Messages 45 | 46 | 47 | Android > Lint > Internationalization 48 | 49 | 50 | Android > Lint > Performance 51 | 52 | 53 | Android > Lint > Security 54 | 55 | 56 | Android > Lint > Usability 57 | 58 | 59 | Android > Lint > Usability > Icons 60 | 61 | 62 | Android Lint for Kotlin 63 | 64 | 65 | C/C++ 66 | 67 | 68 | Class structureJava 69 | 70 | 71 | Control flow issuesJava 72 | 73 | 74 | Error handlingJava 75 | 76 | 77 | General 78 | 79 | 80 | Groovy 81 | 82 | 83 | HTML 84 | 85 | 86 | ImportsJava 87 | 88 | 89 | Internationalization issues 90 | 91 | 92 | Internationalization issuesJava 93 | 94 | 95 | J2ME issuesJava 96 | 97 | 98 | JSON 99 | 100 | 101 | JUnit issuesJava 102 | 103 | 104 | Java 105 | 106 | 107 | Java language level migration aidsJava 108 | 109 | 110 | Javadoc issuesJava 111 | 112 | 113 | Manifest 114 | 115 | 116 | OtherGroovy 117 | 118 | 119 | Portability issuesJava 120 | 121 | 122 | Potentially confusing code constructsGroovy 123 | 124 | 125 | Probable bugsJava 126 | 127 | 128 | Properties Files 129 | 130 | 131 | Properties FilesJava 132 | 133 | 134 | RELAX NG 135 | 136 | 137 | Resource management issuesJava 138 | 139 | 140 | TestNGJava 141 | 142 | 143 | Threading issuesJava 144 | 145 | 146 | Unused codeC/C++ 147 | 148 | 149 | Validity issuesGroovy 150 | 151 | 152 | XML 153 | 154 | 155 | 156 | 157 | Android 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 169 | 170 | $USER_HOME$/.subversion 171 | 172 | 173 | 174 | 175 | 176 | 177 | 182 | 183 | 184 | 185 | 186 | 187 | Android API 23 Platform 188 | 189 | 194 | 195 | 196 | 197 | 198 | 199 | Android API 23 Platform 200 | 201 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SpacesItemDecoration 2 | 自定义RecyclerView.ItemDecoration,实现RecyclerView的分割线效果 3 | 4 | 简书地址:http://www.jianshu.com/p/3b860938e503 5 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "26.0.1" 6 | 7 | defaultConfig { 8 | applicationId "cn.xmrk.Itemdecoration" 9 | minSdkVersion 15 10 | targetSdkVersion 26 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(dir: 'libs', include: ['*.jar']) 25 | compile 'com.android.support:appcompat-v7:26.1.0' 26 | compile 'com.android.support:recyclerview-v7:26.1.0' 27 | } 28 | -------------------------------------------------------------------------------- /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 /Users/hzl/Library/Android/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/cn/xmrk/Itemdecoration/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration; 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("cn.xmrk.Itemdecoration", 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 | -------------------------------------------------------------------------------- /app/src/main/java/cn/xmrk/Itemdecoration/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration.activity; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | import cn.xmrk.Itemdecoration.R; 10 | 11 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 12 | 13 | private Button btn_linear_v; 14 | private Button btn_linear_h; 15 | private Button btn_grid_v; 16 | private Button btn_grid_h; 17 | private Button btn_stagger_v; 18 | private Button btn_stagger_h; 19 | 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_main); 25 | setStatusColor(); 26 | initView(); 27 | } 28 | 29 | 30 | public void setStatusColor() { 31 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 32 | getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimary)); 33 | } 34 | } 35 | 36 | private void initView() { 37 | btn_linear_v = (Button) findViewById(R.id.btn_linear_v); 38 | btn_linear_h = (Button) findViewById(R.id.btn_linear_h); 39 | btn_grid_v = (Button) findViewById(R.id.btn_grid_v); 40 | btn_grid_h = (Button) findViewById(R.id.btn_grid_h); 41 | btn_stagger_v = (Button) findViewById(R.id.btn_stagger_v); 42 | btn_stagger_h = (Button) findViewById(R.id.btn_stagger_h); 43 | 44 | 45 | btn_linear_v.setOnClickListener(this); 46 | btn_linear_h.setOnClickListener(this); 47 | btn_grid_v.setOnClickListener(this); 48 | btn_grid_h.setOnClickListener(this); 49 | btn_stagger_v.setOnClickListener(this); 50 | btn_stagger_h.setOnClickListener(this); 51 | } 52 | 53 | @Override 54 | public void onClick(View v) { 55 | switch (v.getId()) { 56 | case R.id.btn_linear_v: 57 | RecyclerViewActivity.startRecyclerViewActivity(this, RecyclerViewActivity.LINEAR_VERTICAL); 58 | break; 59 | case R.id.btn_linear_h: 60 | RecyclerViewActivity.startRecyclerViewActivity(this, RecyclerViewActivity.LINEAR_HORIZONTAL); 61 | break; 62 | case R.id.btn_grid_v: 63 | RecyclerViewActivity.startRecyclerViewActivity(this, RecyclerViewActivity.GRID_VERTICAL); 64 | break; 65 | case R.id.btn_grid_h: 66 | RecyclerViewActivity.startRecyclerViewActivity(this, RecyclerViewActivity.GRID_HORIZONTAL); 67 | break; 68 | case R.id.btn_stagger_v: 69 | RecyclerViewActivity.startRecyclerViewActivity(this, RecyclerViewActivity.STAGGER_VERTICAL); 70 | break; 71 | case R.id.btn_stagger_h: 72 | RecyclerViewActivity.startRecyclerViewActivity(this, RecyclerViewActivity.STAGGER_HORIZONTAL); 73 | break; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/cn/xmrk/Itemdecoration/activity/RecyclerViewActivity.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration.activity; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.support.annotation.Nullable; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.support.v7.widget.GridLayoutManager; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.RecyclerView; 12 | import android.support.v7.widget.StaggeredGridLayoutManager; 13 | import android.util.TypedValue; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | import cn.xmrk.Itemdecoration.R; 19 | import cn.xmrk.Itemdecoration.adapter.RecyclerAdapter; 20 | import cn.xmrk.Itemdecoration.decoration.SpacesItemDecoration; 21 | import cn.xmrk.Itemdecoration.pojo.AdapterInfo; 22 | 23 | /** 24 | * 作者:请叫我百米冲刺 on 2016/12/6 下午1:27 25 | * 邮箱:mail@hezhilin.cc 26 | */ 27 | 28 | public class RecyclerViewActivity extends AppCompatActivity { 29 | 30 | public static final int LINEAR_VERTICAL = 1; 31 | public static final int LINEAR_HORIZONTAL = 2; 32 | public static final int GRID_VERTICAL = 3; 33 | public static final int GRID_HORIZONTAL = 4; 34 | public static final int STAGGER_VERTICAL = 5; 35 | public static final int STAGGER_HORIZONTAL = 6; 36 | 37 | private int type; 38 | 39 | private RecyclerView rv_content; 40 | private RecyclerView.LayoutManager mLayoutManager; 41 | private RecyclerAdapter mAdapter; 42 | 43 | public static void startRecyclerViewActivity(Activity activity, int type) { 44 | Intent intent = new Intent(activity, RecyclerViewActivity.class); 45 | intent.putExtra("type", type); 46 | activity.startActivity(intent); 47 | } 48 | 49 | 50 | @Override 51 | protected void onCreate(@Nullable Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | setContentView(R.layout.activity_recycler); 54 | setStatusColor(); 55 | initView(); 56 | chooseLayoutManager(); 57 | initRvContent(); 58 | } 59 | 60 | public void setStatusColor() { 61 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 62 | getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimary)); 63 | } 64 | } 65 | 66 | private List getAdapterInfos() { 67 | List infos = new ArrayList<>(); 68 | AdapterInfo info = null; 69 | for (int i = 0; i < 40; i++) { 70 | info = new AdapterInfo(); 71 | if ((type == STAGGER_VERTICAL || type == STAGGER_HORIZONTAL) && i % 3 == 0) { 72 | info.message = ""; 73 | } else { 74 | info.message = "item" + (i + 1); 75 | } 76 | infos.add(info); 77 | } 78 | return infos; 79 | } 80 | 81 | 82 | private void chooseLayoutManager() { 83 | switch (type) { 84 | case LINEAR_VERTICAL: 85 | mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); 86 | break; 87 | case LINEAR_HORIZONTAL: 88 | mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); 89 | break; 90 | case GRID_VERTICAL: 91 | mLayoutManager = new GridLayoutManager(this, 3, GridLayoutManager.VERTICAL, false); 92 | final GridLayoutManager manager = (GridLayoutManager) mLayoutManager; 93 | manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 94 | @Override 95 | public int getSpanSize(int position) { 96 | return position % (manager.getSpanCount() + 1) == 0 ? manager.getSpanCount() : 1; 97 | } 98 | }); 99 | break; 100 | case GRID_HORIZONTAL: 101 | mLayoutManager = new GridLayoutManager(this, 3, GridLayoutManager.HORIZONTAL, false); 102 | break; 103 | case STAGGER_VERTICAL: 104 | mLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL); 105 | break; 106 | case STAGGER_HORIZONTAL: 107 | mLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.HORIZONTAL); 108 | break; 109 | } 110 | } 111 | 112 | private void initRvContent() { 113 | mAdapter = new RecyclerAdapter(getAdapterInfos()); 114 | rv_content.setAdapter(mAdapter); 115 | rv_content.setLayoutManager(mLayoutManager); 116 | 117 | //添加ItemDecoration,item之间的间隔 118 | int leftRight = dip2px(15); 119 | int topBottom = dip2px(15); 120 | 121 | rv_content.addItemDecoration(new SpacesItemDecoration(leftRight, topBottom)); 122 | //rv_content.addItemDecoration(new SpacesItemDecoration(dip2px(1), dip2px(1), Color.BLUE)); 123 | } 124 | 125 | public int dip2px(float dpValue) { 126 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getResources().getDisplayMetrics()); 127 | } 128 | 129 | private void initView() { 130 | type = getIntent().getExtras().getInt("type"); 131 | rv_content = (RecyclerView) findViewById(R.id.rv_content); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /app/src/main/java/cn/xmrk/Itemdecoration/adapter/RecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration.adapter; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.text.TextUtils; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import java.util.List; 11 | 12 | import cn.xmrk.Itemdecoration.R; 13 | import cn.xmrk.Itemdecoration.pojo.AdapterInfo; 14 | 15 | /** 16 | * 作者:请叫我百米冲刺 on 2016/12/6 下午1:33 17 | * 邮箱:mail@hezhilin.cc 18 | */ 19 | 20 | public class RecyclerAdapter extends RecyclerView.Adapter { 21 | 22 | private List mDatas; 23 | 24 | public RecyclerAdapter(@NonNull List mDatas) { 25 | this.mDatas = mDatas; 26 | } 27 | 28 | public List getmDatas() { 29 | return mDatas; 30 | } 31 | 32 | @Override 33 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 34 | return new RecyclerAdapter.ViewHolder(View.inflate(parent.getContext(), R.layout.item_recycler, null)); 35 | } 36 | 37 | @Override 38 | public void onBindViewHolder(ViewHolder holder, int position) { 39 | AdapterInfo info = mDatas.get(position); 40 | // if (holder.itemView.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams) { 41 | // StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams(); 42 | // layoutParams.setFullSpan(position % 3 == 0); 43 | // } 44 | if (!TextUtils.isEmpty(info.message)) { 45 | holder.tvInfo.setText(info.message); 46 | } else { 47 | holder.tvInfo.setText(R.string.long_text); 48 | } 49 | } 50 | 51 | @Override 52 | public int getItemCount() { 53 | return mDatas == null ? 0 : mDatas.size(); 54 | } 55 | 56 | class ViewHolder extends RecyclerView.ViewHolder { 57 | 58 | TextView tvInfo; 59 | 60 | public ViewHolder(View itemView) { 61 | super(itemView); 62 | tvInfo = (TextView) itemView.findViewById(R.id.tv_info); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/cn/xmrk/Itemdecoration/decoration/GridEntrust.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.support.v7.widget.GridLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.View; 8 | 9 | /** 10 | * 作者:请叫我百米冲刺 on 2016/12/6 上午11:39 11 | * 邮箱:mail@hezhilin.cc 12 | */ 13 | 14 | public class GridEntrust extends SpacesItemDecorationEntrust { 15 | 16 | public GridEntrust(int leftRight, int topBottom, int mColor) { 17 | super(leftRight, topBottom, mColor); 18 | } 19 | 20 | @Override 21 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 22 | final GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager(); 23 | final GridLayoutManager.SpanSizeLookup lookup = layoutManager.getSpanSizeLookup(); 24 | 25 | if (mDivider == null || layoutManager.getChildCount() == 0) { 26 | return; 27 | } 28 | //判断总的数量是否可以整除 29 | int spanCount = layoutManager.getSpanCount(); 30 | int left, right, top, bottom; 31 | final int childCount = parent.getChildCount(); 32 | if (layoutManager.getOrientation() == GridLayoutManager.VERTICAL) { 33 | for (int i = 0; i < childCount; i++) { 34 | final View child = parent.getChildAt(i); 35 | //将带有颜色的分割线处于中间位置 36 | final float centerLeft = ((float) (layoutManager.getLeftDecorationWidth(child) + layoutManager.getRightDecorationWidth(child)) 37 | * spanCount / (spanCount + 1) + 1 - leftRight) / 2; 38 | final float centerTop = (layoutManager.getBottomDecorationHeight(child) + 1 - topBottom) / 2; 39 | //得到它在总数里面的位置 40 | final int position = parent.getChildAdapterPosition(child); 41 | //获取它所占有的比重 42 | final int spanSize = lookup.getSpanSize(position); 43 | //获取每排的位置 44 | final int spanIndex = lookup.getSpanIndex(position, layoutManager.getSpanCount()); 45 | //判断是否为第一排 46 | boolean isFirst = layoutManager.getSpanSizeLookup().getSpanGroupIndex(position, spanCount) == 0; 47 | //画上边的,第一排不需要上边的,只需要在最左边的那项的时候画一次就好 48 | if (!isFirst && spanIndex == 0) { 49 | left = layoutManager.getLeftDecorationWidth(child); 50 | right = parent.getWidth() - layoutManager.getLeftDecorationWidth(child); 51 | top = (int) (child.getTop() - centerTop) - topBottom; 52 | bottom = top + topBottom; 53 | mDivider.setBounds(left, top, right, bottom); 54 | mDivider.draw(c); 55 | } 56 | //最右边的一排不需要右边的 57 | boolean isRight = spanIndex + spanSize == spanCount; 58 | if (!isRight) { 59 | //计算右边的 60 | left = (int) (child.getRight() + centerLeft); 61 | right = left + leftRight; 62 | top = child.getTop(); 63 | if (!isFirst) { 64 | top -= centerTop; 65 | } 66 | bottom = (int) (child.getBottom() + centerTop); 67 | mDivider.setBounds(left, top, right, bottom); 68 | mDivider.draw(c); 69 | } 70 | } 71 | } else { 72 | for (int i = 0; i < childCount; i++) { 73 | final View child = parent.getChildAt(i); 74 | //将带有颜色的分割线处于中间位置 75 | final float centerLeft = (layoutManager.getRightDecorationWidth(child) + 1 - leftRight) / 2; 76 | final float centerTop = ((float) (layoutManager.getTopDecorationHeight(child) + layoutManager.getBottomDecorationHeight(child)) 77 | * spanCount / (spanCount + 1) - topBottom) / 2; 78 | //得到它在总数里面的位置 79 | final int position = parent.getChildAdapterPosition(child); 80 | //获取它所占有的比重 81 | final int spanSize = lookup.getSpanSize(position); 82 | //获取每排的位置 83 | final int spanIndex = lookup.getSpanIndex(position, layoutManager.getSpanCount()); 84 | //判断是否为第一列 85 | boolean isFirst = layoutManager.getSpanSizeLookup().getSpanGroupIndex(position, spanCount) == 0; 86 | //画左边的,第一排不需要左边的,只需要在最上边的那项的时候画一次就好 87 | if (!isFirst && spanIndex == 0) { 88 | left = (int) (child.getLeft() - centerLeft) - leftRight; 89 | right = left + leftRight; 90 | top = layoutManager.getRightDecorationWidth(child); 91 | bottom = parent.getHeight() - layoutManager.getTopDecorationHeight(child); 92 | mDivider.setBounds(left, top, right, bottom); 93 | mDivider.draw(c); 94 | } 95 | //最下的一排不需要下边的 96 | boolean isRight = spanIndex + spanSize == spanCount; 97 | if (!isRight) { 98 | //计算右边的 99 | left = child.getLeft(); 100 | if (!isFirst) { 101 | left -= centerLeft; 102 | } 103 | right = (int) (child.getRight() + centerTop); 104 | top = (int) (child.getBottom() + centerLeft); 105 | bottom = top + leftRight; 106 | mDivider.setBounds(left, top, right, bottom); 107 | mDivider.draw(c); 108 | } 109 | } 110 | } 111 | } 112 | 113 | @Override 114 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 115 | GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager(); 116 | final GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams) view.getLayoutParams(); 117 | final int childPosition = parent.getChildAdapterPosition(view); 118 | final int spanCount = layoutManager.getSpanCount(); 119 | 120 | if (layoutManager.getOrientation() == GridLayoutManager.VERTICAL) { 121 | //判断是否在第一排 122 | if (layoutManager.getSpanSizeLookup().getSpanGroupIndex(childPosition, spanCount) == 0) {//第一排的需要上面 123 | outRect.top = topBottom; 124 | } 125 | outRect.bottom = topBottom; 126 | //这里忽略和合并项的问题,只考虑占满和单一的问题 127 | if (lp.getSpanSize() == spanCount) {//占满 128 | outRect.left = leftRight; 129 | outRect.right = leftRight; 130 | } else { 131 | outRect.left = (int) (((float) (spanCount - lp.getSpanIndex())) / spanCount * leftRight); 132 | outRect.right = (int) (((float) leftRight * (spanCount + 1) / spanCount) - outRect.left); 133 | } 134 | } else { 135 | if (layoutManager.getSpanSizeLookup().getSpanGroupIndex(childPosition, spanCount) == 0) {//第一排的需要left 136 | outRect.left = leftRight; 137 | } 138 | outRect.right = leftRight; 139 | //这里忽略和合并项的问题,只考虑占满和单一的问题 140 | if (lp.getSpanSize() == spanCount) {//占满 141 | outRect.top = topBottom; 142 | outRect.bottom = topBottom; 143 | } else { 144 | outRect.top = (int) (((float) (spanCount - lp.getSpanIndex())) / spanCount * topBottom); 145 | outRect.bottom = (int) (((float) topBottom * (spanCount + 1) / spanCount) - outRect.top); 146 | } 147 | } 148 | } 149 | 150 | 151 | } 152 | -------------------------------------------------------------------------------- /app/src/main/java/cn/xmrk/Itemdecoration/decoration/LinearEntrust.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 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.View; 9 | 10 | /** 11 | * 作者:请叫我百米冲刺 on 2016/12/6 上午11:32 12 | * 邮箱:mail@hezhilin.cc 13 | */ 14 | 15 | public class LinearEntrust extends SpacesItemDecorationEntrust { 16 | 17 | 18 | public LinearEntrust(int leftRight, int topBottom, int mColor) { 19 | super(leftRight, topBottom, mColor); 20 | } 21 | 22 | @Override 23 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 24 | LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager(); 25 | //没有子view或者没有没有颜色直接return 26 | if (mDivider == null || layoutManager.getChildCount() == 0) { 27 | return; 28 | } 29 | int left; 30 | int right; 31 | int top; 32 | int bottom; 33 | final int childCount = parent.getChildCount(); 34 | if (layoutManager.getOrientation() == GridLayoutManager.VERTICAL) { 35 | for (int i = 0; i < childCount - 1; i++) { 36 | final View child = parent.getChildAt(i); 37 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); 38 | //将有颜色的分割线处于中间位置 39 | final float center = (layoutManager.getTopDecorationHeight(child) + 1 - topBottom) / 2; 40 | //计算下边的 41 | left = layoutManager.getLeftDecorationWidth(child); 42 | right = parent.getWidth() - layoutManager.getLeftDecorationWidth(child); 43 | top = (int) (child.getBottom() + center); 44 | bottom = top + topBottom; 45 | mDivider.setBounds(left, top, right, bottom); 46 | mDivider.draw(c); 47 | } 48 | } else { 49 | for (int i = 0; i < childCount - 1; i++) { 50 | final View child = parent.getChildAt(i); 51 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); 52 | //将有颜色的分割线处于中间位置 53 | final float center = (layoutManager.getLeftDecorationWidth(child) + 1 - leftRight) / 2; 54 | //计算右边的 55 | left = (int) (child.getRight() + center); 56 | right = left + leftRight; 57 | top = layoutManager.getTopDecorationHeight(child); 58 | bottom = parent.getHeight() - layoutManager.getTopDecorationHeight(child); 59 | mDivider.setBounds(left, top, right, bottom); 60 | mDivider.draw(c); 61 | } 62 | } 63 | 64 | } 65 | 66 | @Override 67 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 68 | LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager(); 69 | //竖直方向的 70 | if (layoutManager.getOrientation() == LinearLayoutManager.VERTICAL) { 71 | //最后一项需要 bottom 72 | if (parent.getChildAdapterPosition(view) == layoutManager.getItemCount() - 1) { 73 | outRect.bottom = topBottom; 74 | } 75 | outRect.top = topBottom; 76 | outRect.left = leftRight; 77 | outRect.right = leftRight; 78 | } else { 79 | //最后一项需要right 80 | if (parent.getChildAdapterPosition(view) == layoutManager.getItemCount() - 1) { 81 | outRect.right = leftRight; 82 | } 83 | outRect.top = topBottom; 84 | outRect.left = leftRight; 85 | outRect.bottom = topBottom; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/cn/xmrk/Itemdecoration/decoration/SpacesItemDecoration.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.support.v7.widget.GridLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.StaggeredGridLayoutManager; 8 | import android.view.View; 9 | 10 | /** 11 | * Created by Au61 on 2016/1/15. 12 | */ 13 | public class SpacesItemDecoration extends RecyclerView.ItemDecoration { 14 | 15 | private SpacesItemDecorationEntrust mEntrust; 16 | private int mColor; 17 | private int leftRight; 18 | private int topBottom; 19 | 20 | 21 | public SpacesItemDecoration(int leftRight, int topBottom) { 22 | this.leftRight = leftRight; 23 | this.topBottom = topBottom; 24 | } 25 | 26 | public SpacesItemDecoration(int leftRight, int topBottom, int mColor) { 27 | this(leftRight, topBottom); 28 | this.mColor = mColor; 29 | } 30 | 31 | @Override 32 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 33 | if (mEntrust == null) { 34 | mEntrust = getEntrust(parent.getLayoutManager()); 35 | } 36 | mEntrust.onDraw(c, parent, state); 37 | super.onDraw(c, parent, state); 38 | } 39 | 40 | @Override 41 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 42 | if (mEntrust == null) { 43 | mEntrust = getEntrust(parent.getLayoutManager()); 44 | } 45 | mEntrust.getItemOffsets(outRect, view, parent, state); 46 | } 47 | 48 | private SpacesItemDecorationEntrust getEntrust(RecyclerView.LayoutManager manager) { 49 | SpacesItemDecorationEntrust entrust = null; 50 | //要注意这边的GridLayoutManager是继承LinearLayoutManager,所以要先判断GridLayoutManager 51 | if (manager instanceof GridLayoutManager) { 52 | entrust = new GridEntrust(leftRight, topBottom, mColor); 53 | } else if (manager instanceof StaggeredGridLayoutManager) { 54 | entrust = new StaggeredGridEntrust(leftRight, topBottom, mColor); 55 | } else {//其他的都当做Linear来进行计算 56 | entrust = new LinearEntrust(leftRight, topBottom, mColor); 57 | } 58 | return entrust; 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/xmrk/Itemdecoration/decoration/SpacesItemDecorationEntrust.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.View; 9 | 10 | /** 11 | * 作者:请叫我百米冲刺 on 2016/12/6 上午11:37 12 | * 邮箱:mail@hezhilin.cc 13 | */ 14 | 15 | public abstract class SpacesItemDecorationEntrust { 16 | 17 | //color的传入方式是resouce.getcolor 18 | protected Drawable mDivider; 19 | 20 | protected int leftRight; 21 | 22 | protected int topBottom; 23 | 24 | public SpacesItemDecorationEntrust(int leftRight, int topBottom, int mColor) { 25 | this.leftRight = leftRight; 26 | this.topBottom = topBottom; 27 | if (mColor != 0) { 28 | mDivider = new ColorDrawable(mColor); 29 | } 30 | } 31 | 32 | abstract void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state); 33 | 34 | abstract void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/cn/xmrk/Itemdecoration/decoration/StaggeredGridEntrust.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.support.v7.widget.GridLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.StaggeredGridLayoutManager; 8 | import android.view.View; 9 | 10 | /** 11 | * 作者:请叫我百米冲刺 on 2016/12/21 下午12:45 12 | * 邮箱:mail@hezhilin.cc 13 | */ 14 | 15 | public class StaggeredGridEntrust extends SpacesItemDecorationEntrust { 16 | 17 | 18 | public StaggeredGridEntrust(int leftRight, int topBottom, int mColor) { 19 | super(leftRight, topBottom, mColor); 20 | 21 | } 22 | 23 | @Override 24 | void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 25 | //TODO 因为排列的不确定性,暂时没找到比较好的处理方式 26 | // StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) parent.getLayoutManager(); 27 | // if (mDivider == null || layoutManager.getChildCount() == 0) { 28 | // return; 29 | // } 30 | // int left; 31 | // int right; 32 | // int top; 33 | // int bottom; 34 | // 35 | // final int spanCount = layoutManager.getSpanCount(); 36 | // final int childCount = parent.getChildCount(); 37 | // 38 | // //获取最后显示的几项 39 | // int[] intos = new int[spanCount]; 40 | // layoutManager.findLastVisibleItemPositions(intos); 41 | // 42 | // //换个思路,每个item都画边和右边,当然第一排的不需要上边,最右边的不需要右边 43 | // if (layoutManager.getOrientation() == StaggeredGridLayoutManager.VERTICAL) { 44 | // for (int i = 0; i < childCount; i++) { 45 | // final View child = parent.getChildAt(i); 46 | // final StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) child.getLayoutParams(); 47 | // //得到它在总数里面的位置 48 | // final int position = parent.getChildAdapterPosition(child); 49 | // //它在每列的位置 50 | // final int spanPosition = params.getSpanIndex(); 51 | // //将带有颜色的分割线处于中间位置 52 | // final float centerLeft = (layoutManager.getLeftDecorationWidth(child) + 1 - leftRight) / 2; 53 | // final float centerTop = (layoutManager.getBottomDecorationHeight(child) + 1 - topBottom) / 2; 54 | // //画上边的 55 | // if (position > spanCount - 1) { 56 | // left = child.getLeft() + params.leftMargin; 57 | // if (spanPosition > 0) { 58 | // left -= centerLeft; 59 | // } 60 | // right = child.getRight() + params.rightMargin; 61 | // if (spanPosition + 1 != spanCount) {//最右边的不需要那一丢丢 62 | // right += centerLeft; 63 | // } 64 | // top = (int) (child.getTop() + params.topMargin - centerTop - topBottom); 65 | // bottom = top + topBottom; 66 | // mDivider.setBounds(left, top, right, bottom); 67 | // mDivider.draw(c); 68 | // } 69 | // //画右边的 70 | // if ((spanPosition + 1) % spanCount != 0) { 71 | // left = (int) (child.getRight() + params.rightMargin + centerLeft); 72 | // right = left + leftRight; 73 | // top = child.getTop() + params.topMargin; 74 | // //第一排的不需要上面那一丢丢 75 | // if (position > spanCount - 1) {//换个思路,都给top了 76 | // top -= centerTop + centerTop + topBottom; 77 | // } 78 | // bottom = child.getBottom() + params.bottomMargin; 79 | // mDivider.setBounds(left, top, right, bottom); 80 | // mDivider.draw(c); 81 | // } 82 | // } 83 | // 84 | // } else { 85 | // for (int i = 0; i < childCount; i++) { 86 | // final View child = parent.getChildAt(i); 87 | // final StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) child.getLayoutParams(); 88 | // //得到它在总数里面的位置 89 | // final int position = parent.getChildAdapterPosition(child); 90 | // //它在每列的位置 91 | // final int spanPosition = params.getSpanIndex(); 92 | // //将带有颜色的分割线处于中间位置 93 | // final float centerLeft = (layoutManager.getRightDecorationWidth(child) + 1 - leftRight) / 2; 94 | // final float centerTop = (layoutManager.getTopDecorationHeight(child) + 1 - topBottom) / 2; 95 | // //画左边 96 | // if (position > spanCount - 1) { 97 | // left = (int) (child.getLeft() + params.leftMargin - centerLeft - leftRight); 98 | // right = left + leftRight; 99 | // top = (int) (child.getTop() + params.topMargin - centerTop); 100 | // if (spanPosition == 0) { 101 | // top += centerTop; 102 | // } 103 | // bottom = child.getBottom() + params.bottomMargin; 104 | // if (spanPosition + 1 != spanCount) { 105 | // bottom += centerTop; 106 | // } 107 | // mDivider.setBounds(left, top, right, bottom); 108 | // mDivider.draw(c); 109 | // } 110 | // //画上面的 111 | // if (spanPosition > 0) { 112 | // left = child.getLeft() + params.leftMargin; 113 | // if (position > spanCount - 1) {//换个思路,都给left了 114 | // left -= centerLeft + centerLeft + leftRight; 115 | // } 116 | // right = child.getRight() + params.rightMargin; 117 | // top = (int) (child.getTop() + params.bottomMargin - centerTop - topBottom); 118 | // bottom = top + topBottom; 119 | // mDivider.setBounds(left, top, right, bottom); 120 | // mDivider.draw(c); 121 | // } 122 | // } 123 | // } 124 | } 125 | 126 | @Override 127 | void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 128 | StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) parent.getLayoutManager(); 129 | final StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams(); 130 | final int childPosition = parent.getChildAdapterPosition(view); 131 | final int spanCount = layoutManager.getSpanCount(); 132 | final int spanSize = lp.isFullSpan() ? layoutManager.getSpanCount() : 1; 133 | 134 | if (layoutManager.getOrientation() == GridLayoutManager.VERTICAL) { 135 | if (getSpanGroupIndex(childPosition, spanCount, spanSize) == 0) {//第一排的需要上面 136 | outRect.top = topBottom; 137 | } 138 | outRect.bottom = topBottom; 139 | //这里忽略和合并项的问题,只考虑占满和单一的问题 140 | if (lp.isFullSpan()) {//占满 141 | outRect.left = leftRight; 142 | outRect.right = leftRight; 143 | } else { 144 | outRect.left = (int) (((float) (spanCount - lp.getSpanIndex())) / spanCount * leftRight); 145 | outRect.right = (int) (((float) leftRight * (spanCount + 1) / spanCount) - outRect.left); 146 | } 147 | } else { 148 | if (getSpanGroupIndex(childPosition, spanCount, spanSize) == 0) {//第一排的需要left 149 | outRect.left = leftRight; 150 | } 151 | outRect.right = leftRight; 152 | //这里忽略和合并项的问题,只考虑占满和单一的问题 153 | if (lp.isFullSpan()) {//占满 154 | outRect.top = topBottom; 155 | outRect.bottom = topBottom; 156 | } else { 157 | outRect.top = (int) (((float) (spanCount - lp.getSpanIndex())) / spanCount * topBottom); 158 | outRect.bottom = (int) (((float) topBottom * (spanCount + 1) / spanCount) - outRect.top); 159 | } 160 | } 161 | } 162 | 163 | public int getSpanGroupIndex(int adapterPosition, int spanCount, int spanSize) { 164 | int span = 0; 165 | int group = 0; 166 | int positionSpanSize = spanSize; 167 | for (int i = 0; i < adapterPosition; i++) { 168 | int size = spanSize; 169 | span += size; 170 | if (span == spanCount) { 171 | span = 0; 172 | group++; 173 | } else if (span > spanCount) { 174 | // did not fit, moving to next row / column 175 | span = size; 176 | group++; 177 | } 178 | } 179 | if (span + positionSpanSize > spanCount) { 180 | group++; 181 | } 182 | return group; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /app/src/main/java/cn/xmrk/Itemdecoration/pojo/AdapterInfo.java: -------------------------------------------------------------------------------- 1 | package cn.xmrk.Itemdecoration.pojo; 2 | 3 | /** 4 | * 作者:请叫我百米冲刺 on 2016/12/6 下午1:48 5 | * 邮箱:mail@hezhilin.cc 6 | */ 7 | 8 | public class AdapterInfo { 9 | public String message; 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_item_press.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 |