├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── mcxtzhang │ │ └── flowlayoutmanager │ │ ├── LauncherActivity.java │ │ ├── MainActivity.java │ │ ├── TestBean.java │ │ ├── gallary │ │ ├── GalleryActivity.java │ │ └── GalleryLayoutManager.java │ │ ├── other │ │ └── ImgAdapter.java │ │ ├── swipecard │ │ ├── SwipeCardActivity.java │ │ └── SwipeCardBean.java │ │ ├── tantan │ │ ├── TanTanActivity.java │ │ └── TanTanCallback.java │ │ └── zuimei │ │ ├── ScaleCardActivity.java │ │ └── ScaleCardLayoutManager.java │ └── res │ ├── drawable-xxhdpi │ ├── icon_del.png │ ├── icon_love.png │ ├── pic1.jpg │ ├── pic10.jpg │ ├── pic2.jpg │ ├── pic3.jpg │ ├── pic4.jpg │ ├── pic5.jpg │ ├── pic6.jpg │ ├── pic7.jpg │ ├── pic8.jpg │ └── pic9.jpg │ ├── drawable │ ├── item_bg_flow_round.xml │ └── item_text_bg_flow.xml │ ├── layout │ ├── activity_gallery.xml │ ├── activity_launcher.xml │ ├── activity_main.xml │ ├── activity_scale_card.xml │ ├── activity_swipe_card.xml │ ├── item_flow.xml │ ├── item_gallery.xml │ ├── item_rv_1.xml │ ├── item_swipe_card.xml │ └── item_zuimei.xml │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gifs ├── gif1 ├── gif2 ├── renren.gif ├── tantan.gif └── tantan_6page.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── layoutmanager ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── mcxtzhang │ └── layoutmanager │ ├── flow │ └── FlowLayoutManager.java │ └── swipecard │ ├── CardConfig.java │ ├── OverLayCardLayoutManager.java │ └── RenRenCallback.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea 38 | 39 | # Keystore files 40 | *.jks 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LayoutManagerDemo 2 | [![](https://jitpack.io/v/mcxtzhang/LayoutManagerDemo.svg)](https://jitpack.io/#mcxtzhang/LayoutManagerDemo) 3 | 4 | ### 在原库上作了更改优化。 5 | 6 | 利用自定义LayoutManager 的一些实战实例。 7 | 8 | 9 | 相关博文: 10 | 11 | [流式布局](http://blog.csdn.net/zxt0601/article/details/52956504) 12 | 13 | [仿探探、人人影视 卡片层叠 炫动滑动布局](http://blog.csdn.net/zxt0601/article/details/52956504) 14 | 15 | 16 | 想经济上支持我 or 想通过视频看我是怎么实现的: 17 | 18 | http://edu.csdn.net/course/detail/3956 19 | 20 | 21 | If you like, point a star .Thank you very much! 22 | 23 | 喜欢随手点个star 多谢 24 | 25 | ## 在哪里找到我: 26 | 27 | 我的github: 28 | 29 | https://github.com/mcxtzhang 30 | 31 | 我的CSDN博客: 32 | 33 | http://blog.csdn.net/zxt0601 34 | 35 | 我的稀土掘金: 36 | 37 | http://gold.xitu.io/user/56de210b816dfa0052e66495 38 | 39 | 我的简书: 40 | 41 | http://www.jianshu.com/users/8e91ff99b072/timeline 42 | *** 43 | 44 | 45 | # 效果一览: 46 | 47 | 48 | [仿探探、人人影视 卡片层叠 炫动滑动布局](http://blog.csdn.net/zxt0601/article/details/52956504) 49 | 50 | 探探皇帝翻牌子即视感 51 | 52 | ![探探皇帝翻牌子即视感](https://github.com/mcxtzhang/LayoutManagerDemo/blob/master/gifs/tantan.gif) 53 | 54 | 人人美剧订阅界面 55 | 56 | ![人人美剧订阅界面](https://github.com/mcxtzhang/LayoutManagerDemo/blob/master/gifs/renren.gif) 57 | 58 | 可配置参数(同时显示6页): 59 | 60 | ![人人美剧订阅界面](https://github.com/mcxtzhang/LayoutManagerDemo/blob/master/gifs/tantan_6page.gif) 61 | 62 | 63 | [流式布局](http://blog.csdn.net/zxt0601/article/details/52956504) 64 | 65 | ![这里写图片描述](https://github.com/mcxtzhang/FlowLayoutManager/blob/master/gifs/gif1) 66 | 67 | 艾玛,换成妹子图后貌似好看了许多,我都不认识它了,好吧,项目里它一般长下面这样: 68 | 69 | ![这里写图片描述](https://github.com/mcxtzhang/FlowLayoutManager/blob/master/gifs/gif2) 70 | 71 | 往常这种效果,我们一般使用自定义ViewGroup实现,我以前也写了一个。[自定义VG实现流式布局](http://blog.csdn.net/zxt0601/article/details/50533658) 72 | 73 | 74 | # 使用: 75 | 76 | **Step 1. 在项目根build.gradle文件中增加JitPack仓库依赖。** 77 | ``` 78 | allprojects { 79 | repositories { 80 | ... 81 | maven { url "https://jitpack.io" } 82 | } 83 | } 84 | ``` 85 | Step 2. Add the dependency 86 | ``` 87 | dependencies { 88 | compile 'com.github.mcxtzhang:ZLayoutManager:V1.1.0' 89 | } 90 | ``` 91 | 92 | Step 3. 93 | [仿探探、人人影视 卡片层叠 炫动滑动布局](http://blog.csdn.net/zxt0601/article/details/52956504): 94 | 95 | 以后老板让你做这种效果,你只需要: 96 | ``` 97 | mRv.setLayoutManager(new OverLayCardLayoutManager()); 98 | CardConfig.initConfig(this); 99 | ItemTouchHelper.Callback callback = new RenRenCallback(mRv, mAdapter, mDatas); 100 | ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback); 101 | itemTouchHelper.attachToRecyclerView(mRv); 102 | ``` 103 | 104 | 如果需要定制特殊的参数,例如显示6层: 105 | 106 | ``` 107 | CardConfig.MAX_SHOW_COUNT = 6; 108 | ``` 109 | 110 | 设置仿探探竖直上下滑动,不删除Item。 111 | 112 | 水平方向判断误差阈值x: 113 | ``` 114 | final TanTanCallback callback = new TanTanCallback(mRv, mAdapter, mDatas); 115 | callback.setHorizontalDeviation(x); 116 | ``` 117 | 118 | [流式布局](http://blog.csdn.net/zxt0601/article/details/52956504): 119 | ``` 120 | mRv.setLayoutManager(new FlowLayoutManager()); 121 | ``` 122 | 123 | 刚建了个QQ搞基交流群: 124 | 557266366 125 | 里面现在没有人。 126 | 嗯,就这样吧。 127 | 128 | ## 使用的Adapter: 129 | https://github.com/mcxtzhang/all-base-adapter 130 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion '25.0.0' 6 | defaultConfig { 7 | applicationId "com.mcxtzhang.flowlayoutmanager" 8 | minSdkVersion 14 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(include: ['*.jar'], dir: 'libs') 23 | compile 'com.android.support:appcompat-v7:24.2.1' 24 | 25 | //Adapter终结者 地址:https://github.com/mcxtzhang/all-base-adapter 26 | compile 'com.github.mcxtzhang:all-base-adapter:V1.3.0' 27 | compile 'com.android.support:cardview-v7:25.1.0' 28 | compile 'com.squareup.picasso:picasso:2.3.2' 29 | compile project(':layoutmanager') 30 | } 31 | -------------------------------------------------------------------------------- /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 C:\Users\admin\AppData\Local\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/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/LauncherActivity.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | 8 | import com.mcxtzhang.flowlayoutmanager.gallary.GalleryActivity; 9 | import com.mcxtzhang.flowlayoutmanager.swipecard.SwipeCardActivity; 10 | import com.mcxtzhang.flowlayoutmanager.tantan.TanTanActivity; 11 | import com.mcxtzhang.flowlayoutmanager.zuimei.ScaleCardActivity; 12 | 13 | public class LauncherActivity extends AppCompatActivity { 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_launcher); 19 | findViewById(R.id.btnFlow).setOnClickListener(new View.OnClickListener() { 20 | @Override 21 | public void onClick(View view) { 22 | startActivity(new Intent(LauncherActivity.this, MainActivity.class)); 23 | } 24 | }); 25 | findViewById(R.id.btnSwipeCard).setOnClickListener(new View.OnClickListener() { 26 | @Override 27 | public void onClick(View view) { 28 | startActivity(new Intent(LauncherActivity.this, SwipeCardActivity.class)); 29 | } 30 | }); 31 | findViewById(R.id.btnKing).setOnClickListener(new View.OnClickListener() { 32 | @Override 33 | public void onClick(View view) { 34 | startActivity(new Intent(LauncherActivity.this, TanTanActivity.class)); 35 | } 36 | }); 37 | findViewById(R.id.btnGallery).setOnClickListener(new View.OnClickListener() { 38 | @Override 39 | public void onClick(View view) { 40 | startActivity(new Intent(LauncherActivity.this, GalleryActivity.class)); 41 | } 42 | }); 43 | findViewById(R.id.btnZuimeiCard).setOnClickListener(new View.OnClickListener() { 44 | @Override 45 | public void onClick(View view) { 46 | startActivity(new Intent(LauncherActivity.this, ScaleCardActivity.class)); 47 | } 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager; 2 | 3 | import android.graphics.Canvas; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.helper.ItemTouchHelper; 8 | import android.util.Log; 9 | import android.view.View; 10 | 11 | import com.mcxtzhang.commonadapter.rv.CommonAdapter; 12 | import com.mcxtzhang.commonadapter.rv.ViewHolder; 13 | import com.mcxtzhang.flowlayoutmanager.other.ImgAdapter; 14 | import com.mcxtzhang.layoutmanager.flow.FlowLayoutManager; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Collections; 18 | import java.util.List; 19 | 20 | public class MainActivity extends AppCompatActivity { 21 | private RecyclerView mRv; 22 | private CommonAdapter mAdapter; 23 | private List mDatas; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_main); 29 | initDatas(); 30 | mRv = (RecyclerView) findViewById(R.id.rv); 31 | 32 | 33 | 34 | /* mRv.setAdapter(mAdapter = new CommonAdapter(this, R.layout.item_flow, mDatas) { 35 | @Override 36 | public void convert(ViewHolder holder, TestBean testBean) { 37 | Log.d("zxt", "convert() called with: holder = [" + holder + "], testBean = [" + testBean + "]"); 38 | holder.setText(R.id.tv, testBean.getName() + testBean.getUrl()); 39 | holder.setOnClickListener(R.id.tv, new View.OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | Log.e("TAG1", "onClick() called with: v = [" + v + "]"); 43 | } 44 | }); 45 | } 46 | });*/ 47 | 48 | 49 | mAdapter = new CommonAdapter(this, mDatas, R.layout.item_flow) { 50 | @Override 51 | public void convert(ViewHolder holder, TestBean testBean) { 52 | Log.d("zxt", "convert() called with: holder = [" + holder + "], testBean = [" + testBean + "]"); 53 | holder.setText(R.id.tv, testBean.getName() + testBean.getUrl()); 54 | holder.setOnClickListener(R.id.tv, new View.OnClickListener() { 55 | @Override 56 | public void onClick(View v) { 57 | Log.e("TAG1", "onClick() called with: v = [" + v + "]"); 58 | } 59 | }); 60 | } 61 | }; 62 | 63 | //图片的Adapter 64 | final ImgAdapter imgAdapter = new ImgAdapter(this); 65 | mRv.setAdapter(mAdapter); 66 | 67 | 68 | final ItemTouchHelper.Callback callback = new ItemTouchHelper.SimpleCallback(0, 69 | /* ItemTouchHelper.DOWN | ItemTouchHelper.UP | */ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT 70 | ) { 71 | @Override 72 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 73 | return false; 74 | } 75 | 76 | @Override 77 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 78 | Log.e("swipecard", "onSwiped() called with: viewHolder = [" + viewHolder + "], direction = [" + direction + "]"); 79 | //rollBack(viewHolder); 80 | mAdapter.notifyDataSetChanged(); 81 | mDatas.remove(viewHolder.getLayoutPosition()); 82 | 83 | } 84 | 85 | @Override 86 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { 87 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 88 | /* c.drawColor(Color.GREEN); 89 | View childAt = recyclerView.getChildAt(viewHolder.getLayoutPosition() - 1); 90 | childAt.setScaleX(1.5f); 91 | childAt.setScaleY(1.5f);*/ 92 | Log.e("swipecard", "onChildDraw() viewHolder = [" + viewHolder + "], dX = [" + dX + "], dY = [" + dY + "], actionState = [" + actionState + "], isCurrentlyActive = [" + isCurrentlyActive + "]"); 93 | //小马的效果 94 | /* if (isCurrentlyActive) { 95 | View ViewLast1 = recyclerView.getChildAt(viewHolder.getLayoutPosition() - 1); 96 | ViewLast1.setTranslationX(dX / 2); 97 | ViewLast1.setRotation(10); 98 | //ViewLast1.setTranslationY(dY/2); 99 | View ViewLast2 = recyclerView.getChildAt(viewHolder.getLayoutPosition() - 2); 100 | ViewLast2.setTranslationX(dX / 4); 101 | ViewLast2.setRotation(5); 102 | //ViewLast2.setTranslationY(dY / 4); 103 | } else { 104 | //rollBack(viewHolder); 105 | }*/ 106 | 107 | 108 | //人人影视的效果 109 | if (isCurrentlyActive) { 110 | 111 | } 112 | 113 | } 114 | 115 | public void rollBack(RecyclerView.ViewHolder viewHolder) { 116 | View ViewLast1 = mRv.getChildAt(viewHolder.getLayoutPosition() - 1); 117 | ViewLast1.animate().translationX(0).setDuration(100).start(); 118 | View ViewLast2 = mRv.getChildAt(viewHolder.getLayoutPosition() - 2); 119 | ViewLast2.animate().translationX(0).setDuration(100).start(); 120 | } 121 | 122 | }; 123 | final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback); 124 | 125 | 126 | findViewById(R.id.btnFlow).setOnClickListener(new View.OnClickListener() { 127 | @Override 128 | public void onClick(View v) { 129 | mRv.setLayoutManager(new FlowLayoutManager());//自己写的流式布局 130 | itemTouchHelper.attachToRecyclerView(null); 131 | } 132 | }); 133 | 134 | findViewById(R.id.btnCard).setOnClickListener(new View.OnClickListener() { 135 | @Override 136 | public void onClick(View v) { 137 | //mRv.setLayoutManager(new OverLayCardLayoutManager(); 138 | itemTouchHelper.attachToRecyclerView(mRv); 139 | } 140 | }); 141 | 142 | 143 | /* final GridLayoutManager gridLayoutManager = new GridLayoutManager(this,2); 144 | mRv.setLayoutManager(gridLayoutManager); 145 | gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 146 | @Override 147 | public int getSpanSize(int position) { 148 | if (position==1){ 149 | return gridLayoutManager.getSpanCount(); 150 | } 151 | return 1; 152 | } 153 | });*/ 154 | } 155 | 156 | private int i = 0; 157 | 158 | public List initDatas() { 159 | mDatas = new ArrayList<>(); 160 | for (int j = 0; j < 1; j++) { 161 | mDatas.add(new TestBean((i++) + " ", "张旭童")); 162 | mDatas.add(new TestBean((i++) + " ", "旭童")); 163 | mDatas.add(new TestBean((i++) + " ", "多种type")); 164 | mDatas.add(new TestBean((i++) + " ", "遍")); 165 | mDatas.add(new TestBean((i++) + " ", "多种type")); 166 | mDatas.add(new TestBean((i++) + " ", "多种type")); 167 | mDatas.add(new TestBean((i++) + " ", "多种type")); 168 | mDatas.add(new TestBean((i++) + " ", "多种type")); 169 | } 170 | return mDatas; 171 | } 172 | 173 | public void add(View vIew) { 174 | mDatas.add(new TestBean((i++) + " ", "新增的一个Item")); 175 | mAdapter.notifyItemInserted(mDatas.size() - 1); 176 | } 177 | 178 | public void del(View vIew) { 179 | /* mDatas.remove(mDatas.size() - 1); 180 | mAdapter.notifyItemRemoved(mDatas.size());*/ 181 | Collections.shuffle(mDatas); 182 | mRv.setAdapter(mAdapter = new CommonAdapter(this, mDatas, R.layout.item_rv_1) { 183 | @Override 184 | public void convert(ViewHolder holder, TestBean testBean) { 185 | Log.d("zxt", "convert() called with: holder = [" + holder + "], testBean = [" + testBean + "]"); 186 | holder.setText(R.id.tv, testBean.getName() + testBean.getUrl()); 187 | holder.setOnClickListener(R.id.tv, new View.OnClickListener() { 188 | @Override 189 | public void onClick(View v) { 190 | Log.e("TAG1", "onClick() called with: v = [" + v + "]"); 191 | } 192 | }); 193 | } 194 | }); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/TestBean.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager; 2 | 3 | /** 4 | * 介绍: 5 | * 作者:zhangxutong 6 | * 邮箱:zhangxutong@imcoming.com 7 | * 时间: 2016/9/9. 8 | */ 9 | public class TestBean { 10 | private String name; 11 | private String url; 12 | 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | public String getUrl() { 23 | return url; 24 | } 25 | 26 | public void setUrl(String url) { 27 | this.url = url; 28 | } 29 | 30 | public TestBean(String name, String url) { 31 | this.name = name; 32 | this.url = url; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/gallary/GalleryActivity.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager.gallary; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.support.v7.widget.LinearSnapHelper; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.SnapHelper; 8 | import android.util.Log; 9 | import android.widget.ImageView; 10 | 11 | import com.mcxtzhang.commonadapter.rv.CommonAdapter; 12 | import com.mcxtzhang.commonadapter.rv.ViewHolder; 13 | import com.mcxtzhang.flowlayoutmanager.R; 14 | import com.mcxtzhang.flowlayoutmanager.swipecard.SwipeCardBean; 15 | import com.squareup.picasso.Picasso; 16 | 17 | import java.util.List; 18 | 19 | import static com.mcxtzhang.flowlayoutmanager.swipecard.SwipeCardBean.initDatas; 20 | 21 | public class GalleryActivity extends AppCompatActivity { 22 | private RecyclerView mRv; 23 | private CommonAdapter mAdapter; 24 | private List mDatas; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_gallery); 30 | 31 | mRv = (RecyclerView) findViewById(R.id.rv); 32 | 33 | mRv.setAdapter(mAdapter = new CommonAdapter(this, mDatas = initDatas(), R.layout.item_gallery) { 34 | public static final String TAG = "zxt/Adapter"; 35 | 36 | @Override 37 | public void convert(ViewHolder viewHolder, SwipeCardBean swipeCardBean) { 38 | Log.d(TAG, "convert() called with: viewHolder = [" + viewHolder + "], swipeCardBean = [" + swipeCardBean + "]"); 39 | viewHolder.setText(R.id.tvName, swipeCardBean.getName()); 40 | viewHolder.setText(R.id.tvPrecent, swipeCardBean.getPostition() + " /" + mDatas.size()); 41 | Picasso.with(GalleryActivity.this).load(swipeCardBean.getUrl()).into((ImageView) viewHolder.getView(R.id.iv)); 42 | } 43 | }); 44 | 45 | mRv.setLayoutManager(new GalleryLayoutManager()); 46 | SnapHelper snapHelper = new LinearSnapHelper(); 47 | snapHelper.attachToRecyclerView(mRv); 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/gallary/GalleryLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager.gallary; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.util.Log; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.Toast; 8 | 9 | /** 10 | * 介绍:一个酷炫画廊效果,假设所有Item大小一样 11 | * 作者:zhangxutong 12 | * 邮箱:mcxtzhang@163.com 13 | * 主页:http://blog.csdn.net/zxt0601 14 | * 时间: 2016/12/23. 15 | */ 16 | 17 | public class GalleryLayoutManager extends RecyclerView.LayoutManager { 18 | 19 | private static final String TAG = "zxt/画廊"; 20 | //private int mFirstVisiblePosition, mLastVisiblePosition; 21 | 22 | private int mChildWidth, mChildHeight; 23 | 24 | @Override 25 | public RecyclerView.LayoutParams generateDefaultLayoutParams() { 26 | return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 27 | } 28 | 29 | @Override 30 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 31 | super.onLayoutChildren(recycler, state); 32 | if (getItemCount() == 0) {//没有Item,界面空着吧 33 | detachAndScrapAttachedViews(recycler); 34 | return; 35 | } 36 | if (getChildCount() == 0 && state.isPreLayout()) {//state.isPreLayout()是支持动画的 37 | return; 38 | } 39 | //onLayoutChildren方法在RecyclerView 初始化时 会执行两遍 40 | //detachAndScrapAttachedViews(recycler); 41 | 42 | if (mChildHeight==0 || mChildWidth ==0){ 43 | View firstView = recycler.getViewForPosition(0); 44 | addView(firstView); 45 | measureChildWithMargins(firstView, 0, 0); 46 | mChildWidth = getDecoratedMeasuredWidth(firstView); 47 | mChildHeight = getDecoratedMeasuredHeight(firstView); 48 | removeAndRecycleView(firstView, recycler); 49 | } 50 | 51 | 52 | //mFirstVisiblePosition = 0; 53 | 54 | fill(recycler, state); 55 | Log.d(TAG, "循环f @$@$@@!!!!!!!!!!!!!!!!!() onLayoutChildren: " + mLastRecyclePosition+",childcouht:"+getChildCount() ); 56 | 57 | } 58 | 59 | 60 | @Override 61 | public boolean canScrollHorizontally() { 62 | return true; 63 | } 64 | 65 | @Override 66 | public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 67 | int realOffset; 68 | //先考虑滑动位移进行View的回收、填充(fill()函数),然后再真正的位移这些子Item。 69 | realOffset = fill(recycler, state, dx); 70 | offsetChildrenHorizontal(-realOffset); 71 | return realOffset; 72 | } 73 | 74 | 75 | private void fill(RecyclerView.Recycler recycler, RecyclerView.State state) { 76 | fill(recycler, state, 0); 77 | } 78 | 79 | /** 80 | * @param recycler 81 | * @param state 82 | * @param dx >0,load more , <0.load left 83 | * @return 84 | */ 85 | public int fill(RecyclerView.Recycler recycler, RecyclerView.State state, int dx) { 86 | Log.d(TAG, "fill() called with: recycler = [" + recycler + "], state = [" + state + "], dx = [" + dx + "]"); 87 | //step 1 :回收越界子View 88 | recycleHideViews(recycler, state, dx); 89 | 90 | 91 | 92 | //为了能给每个childView做动画 93 | for (int i = 0; i < getChildCount(); i++) { 94 | View child = getChildAt(i); 95 | changeViewUIProperty(dx, child); 96 | } 97 | 98 | 99 | //Step2. layout right views 100 | int itemCount = getItemCount(); 101 | if (dx >= 0) { 102 | View child; 103 | int startPos = 0; 104 | if (mLastRecyclePosition != -1) { 105 | Log.d(TAG, "循环fill() mLastRecyclePosition: " + mLastRecyclePosition+",childcouht:"+getChildCount() ); 106 | //界面 1 2 , 1回收, 应该从 3 = 1 + 1 + 1. 107 | startPos = mLastRecyclePosition + getChildCount() + 1; 108 | } 109 | int left = getPaddingLeft(); 110 | int top = getPaddingTop(); 111 | 112 | //如果界面上还有子View 113 | if (getChildCount() > 0) { 114 | child = getChildAt(getChildCount() - 1); 115 | int lastPosition = getPosition(child); 116 | startPos = lastPosition + 1; 117 | left = getNextViewLeft(child); 118 | } 119 | 120 | 121 | for (int i = startPos; i < itemCount; i++) { 122 | Log.d(TAG, "循环add() called with: i = [" + i+",childcouht:"+getChildCount() ); 123 | //如果左边界已经大于屏幕可见(考虑offset) 124 | if (left - dx > getWidth() - getPaddingRight()) { 125 | Log.d(TAG, "循环break() called with: i = [" + i +",childcouht:"+getChildCount() ); 126 | break; 127 | } 128 | 129 | child = recycler.getViewForPosition(i); 130 | addView(child); 131 | 132 | //measure 还是需要的 133 | measureChildWithMargins(child, 0, 0); 134 | 135 | changeViewUIProperty(dx, child); 136 | 137 | 138 | /* 139 | int width = getDecoratedMeasuredWidth(child); 140 | int height = getDecoratedMeasuredHeight(child);*/ 141 | layoutDecoratedWithMargins(child, left, top 142 | , left + mChildWidth, top + mChildHeight); 143 | left += mChildWidth; 144 | } 145 | 146 | } else { 147 | //Step2. layout left views 148 | //这种情况屏幕上一定有子View 149 | View leftChild = getChildAt(0); 150 | int endPos = getPosition(leftChild) - 1; 151 | if (mLastRecyclePosition != -1) { 152 | //界面 1 2 , 2回收, 应该从 0 = 2 - 1 - 1. 153 | endPos = mLastRecyclePosition - getChildCount() - 1; 154 | } 155 | 156 | int right = getLastViewRight(leftChild); 157 | int top = getPaddingTop(); 158 | 159 | for (int pos = endPos; pos >= 0; pos--) { 160 | //只layout可见的 161 | if (right - dx < getPaddingLeft()) { 162 | break; 163 | } 164 | leftChild = recycler.getViewForPosition(pos); 165 | //这里是重点重点重点!!!作者每次在这里都踩坑, 166 | addView(leftChild, 0); 167 | 168 | measureChildWithMargins(leftChild, 0, 0); 169 | 170 | changeViewUIProperty(dx, leftChild); 171 | 172 | layoutDecoratedWithMargins(leftChild, right - mChildWidth, top 173 | , right, top + mChildHeight); 174 | right -= mChildWidth; 175 | 176 | } 177 | 178 | } 179 | 180 | 181 | return dx; 182 | } 183 | 184 | private float mFraction; 185 | 186 | /** 187 | * 根据滑动值改变View的UI状态 188 | * 189 | * @param dx 190 | * @param child 191 | */ 192 | private void changeViewUIProperty(int dx, View child) { 193 | /* float fraction = dx * 1.0f / 45; 194 | if (fraction > 1) { 195 | fraction = 1; 196 | } 197 | mFraction = Math.max(mFraction, fraction); 198 | child.animate().rotationY(mFraction * 15).setDuration(100).start();*/ 199 | int parentMiddle = getPaddingLeft() + getWidth() / 2; 200 | int childMiddle = (int) (child.getX() + child.getWidth() / 2); 201 | int distance = parentMiddle - childMiddle; 202 | float fraction = distance * 1.0f / getWidth() / 2; 203 | Toast.makeText(child.getContext(), "fraction:" + fraction, Toast.LENGTH_SHORT).show(); 204 | // Counteract the default slide transition 205 | //child.setTranslationX(child.getWidth() * -fraction); 206 | // Scale the page down (between MIN_SCALE and 1) 207 | scale(child, fraction); 208 | 209 | 210 | rotation(child, fraction); 211 | 212 | 213 | } 214 | 215 | private void rotation(View child, float fraction) { 216 | child.setRotationY(45 * fraction); 217 | child.setAlpha(0.5f * (1 - fraction) + 0.5f); 218 | } 219 | 220 | private void scale(View child, float fraction) { 221 | final float MIN_SCALE = 0.75f; 222 | float scaleFactor = MIN_SCALE 223 | + (1 - MIN_SCALE) * (1 - Math.abs(fraction)); 224 | child.setScaleX(scaleFactor); 225 | child.setScaleY(scaleFactor); 226 | } 227 | 228 | /** 229 | * 根据dx 回收界面不可见的View 230 | * 231 | * @param recycler 232 | * @param state 233 | * @param dx 234 | */ 235 | protected int mLastRecyclePosition= -1; 236 | 237 | private void recycleHideViews(RecyclerView.Recycler recycler, RecyclerView.State state, int dx) { 238 | int childCount = getChildCount(); 239 | if (childCount > 0 && dx != 0) { 240 | mLastRecyclePosition = -1; 241 | for (int i = childCount - 1; i >= 0; i--) { 242 | View child = getChildAt(i); 243 | if (dx > 0) { 244 | //load right,recycle left 245 | //child的右边不再屏幕内 recycle 246 | if (getDecoratedRight(child) - dx < getPaddingLeft()) { 247 | Log.d(TAG, "循环 删除 () called with: getPosition(child) = [" + getPosition(child) + "], mLastRecyclePosition = [" + mLastRecyclePosition + "], dx = [" + dx + "]"); 248 | //逆序的 所以取最大的 249 | mLastRecyclePosition = Math.max(mLastRecyclePosition, getPosition(child)); 250 | removeAndRecycleView(child, recycler); 251 | } else { 252 | //mFirstVisiblePosition = i; 253 | continue; 254 | } 255 | } else { 256 | //load left,recycle right 257 | //child 的左边 不在屏幕内 recycle 258 | if (getDecoratedLeft(child) - dx > getWidth() - getPaddingRight()) { 259 | Log.d(TAG, "循环 删除 () called with: getPosition(child) = [" + getPosition(child) + "], mLastRecyclePosition = [" + mLastRecyclePosition + "], dx = [" + dx + "]"); 260 | //本身就是应该逆序,所以直接取 261 | mLastRecyclePosition = getPosition(child); 262 | removeAndRecycleView(child, recycler); 263 | } else { 264 | //mLastVisiblePosition = i; 265 | continue; 266 | } 267 | } 268 | } 269 | } 270 | } 271 | 272 | //由于上述方法没有考虑margin的存在,所以我参考LinearLayoutManager的源码: 273 | 274 | /** 275 | * 获取某个childView在水平方向所占的空间 276 | * 277 | * @param view 278 | * @return 279 | */ 280 | public int getDecoratedMeasurementHorizontal(View view) { 281 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) 282 | view.getLayoutParams(); 283 | return getDecoratedMeasuredWidth(view) + params.leftMargin 284 | + params.rightMargin; 285 | } 286 | 287 | /** 288 | * 获取下一个View的left 289 | * 290 | * @param view 291 | * @return 292 | */ 293 | public int getNextViewLeft(View view) { 294 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) 295 | view.getLayoutParams(); 296 | return getDecoratedRight(view) + params.rightMargin; 297 | } 298 | 299 | /** 300 | * 获取上一个View的Right 301 | * 302 | * @param view 303 | * @return 304 | */ 305 | public int getLastViewRight(View view) { 306 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) 307 | view.getLayoutParams(); 308 | return getDecoratedLeft(view) - params.leftMargin; 309 | } 310 | 311 | /** 312 | * 获取某个childView在竖直方向所占的空间 313 | * 314 | * @param view 315 | * @return 316 | */ 317 | public int getDecoratedMeasurementVertical(View view) { 318 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) 319 | view.getLayoutParams(); 320 | return getDecoratedMeasuredHeight(view) + params.topMargin 321 | + params.bottomMargin; 322 | } 323 | 324 | 325 | public int getVerticalSpace() { 326 | return getHeight() - getPaddingTop() - getPaddingBottom(); 327 | } 328 | 329 | public int getHorizontalSpace() { 330 | return getWidth() - getPaddingLeft() - getPaddingRight(); 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/other/ImgAdapter.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager.other; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.DrawableRes; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.ViewGroup; 7 | import android.widget.ImageView; 8 | 9 | import com.mcxtzhang.flowlayoutmanager.R; 10 | 11 | /** 12 | * 介绍: 13 | * 作者:zhangxutong 14 | * 邮箱:zhangxutong@imcoming.com 15 | * 时间: 2016/10/28. 16 | */ 17 | 18 | public class ImgAdapter extends RecyclerView.Adapter { 19 | @DrawableRes 20 | public static final int[] IMAGES = new int[]{ 21 | R.drawable.pic1, 22 | R.drawable.pic2, 23 | R.drawable.pic3, 24 | R.drawable.pic4, 25 | R.drawable.pic5, 26 | R.drawable.pic6, 27 | R.drawable.pic7, 28 | R.drawable.pic8, 29 | R.drawable.pic9, 30 | R.drawable.pic10, 31 | }; 32 | private final Context mContext; 33 | 34 | public class ImgViewHolder extends RecyclerView.ViewHolder { 35 | private ImageView mImageView; 36 | 37 | public ImgViewHolder(ImageView imageView) { 38 | super(imageView); 39 | mImageView = imageView; 40 | } 41 | } 42 | 43 | public ImgAdapter(Context context) { 44 | mContext = context; 45 | } 46 | 47 | @Override 48 | public ImgViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 49 | ImageView imageView = new ImageView(mContext); 50 | imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); 51 | 52 | ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams( 53 | 400, 54 | 400 55 | ); 56 | lp.leftMargin = 5; 57 | lp.topMargin = 5; 58 | lp.bottomMargin = 5; 59 | lp.rightMargin = 5; 60 | imageView.setLayoutParams(lp); 61 | return new ImgViewHolder(imageView); 62 | } 63 | 64 | @Override 65 | public void onBindViewHolder(ImgViewHolder holder, int position) { 66 | holder.mImageView.setImageResource(IMAGES[position % IMAGES.length]); 67 | } 68 | 69 | @Override 70 | public int getItemCount() { 71 | return IMAGES.length * 10; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/swipecard/SwipeCardActivity.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager.swipecard; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.support.v7.widget.helper.ItemTouchHelper; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | 11 | import com.mcxtzhang.commonadapter.rv.CommonAdapter; 12 | import com.mcxtzhang.commonadapter.rv.ViewHolder; 13 | import com.mcxtzhang.flowlayoutmanager.R; 14 | import com.mcxtzhang.layoutmanager.swipecard.CardConfig; 15 | import com.mcxtzhang.layoutmanager.swipecard.OverLayCardLayoutManager; 16 | import com.mcxtzhang.layoutmanager.swipecard.RenRenCallback; 17 | import com.squareup.picasso.Picasso; 18 | 19 | import java.util.List; 20 | 21 | public class SwipeCardActivity extends AppCompatActivity { 22 | RecyclerView mRv; 23 | CommonAdapter mAdapter; 24 | List mDatas; 25 | 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_swipe_card); 31 | mRv = (RecyclerView) findViewById(R.id.rv); 32 | mRv.setLayoutManager(new OverLayCardLayoutManager()); 33 | mRv.setAdapter(mAdapter = new CommonAdapter(this, mDatas = SwipeCardBean.initDatas(), R.layout.item_swipe_card) { 34 | public static final String TAG = "zxt/Adapter"; 35 | 36 | @Override 37 | public void convert(ViewHolder viewHolder, SwipeCardBean swipeCardBean) { 38 | Log.d(TAG, "convert() called with: viewHolder = [" + viewHolder + "], swipeCardBean = [" + swipeCardBean + "]"); 39 | viewHolder.setText(R.id.tvName, swipeCardBean.getName()); 40 | viewHolder.setText(R.id.tvPrecent, swipeCardBean.getPostition() + " /" + mDatas.size()); 41 | Picasso.with(SwipeCardActivity.this).load(swipeCardBean.getUrl()).into((ImageView) viewHolder.getView(R.id.iv)); 42 | } 43 | }); 44 | 45 | //初始化配置 46 | CardConfig.initConfig(this); 47 | ItemTouchHelper.Callback callback = new RenRenCallback(mRv, mAdapter, mDatas); 48 | ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback); 49 | itemTouchHelper.attachToRecyclerView(mRv); 50 | 51 | 52 | findViewById(R.id.btnRefresh).setOnClickListener(new View.OnClickListener() { 53 | @Override 54 | public void onClick(View view) { 55 | mDatas.add(new SwipeCardBean(100, "http://news.k618.cn/tech/201604/W020160407281077548026.jpg", "增加的")); 56 | mAdapter.notifyDataSetChanged(); 57 | } 58 | }); 59 | 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/swipecard/SwipeCardBean.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager.swipecard; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 介绍: 8 | * 作者:zhangxutong 9 | * 邮箱:mcxtzhang@163.com 10 | * 主页:http://blog.csdn.net/zxt0601 11 | * 时间: 16/12/18. 12 | */ 13 | 14 | public class SwipeCardBean { 15 | private int postition; 16 | private String url; 17 | private String name; 18 | 19 | public SwipeCardBean(int postition, String url, String name) { 20 | this.postition = postition; 21 | this.url = url; 22 | this.name = name; 23 | } 24 | 25 | public int getPostition() { 26 | return postition; 27 | } 28 | 29 | public SwipeCardBean setPostition(int postition) { 30 | this.postition = postition; 31 | return this; 32 | } 33 | 34 | public String getUrl() { 35 | return url; 36 | } 37 | 38 | public SwipeCardBean setUrl(String url) { 39 | this.url = url; 40 | return this; 41 | } 42 | 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | public SwipeCardBean setName(String name) { 48 | this.name = name; 49 | return this; 50 | } 51 | 52 | public static List initDatas() { 53 | List datas = new ArrayList<>(); 54 | int i = 1; 55 | datas.add(new SwipeCardBean(i++, "http://imgs.ebrun.com/resources/2016_03/2016_03_25/201603259771458878793312_origin.jpg", "张")); 56 | datas.add(new SwipeCardBean(i++, "http://p14.go007.com/2014_11_02_05/a03541088cce31b8_1.jpg", "旭童")); 57 | datas.add(new SwipeCardBean(i++, "http://news.k618.cn/tech/201604/W020160407281077548026.jpg", "多种type")); 58 | datas.add(new SwipeCardBean(i++, "http://www.kejik.com/image/1460343965520.jpg", "多种type")); 59 | datas.add(new SwipeCardBean(i++, "http://cn.chinadaily.com.cn/img/attachement/jpg/site1/20160318/eca86bd77be61855f1b81c.jpg", "多种type")); 60 | datas.add(new SwipeCardBean(i++, "http://imgs.ebrun.com/resources/2016_04/2016_04_12/201604124411460430531500.jpg", "多种type")); 61 | datas.add(new SwipeCardBean(i++, "http://imgs.ebrun.com/resources/2016_04/2016_04_24/201604244971461460826484_origin.jpeg", "多种type")); 62 | datas.add(new SwipeCardBean(i++, "http://www.lnmoto.cn/bbs/data/attachment/forum/201408/12/074018gshshia3is1cw3sg.jpg", "多种type")); 63 | return datas; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/tantan/TanTanActivity.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager.tantan; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.support.v7.widget.helper.ItemTouchHelper; 7 | import android.util.Log; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | 11 | import com.mcxtzhang.commonadapter.rv.CommonAdapter; 12 | import com.mcxtzhang.commonadapter.rv.ViewHolder; 13 | import com.mcxtzhang.flowlayoutmanager.R; 14 | import com.mcxtzhang.flowlayoutmanager.swipecard.SwipeCardBean; 15 | import com.mcxtzhang.layoutmanager.swipecard.CardConfig; 16 | import com.mcxtzhang.layoutmanager.swipecard.OverLayCardLayoutManager; 17 | import com.squareup.picasso.Picasso; 18 | 19 | import java.util.List; 20 | 21 | 22 | public class TanTanActivity extends AppCompatActivity { 23 | RecyclerView mRv; 24 | CommonAdapter mAdapter; 25 | List mDatas; 26 | 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_swipe_card); 32 | mRv = (RecyclerView) findViewById(R.id.rv); 33 | mRv.setLayoutManager(new OverLayCardLayoutManager()); 34 | mRv.setAdapter(mAdapter = new CommonAdapter(this, mDatas = SwipeCardBean.initDatas(), R.layout.item_swipe_card) { 35 | public static final String TAG = "zxt/Adapter"; 36 | 37 | @Override 38 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 39 | Log.d(TAG, "onCreateViewHolder() called with: parent = [" + parent + "], viewType = [" + viewType + "]"); 40 | return super.onCreateViewHolder(parent, viewType); 41 | } 42 | 43 | @Override 44 | public void onBindViewHolder(ViewHolder holder, int position) { 45 | Log.d(TAG, "onBindViewHolder() called with: holder = [" + holder + "], position = [" + position + "]"); 46 | super.onBindViewHolder(holder, position); 47 | } 48 | 49 | @Override 50 | public void convert(ViewHolder viewHolder, SwipeCardBean swipeCardBean) { 51 | Log.d(TAG, "convert() called with: viewHolder = [" + viewHolder + "], swipeCardBean = [" + swipeCardBean + "]"); 52 | viewHolder.setText(R.id.tvName, swipeCardBean.getName()); 53 | viewHolder.setText(R.id.tvPrecent, swipeCardBean.getPostition() + " /" + mDatas.size()); 54 | Picasso.with(TanTanActivity.this).load(swipeCardBean.getUrl()).into((ImageView) viewHolder.getView(R.id.iv)); 55 | } 56 | }); 57 | 58 | CardConfig.initConfig(this); 59 | 60 | final TanTanCallback callback = new TanTanCallback(mRv, mAdapter, mDatas); 61 | 62 | //测试竖直滑动是否已经不会被移除屏幕 63 | //callback.setHorizontalDeviation(Integer.MAX_VALUE); 64 | 65 | final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback); 66 | itemTouchHelper.attachToRecyclerView(mRv); 67 | 68 | } 69 | 70 | 71 | } 72 | 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/tantan/TanTanCallback.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager.tantan; 2 | 3 | import android.graphics.Canvas; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.Log; 6 | import android.util.TypedValue; 7 | import android.view.View; 8 | 9 | import com.mcxtzhang.commonadapter.rv.ViewHolder; 10 | import com.mcxtzhang.flowlayoutmanager.R; 11 | import com.mcxtzhang.layoutmanager.swipecard.CardConfig; 12 | import com.mcxtzhang.layoutmanager.swipecard.RenRenCallback; 13 | 14 | import java.util.List; 15 | 16 | import static com.mcxtzhang.layoutmanager.swipecard.CardConfig.ALPHA_GAP; 17 | import static com.mcxtzhang.layoutmanager.swipecard.CardConfig.MAX_SHOW_COUNT; 18 | import static com.mcxtzhang.layoutmanager.swipecard.CardConfig.SCALE_GAP; 19 | import static com.mcxtzhang.layoutmanager.swipecard.CardConfig.TRANS_Y_GAP; 20 | 21 | /** 22 | * 介绍:探探效果定制的Callback 23 | * 作者:zhangxutong 24 | * 邮箱:mcxtzhang@163.com 25 | * 主页:http://blog.csdn.net/zxt0601 26 | * 时间: 16/12/18. 27 | */ 28 | 29 | public class TanTanCallback extends RenRenCallback { 30 | private static final int MAX_ROTATION = 15; 31 | 32 | //2016 12 26 考虑 探探垂直上下方向滑动,不删除卡片, 33 | //判断 此次滑动方向是否是竖直的 ,水平方向上的误差(阈值,默认我给了50dp) 34 | int mHorizontalDeviation; 35 | 36 | 37 | public TanTanCallback(RecyclerView rv, RecyclerView.Adapter adapter, List datas) { 38 | //this(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, rv, adapter, datas); 39 | super(rv, adapter, datas); 40 | mHorizontalDeviation = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, mRv.getContext().getResources().getDisplayMetrics()); 41 | } 42 | 43 | public TanTanCallback(int dragDirs, int swipeDirs, RecyclerView rv, RecyclerView.Adapter adapter, List datas) { 44 | super(dragDirs, swipeDirs, rv, adapter, datas); 45 | } 46 | 47 | public int getHorizontalDeviation() { 48 | return mHorizontalDeviation; 49 | } 50 | 51 | public TanTanCallback setHorizontalDeviation(int horizontalDeviation) { 52 | mHorizontalDeviation = horizontalDeviation; 53 | return this; 54 | } 55 | 56 | @Override 57 | public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) { 58 | /* Log.d("TAG", "getSwipeThreshold() called with: viewHolder.itemView.getX() = [" + viewHolder.itemView.getX() + "]"); 59 | Log.d("TAG", "getSwipeThreshold() called with: viewHolder.itemView.getWidth() / 2 = [" + viewHolder.itemView.getWidth() / 2 + "]"); 60 | Log.d("TAG", "getSwipeThreshold() called with: mRv.getX() = [" + mRv.getX() + "]"); 61 | Log.d("TAG", "getSwipeThreshold() called with: mRv.getWidth() / 2 = [" + mRv.getWidth() / 2 + "]");*/ 62 | 63 | if (isTopViewCenterInHorizontal(viewHolder.itemView)) { 64 | return Float.MAX_VALUE; 65 | } 66 | return super.getSwipeThreshold(viewHolder); 67 | } 68 | 69 | @Override 70 | public float getSwipeEscapeVelocity(float defaultValue) { 71 | View topView = mRv.getChildAt(mRv.getChildCount() - 1); 72 | if (isTopViewCenterInHorizontal(topView)) { 73 | return Float.MAX_VALUE; 74 | } 75 | return super.getSwipeEscapeVelocity(defaultValue); 76 | } 77 | 78 | @Override 79 | public float getSwipeVelocityThreshold(float defaultValue) { 80 | 81 | View topView = mRv.getChildAt(mRv.getChildCount() - 1); 82 | if (isTopViewCenterInHorizontal(topView)) { 83 | return Float.MAX_VALUE; 84 | } 85 | return super.getSwipeVelocityThreshold(defaultValue); 86 | } 87 | 88 | /** 89 | * 返回TopView此时在水平方向上是否是居中的 90 | * 91 | * @return 92 | */ 93 | public boolean isTopViewCenterInHorizontal(View topView) { 94 | //Log.d("TAG", "getSwipeThreshold() called with: viewHolder.itemView.getX() = [" + topView.getX() + "]"); 95 | //Log.d("TAG", "getSwipeThreshold() called with: viewHolder.itemView.getWidth() / 2 = [" + topView.getWidth() / 2 + "]"); 96 | //Log.d("TAG", "getSwipeThreshold() called with: mRv.getX() = [" + mRv.getX() + "]"); 97 | //Log.d("TAG", "getSwipeThreshold() called with: mRv.getWidth() / 2 = [" + mRv.getWidth() / 2 + "]"); 98 | return Math.abs(mRv.getWidth() / 2 - topView.getX() - (topView.getWidth() / 2)) < mHorizontalDeviation; 99 | } 100 | 101 | 102 | @Override 103 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 104 | super.onSwiped(viewHolder, direction); 105 | //如果不需要循环删除 106 | /* Object remove = mDatas.remove(viewHolder.getLayoutPosition()); 107 | mAdapter.notifyDataSetChanged();*/ 108 | Log.e("swipecard", "厉害了"); 109 | 110 | /* if (isLeftSwipe){ 111 | Toast.makeText(mRv.getContext(), "左滑删除", Toast.LENGTH_SHORT).show(); 112 | }else { 113 | Toast.makeText(mRv.getContext(), "右滑删除", Toast.LENGTH_SHORT).show(); 114 | }*/ 115 | 116 | //探探只是第一层加了rotate & alpha的操作 117 | //对rotate进行复位 118 | viewHolder.itemView.setRotation(0); 119 | 120 | //自己感受一下吧 Alpha 121 | if (viewHolder instanceof ViewHolder) { 122 | ViewHolder holder = (ViewHolder) viewHolder; 123 | holder.setAlpha(R.id.iv_love, 0); 124 | holder.setAlpha(R.id.iv_del, 0); 125 | } 126 | 127 | } 128 | 129 | @Override 130 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { 131 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 132 | Log.e("swipecard", "onChildDraw() viewHolder = [" + viewHolder + "], dX = [" + dX + "], dY = [" + dY + "], actionState = [" + actionState + "], isCurrentlyActive = [" + isCurrentlyActive + "]"); 133 | //探探的效果 134 | double swipValue = Math.sqrt(dX * dX + dY * dY); 135 | double fraction = swipValue / getThreshold(viewHolder); 136 | //边界修正 最大为1 137 | if (fraction > 1) { 138 | fraction = 1; 139 | } 140 | int childCount = recyclerView.getChildCount(); 141 | for (int i = 0; i < childCount; i++) { 142 | View child = recyclerView.getChildAt(i); 143 | //第几层,举例子,count =7, 最后一个TopView(6)是第0层, 144 | int level = childCount - i - 1; 145 | if (level > 0) { 146 | child.setScaleX((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP)); 147 | 148 | if (level < MAX_SHOW_COUNT - 1) { 149 | child.setScaleY((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP)); 150 | child.setAlpha((float) (1 - ALPHA_GAP * level + fraction * ALPHA_GAP)); 151 | if (CardConfig.TRANS_FLAG == 0) { 152 | child.setTranslationY(-(float) (TRANS_Y_GAP * level - fraction * TRANS_Y_GAP)); 153 | } else { 154 | child.setTranslationY((float) (TRANS_Y_GAP * level - fraction * TRANS_Y_GAP)); 155 | } 156 | } else if (level < MAX_SHOW_COUNT) { 157 | child.setAlpha((float) (1 - ALPHA_GAP * (level + 1) + fraction * ALPHA_GAP)); 158 | } else { 159 | //child.setTranslationY((float) (mTranslationYGap * (level - 1) - fraction * mTranslationYGap)); 160 | } 161 | } else { 162 | //探探只是第一层加了rotate & alpha的操作 163 | //不过他区分左右 164 | float xFraction = dX / getThreshold(viewHolder); 165 | //边界修正 最大为1 166 | if (xFraction > 1) { 167 | xFraction = 1; 168 | } else if (xFraction < -1) { 169 | xFraction = -1; 170 | } 171 | //rotate 172 | child.setRotation(xFraction * MAX_ROTATION); 173 | 174 | //自己感受一下吧 Alpha 175 | if (viewHolder instanceof ViewHolder) { 176 | ViewHolder holder = (ViewHolder) viewHolder; 177 | if (dX > 0) { 178 | //露出左边,比心 179 | holder.setAlpha(R.id.iv_love, xFraction); 180 | } else if (dX<0){ 181 | //露出右边,滚犊子 182 | holder.setAlpha(R.id.iv_del, -xFraction); 183 | }else { 184 | holder.setAlpha(R.id.iv_love, 0); 185 | holder.setAlpha(R.id.iv_del, 0); 186 | } 187 | 188 | 189 | } 190 | } 191 | } 192 | 193 | 194 | //可以在此判断左右滑: 195 | float v = mRv.getWidth() / 2 - viewHolder.itemView.getX() - (viewHolder.itemView.getWidth() / 2); 196 | if (v > 0) { 197 | isLeftSwipe = true; 198 | } else if (v < 0) { 199 | isLeftSwipe = false; 200 | } 201 | } 202 | 203 | //一个flag 判断左右滑 204 | private boolean isLeftSwipe; 205 | } 206 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/zuimei/ScaleCardActivity.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager.zuimei; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.util.Log; 7 | import android.widget.ImageView; 8 | 9 | import com.mcxtzhang.commonadapter.rv.CommonAdapter; 10 | import com.mcxtzhang.commonadapter.rv.ViewHolder; 11 | import com.mcxtzhang.flowlayoutmanager.R; 12 | import com.mcxtzhang.flowlayoutmanager.swipecard.SwipeCardBean; 13 | import com.squareup.picasso.Picasso; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | import static com.mcxtzhang.flowlayoutmanager.swipecard.SwipeCardBean.initDatas; 19 | 20 | public class ScaleCardActivity extends AppCompatActivity { 21 | private RecyclerView mRv; 22 | private CommonAdapter mAdapter; 23 | private List mDatas; 24 | 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_scale_card); 30 | 31 | mRv = (RecyclerView) findViewById(R.id.rv); 32 | 33 | mDatas = new ArrayList<>(); 34 | for (int i = 0; i < 10; i++) { 35 | 36 | mDatas.addAll(initDatas()); 37 | } 38 | 39 | mRv.setAdapter(mAdapter = new CommonAdapter(this, mDatas, R.layout.item_zuimei) { 40 | public static final String TAG = "zxt/Adapter"; 41 | 42 | @Override 43 | public void convert(ViewHolder viewHolder, SwipeCardBean swipeCardBean) { 44 | Log.d(TAG, "convert() called with: viewHolder = [" + viewHolder + "], swipeCardBean = [" + swipeCardBean + "]"); 45 | viewHolder.setText(R.id.tvName, swipeCardBean.getName()); 46 | viewHolder.setText(R.id.tvPrecent, swipeCardBean.getPostition() + " /" + mDatas.size()); 47 | Picasso.with(ScaleCardActivity.this).load(swipeCardBean.getUrl()).into((ImageView) viewHolder.getView(R.id.iv)); 48 | } 49 | }); 50 | 51 | mRv.setLayoutManager(new ScaleCardLayoutManager()); 52 | 53 | 54 | 55 | /* mRv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true)); 56 | mRv.addOnScrollListener(new RecyclerView.OnScrollListener() { 57 | @Override 58 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 59 | super.onScrollStateChanged(recyclerView, newState); 60 | } 61 | 62 | @Override 63 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 64 | super.onScrolled(recyclerView, dx, dy); 65 | int childCount = recyclerView.getChildCount(); 66 | for (int i = 0; i < childCount; i++) { 67 | View child = recyclerView.getChildAt(i); 68 | float distance = child.getY() - recyclerView.getPaddingBottom(); 69 | int horizontalSpace = recyclerView.getHeight() - recyclerView.getPaddingTop() - recyclerView.getPaddingBottom(); 70 | //0.8f-1.0f 71 | child.setScaleX(0.8f + distance / horizontalSpace * 0.2f); 72 | Log.d("zxt", "onScrolled() called with: distance = [" + distance + "], horizontalSpace = [" + horizontalSpace + "], i = [" + i + "]"); 73 | Log.d("zxt", "onScrolled() called with: getY = [" + child.getY() + "], getTop [" + child.getTop() + "], getTranslationY = [" + child.getTranslationY() + "]"); 74 | } 75 | } 76 | });*/ 77 | /* SnapHelper snapHelper = new LinearSnapHelper(); 78 | snapHelper.attachToRecyclerView(mRv);*/ 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/mcxtzhang/flowlayoutmanager/zuimei/ScaleCardLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.mcxtzhang.flowlayoutmanager.zuimei; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.util.Log; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | /** 9 | * 介绍:最美首页 缩放 位移Card LayoutManager 10 | * 作者:zhangxutong 11 | * 邮箱:mcxtzhang@163.com 12 | * 主页:http://blog.csdn.net/zxt0601 13 | * 时间: 2017/1/3. 14 | */ 15 | 16 | public class ScaleCardLayoutManager extends RecyclerView.LayoutManager { 17 | private static final String TAG = "zxt/最美"; 18 | 19 | private int mChildWidth, mChildHeight; 20 | 21 | @Override 22 | public RecyclerView.LayoutParams generateDefaultLayoutParams() { 23 | return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 24 | } 25 | 26 | @Override 27 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 28 | super.onLayoutChildren(recycler, state); 29 | //没有Item,界面空着吧 30 | if (getItemCount() == 0) { 31 | detachAndScrapAttachedViews(recycler); 32 | return; 33 | } 34 | 35 | //state.isPreLayout()是支持动画的 36 | if (getChildCount() == 0 && state.isPreLayout()) { 37 | return; 38 | } 39 | 40 | //onLayoutChildren方法在RecyclerView 初始化时 会执行两遍 41 | detachAndScrapAttachedViews(recycler); 42 | 43 | if (mChildHeight == 0 || mChildWidth == 0) { 44 | View firstView = recycler.getViewForPosition(0); 45 | addView(firstView); 46 | measureChildWithMargins(firstView, 0, 0); 47 | mChildWidth = getDecoratedMeasuredWidth(firstView); 48 | mChildHeight = getDecoratedMeasuredHeight(firstView); 49 | removeAndRecycleView(firstView, recycler); 50 | } 51 | 52 | 53 | int itemCount = getItemCount(); 54 | View child; 55 | int leftOffset = getPaddingLeft(); 56 | int bottomOffset = getHeight() - getPaddingBottom(); 57 | for (int i = 0; i < itemCount; i++) { 58 | child = recycler.getViewForPosition(i); 59 | addView(child); 60 | measureChildWithMargins(child, 0, 0); 61 | layoutDecoratedWithMargins(child, leftOffset, bottomOffset - mChildHeight 62 | , leftOffset + mChildWidth, bottomOffset); 63 | 64 | 65 | bottomOffset -= mChildHeight / 2; 66 | 67 | } 68 | 69 | //为了能给每个childView做动画 70 | for (int i = 0; i < getChildCount(); i++) { 71 | child = getChildAt(i); 72 | changeViewUIProperty(0, child); 73 | } 74 | 75 | } 76 | 77 | private void changeViewUIProperty(int dy, View child) { 78 | float distance = child.getY() - getPaddingBottom(); 79 | int horizontalSpace = getHeight() - getPaddingTop() - getPaddingBottom(); 80 | //0.8f-1.0f 81 | child.setScaleX(0.8f + distance / horizontalSpace * 0.2f); 82 | Log.d("zxt", "changeViewUIProperty() called with: distance = [" + distance + "], horizontalSpace = [" + horizontalSpace ); 83 | Log.d("zxt", "changeViewUIProperty() called with: getY = [" + child.getY() + "], getTop [" + child.getTop() + "], getTranslationY = [" + child.getTranslationY() + "]"); 84 | 85 | } 86 | 87 | @Override 88 | public boolean canScrollVertically() { 89 | return true; 90 | } 91 | 92 | @Override 93 | public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { 94 | int offset = dy; 95 | offsetChildrenVertical(-offset); 96 | //为了能给每个childView做动画 97 | for (int i = 0; i < getChildCount(); i++) { 98 | View child = getChildAt(i); 99 | changeViewUIProperty(0, child); 100 | } 101 | return offset; 102 | } 103 | 104 | //由于上述方法没有考虑margin的存在,所以我参考LinearLayoutManager的源码: 105 | 106 | /** 107 | * 获取某个childView在水平方向所占的空间 108 | * 109 | * @param view 110 | * @return 111 | */ 112 | public int getDecoratedMeasurementHorizontal(View view) { 113 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) 114 | view.getLayoutParams(); 115 | return getDecoratedMeasuredWidth(view) + params.leftMargin 116 | + params.rightMargin; 117 | } 118 | 119 | /** 120 | * 获取下一个View的left 121 | * 122 | * @param view 123 | * @return 124 | */ 125 | public int getNextViewLeft(View view) { 126 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) 127 | view.getLayoutParams(); 128 | return getDecoratedRight(view) + params.rightMargin; 129 | } 130 | 131 | /** 132 | * 获取上一个View的Right 133 | * 134 | * @param view 135 | * @return 136 | */ 137 | public int getLastViewRight(View view) { 138 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) 139 | view.getLayoutParams(); 140 | return getDecoratedLeft(view) - params.leftMargin; 141 | } 142 | 143 | /** 144 | * 获取某个childView在竖直方向所占的空间 145 | * 146 | * @param view 147 | * @return 148 | */ 149 | public int getDecoratedMeasurementVertical(View view) { 150 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) 151 | view.getLayoutParams(); 152 | return getDecoratedMeasuredHeight(view) + params.topMargin 153 | + params.bottomMargin; 154 | } 155 | 156 | 157 | public int getVerticalSpace() { 158 | return getHeight() - getPaddingTop() - getPaddingBottom(); 159 | } 160 | 161 | public int getHorizontalSpace() { 162 | return getWidth() - getPaddingLeft() - getPaddingRight(); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_del.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/icon_del.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/icon_love.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/icon_love.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic10.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic4.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic5.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic6.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic7.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic8.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/pic9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/ZLayoutManager/de3821e4359bb12b0effee03fa0ff113710e1129/app/src/main/res/drawable-xxhdpi/pic9.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/item_bg_flow_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/item_text_bg_flow.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_gallery.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 |