├── .gitignore ├── .idea ├── caches │ └── build_file_checksums.ser ├── codeStyles │ └── Project.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── gwb │ │ └── superrecycleview │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── gwb │ │ │ └── superrecycleview │ │ │ ├── App.java │ │ │ ├── adapter │ │ │ ├── BaseAdapter.java │ │ │ ├── BaseViewHolder.java │ │ │ ├── GoodsPropertyAdapter.java │ │ │ ├── HeaderAndFooterWrapper.java │ │ │ └── OnItemClickListener.java │ │ │ ├── entity │ │ │ ├── GoodsPropertyBean.java │ │ │ ├── ShopGoods.java │ │ │ ├── ShopGoodsBean.java │ │ │ └── StoreGoodsBean.java │ │ │ ├── imp │ │ │ └── AppBarStateChangeListener.java │ │ │ ├── ui │ │ │ ├── BaseActivity.java │ │ │ ├── BaseFitsSystemWindowsActivity.java │ │ │ ├── activity │ │ │ │ ├── HeaderAndFooterActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── ShoppingGoodsActivity.java │ │ │ │ ├── SkuActivity.java │ │ │ │ └── SteamActivity.java │ │ │ ├── dialog │ │ │ │ ├── BaseDialog.java │ │ │ │ ├── ClearShoppingCartDialog.java │ │ │ │ ├── DiscountCouponDialog.java │ │ │ │ └── ShoppingCartDialog.java │ │ │ └── wedgit │ │ │ │ ├── ArrowDrawable.java │ │ │ │ └── FlowLayout.java │ │ │ └── utils │ │ │ ├── ActivityManager.java │ │ │ ├── ShoppingCartHistoryManager.java │ │ │ ├── ToastUtil.java │ │ │ └── Util.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── empty.xml │ │ ├── ic_launcher_background.xml │ │ ├── light_gray_rectangle_7.xml │ │ ├── lucency_black_rectangle_10.xml │ │ ├── normal.xml │ │ ├── pink_rectangle_right_8.xml │ │ ├── red_circle.xml │ │ ├── red_gradient_rectangle.xml │ │ ├── red_rectangle_left_8.xml │ │ └── select.xml │ │ ├── layout │ │ ├── activity_header_and_footer.xml │ │ ├── activity_main.xml │ │ ├── activity_shopping_goods.xml │ │ ├── activity_sku.xml │ │ ├── activity_steam.xml │ │ ├── dialog_clear_shopping_cart.xml │ │ ├── dialog_discount_coupon.xml │ │ ├── dialog_shopping_cart.xml │ │ ├── item.xml │ │ ├── item_cart_goods.xml │ │ ├── item_goods.xml │ │ ├── item_shop_goods.xml │ │ ├── item_text.xml │ │ ├── layout_shopping_cart.xml │ │ ├── layout_toolbar.xml │ │ ├── refresh_footer.xml │ │ └── refresh_header.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── icon_back.png │ │ ├── icon_blue_point.png │ │ ├── icon_delete.png │ │ ├── icon_discount_coupon.png │ │ ├── icon_discount_coupon_succeed.png │ │ ├── icon_goods_add.png │ │ ├── icon_goods_reduce.png │ │ ├── icon_shopping_cart.png │ │ └── icon_shopping_goods_bg.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── icon_back.png │ │ ├── icon_blue_point.png │ │ ├── icon_delete.png │ │ ├── icon_discount_coupon.png │ │ ├── icon_discount_coupon_succeed.png │ │ ├── icon_goods_add.png │ │ ├── icon_goods_reduce.png │ │ ├── icon_shopping_cart.png │ │ └── icon_shopping_goods_bg.png │ │ ├── mipmap-xhdpi │ │ ├── arrow.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── icon_back.png │ │ ├── icon_blue_point.png │ │ ├── icon_delete.png │ │ ├── icon_discount_coupon.png │ │ ├── icon_discount_coupon_succeed.png │ │ ├── icon_goods_add.png │ │ ├── icon_goods_reduce.png │ │ ├── icon_shopping_cart.png │ │ └── icon_shopping_goods_bg.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── icon_back.png │ │ ├── icon_blue_point.png │ │ ├── icon_delete.png │ │ ├── icon_discount_coupon.png │ │ ├── icon_discount_coupon_succeed.png │ │ ├── icon_goods_add.png │ │ ├── icon_goods_reduce.png │ │ ├── icon_shopping_cart.png │ │ └── icon_shopping_goods_bg.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── icon_back.png │ │ ├── icon_blue_point.png │ │ ├── icon_delete.png │ │ ├── icon_discount_coupon.png │ │ ├── icon_discount_coupon_succeed.png │ │ ├── icon_goods_add.png │ │ ├── icon_goods_reduce.png │ │ ├── icon_shopping_cart.png │ │ └── icon_shopping_goods_bg.png │ │ ├── values-v19 │ │ └── styles.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── raw │ └── master │ │ └── images-folder │ │ ├── headerandfooter.gif │ │ ├── shoppingcart.gif │ │ └── sku.gif │ └── test │ └── java │ └── com │ └── gwb │ └── superrecycleview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GongWnbo/SuperRecycleView/32c92b905a643a07f065da046156771d58661fcd/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SuperRecycleView 2 | 3 | 仿饿了么购物车效果
4 | ![image](https://github.com/GongWnbo/SuperRecycleView/blob/master/app/src/raw/master/images-folder/shoppingcart.gif) 5 | --- 6 | 商城shu算法
7 | ![image](https://github.com/GongWnbo/SuperRecycleView/blob/master/app/src/raw/master/images-folder/sku.gif) 8 | --- 9 | 多条目的头部和尾部
10 | ![image](https://github.com/GongWnbo/SuperRecycleView/blob/master/app/src/raw/master/images-folder/headerandfooter.gif) 11 | --- 12 | 13 | 14 | 15 | >[我的博客](https://www.jianshu.com/u/0b51eed8edba "悬停显示") -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "com.gwb.superrecycleview" 7 | minSdkVersion 19 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(include: ['*.jar'], dir: 'libs') 23 | implementation 'com.android.support:appcompat-v7:27.1.1' 24 | implementation 'com.android.support.constraint:constraint-layout:1.1.0' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 28 | implementation 'com.android.support:recyclerview-v7:27.1.1' 29 | // butterknife 30 | api 'com.jakewharton:butterknife:8.8.1' 31 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' 32 | // gson 33 | compile 'com.google.code.gson:gson:2.8.4' 34 | // glide 35 | implementation 'com.github.bumptech.glide:glide:4.7.1' 36 | annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1' 37 | // SmartRefreshLayout 38 | compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-5' 39 | implementation 'com.android.support:design:27.1.1' 40 | // logger 41 | implementation 'com.orhanobut:logger:2.1.1' 42 | // easypermissions 43 | implementation 'pub.devrel:easypermissions:1.2.0' 44 | //leakca 45 | implementation 'com.squareup.leakcanary:leakcanary-android:1.6.1' 46 | } 47 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/gwb/superrecycleview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.gwb.superrecycleview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 17 | 20 | 23 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/App.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview; 2 | 3 | import android.app.Application; 4 | 5 | import com.orhanobut.logger.AndroidLogAdapter; 6 | import com.orhanobut.logger.Logger; 7 | import com.squareup.leakcanary.LeakCanary; 8 | 9 | /** 10 | * Created by ${GongWenbo} on 2018/5/22 0022. 11 | */ 12 | public class App extends Application { 13 | 14 | private static App sApp; 15 | 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | // Logger日志 20 | Logger.addLogAdapter(new AndroidLogAdapter()); 21 | LeakCanary.install(this); 22 | sApp = this; 23 | } 24 | 25 | public static App getApp() { 26 | return sApp; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/adapter/BaseAdapter.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.adapter; 2 | 3 | import android.support.annotation.LayoutRes; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Created by ${GongWenbo} on 2018/3/30 0030. 13 | */ 14 | 15 | public class BaseAdapter extends RecyclerView.Adapter implements View.OnClickListener { 16 | 17 | private List mDatas; 18 | private int layoutId; 19 | private BaseAdapterListener mBaseAdapterListener; 20 | private OnItemClickListener mOnItemClickListener; 21 | 22 | public BaseAdapter(List datas, @LayoutRes int layoutId, BaseAdapterListener baseAdapterListener) { 23 | this.mDatas = datas; 24 | this.layoutId = layoutId; 25 | this.mBaseAdapterListener = baseAdapterListener; 26 | } 27 | 28 | @Override 29 | public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 30 | View view = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); 31 | view.setOnClickListener(this); 32 | return new BaseViewHolder(parent.getContext(), view); 33 | } 34 | 35 | @Override 36 | public void onBindViewHolder(BaseViewHolder holder, int position) { 37 | if (mBaseAdapterListener != null) { 38 | mBaseAdapterListener.convert(holder, mDatas.get(position)); 39 | holder.itemView.setTag(position); 40 | } 41 | } 42 | 43 | @Override 44 | public int getItemCount() { 45 | return mDatas == null ? 0 : mDatas.size(); 46 | } 47 | 48 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 49 | mOnItemClickListener = onItemClickListener; 50 | } 51 | 52 | @Override 53 | public void onClick(View v) { 54 | if (mOnItemClickListener != null) { 55 | Integer tag = (Integer) v.getTag(); 56 | mOnItemClickListener.onItemClick(tag,mDatas.get(tag)); 57 | } 58 | } 59 | 60 | public interface BaseAdapterListener { 61 | 62 | void convert(BaseViewHolder holder, T t); 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/adapter/BaseViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.support.annotation.IdRes; 6 | import android.support.annotation.LayoutRes; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.util.SparseArray; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.TextView; 13 | 14 | /** 15 | * Created by ${GongWenbo} on 2018/3/30 0030. 16 | */ 17 | 18 | public class BaseViewHolder extends RecyclerView.ViewHolder { 19 | public View itemView; 20 | private SparseArray views; 21 | private Context mContext; 22 | 23 | public BaseViewHolder(Context context, View itemView) { 24 | super(itemView); 25 | mContext = context; 26 | this.views = new SparseArray<>(); 27 | this.itemView = itemView; 28 | } 29 | 30 | public static BaseViewHolder createViewHolder(Context context, View itemView) { 31 | return new BaseViewHolder(context, itemView); 32 | } 33 | 34 | public static BaseViewHolder createViewHolder(Context context, ViewGroup parent, @LayoutRes int layoutId) { 35 | View view = LayoutInflater.from(context).inflate(layoutId, parent, false); 36 | return new BaseViewHolder(context, view); 37 | } 38 | 39 | public View getConvertView() { 40 | return itemView; 41 | } 42 | 43 | public T getView(@IdRes int viewId) { 44 | View view = views.get(viewId); 45 | if (view == null) { 46 | view = itemView.findViewById(viewId); 47 | views.put(viewId, view); 48 | } 49 | return (T) view; 50 | } 51 | 52 | public View setTitle(@IdRes int viewId, String title) { 53 | View view = getView(viewId); 54 | if (view instanceof TextView) { 55 | ((TextView) view).setText(title); 56 | } else { 57 | throw new ClassCastException("you need give me TextView!"); 58 | } 59 | return view; 60 | } 61 | 62 | public View setVisible(@IdRes int viewId) { 63 | return setVisible(viewId, true); 64 | } 65 | 66 | public View setVisible(@IdRes int viewId, boolean visible) { 67 | View view = getView(viewId); 68 | view.setVisibility(visible ? View.VISIBLE : View.GONE); 69 | return view; 70 | } 71 | 72 | public void setBackgroundColor(@IdRes int viewId, String color) { 73 | View view = getView(viewId); 74 | view.setBackgroundColor(Color.parseColor(color)); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/adapter/GoodsPropertyAdapter.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.support.annotation.LayoutRes; 6 | import android.support.v4.util.SimpleArrayMap; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.text.TextUtils; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.LinearLayout; 13 | import android.widget.TextView; 14 | 15 | import com.gwb.superrecycleview.R; 16 | import com.gwb.superrecycleview.entity.GoodsPropertyBean; 17 | import com.gwb.superrecycleview.ui.wedgit.FlowLayout; 18 | 19 | import java.util.ArrayList; 20 | import java.util.HashMap; 21 | import java.util.Iterator; 22 | import java.util.List; 23 | import java.util.Set; 24 | 25 | /** 26 | * Created by ${GongWenbo} on 2018/3/30 0030. 27 | */ 28 | 29 | public class GoodsPropertyAdapter extends RecyclerView.Adapter { 30 | private static final String TAG = "GoodsPropertyAdapter"; 31 | private final String COLOR_SELECT = "#ffffff"; 32 | private final String COLOR_EMPTY = "#BBBBBB"; 33 | private final String COLOR_NORMAL = "#6D6D6D"; 34 | private List mAttributes; 35 | private List mStockGoods; 36 | private Context mContext; 37 | private int layoutId; 38 | private TextView[][] mTextViews; 39 | // 每一行选中的属性 40 | private HashMap sam = new HashMap<>(); 41 | // 每一行可选的属性 42 | private SimpleArrayMap> sams = new SimpleArrayMap<>(); 43 | private int index = 0; 44 | private GoodsSelectListener mGoodsSelectListener; 45 | 46 | public GoodsPropertyAdapter(List attributes, List stockGoods, Context context, @LayoutRes int layoutId) { 47 | this.mAttributes = attributes; 48 | this.mStockGoods = stockGoods; 49 | this.mContext = context; 50 | this.layoutId = layoutId; 51 | int size = attributes.size(); 52 | mTextViews = new TextView[size][0]; 53 | } 54 | 55 | public void setGoodsSelectListener(GoodsSelectListener goodsSelectListener) { 56 | mGoodsSelectListener = goodsSelectListener; 57 | } 58 | 59 | @Override 60 | public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 61 | return BaseViewHolder.createViewHolder(mContext, parent, layoutId); 62 | } 63 | 64 | @Override 65 | public void onBindViewHolder(BaseViewHolder holder, final int position) { 66 | GoodsPropertyBean.AttributesBean attributesBean = mAttributes.get(position); 67 | // 标题 68 | holder.setTitle(R.id.tv_title, attributesBean.getTabName()); 69 | // 一行具体的view 70 | FlowLayout flowLayout = holder.getView(R.id.flowLayout); 71 | List attributesItem = attributesBean.getAttributesItem(); 72 | int size = attributesItem.size(); 73 | TextView[] textViews = new TextView[size]; 74 | for (int i = 0; i < attributesItem.size(); i++) { 75 | final String property = attributesItem.get(i); 76 | TextView textView = getTextView(property, holder); 77 | flowLayout.addView(textView); 78 | textViews[i] = textView; 79 | } 80 | mTextViews[position] = textViews; 81 | 82 | } 83 | 84 | public TextView getTextView(final String title, final BaseViewHolder holder) { 85 | LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 86 | final TextView tv = new TextView(mContext); 87 | lp.setMargins(10, 10, 10, 10); 88 | tv.setPadding(40, 20, 40, 20); 89 | tv.setBackgroundResource(R.drawable.normal); 90 | tv.setTextColor(Color.parseColor(COLOR_NORMAL)); 91 | tv.setLayoutParams(lp); 92 | tv.setText(title); 93 | tv.setOnClickListener(new View.OnClickListener() { 94 | @Override 95 | public void onClick(View v) { 96 | int position = holder.getLayoutPosition(); 97 | Log.d(TAG, "position== " + position); 98 | // TODO: 2018/5/7 0007 每一行选中的属性 99 | put(position, title); 100 | // TODO: 2018/5/6 每一行有的属性 101 | addProperty(position); 102 | // TODO: 2018/5/6 根据商品的状态绘制 103 | initStatus(); 104 | 105 | Log.d(TAG, "onClick: sam" + sam.toString()); 106 | Log.d(TAG, "onClick: sams" + sams.toString()); 107 | 108 | // 回调 109 | if (mGoodsSelectListener != null) { 110 | mGoodsSelectListener.select(sam); 111 | } 112 | } 113 | }); 114 | return tv; 115 | } 116 | 117 | private void addProperty(int position) { 118 | // TODO: 2018/5/6 每一行的属性容器 119 | for (int i = 0; i < mAttributes.size(); i++) { 120 | List list = new ArrayList<>(); 121 | sams.put(i, list); 122 | } 123 | for (int i = 0; i < mStockGoods.size(); i++) { 124 | GoodsPropertyBean.StockGoodsBean stockGoodsBean = mStockGoods.get(i); 125 | List goodsInfo = stockGoodsBean.getGoodsInfo(); 126 | boolean flag = false; 127 | for (int j = 0; j < goodsInfo.size(); j++) { 128 | GoodsPropertyBean.StockGoodsBean.GoodsInfoBean goodsInfoBean = goodsInfo.get(j); 129 | String tabValue = goodsInfoBean.getTabValue(); 130 | Set keySet = sam.keySet(); 131 | Iterator iterator = keySet.iterator(); 132 | while (iterator.hasNext()) { 133 | Integer key = iterator.next(); 134 | String arr = sam.get(key); 135 | // TODO: 2018/5/7 0007 如果是选中的行,改行可选的,如果是没选中的,那就看附和所有条件的 136 | if (key == j) { 137 | if (arr.equals(tabValue)) { 138 | index++; 139 | } 140 | } 141 | } 142 | // TODO: 2018/5/7 0007 如果是选中的都符合条件 143 | if (index == keySet.size()) { 144 | flag = true; 145 | } 146 | } 147 | // 重置 148 | index = 0; 149 | if (flag) { 150 | for (int j = 0; j < goodsInfo.size(); j++) { 151 | String tabValue = goodsInfo.get(j).getTabValue(); 152 | List list = sams.get(j); 153 | if (!list.contains(tabValue)) { 154 | list.add(tabValue); 155 | } 156 | } 157 | flag = false; 158 | } 159 | } 160 | } 161 | 162 | private void initStatus() { 163 | for (int i = 0; i < mTextViews.length; i++) { 164 | List list = sams.get(i); 165 | // 之前选中的 166 | String select = sam.get(i); 167 | TextView[] textViews = mTextViews[i]; 168 | for (TextView textView : textViews) { 169 | String title = textView.getText().toString(); 170 | // 如果是之前选中的,不做处理 171 | if (!TextUtils.isEmpty(select) && select.equals(title)) { 172 | textView.setBackgroundResource(R.drawable.select); 173 | textView.setTextColor(Color.parseColor(COLOR_SELECT)); 174 | } else if (list.contains(title)) { 175 | // 如果是可选的 176 | textView.setEnabled(true); 177 | textView.setBackgroundResource(R.drawable.normal); 178 | textView.setTextColor(Color.parseColor(COLOR_NORMAL)); 179 | } else { 180 | // 如果是不可选的 181 | textView.setEnabled(false); 182 | textView.setBackgroundResource(R.drawable.empty); 183 | textView.setTextColor(Color.parseColor(COLOR_EMPTY)); 184 | } 185 | } 186 | } 187 | } 188 | 189 | public void put(int position, String title) { 190 | // TODO: 2018/5/6 如果点击的时候同一个,不做处理 191 | String str = sam.get(position); 192 | if (!TextUtils.isEmpty(str)) { 193 | if (str.equals(title)) { 194 | sam.remove(position); 195 | } else { 196 | // TODO: 2018/5/7 0007 如果点击的是同一行已有的,先清空掉 197 | sam.clear(); 198 | sam.put(position, title); 199 | } 200 | } else { 201 | // TODO: 2018/5/7 0007 如果点击的是没有的话,清空重置 202 | List list = sams.get(position); 203 | if (list != null && !list.contains(title)) { 204 | sam.clear(); 205 | } 206 | sam.put(position, title); 207 | } 208 | } 209 | 210 | @Override 211 | public int getItemCount() { 212 | return mAttributes == null ? 0 : mAttributes.size(); 213 | } 214 | 215 | public interface GoodsSelectListener { 216 | 217 | void select(HashMap sam); 218 | 219 | } 220 | 221 | } 222 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/adapter/HeaderAndFooterWrapper.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.adapter; 2 | 3 | import android.support.v7.widget.GridLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.support.v7.widget.StaggeredGridLayoutManager; 6 | import android.util.SparseArray; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | /** 11 | * Created by ${GongWenbo} on 2018/4/24 0024. 12 | */ 13 | 14 | public class HeaderAndFooterWrapper extends RecyclerView.Adapter { 15 | 16 | private static final int BASE_ITEM_TYPE_HEADER = 100000; 17 | private static final int BASE_ITEM_TYPE_FOOTER = 200000; 18 | private final SparseArray mHeaderViews = new SparseArray<>(); 19 | private final SparseArray mFooterViews = new SparseArray<>(); 20 | private RecyclerView.Adapter mInnerAdapter; 21 | 22 | public HeaderAndFooterWrapper(RecyclerView.Adapter innerAdapter) { 23 | if (innerAdapter == null) { 24 | throw new NullPointerException("you must give me a adapter!"); 25 | } 26 | mInnerAdapter = innerAdapter; 27 | } 28 | 29 | public int getHeaderCount() { 30 | return mHeaderViews.size(); 31 | } 32 | 33 | public int getFooterCount() { 34 | return mFooterViews.size(); 35 | } 36 | 37 | public int getInnerCount() { 38 | return mInnerAdapter.getItemCount(); 39 | } 40 | 41 | public void addHeader(View view) { 42 | mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view); 43 | } 44 | 45 | public void addFooter(View view) { 46 | mFooterViews.put(mFooterViews.size() + BASE_ITEM_TYPE_FOOTER, view); 47 | } 48 | 49 | private boolean isHeaderViewPos(int position) { 50 | return position < getHeaderCount(); 51 | } 52 | 53 | private boolean isFooterViewPos(int position) { 54 | return position >= getHeaderCount() + getInnerCount(); 55 | } 56 | 57 | @Override 58 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 59 | if (mHeaderViews.get(viewType) != null) { 60 | return BaseViewHolder.createViewHolder(parent.getContext(), mHeaderViews.get(viewType)); 61 | } else if (mFooterViews.get(viewType) != null) { 62 | return BaseViewHolder.createViewHolder(parent.getContext(), mFooterViews.get(viewType)); 63 | } 64 | return mInnerAdapter.onCreateViewHolder(parent, viewType); 65 | } 66 | 67 | @Override 68 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 69 | if (isHeaderViewPos(position)) { 70 | return; 71 | } else if (isFooterViewPos(position)) { 72 | return; 73 | } 74 | mInnerAdapter.onBindViewHolder(holder, position - getHeaderCount()); 75 | } 76 | 77 | @Override 78 | public int getItemViewType(int position) { 79 | if (isHeaderViewPos(position)) { 80 | return mHeaderViews.keyAt(position); 81 | } else if (isFooterViewPos(position)) { 82 | return mFooterViews.keyAt(position - getHeaderCount() - getInnerCount()); 83 | } 84 | return mInnerAdapter.getItemViewType(position - getHeaderCount()); 85 | } 86 | 87 | @Override 88 | public int getItemCount() { 89 | return getHeaderCount() + getInnerCount() + getFooterCount(); 90 | } 91 | 92 | /** 93 | * 解决GridLayoutManager一行显示问题 94 | * 95 | * @param recyclerView 96 | */ 97 | @Override 98 | public void onAttachedToRecyclerView(RecyclerView recyclerView) { 99 | // 此处为什么要添加这行,考虑到被装饰类的重写 100 | mInnerAdapter.onAttachedToRecyclerView(recyclerView); 101 | final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 102 | if (layoutManager instanceof GridLayoutManager) { 103 | final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager; 104 | final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup(); 105 | gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 106 | @Override 107 | public int getSpanSize(int position) { 108 | // TODO: 2018/4/24 0024 默认是一个view占一个位置,header和footer只要让他们占据一行,就可以完美解决 109 | int viewType = getItemViewType(position); 110 | if (mHeaderViews.get(viewType) != null) { 111 | return gridLayoutManager.getSpanCount(); 112 | } else if (mFooterViews.get(viewType) != null) { 113 | return gridLayoutManager.getSpanCount(); 114 | } 115 | if (spanSizeLookup != null) { 116 | return spanSizeLookup.getSpanSize(position); 117 | } 118 | return 1; 119 | } 120 | }); 121 | gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount()); 122 | } 123 | } 124 | 125 | /** 126 | * 解决StaggeredGridLayoutManager一行显示问题 127 | * 128 | * @param holder 129 | */ 130 | @Override 131 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { 132 | // 同上面 133 | mInnerAdapter.onViewAttachedToWindow(holder); 134 | int layoutPosition = holder.getLayoutPosition(); 135 | if (isHeaderViewPos(layoutPosition) || isFooterViewPos(layoutPosition)) { 136 | ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); 137 | if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) { 138 | ((StaggeredGridLayoutManager.LayoutParams) lp).setFullSpan(true); 139 | } 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/adapter/OnItemClickListener.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.adapter; 2 | 3 | /** 4 | * Created by GongWenBo on 2018/4/7. 5 | */ 6 | 7 | public interface OnItemClickListener { 8 | void onItemClick(int position, T t); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/entity/GoodsPropertyBean.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.entity; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by ${GongWenbo} on 2018/5/3 0003. 7 | */ 8 | 9 | public class GoodsPropertyBean { 10 | 11 | private List attributes; 12 | private List stockGoods; 13 | 14 | public List getAttributes() { 15 | return attributes; 16 | } 17 | 18 | public void setAttributes(List attributes) { 19 | this.attributes = attributes; 20 | } 21 | 22 | public List getStockGoods() { 23 | return stockGoods; 24 | } 25 | 26 | public void setStockGoods(List stockGoods) { 27 | this.stockGoods = stockGoods; 28 | } 29 | 30 | public static class AttributesBean { 31 | /** 32 | * tabID : 0 33 | * tabName : 颜色 34 | * attributesItem : ["白","蓝","黑"] 35 | */ 36 | 37 | private int tabID; 38 | private String tabName; 39 | private List attributesItem; 40 | 41 | public int getTabID() { 42 | return tabID; 43 | } 44 | 45 | public void setTabID(int tabID) { 46 | this.tabID = tabID; 47 | } 48 | 49 | public String getTabName() { 50 | return tabName; 51 | } 52 | 53 | public void setTabName(String tabName) { 54 | this.tabName = tabName; 55 | } 56 | 57 | public List getAttributesItem() { 58 | return attributesItem; 59 | } 60 | 61 | public void setAttributesItem(List attributesItem) { 62 | this.attributesItem = attributesItem; 63 | } 64 | } 65 | 66 | public static class StockGoodsBean { 67 | /** 68 | * goodsID : 1 69 | * goodsCount : 4 70 | * goodsInfo : [{"tabID":0,"tabName":"颜色","tabValue":"白"},{"tabID":1,"tabName":"型号","tabValue":"X"},{"tabID":2,"tabName":"衣服","tabValue":"羽绒服"},{"tabID":3,"tabName":"大小","tabValue":"中"}] 71 | */ 72 | 73 | private int goodsID; 74 | private int goodsCount; 75 | private List goodsInfo; 76 | 77 | public int getGoodsID() { 78 | return goodsID; 79 | } 80 | 81 | public void setGoodsID(int goodsID) { 82 | this.goodsID = goodsID; 83 | } 84 | 85 | public int getGoodsCount() { 86 | return goodsCount; 87 | } 88 | 89 | public void setGoodsCount(int goodsCount) { 90 | this.goodsCount = goodsCount; 91 | } 92 | 93 | public List getGoodsInfo() { 94 | return goodsInfo; 95 | } 96 | 97 | public void setGoodsInfo(List goodsInfo) { 98 | this.goodsInfo = goodsInfo; 99 | } 100 | 101 | public static class GoodsInfoBean { 102 | /** 103 | * tabID : 0 104 | * tabName : 颜色 105 | * tabValue : 白 106 | */ 107 | 108 | private int tabID; 109 | private String tabName; 110 | private String tabValue; 111 | 112 | public int getTabID() { 113 | return tabID; 114 | } 115 | 116 | public void setTabID(int tabID) { 117 | this.tabID = tabID; 118 | } 119 | 120 | public String getTabName() { 121 | return tabName; 122 | } 123 | 124 | public void setTabName(String tabName) { 125 | this.tabName = tabName; 126 | } 127 | 128 | public String getTabValue() { 129 | return tabValue; 130 | } 131 | 132 | public void setTabValue(String tabValue) { 133 | this.tabValue = tabValue; 134 | } 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/entity/ShopGoods.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | 6 | /** 7 | * Created by GongWenBo on 2018/5/26. 8 | */ 9 | 10 | public class ShopGoods implements Serializable { 11 | 12 | private ArrayList mList = new ArrayList<>(); 13 | 14 | public ShopGoods(ArrayList list) { 15 | mList = list; 16 | } 17 | 18 | public ArrayList getList() { 19 | return mList; 20 | } 21 | 22 | public void setList(ArrayList list) { 23 | mList = list; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/entity/ShopGoodsBean.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by ${GongWenbo} on 2018/5/18 0018. 7 | */ 8 | public class ShopGoodsBean implements Serializable { 9 | 10 | private int count; 11 | private String goods; 12 | private String goodsId; 13 | 14 | public ShopGoodsBean(int count, String goods, String goodsId) { 15 | this.count = count; 16 | this.goods = goods; 17 | this.goodsId = goodsId; 18 | } 19 | 20 | public String getGoodsId() { 21 | return goodsId; 22 | } 23 | 24 | public void setGoodsId(String goodsId) { 25 | this.goodsId = goodsId; 26 | } 27 | 28 | public int getCount() { 29 | return count; 30 | } 31 | 32 | public void setCount(int count) { 33 | this.count = count; 34 | } 35 | 36 | public String getGoods() { 37 | return goods == null ? "" : goods; 38 | } 39 | 40 | public void setGoods(String goods) { 41 | this.goods = goods; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "count=" + count + ",goods=" + goods; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/entity/StoreGoodsBean.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.entity; 2 | 3 | 4 | import java.io.Serializable; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by ${GongWenbo} on 2018/6/4 0004. 10 | */ 11 | public class StoreGoodsBean implements Serializable { 12 | 13 | private int allCount; // 商品总数 14 | 15 | private HashMap mHashMap; // 每件商品的个数 16 | 17 | public StoreGoodsBean(HashMap hashMap) { 18 | this.mHashMap = hashMap; 19 | for (Map.Entry entry : hashMap.entrySet()) { 20 | Integer value = entry.getValue(); 21 | if (value != 0) { 22 | allCount += value; 23 | } 24 | } 25 | } 26 | 27 | public int getAllCount() { 28 | return allCount; 29 | } 30 | 31 | public HashMap getHashMap() { 32 | return mHashMap; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/imp/AppBarStateChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.imp; 2 | 3 | import android.support.design.widget.AppBarLayout; 4 | 5 | import com.orhanobut.logger.Logger; 6 | 7 | 8 | /** 9 | * Created by ${GongWenbo} on 2018/5/21 0021. 10 | */ 11 | public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener { 12 | 13 | private State mCurrentState = State.IDLE; 14 | 15 | @Override 16 | public final void onOffsetChanged(AppBarLayout appBarLayout, int i) { 17 | if (i == 0) { 18 | if (mCurrentState != State.EXPANDED) { 19 | onStateChanged(appBarLayout, State.EXPANDED); 20 | } 21 | mCurrentState = State.EXPANDED; 22 | } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) { 23 | if (mCurrentState != State.COLLAPSED) { 24 | onStateChanged(appBarLayout, State.COLLAPSED); 25 | } 26 | mCurrentState = State.COLLAPSED; 27 | } else { 28 | if (mCurrentState != State.IDLE) { 29 | onStateChanged(appBarLayout, State.IDLE); 30 | } 31 | mCurrentState = State.IDLE; 32 | } 33 | onStateChanged(i); 34 | Logger.d("滑动的的高度" + i); 35 | } 36 | 37 | public abstract void onStateChanged(AppBarLayout appBarLayout, State state); 38 | 39 | public void onStateChanged(int i) { 40 | } 41 | 42 | public enum State { 43 | EXPANDED, // 展开状态 44 | COLLAPSED, // 折叠状态 45 | IDLE // 准备状态 46 | } 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui; 2 | 3 | import android.content.Intent; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.support.v7.app.ActionBar; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.text.TextUtils; 10 | import android.view.View; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import com.gwb.superrecycleview.R; 15 | import com.gwb.superrecycleview.utils.ActivityManager; 16 | import com.gwb.superrecycleview.utils.ToastUtil; 17 | import com.orhanobut.logger.Logger; 18 | 19 | import butterknife.ButterKnife; 20 | 21 | /** 22 | * Created by ${GongWenbo} on 2018/4/2 0002. 23 | */ 24 | 25 | public abstract class BaseActivity extends AppCompatActivity { 26 | 27 | protected Toolbar mToolbar; 28 | private TextView mTv_title; 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(getLayoutId()); 34 | ButterKnife.bind(this); 35 | setStatusBarTextLight(false); 36 | initToolBar(setTitle()); 37 | initView(); 38 | initData(savedInstanceState); 39 | ActivityManager.getInstance().addActivity(this); 40 | Logger.d("Activities" + ActivityManager.getInstance().getActivities()); 41 | } 42 | 43 | protected abstract int getLayoutId(); 44 | 45 | protected abstract String setTitle(); 46 | 47 | protected abstract void initView(); 48 | 49 | public void setTitle(String title) { 50 | if (!TextUtils.isEmpty(title)) { 51 | mTv_title.setText(title); 52 | } 53 | } 54 | 55 | protected abstract void initData(Bundle savedInstanceState); 56 | 57 | protected void initToolBar(String title) { 58 | mToolbar = findViewById(R.id.toolbar); 59 | if (mToolbar != null) { 60 | setSupportActionBar(mToolbar); 61 | ActionBar actionBar = getSupportActionBar(); 62 | actionBar.setTitle(""); 63 | mTv_title = findViewById(R.id.tv_title); 64 | if (!TextUtils.isEmpty(title) && mTv_title != null) { 65 | mTv_title.setText(title); 66 | } 67 | ImageView iv_back = findViewById(R.id.iv_back); 68 | if (iv_back != null) { 69 | iv_back.setOnClickListener(new View.OnClickListener() { 70 | @Override 71 | public void onClick(View v) { 72 | finish(); 73 | } 74 | }); 75 | } 76 | } 77 | } 78 | 79 | public void startActivity(Class clazz) { 80 | Intent intent = new Intent(this, clazz); 81 | startActivity(intent); 82 | } 83 | 84 | public void showToast(String content) { 85 | ToastUtil.showToast(this, content); 86 | } 87 | 88 | /** 89 | * 设置状态栏问题颜色(黑/白) 90 | * 91 | * @param isLight true:白色 false:黑色 92 | */ 93 | protected void setStatusBarTextLight(boolean isLight) { 94 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 95 | // View.SYSTEM_UI_FLAG_LAYOUT_STABLE 96 | getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 97 | | (isLight ? View.SYSTEM_UI_FLAG_LAYOUT_STABLE : View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)); 98 | } 99 | } 100 | 101 | @Override 102 | protected void onDestroy() { 103 | super.onDestroy(); 104 | ActivityManager.getInstance().finish(this); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/BaseFitsSystemWindowsActivity.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | /** 11 | * Created by ${GongWenbo} on 2018/5/23 0023. 12 | */ 13 | public abstract class BaseFitsSystemWindowsActivity extends BaseActivity { 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 19 | setHeight(mToolbar); 20 | } 21 | } 22 | 23 | public void setHeight(View view) { 24 | // 获取actionbar的高度 25 | TypedArray actionbarSizeTypedArray = obtainStyledAttributes(new int[]{ 26 | android.R.attr.actionBarSize 27 | }); 28 | float height = actionbarSizeTypedArray.getDimension(0, 0); 29 | // ToolBar的top值 30 | ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); 31 | double statusBarHeight = getStatusBarHeight(this); 32 | lp.height = (int) (statusBarHeight + height); 33 | view.setPadding(0,(int) statusBarHeight,0, 0); 34 | mToolbar.setLayoutParams(lp); 35 | } 36 | 37 | private double getStatusBarHeight(Context context) { 38 | int result = 0; 39 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", 40 | "android"); 41 | if (resourceId > 0) { 42 | result = context.getResources().getDimensionPixelSize(resourceId); 43 | } 44 | return result; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/activity/HeaderAndFooterActivity.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.widget.GridLayoutManager; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.StaggeredGridLayoutManager; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.gwb.superrecycleview.R; 13 | import com.gwb.superrecycleview.adapter.BaseAdapter; 14 | import com.gwb.superrecycleview.adapter.BaseViewHolder; 15 | import com.gwb.superrecycleview.adapter.HeaderAndFooterWrapper; 16 | import com.gwb.superrecycleview.adapter.OnItemClickListener; 17 | import com.gwb.superrecycleview.ui.BaseFitsSystemWindowsActivity; 18 | import com.gwb.superrecycleview.utils.ToastUtil; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import butterknife.BindView; 24 | import butterknife.OnClick; 25 | 26 | public class HeaderAndFooterActivity extends BaseFitsSystemWindowsActivity implements BaseAdapter.BaseAdapterListener, OnItemClickListener { 27 | 28 | @BindView(R.id.rv_show) 29 | RecyclerView mRvShow; 30 | private List mList = new ArrayList<>(); 31 | private BaseAdapter mAdapter; 32 | private HeaderAndFooterWrapper mHeaderAndFooterWrapper; 33 | 34 | @Override 35 | protected int getLayoutId() { 36 | return R.layout.activity_header_and_footer; 37 | } 38 | 39 | @Override 40 | protected String setTitle() { 41 | return "HeaderAndFooter"; 42 | } 43 | 44 | @Override 45 | protected void initView() { 46 | mToolbar.setBackgroundColor(getResources().getColor(R.color.colorAccent)); 47 | initAdapter(); 48 | } 49 | 50 | @Override 51 | protected void initData(Bundle savedInstanceState) { 52 | 53 | } 54 | 55 | private void initAdapter() { 56 | mAdapter = new BaseAdapter(mList, R.layout.item, this); 57 | mHeaderAndFooterWrapper = new HeaderAndFooterWrapper(mAdapter); 58 | 59 | for (int i = 0; i < 20; i++) { 60 | mList.add("我是数据" + i); 61 | } 62 | 63 | // header 64 | TextView tv1 = new TextView(this); 65 | tv1.setText("header 1"); 66 | mHeaderAndFooterWrapper.addHeader(tv1); 67 | ImageView iv1 = new ImageView(this); 68 | iv1.setImageResource(R.mipmap.ic_launcher); 69 | mHeaderAndFooterWrapper.addHeader(iv1); 70 | TextView tv2 = new TextView(this); 71 | tv2.setText("header 2"); 72 | mHeaderAndFooterWrapper.addHeader(tv2); 73 | 74 | // footer 75 | TextView tv11 = new TextView(this); 76 | tv11.setText("footer 1"); 77 | mHeaderAndFooterWrapper.addFooter(tv11); 78 | TextView tv12 = new TextView(this); 79 | tv12.setText("footer 2"); 80 | mHeaderAndFooterWrapper.addFooter(tv12); 81 | 82 | 83 | mRvShow.setLayoutManager(new GridLayoutManager(this, 3)); 84 | mRvShow.setAdapter(mHeaderAndFooterWrapper); 85 | mAdapter.setOnItemClickListener(this); 86 | } 87 | 88 | @Override 89 | public void convert(BaseViewHolder holder, String str) { 90 | holder.setTitle(R.id.tv, str); 91 | } 92 | 93 | @OnClick({R.id.btn_linear, R.id.btn_grid, R.id.btn_stagger}) 94 | public void onViewClicked(View view) { 95 | switch (view.getId()) { 96 | case R.id.btn_linear: 97 | mRvShow.setLayoutManager(new LinearLayoutManager(this)); 98 | break; 99 | case R.id.btn_grid: 100 | mRvShow.setLayoutManager(new GridLayoutManager(this, 3)); 101 | break; 102 | case R.id.btn_stagger: 103 | mRvShow.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); 104 | break; 105 | } 106 | // TODO: 2018/4/24 0024 只有在adapter初始化的时候会调用,切换的时候导致内部设置的方法失效 107 | mHeaderAndFooterWrapper.onAttachedToRecyclerView(mRvShow); 108 | } 109 | 110 | @Override 111 | public void onItemClick(int position, String s) { 112 | ToastUtil.showToast(this, "位置" + position); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.activity; 2 | 3 | import android.content.Intent; 4 | import android.content.SharedPreferences; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | 9 | import com.gwb.superrecycleview.R; 10 | import com.gwb.superrecycleview.ui.BaseActivity; 11 | 12 | import butterknife.ButterKnife; 13 | import butterknife.OnClick; 14 | 15 | public class MainActivity extends AppCompatActivity { 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_main); 21 | ButterKnife.bind(this); 22 | getClass().getSimpleName(); 23 | 24 | range(0); 25 | 26 | range(1); 27 | range(10); 28 | 29 | range(11); 30 | range(20); 31 | 32 | range(91); 33 | range(100); 34 | 35 | int color = R.color.colorAccent; 36 | } 37 | 38 | public void range(int num) { 39 | int pic = 0; 40 | if (num != 0) { 41 | int i = (num - 1) / 10; 42 | pic = i + 1; 43 | } 44 | System.out.println("图片" + pic + "\n"); 45 | } 46 | 47 | @OnClick({R.id.btn_headerAndFooter, R.id.btn_sku, R.id.btn_steam, R.id.btn_shoppingGoods}) 48 | public void onViewClicked(View view) { 49 | Class mainActivityClass = MainActivity.class; 50 | switch (view.getId()) { 51 | case R.id.btn_headerAndFooter: 52 | startActivity(HeaderAndFooterActivity.class); 53 | break; 54 | case R.id.btn_sku: 55 | startActivity(SkuActivity.class); 56 | break; 57 | case R.id.btn_steam: 58 | startActivity(SteamActivity.class); 59 | break; 60 | case R.id.btn_shoppingGoods: 61 | startActivity(ShoppingGoodsActivity.class); 62 | break; 63 | } 64 | } 65 | 66 | public void startActivity(Class clazz) { 67 | Intent intent = new Intent(this, clazz); 68 | startActivity(intent); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/activity/ShoppingGoodsActivity.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.activity; 2 | 3 | import android.Manifest; 4 | import android.animation.Animator; 5 | import android.animation.AnimatorListenerAdapter; 6 | import android.animation.AnimatorSet; 7 | import android.animation.ObjectAnimator; 8 | import android.animation.ValueAnimator; 9 | import android.content.Context; 10 | import android.graphics.Path; 11 | import android.graphics.PathMeasure; 12 | import android.os.Bundle; 13 | import android.support.design.widget.AppBarLayout; 14 | import android.support.design.widget.CoordinatorLayout; 15 | import android.support.v7.widget.LinearLayoutManager; 16 | import android.support.v7.widget.RecyclerView; 17 | import android.view.View; 18 | import android.view.ViewGroup; 19 | import android.view.ViewTreeObserver; 20 | import android.view.animation.AccelerateInterpolator; 21 | import android.widget.ImageView; 22 | import android.widget.RelativeLayout; 23 | import android.widget.TextView; 24 | 25 | import com.gwb.superrecycleview.R; 26 | import com.gwb.superrecycleview.adapter.BaseAdapter; 27 | import com.gwb.superrecycleview.adapter.BaseViewHolder; 28 | import com.gwb.superrecycleview.entity.ShopGoods; 29 | import com.gwb.superrecycleview.entity.ShopGoodsBean; 30 | import com.gwb.superrecycleview.entity.StoreGoodsBean; 31 | import com.gwb.superrecycleview.imp.AppBarStateChangeListener; 32 | import com.gwb.superrecycleview.ui.BaseActivity; 33 | import com.gwb.superrecycleview.ui.dialog.DiscountCouponDialog; 34 | import com.gwb.superrecycleview.ui.dialog.ShoppingCartDialog; 35 | import com.gwb.superrecycleview.utils.ShoppingCartHistoryManager; 36 | import com.gwb.superrecycleview.utils.ToastUtil; 37 | import com.gwb.superrecycleview.utils.Util; 38 | import com.orhanobut.logger.Logger; 39 | import com.scwang.smartrefresh.layout.util.DensityUtil; 40 | 41 | import java.util.ArrayList; 42 | import java.util.HashMap; 43 | 44 | import butterknife.BindView; 45 | import butterknife.OnClick; 46 | import pub.devrel.easypermissions.EasyPermissions; 47 | 48 | public class ShoppingGoodsActivity extends BaseActivity implements BaseAdapter.BaseAdapterListener { 49 | 50 | private static final long TIME = 300; // 动画的执行时间 51 | @BindView(R.id.rv_goods) 52 | RecyclerView mRvGoods; 53 | int reduceLeft = 0; 54 | int addLeft = 0; 55 | @BindView(R.id.coordinatorLayout) 56 | CoordinatorLayout mCoordinatorLayout; 57 | @BindView(R.id.iv_shopping_cart) 58 | ImageView mIvShoppingCart; 59 | @BindView(R.id.tv_shopping_cart_count) 60 | TextView mTvShoppingCartCount; 61 | @BindView(R.id.appBarLayout) 62 | AppBarLayout mAppBarLayout; 63 | @BindView(R.id.tv_title) 64 | TextView mTvTitle; 65 | @BindView(R.id.rl_header) 66 | RelativeLayout mRlHeader; 67 | String[] perms = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}; 68 | private ArrayList mGoodsList = new ArrayList<>(); 69 | // 贝塞尔曲线中间过程点坐标 70 | private float[] mCurrentPosition = new float[2]; 71 | private int allCount; 72 | private BaseAdapter mAdapter; 73 | private int RC_CAMERA_AND_LOCATION = 0x1; 74 | // 商品的id 75 | private String SHOP_ID = "12"; 76 | 77 | @Override 78 | protected int getLayoutId() { 79 | return R.layout.activity_shopping_goods; 80 | } 81 | 82 | @Override 83 | protected String setTitle() { 84 | return "ShoppingGoods"; 85 | } 86 | 87 | private void initToolbar() { 88 | mAppBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { 89 | @Override 90 | public void onStateChanged(AppBarLayout appBarLayout, State state) { 91 | if (state == State.EXPANDED) { 92 | // 展开状态 93 | mTvTitle.setText(""); 94 | mRlHeader.setVisibility(View.VISIBLE); 95 | } else if (state == State.COLLAPSED) { 96 | // 折叠状态 97 | mTvTitle.setText("芭比馒头"); 98 | mRlHeader.setVisibility(View.GONE); 99 | } else { 100 | mTvTitle.setText(""); 101 | mRlHeader.setVisibility(View.VISIBLE); 102 | } 103 | } 104 | 105 | @Override 106 | public void onStateChanged(int i) { 107 | float height = mRlHeader.getHeight(); 108 | float alpha = i / height; 109 | Logger.d("透明度" + (1 - Math.abs(alpha))); 110 | mRlHeader.setAlpha(1 - Math.abs(alpha)); 111 | } 112 | }); 113 | } 114 | 115 | public void initHeight() { 116 | // ToolBar的top值 117 | ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mToolbar.getLayoutParams(); 118 | lp.topMargin = (int) getStatusBarHeight(this); 119 | mToolbar.setLayoutParams(lp); 120 | // AppBarLayout的高度 121 | ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) mAppBarLayout.getLayoutParams(); 122 | layoutParams.height = DensityUtil.dp2px(200) + (int) getStatusBarHeight(this); 123 | mAppBarLayout.setLayoutParams(layoutParams); 124 | } 125 | 126 | private double getStatusBarHeight(Context context) { 127 | int result = 0; 128 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", 129 | "android"); 130 | if (resourceId > 0) { 131 | result = context.getResources().getDimensionPixelSize(resourceId); 132 | } 133 | return result; 134 | } 135 | 136 | private void initData() { 137 | int id = 0x100; 138 | HashMap hashMap = ShoppingCartHistoryManager.getInstance().get(SHOP_ID); 139 | this.allCount = ShoppingCartHistoryManager.getInstance().getAllGoodsCount(SHOP_ID); 140 | showToast("商品总数" + allCount); 141 | // 根据缓存是否显示 142 | mTvShoppingCartCount.setVisibility(allCount == 0 ? View.GONE : View.VISIBLE); 143 | mTvShoppingCartCount.setText(String.valueOf(allCount)); 144 | // TODO: 2018/6/5 0005 模拟请求到的数据 145 | for (int i = 0; i < 10; i++) { 146 | mGoodsList.add(new ShopGoodsBean(0, "小猪包套餐" + i, id++ + "")); 147 | } 148 | if (hashMap != null) { 149 | for (ShopGoodsBean bean : mGoodsList) { 150 | String goodsId = bean.getGoodsId(); 151 | if (hashMap.containsKey(goodsId)) { 152 | Integer count = hashMap.get(goodsId); 153 | bean.setCount(count); 154 | } 155 | } 156 | } 157 | } 158 | 159 | @Override 160 | protected void initView() { 161 | EasyPermissions.requestPermissions(this, null, RC_CAMERA_AND_LOCATION, perms); 162 | 163 | initData(); 164 | initToolbar(); 165 | initHeight(); 166 | initAdapter(); 167 | } 168 | 169 | private void initAdapter() { 170 | mAdapter = new BaseAdapter(mGoodsList, R.layout.item_shop_goods, this); 171 | mRvGoods.setLayoutManager(new LinearLayoutManager(this)); 172 | mRvGoods.setAdapter(mAdapter); 173 | mRvGoods.setItemAnimator(null); 174 | } 175 | 176 | @Override 177 | protected void initData(Bundle savedInstanceState) { 178 | 179 | } 180 | 181 | @Override 182 | public void convert(final BaseViewHolder holder, ShopGoodsBean bean) { 183 | // 原价 184 | TextView tv_goods_original_price = holder.getView(R.id.tv_goods_original_price); 185 | // 中划线 186 | Util.drawStrikethrough(tv_goods_original_price); 187 | // 商品数 188 | final TextView tv_goods_count = holder.getView(R.id.tv_goods_count); 189 | // 减少 190 | final ImageView iv_goods_reduce = holder.getView(R.id.iv_goods_reduce); 191 | iv_goods_reduce.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 192 | @Override 193 | public void onGlobalLayout() { 194 | // 获取减少图标的位置 195 | reduceLeft = iv_goods_reduce.getLeft(); 196 | iv_goods_reduce.getViewTreeObserver().removeOnGlobalLayoutListener(this); 197 | } 198 | }); 199 | iv_goods_reduce.setOnClickListener(new View.OnClickListener() { 200 | @Override 201 | public void onClick(View v) { 202 | int position = holder.getLayoutPosition(); 203 | ShopGoodsBean shopGoodsBean = mGoodsList.get(position); 204 | int count = shopGoodsBean.getCount(); 205 | count--; 206 | // 防止过快点击出现多个关闭动画 207 | if (count == 0) { 208 | animClose(iv_goods_reduce); 209 | tv_goods_count.setText(""); 210 | // 考虑到用户点击过快 211 | allCount--; 212 | } else if (count < 0) { 213 | // 防止过快点击出现商品数为负数 214 | count = 0; 215 | } else { 216 | allCount--; 217 | tv_goods_count.setText(String.valueOf(count)); 218 | } 219 | // 商品的数量是否显示 220 | if (allCount <= 0) { 221 | allCount = 0; 222 | mTvShoppingCartCount.setVisibility(View.GONE); 223 | } else { 224 | mTvShoppingCartCount.setText(String.valueOf(allCount)); 225 | mTvShoppingCartCount.setVisibility(View.VISIBLE); 226 | } 227 | shopGoodsBean.setCount(count); 228 | } 229 | }); 230 | // 增加 231 | final ImageView iv_goods_add = holder.getView(R.id.iv_goods_add); 232 | iv_goods_add.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 233 | @Override 234 | public void onGlobalLayout() { 235 | // 获取增加图标的位置 236 | addLeft = iv_goods_add.getLeft(); 237 | iv_goods_add.getViewTreeObserver().removeOnGlobalLayoutListener(this); 238 | } 239 | }); 240 | iv_goods_add.setOnClickListener(new View.OnClickListener() { 241 | @Override 242 | public void onClick(View v) { 243 | int position = holder.getLayoutPosition(); 244 | ShopGoodsBean shopGoodsBean = mGoodsList.get(position); 245 | int count = shopGoodsBean.getCount(); 246 | count++; 247 | allCount++; 248 | if (allCount > 0) { 249 | mTvShoppingCartCount.setVisibility(View.VISIBLE); 250 | } 251 | mTvShoppingCartCount.setText(String.valueOf(allCount)); 252 | if (count == 1) { 253 | iv_goods_reduce.setVisibility(View.VISIBLE); 254 | animOpen(iv_goods_reduce); 255 | } 256 | addGoods2CartAnim(iv_goods_add); 257 | tv_goods_count.setText(String.valueOf(count)); 258 | shopGoodsBean.setCount(count); 259 | } 260 | }); 261 | int count = bean.getCount(); 262 | tv_goods_count.setText(count == 0 ? "" : String.valueOf(count)); 263 | iv_goods_reduce.setVisibility(count == 0 ? View.INVISIBLE : View.VISIBLE); 264 | // 标题 265 | holder.setTitle(R.id.tv_goods_title, bean.getGoods()); 266 | } 267 | 268 | public void animOpen(final ImageView imageView) { 269 | AnimatorSet animatorSet = new AnimatorSet(); 270 | ObjectAnimator translationAnim = ObjectAnimator.ofFloat(imageView, "translationX", addLeft - reduceLeft, 0); 271 | ObjectAnimator rotationAnim = ObjectAnimator.ofFloat(imageView, "rotation", 0, 180); 272 | animatorSet.play(translationAnim).with(rotationAnim); 273 | animatorSet.setDuration(TIME).start(); 274 | } 275 | 276 | public void animClose(final ImageView imageView) { 277 | AnimatorSet animatorSet = new AnimatorSet(); 278 | ObjectAnimator translationAnim = ObjectAnimator.ofFloat(imageView, "translationX", 0, addLeft - reduceLeft); 279 | ObjectAnimator rotationAnim = ObjectAnimator.ofFloat(imageView, "rotation", 0, 180); 280 | animatorSet.play(translationAnim).with(rotationAnim); 281 | animatorSet.setDuration(TIME).start(); 282 | animatorSet.addListener(new AnimatorListenerAdapter() { 283 | @Override 284 | public void onAnimationEnd(Animator animation) { 285 | // TODO: 2018/5/19 因为属性动画会改变位置,所以当结束的时候,要回退的到原来的位置,同时用补间动画的位移不好控制 286 | ObjectAnimator oa = ObjectAnimator.ofFloat(imageView, "translationX", addLeft - reduceLeft, 0); 287 | oa.setDuration(0); 288 | oa.start(); 289 | imageView.setVisibility(View.GONE); 290 | } 291 | }); 292 | } 293 | 294 | /** 295 | * 贝塞尔曲线动画 296 | * 297 | * @param goodsImageView 298 | */ 299 | public void addGoods2CartAnim(ImageView goodsImageView) { 300 | final ImageView goods = new ImageView(ShoppingGoodsActivity.this); 301 | goods.setImageResource(R.mipmap.icon_goods_add); 302 | int size = Util.dp2px(ShoppingGoodsActivity.this, 24); 303 | ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(size, size); 304 | goods.setLayoutParams(lp); 305 | mCoordinatorLayout.addView(goods); 306 | // 控制点的位置 307 | int[] recyclerLocation = new int[2]; 308 | mCoordinatorLayout.getLocationInWindow(recyclerLocation); 309 | // 加入点的位置起始点 310 | int[] startLocation = new int[2]; 311 | goodsImageView.getLocationInWindow(startLocation); 312 | // 购物车的位置终点 313 | int[] endLocation = new int[2]; 314 | mIvShoppingCart.getLocationInWindow(endLocation); 315 | // TODO: 2018/5/21 0021 考虑到状态栏的问题,不然会往下偏移状态栏的高度 316 | int startX = startLocation[0] - recyclerLocation[0]; 317 | int startY = startLocation[1] - recyclerLocation[1]; 318 | // TODO: 2018/5/21 0021 和上面一样 319 | int endX = endLocation[0] - recyclerLocation[0]; 320 | int endY = endLocation[1] - recyclerLocation[1]; 321 | // 开始绘制贝塞尔曲线 322 | Path path = new Path(); 323 | // 移动到起始点位置(即贝塞尔曲线的起点) 324 | path.moveTo(startX, startY); 325 | // 使用二阶贝塞尔曲线:注意第一个起始坐标越大,贝塞尔曲线的横向距离就会越大,一般按照下面的式子取即可 326 | path.quadTo((startX + endX) / 2, startY, endX, endY); 327 | // mPathMeasure用来计算贝塞尔曲线的曲线长度和贝塞尔曲线中间插值的坐标,如果是true,path会形成一个闭环 328 | final PathMeasure pathMeasure = new PathMeasure(path, false); 329 | // 属性动画实现(从0到贝塞尔曲线的长度之间进行插值计算,获取中间过程的距离值) 330 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, pathMeasure.getLength()); 331 | // 计算距离 332 | int tempX = Math.abs(startX - endX); 333 | int tempY = Math.abs(startY - endY); 334 | // 根据距离计算时间 335 | int time = (int) (0.3 * Math.sqrt((tempX * tempX) + tempY * tempY)); 336 | valueAnimator.setDuration(time); 337 | valueAnimator.start(); 338 | valueAnimator.setInterpolator(new AccelerateInterpolator()); 339 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 340 | @Override 341 | public void onAnimationUpdate(ValueAnimator animation) { 342 | // 当插值计算进行时,获取中间的每个值, 343 | // 这里这个值是中间过程中的曲线长度(下面根据这个值来得出中间点的坐标值) 344 | float value = (Float) animation.getAnimatedValue(); 345 | // 获取当前点坐标封装到mCurrentPosition 346 | // boolean getPosTan(float distance, float[] pos, float[] tan) : 347 | // 传入一个距离distance(0<=distance<=getLength()),然后会计算当前距离的坐标点和切线,pos会自动填充上坐标,这个方法很重要。 348 | // mCurrentPosition此时就是中间距离点的坐标值 349 | pathMeasure.getPosTan(value, mCurrentPosition, null); 350 | // 移动的商品图片(动画图片)的坐标设置为该中间点的坐标 351 | goods.setTranslationX(mCurrentPosition[0]); 352 | goods.setTranslationY(mCurrentPosition[1]); 353 | } 354 | }); 355 | valueAnimator.addListener(new AnimatorListenerAdapter() { 356 | @Override 357 | public void onAnimationEnd(Animator animation) { 358 | // 移除图片 359 | mCoordinatorLayout.removeView(goods); 360 | // 购物车数量增加 361 | mTvShoppingCartCount.setText(String.valueOf(allCount)); 362 | } 363 | }); 364 | } 365 | 366 | @OnClick({R.id.iv_back, R.id.layout_shopping_cart, R.id.tv_shopping_cart_pay, R.id.tv_goods_get}) 367 | public void onViewClicked(View view) { 368 | switch (view.getId()) { 369 | // 返回 370 | case R.id.iv_back: 371 | ToastUtil.showToast(ShoppingGoodsActivity.this, "返回"); 372 | break; 373 | // 购物车的弹窗 374 | case R.id.layout_shopping_cart: 375 | shoppingCartDialog(); 376 | break; 377 | // 支付 378 | case R.id.tv_shopping_cart_pay: 379 | pay(); 380 | break; 381 | // 领取 382 | case R.id.tv_goods_get: 383 | showDiscountCouponDialog(); 384 | break; 385 | } 386 | } 387 | 388 | public void shoppingCartDialog() { 389 | ShoppingCartDialog dialog = new ShoppingCartDialog(); 390 | Bundle bundle = new Bundle(); 391 | bundle.putSerializable(ShoppingCartDialog.CART_GOODS, mGoodsList); 392 | dialog.setArguments(bundle); 393 | dialog.show(getFragmentManager(), "cartGoods"); 394 | dialog.setCartGoodsDialogListener(new ShoppingCartDialog.CartGoodsDialogListener() { 395 | @Override 396 | public void add(int allCount, ShopGoodsBean shopGoodsBean) { 397 | notifyItemChanged(allCount, shopGoodsBean); 398 | } 399 | 400 | @Override 401 | public void reduce(int allCount, ShopGoodsBean shopGoodsBean) { 402 | notifyItemChanged(allCount, shopGoodsBean); 403 | } 404 | 405 | @Override 406 | public void clear() { 407 | clearShoppingGoods(); 408 | } 409 | }); 410 | } 411 | 412 | public void showDiscountCouponDialog() { 413 | DiscountCouponDialog dialog = new DiscountCouponDialog(); 414 | dialog.show(getFragmentManager(), "discountCoupon", true); 415 | } 416 | 417 | public void pay() { 418 | String remind = "购物车中空空如也"; 419 | if (allCount > 0) { 420 | remind = "去支付"; 421 | } 422 | ToastUtil.showToast(ShoppingGoodsActivity.this, remind); 423 | } 424 | 425 | public void notifyItemChanged(int allCount, ShopGoodsBean shopGoodsBean) { 426 | this.allCount = allCount; 427 | mTvShoppingCartCount.setVisibility(allCount == 0 ? View.GONE : View.VISIBLE); 428 | mTvShoppingCartCount.setText(String.valueOf(allCount)); 429 | // 遍历,格局id查找对象 430 | for (int i = 0; i < mGoodsList.size(); i++) { 431 | ShopGoodsBean bean = mGoodsList.get(i); 432 | String goodsId = bean.getGoodsId(); 433 | if (goodsId.equals(shopGoodsBean.getGoodsId())) { 434 | bean = shopGoodsBean; 435 | mAdapter.notifyItemChanged(i); 436 | break; 437 | } 438 | } 439 | } 440 | 441 | public void clearShoppingGoods() { 442 | allCount = 0; 443 | mTvShoppingCartCount.setVisibility(View.GONE); 444 | for (ShopGoodsBean bean : mGoodsList) { 445 | bean.setCount(0); 446 | } 447 | mAdapter.notifyDataSetChanged(); 448 | } 449 | 450 | @Override 451 | protected void onDestroy() { 452 | super.onDestroy(); 453 | if (allCount != 0) { 454 | HashMap hashMap = new HashMap<>(); 455 | StoreGoodsBean storeGoodsBean = new StoreGoodsBean(hashMap); 456 | for (ShopGoodsBean bean : mGoodsList) { 457 | int count = bean.getCount(); 458 | String goodsId = bean.getGoodsId(); 459 | if (count != 0) { 460 | hashMap.put(goodsId, count); 461 | } 462 | } 463 | ShoppingCartHistoryManager.getInstance().add(SHOP_ID, storeGoodsBean); 464 | } else { 465 | ShoppingCartHistoryManager.getInstance().delete(SHOP_ID); 466 | } 467 | } 468 | } 469 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/activity/SkuActivity.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.activity; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.os.Bundle; 8 | import android.support.annotation.NonNull; 9 | import android.support.annotation.Nullable; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.RecyclerView; 12 | import android.text.TextUtils; 13 | import android.util.Log; 14 | import android.widget.ImageView; 15 | import android.widget.TextView; 16 | 17 | import com.bumptech.glide.Glide; 18 | import com.bumptech.glide.request.target.SimpleTarget; 19 | import com.bumptech.glide.request.transition.Transition; 20 | import com.google.gson.Gson; 21 | import com.gwb.superrecycleview.App; 22 | import com.gwb.superrecycleview.R; 23 | import com.gwb.superrecycleview.adapter.GoodsPropertyAdapter; 24 | import com.gwb.superrecycleview.entity.GoodsPropertyBean; 25 | import com.gwb.superrecycleview.ui.BaseFitsSystemWindowsActivity; 26 | import com.gwb.superrecycleview.utils.ToastUtil; 27 | 28 | import java.util.ArrayList; 29 | import java.util.HashMap; 30 | import java.util.List; 31 | 32 | import butterknife.BindView; 33 | import butterknife.ButterKnife; 34 | import butterknife.OnClick; 35 | 36 | 37 | public class SkuActivity extends BaseFitsSystemWindowsActivity implements GoodsPropertyAdapter.GoodsSelectListener { 38 | private static final String TAG = "SkuActivity"; 39 | @BindView(R.id.rv_show) 40 | RecyclerView mRvShow; 41 | @BindView(R.id.tv_goods) 42 | TextView mTvGoods; 43 | StringBuilder sb = new StringBuilder(); 44 | @BindView(R.id.tv_count) 45 | TextView mTvCount; 46 | @BindView(R.id.iv) 47 | ImageView mIv; 48 | private List mAttributes; 49 | private String remind = "未选择"; 50 | private List mList = new ArrayList<>(); 51 | private List mStockGoods; 52 | 53 | @Override 54 | protected int getLayoutId() { 55 | return R.layout.activity_sku; 56 | } 57 | 58 | @Override 59 | protected String setTitle() { 60 | return "SKU"; 61 | } 62 | 63 | @Override 64 | protected void initView() { 65 | mToolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); 66 | init(); 67 | // 水印 68 | watermark(); 69 | } 70 | 71 | @Override 72 | protected void initData(Bundle savedInstanceState) { 73 | 74 | } 75 | 76 | private void watermark() { 77 | // TODO: 2018/5/10 0010 78 | String pic = "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=161888459,1712714238&fm=27&gp=0.jpg"; 79 | Glide.with(this).asBitmap().load(pic).into(new SimpleTarget() { 80 | @Override 81 | public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition transition) { 82 | Bitmap bitmap = createWatermark(resource, "叶应是叶" + "http://blog.csdn.net/new_one_object"); 83 | mIv.setImageBitmap(bitmap); 84 | } 85 | }); 86 | 87 | // Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_launcher); 88 | // BitmapDrawable bd = (BitmapDrawable) drawable; 89 | // Bitmap bmp = bd.getBitmap(); 90 | // Bitmap bitmap = createWatermark(bmp, "叶应是叶" + "http://blog.csdn.net/new_one_object"); 91 | // mIv.setImageBitmap(bitmap); 92 | } 93 | 94 | private Bitmap createWatermark(Bitmap bitmap, String mark) { 95 | int w = bitmap.getWidth(); 96 | int h = bitmap.getHeight(); 97 | Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 98 | Canvas canvas = new Canvas(bmp); 99 | Paint p = new Paint(); 100 | // 水印颜色 101 | p.setColor(Color.YELLOW); 102 | // 水印字体大小 103 | p.setTextSize(20); 104 | //抗锯齿 105 | p.setAntiAlias(true); 106 | //绘制图像 107 | canvas.drawBitmap(bitmap, 0, 0, p); 108 | //绘制文字 109 | canvas.drawText(mark, 0, h / 2, p); 110 | canvas.save(Canvas.ALL_SAVE_FLAG); 111 | canvas.restore(); 112 | return bmp; 113 | } 114 | 115 | private void init() { 116 | Gson gson = new Gson(); 117 | GoodsPropertyBean bean = gson.fromJson(getString(R.string.jsonData), GoodsPropertyBean.class); 118 | mAttributes = bean.getAttributes(); 119 | mStockGoods = bean.getStockGoods(); 120 | GoodsPropertyAdapter adapter = new GoodsPropertyAdapter(mAttributes, mStockGoods, this, R.layout.item_goods); 121 | mRvShow.setLayoutManager(new LinearLayoutManager(this)); 122 | mRvShow.setAdapter(adapter); 123 | adapter.setGoodsSelectListener(this); 124 | 125 | sb.append("商品属性"); 126 | for (GoodsPropertyBean.AttributesBean attribute : mAttributes) { 127 | String tabName = attribute.getTabName(); 128 | sb.append(" ").append(tabName).append(" : ").append(remind); 129 | } 130 | mTvGoods.setText(sb.toString()); 131 | } 132 | 133 | @Override 134 | public void select(HashMap sam) { 135 | mList.clear(); 136 | sb.setLength(0); 137 | sb.append("商品属性"); 138 | for (int i = 0; i < mAttributes.size(); i++) { 139 | GoodsPropertyBean.AttributesBean attributesBean = mAttributes.get(i); 140 | String tabName = attributesBean.getTabName(); 141 | String title = sam.get(i); 142 | if (TextUtils.isEmpty(title)) { 143 | title = remind; 144 | } else { 145 | mList.add(title); 146 | } 147 | sb.append(" ").append(tabName).append(" : ").append(title); 148 | } 149 | mTvGoods.setText(sb.toString()); 150 | Log.d(TAG, "select: " + sam.toString()); 151 | // TODO: 2018/5/7 0007 如果都选择了 152 | if (!sb.toString().contains(remind)) { 153 | int goodsID = -1; 154 | int count = -1; 155 | for (GoodsPropertyBean.StockGoodsBean stockGood : mStockGoods) { 156 | List goodsInfo = stockGood.getGoodsInfo(); 157 | boolean flag = false; 158 | for (int i = 0; i < goodsInfo.size(); i++) { 159 | GoodsPropertyBean.StockGoodsBean.GoodsInfoBean goodsInfoBean = goodsInfo.get(i); 160 | if (!mList.contains(goodsInfoBean.getTabValue())) { 161 | break; 162 | } 163 | if (i == goodsInfo.size() - 1) { 164 | flag = true; 165 | } 166 | if (flag) { 167 | goodsID = stockGood.getGoodsID(); 168 | count = stockGood.getGoodsCount(); 169 | } 170 | } 171 | } 172 | mTvCount.setText("商品数量:" + count + "\t商品id" + goodsID); 173 | } else { 174 | mTvCount.setText("商品数量"); 175 | } 176 | } 177 | 178 | @OnClick(R.id.btn_order) 179 | public void onViewClicked() { 180 | String title = mTvGoods.getText().toString(); 181 | if (title.contains(remind)) { 182 | ToastUtil.showToast(App.getApp(), "请选择商品"); 183 | } else 184 | ToastUtil.showToast(App.getApp(), "下单成功"); 185 | } 186 | 187 | @Override 188 | protected void onCreate(Bundle savedInstanceState) { 189 | super.onCreate(savedInstanceState); 190 | // TODO: add setContentView(...) invocation 191 | ButterKnife.bind(this); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/activity/SteamActivity.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.activity; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.google.gson.Gson; 12 | import com.gwb.superrecycleview.R; 13 | import com.gwb.superrecycleview.adapter.GoodsPropertyAdapter; 14 | import com.gwb.superrecycleview.entity.GoodsPropertyBean; 15 | import com.gwb.superrecycleview.ui.BaseActivity; 16 | import com.gwb.superrecycleview.ui.BaseFitsSystemWindowsActivity; 17 | import com.gwb.superrecycleview.ui.wedgit.FlowLayout; 18 | 19 | import java.util.List; 20 | import java.util.Random; 21 | 22 | import butterknife.BindView; 23 | import butterknife.ButterKnife; 24 | 25 | public class SteamActivity extends BaseFitsSystemWindowsActivity { 26 | 27 | @BindView(R.id.fl) 28 | FlowLayout mFl; 29 | private String[] arr = {"京东", "淘宝", "阿里巴巴", "dnf", "神舟七号", "外卖小哥", "马云???"}; 30 | 31 | @Override 32 | protected int getLayoutId() { 33 | return R.layout.activity_steam; 34 | } 35 | 36 | @Override 37 | protected String setTitle() { 38 | return "Steam"; 39 | } 40 | 41 | @Override 42 | protected void initView() { 43 | mToolbar.setBackgroundColor(getResources().getColor(R.color.colorAccent)); 44 | for (int i = 0; i < 20; i++) { 45 | Random random = new Random(); 46 | TextView view = getView(arr[random.nextInt(arr.length)]); 47 | mFl.addView(view); 48 | } 49 | } 50 | 51 | @Override 52 | protected void initData(Bundle savedInstanceState) { 53 | 54 | } 55 | 56 | public TextView getView(String msg) { 57 | TextView tv = new TextView(this); 58 | ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 59 | lp.topMargin = 10; 60 | lp.leftMargin = 10; 61 | lp.rightMargin = 10; 62 | lp.bottomMargin = 10; 63 | tv.setPadding(10, 10, 10, 10); 64 | tv.setLayoutParams(lp); 65 | tv.setTextSize(16); 66 | tv.setText(msg); 67 | tv.setBackgroundColor(getRandomColor()); 68 | tv.setTextColor(getRandomColor()); 69 | return tv; 70 | } 71 | 72 | 73 | public int getRandomColor() { 74 | Random random = new Random(); 75 | String r = Integer.toHexString(random.nextInt(256)).toUpperCase(); 76 | String g = Integer.toHexString(random.nextInt(256)).toUpperCase(); 77 | String b = Integer.toHexString(random.nextInt(256)).toUpperCase(); 78 | 79 | r = r.length() == 1 ? "0" + r : r; 80 | g = g.length() == 1 ? "0" + g : g; 81 | b = b.length() == 1 ? "0" + b : b; 82 | int color = Color.parseColor("#" + r + g + b); 83 | return color; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/dialog/BaseDialog.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.dialog; 2 | 3 | import android.app.Activity; 4 | import android.app.DialogFragment; 5 | import android.app.FragmentManager; 6 | import android.content.Context; 7 | import android.graphics.Color; 8 | import android.graphics.drawable.ColorDrawable; 9 | import android.os.Bundle; 10 | import android.os.Handler; 11 | import android.os.Message; 12 | import android.support.annotation.Nullable; 13 | import android.view.Gravity; 14 | import android.view.LayoutInflater; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.view.Window; 18 | import android.view.WindowManager; 19 | 20 | import butterknife.ButterKnife; 21 | 22 | /** 23 | * Created by ${GongWenbo} on 2018/4/2 0002. 24 | */ 25 | 26 | public abstract class BaseDialog extends DialogFragment { 27 | 28 | private static final int TIME = 600; 29 | protected View mView; 30 | protected Activity mActivity; 31 | private BaseDialogListener mBaseDialogListener; 32 | private Handler mHandler = new Handler() { 33 | @Override 34 | public void handleMessage(Message msg) { 35 | super.handleMessage(msg); 36 | dismiss(); 37 | if (mBaseDialogListener != null) { 38 | mBaseDialogListener.dismiss(); 39 | } 40 | } 41 | }; 42 | 43 | @Override 44 | public void onStart() { 45 | super.onStart(); 46 | Window window = getDialog().getWindow(); 47 | WindowManager.LayoutParams windowAttributes = window.getAttributes(); 48 | windowAttributes.dimAmount = setAlpha(); 49 | window.setGravity(setGravity()); 50 | window.setAttributes(windowAttributes); 51 | } 52 | 53 | /** 54 | * 位置 55 | * 56 | * @return 57 | */ 58 | public int setGravity() { 59 | return Gravity.CENTER; 60 | } 61 | 62 | /** 63 | * 如果要设置阴影 64 | * 65 | * @return 66 | */ 67 | public float setAlpha() { 68 | return 0.0f; 69 | } 70 | 71 | @Nullable 72 | @Override 73 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { 74 | getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);//设置dialog没有title 75 | getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 76 | getDialog().getWindow().setDimAmount(0f); 77 | mView = inflater.inflate(getLayoutId(), container, false); 78 | ButterKnife.bind(this, mView); 79 | init(); 80 | return mView; 81 | } 82 | 83 | @Override 84 | public void onAttach(Activity context) { 85 | super.onAttach(context); 86 | mActivity = context; 87 | } 88 | 89 | protected abstract void init(); 90 | 91 | protected abstract int getLayoutId(); 92 | 93 | @Override 94 | public void onResume() { 95 | super.onResume(); 96 | getDialog().getWindow().setLayout(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT); 97 | } 98 | 99 | public void show(FragmentManager manager, String tag) { 100 | show(manager, tag, false); 101 | } 102 | 103 | public void show(FragmentManager manager, String tag, boolean autoHide) { 104 | if (autoHide) { 105 | mHandler.sendEmptyMessageDelayed(0, TIME); 106 | } 107 | super.show(manager, tag); 108 | } 109 | 110 | public void setBaseDialogListener(BaseDialogListener baseDialogListener) { 111 | mBaseDialogListener = baseDialogListener; 112 | } 113 | 114 | public interface BaseDialogListener { 115 | void dismiss(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/dialog/ClearShoppingCartDialog.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.dialog; 2 | 3 | import android.view.View; 4 | import android.view.WindowManager; 5 | 6 | import com.gwb.superrecycleview.R; 7 | import com.gwb.superrecycleview.utils.ToastUtil; 8 | 9 | import butterknife.OnClick; 10 | 11 | /** 12 | * Created by ${GongWenbo} on 2018/5/22 0022. 13 | */ 14 | public class ClearShoppingCartDialog extends BaseDialog { 15 | 16 | private ShoppingCartDialogListener mShoppingCartDialogListener; 17 | 18 | @Override 19 | protected void init() { 20 | 21 | } 22 | 23 | @Override 24 | public float setAlpha() { 25 | return 0.4f; 26 | } 27 | 28 | @Override 29 | protected int getLayoutId() { 30 | return R.layout.dialog_clear_shopping_cart; 31 | } 32 | 33 | @OnClick({R.id.tv_shopping_cart_clear, R.id.tv_shopping_cart_cancel}) 34 | public void onViewClicked(View view) { 35 | switch (view.getId()) { 36 | case R.id.tv_shopping_cart_clear: 37 | if (mShoppingCartDialogListener != null) { 38 | mShoppingCartDialogListener.clear(); 39 | } 40 | dismiss(); 41 | break; 42 | case R.id.tv_shopping_cart_cancel: 43 | dismiss(); 44 | break; 45 | } 46 | } 47 | 48 | public void setShoppingCartDialogListener(ShoppingCartDialogListener shoppingCartDialogListener) { 49 | mShoppingCartDialogListener = shoppingCartDialogListener; 50 | } 51 | 52 | public interface ShoppingCartDialogListener { 53 | 54 | void clear(); 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/dialog/DiscountCouponDialog.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.dialog; 2 | 3 | import com.gwb.superrecycleview.R; 4 | 5 | /** 6 | * Created by ${GongWenbo} on 2018/5/23 0023. 7 | */ 8 | public class DiscountCouponDialog extends BaseDialog { 9 | 10 | @Override 11 | protected void init() { 12 | setCancelable(false); 13 | } 14 | 15 | @Override 16 | protected int getLayoutId() { 17 | return R.layout.dialog_discount_coupon; 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/dialog/ShoppingCartDialog.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.dialog; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ObjectAnimator; 6 | import android.content.Context; 7 | import android.os.Bundle; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.util.DisplayMetrics; 11 | import android.view.Gravity; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.view.WindowManager; 15 | import android.widget.LinearLayout; 16 | import android.widget.TextView; 17 | 18 | import com.gwb.superrecycleview.R; 19 | import com.gwb.superrecycleview.adapter.BaseAdapter; 20 | import com.gwb.superrecycleview.adapter.BaseViewHolder; 21 | import com.gwb.superrecycleview.entity.ShopGoodsBean; 22 | import com.gwb.superrecycleview.utils.ToastUtil; 23 | import com.scwang.smartrefresh.layout.util.DensityUtil; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import butterknife.BindView; 29 | import butterknife.OnClick; 30 | 31 | /** 32 | * Created by ${GongWenbo} on 2018/5/22 0022. 33 | */ 34 | public class ShoppingCartDialog extends BaseDialog implements BaseAdapter.BaseAdapterListener { 35 | public static final String CART_GOODS = "cartGoods"; 36 | private static final long TIME = 300; // 动画的时间 37 | @BindView(R.id.rv_cart_goods) 38 | RecyclerView mRvCartGoods; 39 | List list = new ArrayList<>(); 40 | @BindView(R.id.tv_shopping_cart_count) 41 | TextView mTvShoppingCartCount; 42 | @BindView(R.id.ll_shopping_cart) 43 | LinearLayout mLlShoppingCart; 44 | private BaseAdapter mAdapter; 45 | private int allCount; 46 | private CartGoodsDialogListener mCartGoodsDialogListener; 47 | private int mHeightPixels; 48 | 49 | @Override 50 | protected void init() { 51 | initData(); 52 | initAdapter(); 53 | initScreen(); 54 | // 打开的动画 55 | openAnim(); 56 | } 57 | 58 | private void initData() { 59 | Bundle bundle = getArguments(); 60 | if (bundle != null) { 61 | List cartGoodsList = (List) bundle.getSerializable(CART_GOODS); 62 | // 将没有个数的商品移除,只是为了模拟数据,网络数据看情况 63 | for (int i = 0; i < cartGoodsList.size(); i++) { 64 | ShopGoodsBean shopGoodsBean = cartGoodsList.get(i); 65 | int count = shopGoodsBean.getCount(); 66 | if (count != 0) { 67 | list.add(shopGoodsBean); 68 | allCount += count; 69 | } 70 | } 71 | } 72 | // 如果个数大于0,那么要显示商品数 73 | if (allCount > 0) { 74 | mTvShoppingCartCount.setVisibility(View.VISIBLE); 75 | mTvShoppingCartCount.setText(String.valueOf(allCount)); 76 | } 77 | } 78 | 79 | private void initScreen() { 80 | WindowManager wm = (WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE); 81 | DisplayMetrics dm = new DisplayMetrics(); 82 | wm.getDefaultDisplay().getMetrics(dm); 83 | // 获取屏幕的高度 84 | mHeightPixels = dm.heightPixels; 85 | } 86 | 87 | public void openAnim() { 88 | ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mLlShoppingCart, "translationY", mHeightPixels, 0); 89 | objectAnimator.setDuration(TIME); 90 | objectAnimator.start(); 91 | } 92 | 93 | public void closeAnim() { 94 | ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mLlShoppingCart, "translationY", 0, mHeightPixels); 95 | objectAnimator.setDuration(TIME); 96 | objectAnimator.start(); 97 | objectAnimator.addListener(new AnimatorListenerAdapter() { 98 | @Override 99 | public void onAnimationEnd(Animator animation) { 100 | super.onAnimationEnd(animation); 101 | dismiss(); 102 | } 103 | }); 104 | } 105 | 106 | private void initAdapter() { 107 | // 如果商品个数大于指定数时,高度写死,其他wrap_content 108 | if (list.size() >= 4) { 109 | ViewGroup.LayoutParams lp = mRvCartGoods.getLayoutParams(); 110 | lp.width = ViewGroup.LayoutParams.MATCH_PARENT; 111 | lp.height = DensityUtil.dp2px(200); 112 | mRvCartGoods.setLayoutParams(lp); 113 | } 114 | mAdapter = new BaseAdapter(list, R.layout.item_cart_goods, this); 115 | mRvCartGoods.setLayoutManager(new LinearLayoutManager(mActivity)); 116 | mRvCartGoods.setAdapter(mAdapter); 117 | } 118 | 119 | @Override 120 | protected int getLayoutId() { 121 | return R.layout.dialog_shopping_cart; 122 | } 123 | 124 | @Override 125 | public float setAlpha() { 126 | return 0.3f; 127 | } 128 | 129 | @Override 130 | public int setGravity() { 131 | return Gravity.BOTTOM; 132 | } 133 | 134 | @Override 135 | public void onResume() { 136 | super.onResume(); 137 | getDialog().getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT); 138 | } 139 | 140 | @OnClick({R.id.view_shadow, R.id.ll_cart_goods_clear, R.id.tv_shopping_cart_pay}) 141 | public void onViewClicked(View view) { 142 | switch (view.getId()) { 143 | // 点击阴影消失 144 | case R.id.view_shadow: 145 | closeAnim(); 146 | break; 147 | // 清空购物车 148 | case R.id.ll_cart_goods_clear: 149 | if (allCount > 0) { 150 | clearCartGoodsDialog(); 151 | }else { 152 | ToastUtil.showToast(mActivity, "购物车中空空如也"); 153 | } 154 | break; 155 | // 去支付 156 | case R.id.tv_shopping_cart_pay: 157 | pay(); 158 | break; 159 | } 160 | } 161 | 162 | public void pay() { 163 | String remind = "购物车中空空如也"; 164 | if (allCount > 0) { 165 | remind = "去支付"; 166 | } 167 | ToastUtil.showToast(mActivity, remind); 168 | } 169 | 170 | public void clearCartGoodsDialog() { 171 | ClearShoppingCartDialog dialog = new ClearShoppingCartDialog(); 172 | dialog.show(getFragmentManager(), "shoppingCart"); 173 | dialog.setShoppingCartDialogListener(new ClearShoppingCartDialog.ShoppingCartDialogListener() { 174 | @Override 175 | public void clear() { 176 | list.clear(); 177 | mAdapter.notifyDataSetChanged(); 178 | if (mCartGoodsDialogListener != null) { 179 | mCartGoodsDialogListener.clear(); 180 | allCount = 0; 181 | mTvShoppingCartCount.setVisibility(View.GONE); 182 | } 183 | dismiss(); 184 | } 185 | }); 186 | } 187 | 188 | @Override 189 | public void convert(final BaseViewHolder holder, final ShopGoodsBean shopGoodsBean) { 190 | // 商品名 191 | holder.setTitle(R.id.tv_cart_goods_title, shopGoodsBean.getGoods()); 192 | // 添加 193 | holder.getView(R.id.iv_cart_goods_add).setOnClickListener(new View.OnClickListener() { 194 | @Override 195 | public void onClick(View v) { 196 | int count = shopGoodsBean.getCount(); 197 | count++; 198 | allCount++; 199 | shopGoodsBean.setCount(count); 200 | holder.setTitle(R.id.tv_cart_goods_count, String.valueOf(count)); 201 | mTvShoppingCartCount.setText(String.valueOf(allCount)); 202 | if (mCartGoodsDialogListener != null) { 203 | mCartGoodsDialogListener.add(allCount, shopGoodsBean); 204 | } 205 | } 206 | }); 207 | // 减少 208 | holder.getView(R.id.iv_cart_goods_reduce).setOnClickListener(new View.OnClickListener() { 209 | @Override 210 | public void onClick(View v) { 211 | int count = shopGoodsBean.getCount(); 212 | count--; 213 | allCount--; 214 | if (count == 0) { 215 | int layoutPosition = holder.getLayoutPosition(); 216 | list.remove(layoutPosition); 217 | mAdapter.notifyItemRemoved(layoutPosition); 218 | } else { 219 | holder.setTitle(R.id.tv_cart_goods_count, String.valueOf(count)); 220 | } 221 | shopGoodsBean.setCount(count); 222 | // 防止点击过快 223 | if (allCount <= 0) { 224 | allCount = 0; 225 | mTvShoppingCartCount.setVisibility(View.GONE); 226 | } 227 | mTvShoppingCartCount.setText(String.valueOf(allCount)); 228 | if (mCartGoodsDialogListener != null) { 229 | mCartGoodsDialogListener.reduce(allCount, shopGoodsBean); 230 | } 231 | } 232 | }); 233 | // 数量 234 | holder.setTitle(R.id.tv_cart_goods_count, String.valueOf(shopGoodsBean.getCount())); 235 | } 236 | 237 | public void setCartGoodsDialogListener(CartGoodsDialogListener cartGoodsDialogListener) { 238 | mCartGoodsDialogListener = cartGoodsDialogListener; 239 | } 240 | 241 | public interface CartGoodsDialogListener { 242 | 243 | void add(int allCount, ShopGoodsBean shopGoodsBean); 244 | 245 | void reduce(int allCount, ShopGoodsBean shopGoodsBean); 246 | 247 | void clear(); 248 | 249 | } 250 | 251 | } 252 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/wedgit/ArrowDrawable.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.wedgit; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Path; 5 | import android.graphics.Rect; 6 | import android.graphics.drawable.Drawable; 7 | import android.support.annotation.NonNull; 8 | 9 | import com.scwang.smartrefresh.layout.internal.PaintDrawable; 10 | 11 | /** 12 | * 箭头图像 13 | * Created by SCWANG on 2018/2/5. 14 | */ 15 | 16 | public class ArrowDrawable extends PaintDrawable { 17 | 18 | private int mWidth = 0; 19 | private int mHeight = 0; 20 | private Path mPath = new Path(); 21 | 22 | @Override 23 | public void draw(@NonNull Canvas canvas) { 24 | final Drawable drawable = this; 25 | final Rect bounds = drawable.getBounds(); 26 | int width = bounds.width(); 27 | int height = bounds.height(); 28 | if (mWidth != width || mHeight != height) { 29 | int lineWidth = width * 30 / 225; 30 | mPath.reset(); 31 | 32 | float vector1 = (float) (lineWidth * Math.sin(Math.PI/4)); 33 | float vector2 = (float) (lineWidth / Math.sin(Math.PI/4)); 34 | mPath.moveTo(width / 2, height); 35 | mPath.lineTo(0, height / 2); 36 | mPath.lineTo(vector1, height / 2 - vector1); 37 | mPath.lineTo(width / 2 - lineWidth / 2, height - vector2 - lineWidth / 2); 38 | mPath.lineTo(width / 2 - lineWidth / 2, 0); 39 | mPath.lineTo(width / 2 + lineWidth / 2, 0); 40 | mPath.lineTo(width / 2 + lineWidth / 2, height - vector2 - lineWidth / 2); 41 | mPath.lineTo(width - vector1, height / 2 - vector1); 42 | mPath.lineTo(width, height / 2); 43 | mPath.close(); 44 | 45 | mWidth = width; 46 | mHeight = height; 47 | } 48 | canvas.drawPath(mPath, mPaint); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/ui/wedgit/FlowLayout.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.ui.wedgit; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.Nullable; 5 | import android.util.AttributeSet; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | public class FlowLayout extends ViewGroup { 11 | 12 | private static final String TAG = "FlowLayout"; 13 | 14 | public FlowLayout(Context context) { 15 | this(context, null); 16 | } 17 | 18 | public FlowLayout(Context context, @Nullable AttributeSet attrs) { 19 | this(context, attrs, 0); 20 | } 21 | 22 | public FlowLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 23 | super(context, attrs, defStyleAttr); 24 | } 25 | 26 | @Override 27 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 28 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 29 | int withMode = MeasureSpec.getMode(widthMeasureSpec); 30 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 31 | int withSize = MeasureSpec.getSize(widthMeasureSpec); 32 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 33 | 34 | int width = 0; 35 | int height = 0; 36 | 37 | int widthLine = 0; 38 | 39 | for (int i = 0; i < getChildCount(); i++) { 40 | View childView = getChildAt(i); 41 | childView.measure(widthMeasureSpec, heightMeasureSpec); 42 | MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams(); 43 | int childWidth = childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; 44 | int childHeight = childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; 45 | // TODO: 2018/6/11 换行 46 | if (widthLine + childWidth > withSize) { 47 | height += childHeight; 48 | width = Math.max(widthLine, width); 49 | // TODO: 2018/6/11 这边要特别注意,要在获取最大值的后面 50 | widthLine = childWidth; 51 | Log.d(TAG, "onMeasure: 换行=" + height); 52 | } else { 53 | Log.d(TAG, "onMeasure: widthLine=" + widthLine); 54 | widthLine += childWidth; 55 | } 56 | if (i == getChildCount() - 1) { 57 | width = Math.max(widthLine, width); 58 | height += childHeight; 59 | Log.d(TAG, "onMeasure: 最后一行=" + height); 60 | } 61 | } 62 | // TODO: 2018/6/19 考虑到padding的情况存在 63 | width += getPaddingLeft() + getPaddingRight(); 64 | height += getPaddingTop() + getPaddingBottom(); 65 | 66 | setMeasuredDimension(withMode == MeasureSpec.EXACTLY ? withSize : width 67 | , heightMode == MeasureSpec.EXACTLY ? heightSize : height); 68 | } 69 | 70 | @Override 71 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 72 | int top = getPaddingTop(); 73 | int left = getPaddingLeft(); 74 | int widthLine = 0; 75 | int width = getWidth(); 76 | for (int i = 0; i < getChildCount(); i++) { 77 | View childView = getChildAt(i); 78 | if (childView.getVisibility() == GONE) { 79 | continue; 80 | } 81 | MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams(); 82 | int childWidth = childView.getMeasuredWidth(); 83 | int childHeight = childView.getMeasuredHeight(); 84 | // TODO: 2018/6/16 item的宽度 85 | int tempWidth = childWidth + lp.leftMargin + lp.rightMargin; 86 | // TODO: 2018/6/16 换行 87 | if (widthLine + tempWidth > width) { 88 | left = getPaddingLeft(); 89 | top += childHeight + lp.topMargin + lp.bottomMargin; 90 | widthLine = tempWidth; 91 | } else { 92 | widthLine += tempWidth; 93 | } 94 | int lc = left + lp.leftMargin; 95 | int tc = top + lp.topMargin; 96 | int rc = lc + childWidth; 97 | int bc = tc + childHeight; 98 | childView.layout(lc, tc, rc, bc); 99 | left += childWidth + lp.rightMargin; 100 | } 101 | 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/utils/ActivityManager.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.utils; 2 | 3 | import android.app.Activity; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by ${GongWenbo} on 2018/5/23 0023. 10 | */ 11 | public class ActivityManager { 12 | 13 | private static ActivityManager sActivityManager; 14 | private List mActivities = new ArrayList<>(); 15 | 16 | private ActivityManager() { 17 | } 18 | 19 | public static ActivityManager getInstance() { 20 | if (sActivityManager == null) { 21 | synchronized (ActivityManager.class) { 22 | if (sActivityManager == null) { 23 | sActivityManager = new ActivityManager(); 24 | } 25 | } 26 | } 27 | return sActivityManager; 28 | } 29 | 30 | public List getActivities() { 31 | return mActivities; 32 | } 33 | 34 | public void addActivity(Activity activity) { 35 | mActivities.add(activity); 36 | } 37 | 38 | public void finish(Activity activity) { 39 | mActivities.remove(activity); 40 | } 41 | 42 | public void finishAll() { 43 | for (int i = 0; i < mActivities.size(); i++) { 44 | Activity activity = mActivities.get(i); 45 | if (!activity.isFinishing()) { 46 | activity.finish(); 47 | } 48 | mActivities.remove(activity); 49 | i--; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/utils/ShoppingCartHistoryManager.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.utils; 2 | 3 | import android.os.Environment; 4 | import android.support.annotation.NonNull; 5 | 6 | 7 | import com.gwb.superrecycleview.entity.StoreGoodsBean; 8 | 9 | import java.io.File; 10 | import java.io.FileInputStream; 11 | import java.io.FileOutputStream; 12 | import java.io.ObjectInputStream; 13 | import java.io.ObjectOutputStream; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | /** 18 | * 购物车缓存的工具类 19 | * Created by GongWenBo on 2018/5/26. 20 | */ 21 | 22 | public class ShoppingCartHistoryManager { 23 | 24 | private static final String PATH = Environment.getExternalStorageDirectory().getPath() + File.separator + "goods"; 25 | private static final String FILE_FORMAT = ".txt"; 26 | private static ShoppingCartHistoryManager sShoppingCartHistoryManager; 27 | 28 | private ShoppingCartHistoryManager() { 29 | 30 | } 31 | 32 | public static ShoppingCartHistoryManager getInstance() { 33 | if (sShoppingCartHistoryManager == null) { 34 | synchronized (ShoppingCartHistoryManager.class) { 35 | if (sShoppingCartHistoryManager == null) { 36 | sShoppingCartHistoryManager = new ShoppingCartHistoryManager(); 37 | } 38 | } 39 | } 40 | return sShoppingCartHistoryManager; 41 | } 42 | 43 | /** 44 | * 添加商品缓存 45 | * 46 | * @param storeId 商品的id 47 | */ 48 | public ShoppingCartHistoryManager add(String storeId, @NonNull StoreGoodsBean storeGoodsBean) { 49 | File file = new File(PATH); 50 | if (!file.exists()) { 51 | file.mkdirs(); 52 | } 53 | FileOutputStream fileOutputStream = null; 54 | ObjectOutputStream objectOutputStream = null; 55 | try { 56 | fileOutputStream = new FileOutputStream(file.getAbsolutePath() + File.separator + storeId + FILE_FORMAT); 57 | objectOutputStream = new ObjectOutputStream(fileOutputStream); 58 | objectOutputStream.writeObject(storeGoodsBean); 59 | objectOutputStream.flush(); 60 | objectOutputStream.close(); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | } 64 | return this; 65 | } 66 | 67 | /** 68 | * 得到商品缓存 69 | * 70 | * @param storeId 商铺的id 71 | */ 72 | public HashMap get(String storeId) { 73 | File file = new File(PATH); 74 | if (!file.exists()) { 75 | return null; 76 | } 77 | FileInputStream FileInputStream = null; 78 | ObjectInputStream objectInputStream = null; 79 | StoreGoodsBean storeGoodsBean = null; 80 | try { 81 | FileInputStream = new FileInputStream(file.getAbsolutePath() + File.separator + storeId + FILE_FORMAT); 82 | objectInputStream = new ObjectInputStream(FileInputStream); 83 | storeGoodsBean = (StoreGoodsBean) objectInputStream.readObject(); 84 | objectInputStream.close(); 85 | } catch (Exception e) { 86 | e.printStackTrace(); 87 | return null; 88 | } 89 | return storeGoodsBean.getHashMap(); 90 | } 91 | 92 | /** 93 | * 获取商铺选择的总个数 94 | * 95 | * @param storeId 商铺id 96 | * @return 97 | */ 98 | public int getAllGoodsCount(String storeId) { 99 | HashMap hashMap = get(storeId); 100 | int allCount = 0; 101 | if (hashMap != null) { 102 | for (Map.Entry entry : hashMap.entrySet()) { 103 | Integer value = entry.getValue(); 104 | if (value != 0) { 105 | allCount += value; 106 | } 107 | } 108 | } 109 | return allCount; 110 | } 111 | 112 | /** 113 | * 删除商铺缓存,如果数量为0 114 | * 115 | * @param storeId 商铺的id 116 | */ 117 | public ShoppingCartHistoryManager delete(@NonNull String storeId) { 118 | File file = new File(PATH, storeId + FILE_FORMAT); 119 | if (file.exists()) { 120 | file.delete(); 121 | } 122 | return this; 123 | } 124 | 125 | 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/utils/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.utils; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.os.Message; 7 | import android.widget.Toast; 8 | 9 | 10 | /** 11 | * Created by ${GongWenbo} on 2018/4/13 0013. 12 | */ 13 | 14 | public class ToastUtil { 15 | 16 | private static final String THREAD_MAIN = "main"; 17 | private static Context sContext; 18 | private static String sContent; 19 | private volatile static Toast sToast; 20 | /** 21 | * 在主线程中做操作 22 | */ 23 | private volatile static Handler mHandler = new Handler(Looper.getMainLooper()) { 24 | @Override 25 | public void handleMessage(Message msg) { 26 | super.handleMessage(msg); 27 | toast(sContext, sContent); 28 | sToast.show(); 29 | } 30 | }; 31 | 32 | public static void showToast(Context context, String content) { 33 | String name = Thread.currentThread().getName(); 34 | // 判断是否是主线程,如果不是通过handler 35 | if (!name.equals(THREAD_MAIN)) { 36 | mHandler.sendEmptyMessage(0); 37 | sContext = context; 38 | sContent = content; 39 | } else { 40 | toast(context, content); 41 | sToast.show(); 42 | } 43 | } 44 | 45 | private static void toast(Context context, String content) { 46 | if (sToast == null) { 47 | sToast = Toast.makeText(context, content, Toast.LENGTH_SHORT); 48 | } else { 49 | sToast.setText(content); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/gwb/superrecycleview/utils/Util.java: -------------------------------------------------------------------------------- 1 | package com.gwb.superrecycleview.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Paint; 5 | import android.widget.TextView; 6 | 7 | /** 8 | * Created by ${GongWenbo} on 2018/5/18 0018. 9 | */ 10 | public class Util { 11 | 12 | // 下划线 13 | public static void drawUnderline(TextView textView) { 14 | textView.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); 15 | } 16 | 17 | // 中划线 18 | public static void drawStrikethrough(TextView textView) { 19 | textView.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); 20 | } 21 | 22 | // dp2px 23 | public static int dp2px(Context context, float dpValue) { 24 | final float scale = context.getResources().getDisplayMetrics().density; 25 | return (int) (dpValue * scale + 0.5f); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/empty.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/light_gray_rectangle_7.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/lucency_black_rectangle_10.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/normal.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/pink_rectangle_right_8.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/red_circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/red_gradient_rectangle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/red_rectangle_left_8.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/select.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_header_and_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 17 | 18 | 23 | 24 |