├── .gitignore ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── angcyo │ │ └── recyclerlayoutmanager │ │ ├── Main2Activity.java │ │ ├── MainActivity.java │ │ ├── OverLayCardLayoutManager.java │ │ ├── RenRenCallback.java │ │ ├── SwipeCardBean.java │ │ └── TanTanCallback.java │ └── res │ ├── layout │ ├── activity_main.xml │ ├── activity_main2.xml │ ├── content_main.xml │ ├── content_main2.xml │ └── item_renren_layout.xml │ ├── menu │ └── menu_main.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-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gif └── gif.gif ├── gradle.properties └── 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 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.angcyo.recyclerlayoutmanager" 8 | minSdkVersion 14 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.1.0' 28 | compile 'com.android.support:design:25.1.0' 29 | testCompile 'junit:junit:4.12' 30 | 31 | compile 'com.android.support:cardview-v7:25.1.0' 32 | compile 'com.github.bumptech.glide:glide:3.7.0' 33 | } 34 | -------------------------------------------------------------------------------- /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/angcyo/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/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/angcyo/recyclerlayoutmanager/Main2Activity.java: -------------------------------------------------------------------------------- 1 | package com.angcyo.recyclerlayoutmanager; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.Toolbar; 8 | import android.support.v7.widget.helper.ItemTouchHelper; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | import com.bumptech.glide.Glide; 16 | 17 | import java.util.List; 18 | 19 | public class Main2Activity extends AppCompatActivity { 20 | 21 | private List mDatas; 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_main2); 27 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 28 | setSupportActionBar(toolbar); 29 | 30 | final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 31 | 32 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 33 | fab.setOnClickListener(new View.OnClickListener() { 34 | @Override 35 | public void onClick(View view) { 36 | mDatas = SwipeCardBean.initDatas(); 37 | recyclerView.getAdapter().notifyDataSetChanged(); 38 | 39 | } 40 | }); 41 | 42 | mDatas = SwipeCardBean.initDatas(); 43 | 44 | recyclerView.setLayoutManager(new OverLayCardLayoutManager(this)); 45 | recyclerView.setAdapter(new MyAdapter()); 46 | 47 | final RenRenCallback callback = new RenRenCallback(); 48 | callback.setSwipeListener(new RenRenCallback.OnSwipeListener() { 49 | @Override 50 | public void onSwiped(int adapterPosition, int direction) { 51 | if (direction == ItemTouchHelper.DOWN || direction == ItemTouchHelper.UP) { 52 | mDatas.add(0, mDatas.remove(adapterPosition)); 53 | // Collections.swap(mDatas, 0, adapterPosition); 54 | recyclerView.getAdapter().notifyDataSetChanged(); 55 | } else { 56 | mDatas.remove(adapterPosition); 57 | // recyclerView.getAdapter().notifyItemRemoved(adapterPosition); 58 | } 59 | recyclerView.getAdapter().notifyDataSetChanged(); 60 | } 61 | 62 | @Override 63 | public void onSwipeTo(RecyclerView.ViewHolder viewHolder, float offset) { 64 | if (offset < -50) { 65 | viewHolder.itemView.findViewById(R.id.like).setVisibility(View.VISIBLE); 66 | viewHolder.itemView.findViewById(R.id.not_like).setVisibility(View.INVISIBLE); 67 | } else if (offset > 50) { 68 | viewHolder.itemView.findViewById(R.id.like).setVisibility(View.INVISIBLE); 69 | viewHolder.itemView.findViewById(R.id.not_like).setVisibility(View.VISIBLE); 70 | } else { 71 | viewHolder.itemView.findViewById(R.id.like).setVisibility(View.INVISIBLE); 72 | viewHolder.itemView.findViewById(R.id.not_like).setVisibility(View.INVISIBLE); 73 | } 74 | } 75 | }); 76 | new ItemTouchHelper(callback).attachToRecyclerView(recyclerView); 77 | 78 | findViewById(R.id.to_left).setOnClickListener(new View.OnClickListener() { 79 | @Override 80 | public void onClick(View v) { 81 | callback.toLeft(recyclerView); 82 | } 83 | }); 84 | findViewById(R.id.to_right).setOnClickListener(new View.OnClickListener() { 85 | @Override 86 | public void onClick(View v) { 87 | callback.toRight(recyclerView); 88 | } 89 | }); 90 | } 91 | 92 | public class MyViewHolder extends RecyclerView.ViewHolder { 93 | 94 | TextView mTextView; 95 | ImageView mImageView; 96 | 97 | public MyViewHolder(View itemView) { 98 | super(itemView); 99 | } 100 | } 101 | 102 | public class MyAdapter extends RecyclerView.Adapter { 103 | 104 | public int dp(int dp) { 105 | final float density = getResources().getDisplayMetrics().density; 106 | return (int) (dp * density); 107 | } 108 | 109 | @Override 110 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 111 | 112 | final View view = LayoutInflater.from(Main2Activity.this).inflate(R.layout.item_renren_layout, parent, false); 113 | 114 | // CardView cardView = new CardView(Main2Activity.this); 115 | // cardView.setLayoutParams(new ViewGroup.LayoutParams(dp(270), dp(300))); 116 | // cardView.setCardBackgroundColor(Color.parseColor("#393F4E")); 117 | //// cardView.setBackgroundColor(Color.BLUE); 118 | // TextView textView = new TextView(Main2Activity.this); 119 | //// textView.setBackgroundColor(Color.YELLOW); 120 | // 121 | // ImageView imageView = new ImageView(Main2Activity.this); 122 | // imageView.setScaleType(ImageView.ScaleType.FIT_XY); 123 | // 124 | // textView.setPadding(0, dp(260), 0, 0); 125 | // 126 | // cardView.addView(textView, new ViewGroup.LayoutParams(dp(270), dp(300))); 127 | // cardView.addView(imageView, new ViewGroup.LayoutParams(dp(270), dp(260))); 128 | 129 | final MyViewHolder myViewHolder = new MyViewHolder(view); 130 | // myViewHolder.mTextView = textView; 131 | // myViewHolder.mImageView = imageView; 132 | return myViewHolder; 133 | } 134 | 135 | @Override 136 | public void onBindViewHolder(final MyViewHolder holder, final int position) { 137 | Glide.with(Main2Activity.this).load(mDatas.get(position).getUrl()).fitCenter().into((ImageView) holder.itemView.findViewById(R.id.image_view)); 138 | ((TextView) holder.itemView.findViewById(R.id.text_view)).setText(mDatas.get(position).getName()); 139 | } 140 | 141 | @Override 142 | public int getItemCount() { 143 | return mDatas.size(); 144 | } 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/com/angcyo/recyclerlayoutmanager/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.angcyo.recyclerlayoutmanager; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.support.design.widget.FloatingActionButton; 7 | import android.support.design.widget.Snackbar; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.support.v7.widget.Toolbar; 11 | import android.support.v7.widget.helper.ItemTouchHelper; 12 | import android.util.Log; 13 | import android.view.MotionEvent; 14 | import android.view.View; 15 | import android.view.ViewGroup; 16 | import android.widget.RelativeLayout; 17 | import android.widget.TextView; 18 | 19 | public class MainActivity extends AppCompatActivity { 20 | 21 | private static final String TAG = "layout_manager"; 22 | private ItemTouchHelper mItemTouchHelper; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_main); 28 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 29 | setSupportActionBar(toolbar); 30 | 31 | final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); 32 | 33 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 34 | fab.setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View view) { 37 | Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 38 | .setAction("Action", null).show(); 39 | // mItemTouchHelper.startSwipe(recyclerView.findViewHolderForAdapterPosition(2)); 40 | recyclerView.findViewHolderForAdapterPosition(2).itemView.dispatchTouchEvent(MotionEvent.obtain(System.currentTimeMillis() - 1000, 41 | System.currentTimeMillis(), MotionEvent.ACTION_DOWN, 0, 0, 0)); 42 | recyclerView.findViewHolderForAdapterPosition(2).itemView.dispatchTouchEvent(MotionEvent.obtain(System.currentTimeMillis() - 1000, 43 | System.currentTimeMillis(), MotionEvent.ACTION_DOWN, 0, 0, 0)); 44 | recyclerView.findViewHolderForAdapterPosition(2).itemView.onTouchEvent(MotionEvent.obtain(System.currentTimeMillis() - 1000, 45 | System.currentTimeMillis(), MotionEvent.ACTION_DOWN, 0, 0, 0)); 46 | 47 | // recyclerView.findViewHolderForAdapterPosition(2).itemView.onTouchEvent(MotionEvent.obtain(System.currentTimeMillis() - 1000, 48 | // System.currentTimeMillis(), MotionEvent.ACTION_UP, 0, 0, 0)); 49 | } 50 | }); 51 | 52 | 53 | recyclerView.setAdapter(new MyAdapter()); 54 | recyclerView.setLayoutManager(new MyLayoutManager()); 55 | mItemTouchHelper = new ItemTouchHelper(new MyCallback2(ItemTouchHelper.DOWN | ItemTouchHelper.UP, 56 | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT)); 57 | mItemTouchHelper.attachToRecyclerView(recyclerView); 58 | } 59 | 60 | public class MyCallback2 extends ItemTouchHelper.SimpleCallback { 61 | 62 | public MyCallback2(int dragDirs, int swipeDirs) { 63 | super(dragDirs, swipeDirs); 64 | } 65 | 66 | @Override 67 | public boolean isLongPressDragEnabled() { 68 | return true; 69 | } 70 | 71 | @Override 72 | public boolean onMove(RecyclerView recyclerView, 73 | RecyclerView.ViewHolder viewHolder, 74 | RecyclerView.ViewHolder target) { 75 | Log.e(TAG, "onMove: " + viewHolder.getAdapterPosition() + "->" + target.getAdapterPosition() 76 | + " : " + viewHolder.getLayoutPosition() + "->" + target.getLayoutPosition()); 77 | recyclerView.getAdapter().notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition()); 78 | return false; 79 | } 80 | 81 | @Override 82 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 83 | Log.e(TAG, "onSwiped: " + viewHolder.getAdapterPosition() + " " + viewHolder.getLayoutPosition() + ":" + direction); 84 | } 85 | 86 | @Override 87 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, 88 | float dX, float dY, int actionState, boolean isCurrentlyActive) { 89 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 90 | Log.e(TAG, "onChildDraw: " + dX + " " + dY); 91 | } 92 | 93 | @Override 94 | public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, 95 | float dX, float dY, int actionState, boolean isCurrentlyActive) { 96 | super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 97 | Log.e(TAG, "onChildDrawOver: " + dX + " " + dY); 98 | } 99 | 100 | @Override 101 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { 102 | super.onSelectedChanged(viewHolder, actionState); 103 | Log.e(TAG, "onSelectedChanged: " + actionState); 104 | } 105 | 106 | @Override 107 | public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 108 | super.clearView(recyclerView, viewHolder); 109 | Log.e(TAG, "clearView: " + viewHolder.getAdapterPosition()); 110 | } 111 | } 112 | 113 | 114 | public class MyViewHolder extends RecyclerView.ViewHolder { 115 | 116 | TextView mTextView; 117 | 118 | public MyViewHolder(View itemView) { 119 | super(itemView); 120 | } 121 | } 122 | 123 | public class MyAdapter extends RecyclerView.Adapter { 124 | 125 | @Override 126 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 127 | RelativeLayout relativeLayout = new RelativeLayout(MainActivity.this); 128 | relativeLayout.setBackgroundColor(Color.BLUE); 129 | TextView textView = new TextView(MainActivity.this); 130 | textView.setBackgroundColor(Color.YELLOW); 131 | relativeLayout.addView(textView, new ViewGroup.LayoutParams(-2, 200)); 132 | final MyViewHolder myViewHolder = new MyViewHolder(relativeLayout); 133 | myViewHolder.mTextView = textView; 134 | return myViewHolder; 135 | } 136 | 137 | @Override 138 | public void onBindViewHolder(final MyViewHolder holder, final int position) { 139 | Log.e(TAG, "onBindViewHolder: " + position); 140 | holder.mTextView.setText("................--> " + position); 141 | // holder.mTextView.setOnClickListener(new View.OnClickListener() { 142 | // @Override 143 | // public void onClick(View v) { 144 | // Log.e(TAG, "onClick: " + position + " " + holder.getAdapterPosition() + " " + holder.getLayoutPosition()); 145 | // Toast.makeText(MainActivity.this, "Hello..." + position, Toast.LENGTH_SHORT).show(); 146 | // mItemTouchHelper.startDrag(holder); 147 | // } 148 | // }); 149 | holder.mTextView.setOnTouchListener(new View.OnTouchListener() { 150 | @Override 151 | public boolean onTouch(View v, MotionEvent event) { 152 | // mItemTouchHelper.startSwipe(holder); 153 | // mItemTouchHelper.startDrag(holder); 154 | return false; 155 | } 156 | }); 157 | } 158 | 159 | @Override 160 | public int getItemCount() { 161 | return 100; 162 | } 163 | } 164 | 165 | public class MyLayoutManager extends RecyclerView.LayoutManager { 166 | 167 | @Override 168 | public RecyclerView.LayoutParams generateDefaultLayoutParams() { 169 | Log.e(TAG, "generateDefaultLayoutParams: "); 170 | final RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(-2, -2); 171 | // layoutParams.setMargins(10, 10, 10, 10); 172 | return layoutParams; 173 | } 174 | 175 | @Override 176 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 177 | Log.e(TAG, "onLayoutChildren: " + recycler.toString() + "\n" + state.toString()); 178 | 179 | int top = 0; 180 | for (int i = 0; i < 60; i++) { 181 | final View view = recycler.getViewForPosition(i); 182 | addView(view); 183 | // measureChild(view, 100, 100); 184 | measureChildWithMargins(view, 100, 200); 185 | // view.measure(View.MeasureSpec.makeMeasureSpec(getWidth(), View.MeasureSpec.AT_MOST), 186 | // View.MeasureSpec.makeMeasureSpec(getHeight(), View.MeasureSpec.AT_MOST)); 187 | Log.e(TAG, "onLayoutChildren: view:" + view.getMeasuredWidth() + " " + view.getMeasuredHeight()); 188 | Log.e(TAG, "onLayoutChildren: " + getWidth() + " " + getHeight() + " :: " + getDecoratedMeasuredWidth(view) + " " + getDecoratedMeasuredHeight(view)); 189 | layoutDecoratedWithMargins(view, 0, top, view.getMeasuredWidth(), top + view.getMeasuredHeight()); 190 | top += view.getMeasuredHeight(); 191 | } 192 | 193 | } 194 | 195 | @Override 196 | public boolean canScrollHorizontally() { 197 | return true; 198 | } 199 | 200 | @Override 201 | public boolean canScrollVertically() { 202 | return true; 203 | } 204 | 205 | @Override 206 | public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { 207 | offsetChildrenVertical(-dy); 208 | return dy; 209 | } 210 | 211 | @Override 212 | public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { 213 | offsetChildrenHorizontal(-dx); 214 | return dx; 215 | } 216 | 217 | @Override 218 | public void onAttachedToWindow(RecyclerView view) { 219 | super.onAttachedToWindow(view); 220 | Log.e(TAG, "onAttachedToWindow: " + view.getMeasuredWidth() + " " + view.getMeasuredHeight()); 221 | } 222 | 223 | @Override 224 | public boolean onRequestChildFocus(RecyclerView parent, RecyclerView.State state, View child, View focused) { 225 | Log.e(TAG, "onRequestChildFocus: "); 226 | return super.onRequestChildFocus(parent, state, child, focused); 227 | } 228 | 229 | @Override 230 | public void onAdapterChanged(RecyclerView.Adapter oldAdapter, RecyclerView.Adapter newAdapter) { 231 | super.onAdapterChanged(oldAdapter, newAdapter); 232 | Log.e(TAG, "onAdapterChanged: "); 233 | } 234 | 235 | @Override 236 | public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { 237 | super.onDetachedFromWindow(view, recycler); 238 | Log.e(TAG, "onDetachedFromWindow: "); 239 | } 240 | 241 | @Override 242 | public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { 243 | super.onItemsAdded(recyclerView, positionStart, itemCount); 244 | Log.e(TAG, "onItemsAdded: "); 245 | } 246 | 247 | @Override 248 | public void onItemsChanged(RecyclerView recyclerView) { 249 | super.onItemsChanged(recyclerView); 250 | Log.e(TAG, "onItemsChanged: "); 251 | } 252 | 253 | @Override 254 | public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) { 255 | super.onItemsMoved(recyclerView, from, to, itemCount); 256 | Log.e(TAG, "onItemsMoved: "); 257 | } 258 | 259 | @Override 260 | public void onLayoutCompleted(RecyclerView.State state) { 261 | super.onLayoutCompleted(state); 262 | Log.e(TAG, "onLayoutCompleted: "); 263 | } 264 | 265 | @Override 266 | public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { 267 | super.onMeasure(recycler, state, widthSpec, heightSpec); 268 | Log.e(TAG, "onMeasure: "); 269 | } 270 | 271 | @Override 272 | public void onScrollStateChanged(int state) { 273 | super.onScrollStateChanged(state); 274 | Log.e(TAG, "onScrollStateChanged: " + state + " " + computeHorizontalScrollOffset(null)); 275 | } 276 | } 277 | 278 | } 279 | -------------------------------------------------------------------------------- /app/src/main/java/com/angcyo/recyclerlayoutmanager/OverLayCardLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.angcyo.recyclerlayoutmanager; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | /** 9 | * 介绍:参考人人影视 最多排列四个 10 | * 重叠卡片布局 11 | * 作者:zhangxutong 12 | * 邮箱:mcxtzhang@163.com 13 | * 主页:http://blog.csdn.net/zxt0601 14 | * 时间: 16/12/15. 15 | */ 16 | 17 | public class OverLayCardLayoutManager extends RecyclerView.LayoutManager { 18 | private static final String TAG = "swipecard"; 19 | public static int MAX_SHOW_COUNT = 4; 20 | public static float SCALE_GAP = 0.05f; 21 | public static int TRANS_Y_GAP; 22 | public int mTopOffset = 0; 23 | 24 | public OverLayCardLayoutManager(Context context) { 25 | TRANS_Y_GAP = (int) (20 * context.getResources().getDisplayMetrics().density); 26 | } 27 | 28 | @Override 29 | public RecyclerView.LayoutParams generateDefaultLayoutParams() { 30 | return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 31 | } 32 | 33 | public OverLayCardLayoutManager setTopOffset(int topOffset) { 34 | mTopOffset = topOffset; 35 | return this; 36 | } 37 | 38 | @Override 39 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 40 | // Log.e(TAG, "onLayoutChildren() called with: recycler = [" + recycler + "], state = [" + state + "]"); 41 | detachAndScrapAttachedViews(recycler); 42 | int itemCount = getItemCount(); 43 | if (itemCount < 1) { 44 | return; 45 | } 46 | //top-3View的position 47 | int bottomPosition; 48 | //边界处理 49 | if (itemCount < MAX_SHOW_COUNT) { 50 | bottomPosition = 0; 51 | } else { 52 | bottomPosition = itemCount - MAX_SHOW_COUNT; 53 | } 54 | 55 | //从可见的最底层View开始layout,依次层叠上去 56 | for (int position = bottomPosition; position < itemCount; position++) { 57 | View view = recycler.getViewForPosition(position); 58 | addView(view); 59 | measureChildWithMargins(view, 0, 0); 60 | int widthSpace = getWidth() - getDecoratedMeasuredWidth(view); 61 | int heightSpace = getHeight() - getDecoratedMeasuredHeight(view); 62 | //我们在布局时,将childView居中处理,这里也可以改为只水平居中 63 | layoutDecoratedWithMargins(view, widthSpace / 2, mTopOffset == 0 ? (heightSpace / 2) : mTopOffset, 64 | widthSpace / 2 + getDecoratedMeasuredWidth(view), 65 | mTopOffset == 0 ? (heightSpace / 2 + getDecoratedMeasuredHeight(view)) : (mTopOffset + getDecoratedMeasuredHeight(view))); 66 | 67 | /** 68 | * TopView的Scale 为1,translationY 0 69 | * 每一级Scale相差0.05f,translationY相差7dp左右 70 | * 71 | * 观察人人影视的UI,拖动时,topView被拖动,Scale不变,一直为1. 72 | * top-1View 的Scale慢慢变化至1,translation也慢慢恢复0 73 | * top-2View的Scale慢慢变化至 top-1View的Scale,translation 也慢慢变化只top-1View的translation 74 | * top-3View的Scale要变化,translation岿然不动 75 | */ 76 | 77 | //第几层,举例子,count =7, 最后一个TopView(6)是第0层, 78 | int level = itemCount - position - 1; 79 | 80 | //除了顶层不需要缩小和位移 81 | if (level > 0 /*&& level < mShowCount - 1*/) { 82 | //每一层都需要X方向的缩小 83 | view.setScaleX(1 - SCALE_GAP * level); 84 | //前N层,依次向下位移和Y方向的缩小 85 | if (level < MAX_SHOW_COUNT - 1) { 86 | view.setTranslationY(TRANS_Y_GAP * level); 87 | view.setScaleY(1 - SCALE_GAP * level); 88 | } else {//第N层在 向下位移和Y方向的缩小的成都与 N-1层保持一致 89 | view.setTranslationY(TRANS_Y_GAP * (level - 1)); 90 | view.setScaleY(1 - SCALE_GAP * (level - 1)); 91 | } 92 | } 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/angcyo/recyclerlayoutmanager/RenRenCallback.java: -------------------------------------------------------------------------------- 1 | package com.angcyo.recyclerlayoutmanager; 2 | 3 | import android.graphics.Canvas; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.support.v7.widget.helper.ItemTouchHelper; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.view.animation.Animation; 9 | import android.view.animation.DecelerateInterpolator; 10 | import android.view.animation.TranslateAnimation; 11 | 12 | import static android.R.attr.x; 13 | import static com.angcyo.recyclerlayoutmanager.OverLayCardLayoutManager.MAX_SHOW_COUNT; 14 | import static com.angcyo.recyclerlayoutmanager.OverLayCardLayoutManager.SCALE_GAP; 15 | import static com.angcyo.recyclerlayoutmanager.OverLayCardLayoutManager.TRANS_Y_GAP; 16 | 17 | /** 18 | * 介绍:人人影视效果的Callback 19 | * 作者:zhangxutong 20 | * 邮箱:mcxtzhang@163.com 21 | * 主页:http://blog.csdn.net/zxt0601 22 | * 时间: 16/12/18. 23 | */ 24 | 25 | public class RenRenCallback extends ItemTouchHelper.SimpleCallback { 26 | 27 | private static final String TAG = "RenRen"; 28 | private static final int MAX_ROTATION = 15; 29 | OnSwipeListener mSwipeListener; 30 | boolean isSwipeAnim = false; 31 | 32 | public RenRenCallback() { 33 | super(0, ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT); 34 | } 35 | 36 | public void setSwipeListener(OnSwipeListener swipeListener) { 37 | mSwipeListener = swipeListener; 38 | } 39 | 40 | //水平方向是否可以被回收掉的阈值 41 | public float getThreshold(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 42 | //2016 12 26 考虑 探探垂直上下方向滑动,不删除卡片,这里参照源码写死0.5f 43 | return recyclerView.getWidth() * /*getSwipeThreshold(viewHolder)*/ 0.5f; 44 | } 45 | 46 | @Override 47 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 48 | return false; 49 | } 50 | 51 | @Override 52 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 53 | viewHolder.itemView.setRotation(0);//恢复最后一次的旋转状态 54 | if (mSwipeListener != null) { 55 | mSwipeListener.onSwipeTo(viewHolder, 0); 56 | } 57 | notifyListener(viewHolder.getAdapterPosition(), direction); 58 | } 59 | 60 | private void notifyListener(int position, int direction) { 61 | Log.w(TAG, "onSwiped: " + position + " " + direction); 62 | if (mSwipeListener != null) { 63 | mSwipeListener.onSwiped(position, direction); 64 | } 65 | } 66 | 67 | @Override 68 | public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) { 69 | //滑动的比例达到多少之后, 视为滑动 70 | return 0.3f; 71 | } 72 | 73 | 74 | @Override 75 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { 76 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 77 | Log.i(TAG, "onChildDraw: dx:" + dX + " dy:" + dY); 78 | //人人影视的效果 79 | //if (isCurrentlyActive) { 80 | //先根据滑动的dxdy 算出现在动画的比例系数fraction 81 | float swipeValue = (float) Math.sqrt(dX * dX + dY * dY); 82 | final float threshold = getThreshold(recyclerView, viewHolder); 83 | float fraction = swipeValue / threshold; 84 | //边界修正 最大为1 85 | if (fraction > 1) { 86 | fraction = 1; 87 | } else if (fraction < -1) { 88 | fraction = -1; 89 | } 90 | //对每个ChildView进行缩放 位移 91 | int childCount = recyclerView.getChildCount(); 92 | for (int i = 0; i < childCount; i++) { 93 | View child = recyclerView.getChildAt(i); 94 | //第几层,举例子,count =7, 最后一个TopView(6)是第0层, 95 | int level = childCount - i - 1; 96 | if (level > 0) { 97 | child.setScaleX(1 - SCALE_GAP * level + fraction * SCALE_GAP); 98 | 99 | if (level < MAX_SHOW_COUNT - 1) { 100 | child.setScaleY(1 - SCALE_GAP * level + fraction * SCALE_GAP); 101 | child.setTranslationY(TRANS_Y_GAP * level - fraction * TRANS_Y_GAP); 102 | } else { 103 | //child.setTranslationY((float) (mTranslationYGap * (level - 1) - fraction * mTranslationYGap)); 104 | } 105 | } else { 106 | //最上层 107 | //rotate 108 | if (dX < -50) { 109 | child.setRotation(-fraction * MAX_ROTATION); 110 | } else if (dX > 50) { 111 | child.setRotation(fraction * MAX_ROTATION); 112 | } else { 113 | child.setRotation(0); 114 | } 115 | 116 | if (mSwipeListener != null) { 117 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); 118 | final int adapterPosition = params.getViewAdapterPosition(); 119 | mSwipeListener.onSwipeTo(recyclerView.findViewHolderForAdapterPosition(adapterPosition), dX); 120 | } 121 | } 122 | } 123 | } 124 | 125 | public void toLeft(RecyclerView recyclerView) { 126 | if (check(recyclerView)) { 127 | animTo(recyclerView, false); 128 | } 129 | } 130 | 131 | public void toRight(RecyclerView recyclerView) { 132 | if (check(recyclerView)) { 133 | animTo(recyclerView, true); 134 | } 135 | } 136 | 137 | private void animTo(final RecyclerView recyclerView, boolean right) { 138 | if (recyclerView == null) { 139 | return; 140 | } 141 | 142 | final int position = recyclerView.getAdapter().getItemCount() - 1; 143 | final RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(position); 144 | if (viewHolder == null) { 145 | return; 146 | } 147 | 148 | final View view = viewHolder.itemView; 149 | 150 | TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, 151 | Animation.RELATIVE_TO_SELF, right ? 1f : -1f, 152 | Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 1.3f); 153 | translateAnimation.setFillAfter(true); 154 | translateAnimation.setDuration(300); 155 | translateAnimation.setInterpolator(new DecelerateInterpolator()); 156 | translateAnimation.setAnimationListener(new Animation.AnimationListener() { 157 | @Override 158 | public void onAnimationStart(Animation animation) { 159 | 160 | } 161 | 162 | @Override 163 | public void onAnimationEnd(Animation animation) { 164 | isSwipeAnim = false; 165 | recyclerView.removeView(view); 166 | notifyListener(position, 167 | x > view.getMeasuredWidth() / 2 168 | ? 169 | ItemTouchHelper.RIGHT : ItemTouchHelper.LEFT); 170 | } 171 | 172 | @Override 173 | public void onAnimationRepeat(Animation animation) { 174 | 175 | } 176 | }); 177 | view.startAnimation(translateAnimation); 178 | } 179 | 180 | private boolean check(RecyclerView recyclerView) { 181 | if (isSwipeAnim) { 182 | return false; 183 | } 184 | if (recyclerView == null || recyclerView.getAdapter() == null) { 185 | return false; 186 | } 187 | if (recyclerView.getAdapter().getItemCount() == 0) { 188 | return false; 189 | } 190 | isSwipeAnim = true; 191 | return true; 192 | } 193 | 194 | public interface OnSwipeListener { 195 | 196 | /** 197 | * @param direction {@link ItemTouchHelper#LEFT} / {@link ItemTouchHelper#RIGHT} 198 | * {@link ItemTouchHelper#UP} or {@link ItemTouchHelper#DOWN}). 199 | */ 200 | void onSwiped(int adapterPosition, int direction); 201 | 202 | /** 203 | * 最上层View滑动时回调. 204 | * 205 | * @param viewHolder 最上层的ViewHolder 206 | * @param offset 距离原始位置的偏移量 207 | */ 208 | void onSwipeTo(RecyclerView.ViewHolder viewHolder, float offset); 209 | } 210 | 211 | public static class SimpleSwipeCallback implements OnSwipeListener { 212 | 213 | /** 214 | * {@inheritDoc} 215 | */ 216 | @Override 217 | public void onSwiped(int adapterPosition, int direction) { 218 | 219 | } 220 | 221 | /** 222 | * {@inheritDoc} 223 | */ 224 | @Override 225 | public void onSwipeTo(RecyclerView.ViewHolder viewHolder, float offset) { 226 | 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /app/src/main/java/com/angcyo/recyclerlayoutmanager/SwipeCardBean.java: -------------------------------------------------------------------------------- 1 | package com.angcyo.recyclerlayoutmanager; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class SwipeCardBean { 7 | private int postition; 8 | private String url; 9 | private String name; 10 | 11 | public SwipeCardBean(int postition, String url, String name) { 12 | this.postition = postition; 13 | this.url = url; 14 | this.name = name; 15 | } 16 | 17 | public static List initDatas() { 18 | List datas = new ArrayList<>(); 19 | int i = 1; 20 | datas.add(new SwipeCardBean(i++, "http://imgs.ebrun.com/resources/2016_03/2016_03_25/201603259771458878793312_origin.jpg", "张")); 21 | datas.add(new SwipeCardBean(i++, "http://p14.go007.com/2014_11_02_05/a03541088cce31b8_1.jpg", "旭童")); 22 | datas.add(new SwipeCardBean(i++, "http://news.k618.cn/tech/201604/W020160407281077548026.jpg", "多种type")); 23 | datas.add(new SwipeCardBean(i++, "http://www.kejik.com/image/1460343965520.jpg", "很多美女")); 24 | datas.add(new SwipeCardBean(i++, "http://cn.chinadaily.com.cn/img/attachement/jpg/site1/20160318/eca86bd77be61855f1b81c.jpg", "美女的很")); 25 | datas.add(new SwipeCardBean(i++, "http://imgs.ebrun.com/resources/2016_04/2016_04_12/201604124411460430531500.jpg", "我的女孩")); 26 | datas.add(new SwipeCardBean(i++, "http://imgs.ebrun.com/resources/2016_04/2016_04_24/201604244971461460826484_origin.jpeg", "我曹汉子")); 27 | datas.add(new SwipeCardBean(i++, "http://www.lnmoto.cn/bbs/data/attachment/forum/201408/12/074018gshshia3is1cw3sg.jpg", "摩托车.🏍")); 28 | return datas; 29 | } 30 | 31 | public int getPostition() { 32 | return postition; 33 | } 34 | 35 | public SwipeCardBean setPostition(int postition) { 36 | this.postition = postition; 37 | return this; 38 | } 39 | 40 | public String getUrl() { 41 | return url; 42 | } 43 | 44 | public SwipeCardBean setUrl(String url) { 45 | this.url = url; 46 | return this; 47 | } 48 | 49 | public String getName() { 50 | return name; 51 | } 52 | 53 | public SwipeCardBean setName(String name) { 54 | this.name = name; 55 | return this; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/angcyo/recyclerlayoutmanager/TanTanCallback.java: -------------------------------------------------------------------------------- 1 | package com.angcyo.recyclerlayoutmanager; 2 | 3 | import android.graphics.Canvas; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.Toast; 8 | 9 | import static com.angcyo.recyclerlayoutmanager.OverLayCardLayoutManager.MAX_SHOW_COUNT; 10 | import static com.angcyo.recyclerlayoutmanager.OverLayCardLayoutManager.SCALE_GAP; 11 | import static com.angcyo.recyclerlayoutmanager.OverLayCardLayoutManager.TRANS_Y_GAP; 12 | 13 | /** 14 | * 介绍:探探效果定制的Callback 15 | * 作者:zhangxutong 16 | * 邮箱:mcxtzhang@163.com 17 | * 主页:http://blog.csdn.net/zxt0601 18 | * 时间: 16/12/18. 19 | */ 20 | 21 | public class TanTanCallback extends RenRenCallback { 22 | private static final int MAX_ROTATION = 15; 23 | 24 | //2016 12 26 考虑 探探垂直上下方向滑动,不删除卡片, 25 | //判断 此次滑动方向是否是竖直的 ,水平方向上的误差(阈值,默认我给了50dp) 26 | int mHorizontalDeviation; 27 | //一个flag 判断左右滑 28 | private boolean isLeftSwipe; 29 | 30 | @Override 31 | public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) { 32 | /* Log.d("TAG", "getSwipeThreshold() called with: viewHolder.itemView.getX() = [" + viewHolder.itemView.getX() + "]"); 33 | Log.d("TAG", "getSwipeThreshold() called with: viewHolder.itemView.getWidth() / 2 = [" + viewHolder.itemView.getWidth() / 2 + "]"); 34 | Log.d("TAG", "getSwipeThreshold() called with: getRV().getX() = [" + getRV().getX() + "]"); 35 | Log.d("TAG", "getSwipeThreshold() called with: getRV().getWidth() / 2 = [" + getRV().getWidth() / 2 + "]");*/ 36 | 37 | if (isTopViewCenterInHorizontal(viewHolder.itemView)) { 38 | return Float.MAX_VALUE; 39 | } 40 | return super.getSwipeThreshold(viewHolder); 41 | } 42 | 43 | @Override 44 | public float getSwipeEscapeVelocity(float defaultValue) { 45 | // View topView = getRV().getChildAt(getRV().getChildCount() - 1); 46 | // if (isTopViewCenterInHorizontal(topView)) { 47 | // return Float.MAX_VALUE; 48 | // } 49 | return super.getSwipeEscapeVelocity(defaultValue); 50 | } 51 | 52 | @Override 53 | public float getSwipeVelocityThreshold(float defaultValue) { 54 | 55 | // View topView = getRV().getChildAt(getRV().getChildCount() - 1); 56 | // if (isTopViewCenterInHorizontal(topView)) { 57 | // return Float.MAX_VALUE; 58 | // } 59 | return super.getSwipeVelocityThreshold(defaultValue); 60 | } 61 | 62 | private RecyclerView getRV() { 63 | return null; 64 | } 65 | 66 | /** 67 | * 返回TopView此时在水平方向上是否是居中的 68 | * 69 | * @return 70 | */ 71 | public boolean isTopViewCenterInHorizontal(View topView) { 72 | Log.d("TAG", "getSwipeThreshold() called with: viewHolder.itemView.getX() = [" + topView.getX() + "]"); 73 | Log.d("TAG", "getSwipeThreshold() called with: viewHolder.itemView.getWidth() / 2 = [" + topView.getWidth() / 2 + "]"); 74 | Log.d("TAG", "getSwipeThreshold() called with: getRV().getX() = [" + getRV().getX() + "]"); 75 | Log.d("TAG", "getSwipeThreshold() called with: getRV().getWidth() / 2 = [" + getRV().getWidth() / 2 + "]"); 76 | return Math.abs(getRV().getWidth() / 2 - topView.getX() - (topView.getWidth() / 2)) < mHorizontalDeviation; 77 | } 78 | 79 | @Override 80 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 81 | super.onSwiped(viewHolder, direction); 82 | //如果不需要循环删除 83 | /* Object remove = mDatas.remove(viewHolder.getLayoutPosition()); 84 | mAdapter.notifyDataSetChanged();*/ 85 | Log.e("swipecard", "厉害了"); 86 | 87 | if (isLeftSwipe) { 88 | Toast.makeText(getRV().getContext(), "左滑删除", Toast.LENGTH_SHORT).show(); 89 | } else { 90 | Toast.makeText(getRV().getContext(), "右滑删除", Toast.LENGTH_SHORT).show(); 91 | } 92 | 93 | //探探只是第一层加了rotate & alpha的操作 94 | //对rotate进行复位 95 | viewHolder.itemView.setRotation(0); 96 | 97 | //自己感受一下吧 Alpha 98 | // if (viewHolder instanceof ViewHolder) { 99 | // ViewHolder holder = (ViewHolder) viewHolder; 100 | // holder.setAlpha(R.id.iv_love, 0); 101 | // holder.setAlpha(R.id.iv_del, 0); 102 | // } 103 | 104 | } 105 | 106 | @Override 107 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { 108 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 109 | Log.e("swipecard", "onChildDraw() viewHolder = [" + viewHolder + "], dX = [" + dX + "], dY = [" + dY + "], actionState = [" + actionState + "], isCurrentlyActive = [" + isCurrentlyActive + "]"); 110 | //探探的效果 111 | double swipeValue = Math.sqrt(dX * dX + dY * dY); 112 | final float threshold = getThreshold(recyclerView, viewHolder); 113 | double fraction = swipeValue / threshold; 114 | //边界修正 最大为1 115 | if (fraction > 1) { 116 | fraction = 1; 117 | } 118 | int childCount = recyclerView.getChildCount(); 119 | for (int i = 0; i < childCount; i++) { 120 | View child = recyclerView.getChildAt(i); 121 | //第几层,举例子,count =7, 最后一个TopView(6)是第0层, 122 | int level = childCount - i - 1; 123 | if (level > 0) { 124 | child.setScaleX((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP)); 125 | 126 | if (level < MAX_SHOW_COUNT - 1) { 127 | child.setScaleY((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP)); 128 | child.setTranslationY((float) (TRANS_Y_GAP * level - fraction * TRANS_Y_GAP)); 129 | } else { 130 | //child.setTranslationY((float) (mTranslationYGap * (level - 1) - fraction * mTranslationYGap)); 131 | } 132 | } else { 133 | //探探只是第一层加了rotate & alpha的操作 134 | //不过他区分左右 135 | float xFraction = dX / threshold; 136 | //边界修正 最大为1 137 | if (xFraction > 1) { 138 | xFraction = 1; 139 | } else if (xFraction < -1) { 140 | xFraction = -1; 141 | } 142 | //rotate 143 | child.setRotation(xFraction * MAX_ROTATION); 144 | 145 | //自己感受一下吧 Alpha 146 | // if (viewHolder instanceof ViewHolder) { 147 | // ViewHolder holder = (ViewHolder) viewHolder; 148 | // if (dX > 0) { 149 | // //露出左边,比心 150 | // holder.setAlpha(R.id.iv_love, xFraction); 151 | // } else { 152 | // //露出右边,滚犊子 153 | // holder.setAlpha(R.id.iv_del, -xFraction); 154 | // } 155 | // } 156 | } 157 | } 158 | 159 | 160 | //可以在此判断左右滑: 161 | float v = getRV().getWidth() / 2 - viewHolder.itemView.getX() - (viewHolder.itemView.getWidth() / 2); 162 | if (v > 0) { 163 | isLeftSwipe = true; 164 | } else if (v < 0) { 165 | isLeftSwipe = false; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main2.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main2.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 17 | 18 |