├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── drawable-xhdpi │ │ │ │ ├── custom.png │ │ │ │ ├── follow.png │ │ │ │ ├── home_msg.png │ │ │ │ ├── shopping.png │ │ │ │ ├── home_camera.png │ │ │ │ ├── home_scan.png │ │ │ │ ├── home_search.png │ │ │ │ ├── home_top_01.png │ │ │ │ ├── home_top_02.png │ │ │ │ ├── home_top_03.png │ │ │ │ ├── home_top_04.png │ │ │ │ ├── home_top_05.png │ │ │ │ ├── home_top_06.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── icon_rate.png │ │ │ │ ├── navtab_cart.png │ │ │ │ ├── navtab_help.png │ │ │ │ ├── navtab_home.png │ │ │ │ ├── navtab_user.png │ │ │ │ ├── navtab_we.png │ │ │ │ └── enter_order_arrow.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── home_msg.png │ │ │ │ ├── home_scan.png │ │ │ │ ├── navtab_we.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── navtab_cart.png │ │ │ │ ├── navtab_help.png │ │ │ │ ├── navtab_home.png │ │ │ │ └── navtab_user.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── home_msg.png │ │ │ │ ├── home_scan.png │ │ │ │ ├── navtab_we.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── navtab_cart.png │ │ │ │ ├── navtab_help.png │ │ │ │ ├── navtab_home.png │ │ │ │ └── navtab_user.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── layout │ │ │ │ ├── item_home_type_divider.xml │ │ │ │ ├── item_place.xml │ │ │ │ ├── item_marquee.xml │ │ │ │ ├── item_footer_loading.xml │ │ │ │ ├── fragment_goods_comment.xml │ │ │ │ ├── layout_toolbar.xml │ │ │ │ ├── fragment_navigation_we.xml │ │ │ │ ├── fragment_navigation_cart.xml │ │ │ │ ├── fragment_navigation_help.xml │ │ │ │ ├── fragment_navigation_home.xml │ │ │ │ ├── fragment_navigation_user.xml │ │ │ │ ├── item_goods_desc_picture.xml │ │ │ │ ├── fragment_goods_desc.xml │ │ │ │ ├── item_goods_desc.xml │ │ │ │ ├── item_home_type_carousel.xml │ │ │ │ ├── item_home_type_live.xml │ │ │ │ ├── layout_loading_more.xml │ │ │ │ ├── item_home_type_header.xml │ │ │ │ ├── item_home_type_headline.xml │ │ │ │ ├── layout_goods_detail_bottom.xml │ │ │ │ ├── item_home_type_hot.xml │ │ │ │ ├── item_home_type_recommend.xml │ │ │ │ ├── item_goods_comment.xml │ │ │ │ ├── activity_main.xml │ │ │ │ ├── activity_detail.xml │ │ │ │ ├── fragment_navigation_home_category.xml │ │ │ │ └── layout_goods_detail_top.xml │ │ │ ├── drawable │ │ │ │ └── rating_bar_result.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ └── values │ │ │ │ ├── integers.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── strings.xml │ │ │ │ ├── styles.xml │ │ │ │ ├── vpi_defaults.xml │ │ │ │ └── attrs.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── smile │ │ │ │ └── taobaodemo │ │ │ │ ├── base │ │ │ │ ├── BaseView.java │ │ │ │ ├── BasePresenter.java │ │ │ │ ├── BundleKey.java │ │ │ │ ├── Constants.java │ │ │ │ └── Type.java │ │ │ │ ├── model │ │ │ │ ├── LoadModel.java │ │ │ │ ├── HomeLoadModel.java │ │ │ │ └── entity │ │ │ │ │ ├── HomeBottom.java │ │ │ │ │ ├── HomeTop.java │ │ │ │ │ ├── DescBase.java │ │ │ │ │ ├── CommentBase.java │ │ │ │ │ ├── HomeBase.java │ │ │ │ │ └── LivePlay.java │ │ │ │ ├── widget │ │ │ │ ├── StatusBarView.java │ │ │ │ ├── glide │ │ │ │ │ ├── GlideConfiguration.java │ │ │ │ │ ├── GlideCircleTransform.java │ │ │ │ │ └── GlideRoundTransform.java │ │ │ │ ├── PageIndicator.java │ │ │ │ ├── FooterLoading.java │ │ │ │ ├── GradientScrollView.java │ │ │ │ ├── LoadMoreRecyclerView.java │ │ │ │ └── RecycleBin.java │ │ │ │ ├── presenter │ │ │ │ ├── OnLoadListener.java │ │ │ │ └── HomePresenter.java │ │ │ │ ├── utils │ │ │ │ ├── ToastUtil.java │ │ │ │ ├── FileUtil.java │ │ │ │ ├── NetWorkUtil.java │ │ │ │ ├── DateFormatUtil.java │ │ │ │ └── GlideUtil.java │ │ │ │ ├── contract │ │ │ │ └── HomeContract.java │ │ │ │ ├── ui │ │ │ │ ├── fragment │ │ │ │ │ ├── NavMyFragment.java │ │ │ │ │ ├── NavWeFragment.java │ │ │ │ │ ├── NavCartFragment.java │ │ │ │ │ ├── NavHelpFragment.java │ │ │ │ │ ├── GoodsDescFragment.java │ │ │ │ │ ├── GoodsCommentFragment.java │ │ │ │ │ └── NavHomeFragment.java │ │ │ │ ├── adapter │ │ │ │ │ ├── ViewPagerAdapter.java │ │ │ │ │ ├── ImageHomeAdapter.java │ │ │ │ │ ├── GoodsDescAdapter.java │ │ │ │ │ ├── GoodsDetailPagerAdapter.java │ │ │ │ │ ├── GoodsCommentAdapter.java │ │ │ │ │ ├── RecyclingPagerAdapter.java │ │ │ │ │ └── HomeAdapter.java │ │ │ │ └── activity │ │ │ │ │ ├── DetailActivity.java │ │ │ │ │ └── MainActivity.java │ │ │ │ └── okhttp │ │ │ │ ├── OkCallback.java │ │ │ │ └── OkHttp.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── smile │ │ │ └── taobaodemo │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── smile │ │ └── taobaodemo │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── demo01.gif ├── demo02.gif ├── .idea ├── copyright │ └── profiles_settings.xml ├── markdown-navigator │ └── profiles_settings.xml ├── encodings.xml ├── vcs.xml ├── modules.xml ├── runConfigurations.xml ├── gradle.xml ├── compiler.xml ├── misc.xml └── markdown-navigator.xml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── README.md ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /demo01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/demo01.gif -------------------------------------------------------------------------------- /demo02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/demo02.gif -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/custom.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/follow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/follow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_msg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_msg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/shopping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/shopping.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_camera.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_scan.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_top_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_top_01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_top_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_top_02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_top_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_top_03.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_top_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_top_04.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_top_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_top_05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/home_top_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/home_top_06.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_rate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/icon_rate.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/navtab_cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/navtab_cart.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/navtab_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/navtab_help.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/navtab_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/navtab_home.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/navtab_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/navtab_user.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/navtab_we.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/navtab_we.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/home_msg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxhdpi/home_msg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/home_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxhdpi/home_scan.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/navtab_we.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxhdpi/navtab_we.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/home_msg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxxhdpi/home_msg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/home_scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxxhdpi/home_scan.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/navtab_we.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxxhdpi/navtab_we.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/navtab_cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxhdpi/navtab_cart.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/navtab_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxhdpi/navtab_help.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/navtab_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxhdpi/navtab_home.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/navtab_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxhdpi/navtab_user.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/navtab_cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxxhdpi/navtab_cart.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/navtab_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxxhdpi/navtab_help.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/navtab_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxxhdpi/navtab_home.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/navtab_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xxxhdpi/navtab_user.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/enter_order_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/HEAD/app/src/main/res/drawable-xhdpi/enter_order_arrow.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | test 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/base/BaseView.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.base; 2 | 3 | /** 4 | * @author Smile Wei 5 | * @since 2016/8/15. 6 | */ 7 | public interface BaseView { 8 | void initView(); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/base/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.base; 2 | 3 | /** 4 | * @author Smile Wei 5 | * @since 2016/8/15. 6 | */ 7 | public interface BasePresenter { 8 | void start(); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/base/BundleKey.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.base; 2 | 3 | /** 4 | * @author Smile Wei 5 | * @since 2017/12/26. 6 | */ 7 | 8 | public class BundleKey { 9 | 10 | public static final String PARCELABLE = "parcelable"; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_type_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Dec 13 17:02:27 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/model/LoadModel.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.model; 2 | 3 | import com.smile.taobaodemo.presenter.OnLoadListener; 4 | 5 | /** 6 | * @author Smile Wei 7 | * @since 2016/7/26. 8 | */ 9 | public interface LoadModel { 10 | void load(OnLoadListener listener); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/base/Constants.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.base; 2 | 3 | /** 4 | * @author Smile Wei 5 | * @since 2017/3/2. 6 | */ 7 | 8 | public class Constants { 9 | 10 | /** 11 | * 缓存文件保存路径 12 | */ 13 | public static final String CACHE_FILE_PATH = "/smile/cache/"; 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_place.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/base/Type.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.base; 2 | 3 | /** 4 | * @author Smile Wei 5 | * @since 2017/3/2. 6 | */ 7 | 8 | public class Type { 9 | 10 | public final static int TYPE_SHOW = 0; 11 | public final static int TYPE_FOOTER_LOAD = 1; 12 | public final static int TYPE_FOOTER_FULL = 2; 13 | } 14 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_marquee.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rating_bar_result.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/widget/StatusBarView.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.View; 6 | 7 | public class StatusBarView extends View { 8 | public StatusBarView(Context context, AttributeSet attrs) { 9 | super(context, attrs); 10 | } 11 | 12 | public StatusBarView(Context context) { 13 | super(context); 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/item_footer_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/test/java/com/smile/taobaodemo/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_goods_comment.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/presenter/OnLoadListener.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.presenter; 2 | 3 | /** 4 | * @author Smile Wei 5 | * @since 2016/7/26. 6 | * 在Presenter层实现,给Model层回调,更改View层的状态,确保Model层不直接操作View层 7 | */ 8 | public interface OnLoadListener { 9 | 10 | /** 11 | * 成功时的回调 12 | * 13 | * @param success 成功信息 14 | */ 15 | void onSuccess(T success); 16 | 17 | /** 18 | * 失败时的回调 19 | * 20 | * @param msg 错误信息 21 | */ 22 | void onError(String state, String msg); 23 | 24 | void networkError(); 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 300 4 | 5 | 20 6 | 300 7 | 8 | 1 9 | 1 10 | 11 | 12 | 6 13 | 1000 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_navigation_we.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_navigation_cart.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_navigation_help.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_navigation_home.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_navigation_user.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_goods_desc_picture.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/model/HomeLoadModel.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.model; 2 | 3 | import android.content.Context; 4 | 5 | import com.smile.taobaodemo.model.entity.HomeBottom; 6 | import com.smile.taobaodemo.model.entity.HomeTop; 7 | import com.smile.taobaodemo.presenter.OnLoadListener; 8 | 9 | /** 10 | * @author Smile Wei 11 | * @since 2016/9/22. 12 | */ 13 | 14 | public interface HomeLoadModel extends LoadModel { 15 | 16 | void load(OnLoadListener listener, Context context, int type); 17 | 18 | void load(OnLoadListener listener, Context context, int type, int page, int pageSize); 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF5000 4 | #AF3600 5 | #1DA1F2 6 | 7 | #141414 8 | #666666 9 | #FF686C 10 | #FF8E00 11 | 12 | #F0F0F0 13 | #CCC 14 | 15 | #C0C0C0 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_goods_desc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_goods_desc.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | 12dp 7 | 2dp 8 | 9 | 44dp 10 | 11 | 4dp 12 | 16dp 13 | 14 | 12dp 15 | 16 | 200dp 17 | 360dp 18 | 19 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_type_carousel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 11 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/utils/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.utils; 2 | 3 | import android.content.Context; 4 | import android.widget.Toast; 5 | 6 | /** 7 | * Toast工具类 8 | * 9 | * @author Smile Wei 10 | * @since 2013-12-13 11 | */ 12 | public class ToastUtil { 13 | 14 | /** 15 | * 显示短时间的Toast 16 | * 17 | * @param context context 18 | * @param msg 提示内容 19 | */ 20 | public static void showShortToast(Context context, String msg) { 21 | Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); 22 | } 23 | 24 | /** 25 | * 显示短时间的Toast 26 | * 27 | * @param context context 28 | * @param resId 提示内容id 29 | */ 30 | public static void showShortToast(Context context, int resId) { 31 | Toast.makeText(context, context.getString(resId), Toast.LENGTH_SHORT).show(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/contract/HomeContract.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.contract; 2 | 3 | 4 | import com.smile.taobaodemo.base.BasePresenter; 5 | import com.smile.taobaodemo.base.BaseView; 6 | import com.smile.taobaodemo.model.entity.HomeBottom; 7 | import com.smile.taobaodemo.model.entity.HomeTop; 8 | 9 | /** 10 | * @author Smile Wei 11 | * @since 2017/3/1. 12 | */ 13 | 14 | public interface HomeContract { 15 | interface View extends BaseView { 16 | void show(HomeTop bean); 17 | 18 | void show(HomeBottom bean); 19 | 20 | void loading(); 21 | 22 | void networkError(); 23 | 24 | void error(String msg); 25 | 26 | void showFailed(String msg); 27 | } 28 | 29 | interface Presenter extends BasePresenter { 30 | void start(int type); 31 | 32 | void start(int type, int page, int pageSize); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/smile/taobaodemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.smile.taobaodemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.utils; 2 | 3 | import android.os.Environment; 4 | 5 | import com.smile.taobaodemo.base.Constants; 6 | 7 | import java.io.File; 8 | 9 | /** 10 | * 文件操作类 11 | * 12 | * @author Smile Wei 13 | * @since 2014/4/4 14 | */ 15 | public class FileUtil { 16 | /** 17 | * 获取SD卡的路径 18 | * 19 | * @return sd卡路径 20 | */ 21 | public static String getSDCardBasePath() { 22 | return Environment.getExternalStorageDirectory().getPath(); 23 | } 24 | 25 | /** 26 | * 获取图片缓存的路径 27 | * 28 | * @return 图片缓存file 29 | */ 30 | public static File getCacheFolder() { 31 | String path = FileUtil.getSDCardBasePath() 32 | + Constants.CACHE_FILE_PATH; 33 | File file = new File(path); 34 | if (!file.exists()) { 35 | file.mkdirs(); 36 | } 37 | return file; 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### TaobaoDemo 2 | > **一个RecyclerView实现淘宝首页** 3 | 4 | > **使用RecyclerView的多条目布局,充分利用spanCount** 5 | 6 | 7 | ### Demo 8 | ![image](https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/master/demo01.gif) 9 | ![image](https://raw.githubusercontent.com/EasyToForget/TaobaoDemo/master/demo02.gif) 10 | 11 | 12 | ### License 13 | 14 | ``` 15 | TaobaoDemo for Android 16 | Copyright (c) 2017 Smile Wei (http://github.com/EasyToForget). 17 | 18 | Licensed under the Apache License, Version 2.0 (the "License"); 19 | you may not use this file except in compliance with the License. 20 | You may obtain a copy of the License at 21 | 22 | http://www.apache.org/licenses/LICENSE-2.0 23 | 24 | Unless required by applicable law or agreed to in writing, software 25 | distributed under the License is distributed on an "AS IS" BASIS, 26 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 27 | See the License for the specific language governing permissions and 28 | limitations under the License. 29 | ``` 30 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 手机淘宝 3 | 4 | 首页 5 | 微淘 6 | 问大家 7 | 购物车 8 | 我的淘宝 9 | 10 | 没有更多了~ 11 | 12 | 天猫 13 | 聚划算 14 | 天猫国际 15 | 外卖 16 | 天猫超市 17 | 充值中心 18 | 飞猪旅行 19 | 领金币 20 | 到家 21 | 分类 22 | 23 | 头条 24 | 25 | 网络错误 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/model/entity/HomeBottom.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.model.entity; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author Smile Wei 7 | * @since 2016/9/22. 8 | */ 9 | 10 | public class HomeBottom { 11 | private String state; 12 | private String msg; 13 | private int totalPage; 14 | private List data; 15 | 16 | public int getTotalPage() { 17 | return totalPage; 18 | } 19 | 20 | public void setTotalPage(int totalPage) { 21 | this.totalPage = totalPage; 22 | } 23 | 24 | public String getState() { 25 | return state; 26 | } 27 | 28 | public void setState(String state) { 29 | this.state = state; 30 | } 31 | 32 | public String getMsg() { 33 | return msg; 34 | } 35 | 36 | public void setMsg(String msg) { 37 | this.msg = msg; 38 | } 39 | 40 | public List getData() { 41 | return data; 42 | } 43 | 44 | public void setData(List data) { 45 | this.data = data; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/widget/glide/GlideConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.widget.glide; 2 | 3 | import android.content.Context; 4 | 5 | import com.bumptech.glide.Glide; 6 | import com.bumptech.glide.GlideBuilder; 7 | import com.bumptech.glide.load.engine.cache.DiskCache; 8 | import com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper; 9 | import com.bumptech.glide.module.GlideModule; 10 | import com.smile.taobaodemo.utils.FileUtil; 11 | 12 | /** 13 | * @author Smile Wei 14 | * @since 2016/2/25. 15 | */ 16 | public class GlideConfiguration implements GlideModule { 17 | @Override 18 | public void applyOptions(Context context, GlideBuilder builder) { 19 | if (!Glide.isSetup()) { 20 | GlideBuilder gb = new GlideBuilder(context); 21 | DiskCache cache = DiskLruCacheWrapper.get(FileUtil.getCacheFolder(), 1000 * 1024 * 1024); 22 | gb.setDiskCache(cache); 23 | Glide.setup(gb); 24 | } 25 | } 26 | 27 | @Override 28 | public void registerComponents(Context context, Glide glide) { 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_type_live.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 16 | 17 | 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/fragment/NavMyFragment.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.smile.taobaodemo.R; 11 | 12 | /** 13 | * @author Smile Wei 14 | * @since 2017/3/2. 15 | */ 16 | 17 | public class NavMyFragment extends Fragment { 18 | 19 | public static NavMyFragment newInstance() { 20 | NavMyFragment fragment = new NavMyFragment(); 21 | Bundle args = new Bundle(); 22 | fragment.setArguments(args); 23 | return fragment; 24 | } 25 | 26 | @Override 27 | public void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | } 30 | 31 | @Nullable 32 | @Override 33 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 34 | return inflater.inflate(R.layout.fragment_navigation_user, container, false); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/fragment/NavWeFragment.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.smile.taobaodemo.R; 11 | 12 | /** 13 | * @author Smile Wei 14 | * @since 2017/3/2. 15 | */ 16 | 17 | public class NavWeFragment extends Fragment { 18 | 19 | public static NavWeFragment newInstance() { 20 | NavWeFragment fragment = new NavWeFragment(); 21 | Bundle args = new Bundle(); 22 | fragment.setArguments(args); 23 | return fragment; 24 | } 25 | 26 | @Override 27 | public void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | } 30 | 31 | @Nullable 32 | @Override 33 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 34 | return inflater.inflate(R.layout.fragment_navigation_we, container, false); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/fragment/NavCartFragment.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.smile.taobaodemo.R; 11 | 12 | /** 13 | * @author Smile Wei 14 | * @since 2017/3/2. 15 | */ 16 | 17 | public class NavCartFragment extends Fragment { 18 | 19 | public static NavCartFragment newInstance() { 20 | NavCartFragment fragment = new NavCartFragment(); 21 | Bundle args = new Bundle(); 22 | fragment.setArguments(args); 23 | return fragment; 24 | } 25 | 26 | @Override 27 | public void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | } 30 | 31 | @Nullable 32 | @Override 33 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 34 | return inflater.inflate(R.layout.fragment_navigation_cart, container, false); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/fragment/NavHelpFragment.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.smile.taobaodemo.R; 11 | 12 | /** 13 | * @author Smile Wei 14 | * @since 2017/3/2. 15 | */ 16 | 17 | public class NavHelpFragment extends Fragment { 18 | 19 | public static NavHelpFragment newInstance() { 20 | NavHelpFragment fragment = new NavHelpFragment(); 21 | Bundle args = new Bundle(); 22 | fragment.setArguments(args); 23 | return fragment; 24 | } 25 | 26 | @Override 27 | public void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | } 30 | 31 | @Nullable 32 | @Override 33 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 34 | return inflater.inflate(R.layout.fragment_navigation_help, container, false); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_loading_more.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 20 | 21 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/widget/PageIndicator.java: -------------------------------------------------------------------------------- 1 | 2 | package com.smile.taobaodemo.widget; 3 | 4 | import android.support.v4.view.ViewPager; 5 | 6 | /** 7 | * A PageIndicator is responsible to show an visual indicator on the total views 8 | * number and the current visible view. 9 | */ 10 | public interface PageIndicator extends ViewPager.OnPageChangeListener { 11 | /** 12 | * Bind the indicator to a ViewPager. 13 | * 14 | * @param view view 15 | */ 16 | void setViewPager(ViewPager view); 17 | 18 | /** 19 | * Bind the indicator to a ViewPager. 20 | * 21 | * @param view view 22 | * @param initialPosition position 23 | */ 24 | void setViewPager(ViewPager view, int initialPosition); 25 | 26 | /** 27 | *

Set the current page of both the ViewPager and indicator.

28 | * 29 | *

This must be used if you need to set the page before 30 | * the views are drawn on screen (e.g., default start page).

31 | * 32 | * @param item 33 | */ 34 | void setCurrentItem(int item); 35 | 36 | /** 37 | * Set a page change listener which will receive forwarded events. 38 | * 39 | * @param listener 40 | */ 41 | void setOnPageChangeListener(ViewPager.OnPageChangeListener listener); 42 | 43 | /** 44 | * Notify the indicator that the fragment list has changed. 45 | */ 46 | void notifyDataSetChanged(); 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_type_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 16 | 17 | 21 | 22 | 30 | 31 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/adapter/ViewPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.adapter; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentPagerAdapter; 6 | 7 | import com.smile.taobaodemo.ui.fragment.NavCartFragment; 8 | import com.smile.taobaodemo.ui.fragment.NavHelpFragment; 9 | import com.smile.taobaodemo.ui.fragment.NavHomeFragment; 10 | import com.smile.taobaodemo.ui.fragment.NavMyFragment; 11 | import com.smile.taobaodemo.ui.fragment.NavWeFragment; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @author Smile Wei 18 | * @since 2017/3/1. 19 | */ 20 | public class ViewPagerAdapter extends FragmentPagerAdapter { 21 | private List fragments = new ArrayList<>(); 22 | 23 | public ViewPagerAdapter(FragmentManager fm) { 24 | super(fm); 25 | 26 | fragments.clear(); 27 | fragments.add(NavHomeFragment.newInstance()); 28 | fragments.add(NavWeFragment.newInstance()); 29 | fragments.add(NavHelpFragment.newInstance()); 30 | fragments.add(NavCartFragment.newInstance()); 31 | fragments.add(NavMyFragment.newInstance()); 32 | 33 | } 34 | 35 | @Override 36 | public Fragment getItem(int position) { 37 | return fragments.get(position); 38 | } 39 | 40 | @Override 41 | public int getCount() { 42 | return fragments.size(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_type_headline.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 17 | 18 | 24 | 25 | 26 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/model/entity/HomeTop.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.model.entity; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author Smile Wei 7 | * @since 2016/9/21. 8 | */ 9 | 10 | public class HomeTop { 11 | 12 | private List carousel; 13 | private List headlines; 14 | private List list; 15 | 16 | 17 | public List getHeadlines() { 18 | return headlines; 19 | } 20 | 21 | public void setHeadlines(List headlines) { 22 | this.headlines = headlines; 23 | } 24 | 25 | 26 | public List getCarousel() { 27 | return carousel; 28 | } 29 | 30 | public void setCarousel(List carousel) { 31 | this.carousel = carousel; 32 | } 33 | 34 | public List getList() { 35 | return list; 36 | } 37 | 38 | public void setList(List list) { 39 | this.list = list; 40 | } 41 | 42 | public static class Carousel { 43 | private String url; 44 | private int id; 45 | 46 | public Carousel(int id, String url) { 47 | this.id = id; 48 | this.url = url; 49 | } 50 | 51 | public String getUrl() { 52 | return url; 53 | } 54 | 55 | public void setUrl(String url) { 56 | this.url = url; 57 | } 58 | 59 | public int getId() { 60 | return id; 61 | } 62 | 63 | public void setId(int id) { 64 | this.id = id; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/widget/FooterLoading.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.ProgressBar; 8 | import android.widget.RelativeLayout; 9 | import android.widget.TextView; 10 | 11 | import com.smile.taobaodemo.R; 12 | 13 | import butterknife.BindView; 14 | import butterknife.ButterKnife; 15 | 16 | /** 17 | * @author Smile Wei 18 | * @since 2016.08.11 19 | */ 20 | public class FooterLoading extends RelativeLayout { 21 | 22 | @BindView(R.id.loading_progress_bar) 23 | ProgressBar loadingProgressBar; 24 | @BindView(R.id.load_full) 25 | TextView loadFull; 26 | 27 | public FooterLoading(Context context, AttributeSet attrs) { 28 | super(context, attrs); 29 | initView(context); 30 | } 31 | 32 | public FooterLoading(Context context) { 33 | super(context); 34 | initView(context); 35 | } 36 | 37 | public FooterLoading(Context context, AttributeSet attrs, int defStyle) { 38 | super(context, attrs, defStyle); 39 | initView(context); 40 | } 41 | 42 | private void initView(Context context) { 43 | View view = LayoutInflater.from(context).inflate(R.layout.layout_loading_more, this, true); 44 | 45 | ButterKnife.bind(view); 46 | } 47 | 48 | public void onLoad(boolean isFull) { 49 | loadingProgressBar.setVisibility(isFull ? GONE : VISIBLE); 50 | loadFull.setVisibility(isFull ? VISIBLE : GONE); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_goods_detail_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 15 | 16 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 40 | 41 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_type_hot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 20 | 21 | 32 | 33 | 42 | 43 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/widget/GradientScrollView.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.Drawable; 6 | import android.support.v4.widget.NestedScrollView; 7 | import android.support.v7.widget.Toolbar; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import com.smile.taobaodemo.R; 12 | 13 | /** 14 | * @author Smile Wei 15 | * @since 2017/12/26. 16 | */ 17 | 18 | public class GradientScrollView extends NestedScrollView { 19 | private int headerHeight; 20 | private Toolbar toolbar; 21 | private Drawable headerDrawable; 22 | private Drawable statusBarDrawable; 23 | public GradientScrollView(Context context) { 24 | super(context); 25 | } 26 | 27 | public GradientScrollView(Context context, AttributeSet attrs) { 28 | super(context, attrs); 29 | } 30 | 31 | public GradientScrollView(Context context, AttributeSet attrs, int defStyleAttr) { 32 | super(context, attrs, defStyleAttr); 33 | } 34 | 35 | public void setHeader(Toolbar toolbar, View statusBar) { 36 | this.toolbar = toolbar; 37 | headerDrawable = toolbar.getBackground().mutate(); 38 | statusBarDrawable = statusBar.getBackground().mutate(); 39 | headerHeight = getContext().getResources().getDimensionPixelSize(R.dimen.default_scroll_gradient_height); 40 | } 41 | 42 | @Override 43 | protected void onScrollChanged(int l, int t, int oldl, int oldt) { 44 | super.onScrollChanged(l, t, oldl, oldt); 45 | float progress = (float) t / headerHeight; 46 | if (progress > 1f) progress = 1f; 47 | toolbar.setTitleTextColor(Color.argb((int) (255 * progress), 255, 255, 255)); 48 | headerDrawable.setAlpha((int) (255 * progress)); 49 | statusBarDrawable.setAlpha((int) (255 * progress)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/widget/glide/GlideCircleTransform.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.widget.glide; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapShader; 6 | import android.graphics.Canvas; 7 | import android.graphics.Paint; 8 | 9 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 10 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 11 | 12 | /** 13 | * @author Smile Wei 14 | * @since 2016/2/25. 15 | */ 16 | public class GlideCircleTransform extends BitmapTransformation { 17 | public GlideCircleTransform(Context context) { 18 | super(context); 19 | } 20 | 21 | @Override 22 | protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { 23 | return circleCrop(pool, toTransform); 24 | } 25 | 26 | private static Bitmap circleCrop(BitmapPool pool, Bitmap source) { 27 | if (source == null) return null; 28 | 29 | int size = Math.min(source.getWidth(), source.getHeight()); 30 | int x = (source.getWidth() - size) / 2; 31 | int y = (source.getHeight() - size) / 2; 32 | 33 | Bitmap squared = Bitmap.createBitmap(source, x, y, size, size); 34 | 35 | Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888); 36 | if (result == null) { 37 | result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); 38 | } 39 | 40 | Canvas canvas = new Canvas(result); 41 | Paint paint = new Paint(); 42 | paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); 43 | paint.setAntiAlias(true); 44 | float r = size / 2f; 45 | canvas.drawCircle(r, r, r, paint); 46 | return result; 47 | } 48 | 49 | @Override 50 | public String getId() { 51 | return getClass().getName(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_type_recommend.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 15 | 16 | 27 | 28 | 34 | 35 | 41 | 42 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/widget/LoadMoreRecyclerView.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.widget; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.LinearLayoutManager; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.util.AttributeSet; 7 | 8 | /** 9 | * @author Smile Wei 10 | * @since 2016.08.11 11 | */ 12 | public class LoadMoreRecyclerView extends RecyclerView { 13 | private OnLoadMoreListener loadMoreListener; 14 | 15 | private int page = 1; 16 | private int lastPage = 1; 17 | private boolean isLoading = false; 18 | 19 | public LoadMoreRecyclerView(Context context) { 20 | super(context); 21 | } 22 | 23 | public LoadMoreRecyclerView(Context context, AttributeSet attrs) { 24 | super(context, attrs); 25 | } 26 | 27 | public LoadMoreRecyclerView(Context context, AttributeSet attrs, int defStyle) { 28 | super(context, attrs, defStyle); 29 | } 30 | 31 | @Override 32 | public void onScrolled(int dx, int dy) { 33 | super.onScrolled(dx, dy); 34 | 35 | int lastVisibleItem = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition(); 36 | int totalItemCount = getLayoutManager().getItemCount(); 37 | 38 | if (lastVisibleItem == totalItemCount - 1 && dy > 0) { 39 | if (!isLoading && page < lastPage) { 40 | isLoading = true; 41 | loadMoreListener.onLoadMore(); 42 | } 43 | } 44 | } 45 | 46 | public void setLoading(boolean isLoading) { 47 | this.isLoading = isLoading; 48 | } 49 | 50 | public void setPage(int page, int lastPage) { 51 | this.page = page; 52 | this.lastPage = lastPage; 53 | } 54 | 55 | public void setOnLoadMoreListener(final OnLoadMoreListener listener) { 56 | this.loadMoreListener = listener; 57 | } 58 | 59 | public interface OnLoadMoreListener { 60 | void onLoadMore(); 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/model/entity/DescBase.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.model.entity; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | /** 7 | * @author Smile Wei 8 | * @since 2016/11/19. 9 | */ 10 | 11 | public class DescBase implements Parcelable { 12 | public static final int TYPE_DESC = 1; 13 | public static final int TYPE_TITLE = 2; 14 | public static final int TYPE_PICTURE = 3; 15 | private int type; 16 | private String name; 17 | private String url; 18 | 19 | public DescBase(int type, String name, String url){ 20 | this.type = type; 21 | this.name = name; 22 | this.url = url; 23 | } 24 | 25 | public int getType() { 26 | return type; 27 | } 28 | 29 | public void setType(int type) { 30 | this.type = type; 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | 37 | public void setName(String name) { 38 | this.name = name; 39 | } 40 | 41 | public String getUrl() { 42 | return url; 43 | } 44 | 45 | public void setUrl(String url) { 46 | this.url = url; 47 | } 48 | 49 | @Override 50 | public int describeContents() { 51 | return 0; 52 | } 53 | 54 | @Override 55 | public void writeToParcel(Parcel dest, int flags) { 56 | dest.writeInt(this.type); 57 | dest.writeString(this.name); 58 | dest.writeString(this.url); 59 | } 60 | 61 | protected DescBase(Parcel in) { 62 | this.type = in.readInt(); 63 | this.name = in.readString(); 64 | this.url = in.readString(); 65 | } 66 | 67 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 68 | @Override 69 | public DescBase createFromParcel(Parcel source) { 70 | return new DescBase(source); 71 | } 72 | 73 | @Override 74 | public DescBase[] newArray(int size) { 75 | return new DescBase[size]; 76 | } 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/widget/glide/GlideRoundTransform.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.widget.glide; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapShader; 7 | import android.graphics.Canvas; 8 | import android.graphics.Paint; 9 | import android.graphics.RectF; 10 | 11 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 12 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 13 | 14 | /** 15 | * @author Smile Wei 16 | * @since 2016/2/25. 17 | */ 18 | public class GlideRoundTransform extends BitmapTransformation { 19 | 20 | private static float radius = 0f; 21 | 22 | public GlideRoundTransform(Context context) { 23 | this(context, 4); 24 | } 25 | 26 | public GlideRoundTransform(Context context, int dp) { 27 | super(context); 28 | radius = Resources.getSystem().getDisplayMetrics().density * dp; 29 | } 30 | 31 | @Override 32 | protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { 33 | return roundCrop(pool, toTransform); 34 | } 35 | 36 | private static Bitmap roundCrop(BitmapPool pool, Bitmap source) { 37 | if (source == null) return null; 38 | 39 | Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); 40 | if (result == null) { 41 | result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); 42 | } 43 | 44 | Canvas canvas = new Canvas(result); 45 | Paint paint = new Paint(); 46 | paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); 47 | paint.setAntiAlias(true); 48 | RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight()); 49 | canvas.drawRoundRect(rectF, radius, radius, paint); 50 | return result; 51 | } 52 | 53 | @Override 54 | public String getId() { 55 | return getClass().getName() + Math.round(radius); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 1.7 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/fragment/GoodsDescFragment.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.fragment; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.os.Parcelable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.widget.GridLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import com.smile.taobaodemo.R; 14 | import com.smile.taobaodemo.model.entity.DescBase; 15 | import com.smile.taobaodemo.ui.adapter.GoodsDescAdapter; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import butterknife.BindView; 21 | import butterknife.ButterKnife; 22 | 23 | public class GoodsDescFragment extends Fragment { 24 | public static final String ARGS_DATA = "args_data"; 25 | @BindView(R.id.recycler_view) 26 | RecyclerView recyclerView; 27 | 28 | private List list = new ArrayList<>(); 29 | 30 | public static GoodsDescFragment newInstance(List bean) { 31 | GoodsDescFragment fragment = new GoodsDescFragment(); 32 | Bundle args = new Bundle(); 33 | args.putParcelableArrayList(ARGS_DATA, (ArrayList) bean); 34 | fragment.setArguments(args); 35 | return fragment; 36 | } 37 | 38 | @Override 39 | public void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | list = getArguments().getParcelableArrayList(ARGS_DATA); 42 | } 43 | 44 | @Override 45 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 46 | Bundle savedInstanceState) { 47 | View view = inflater.inflate(R.layout.fragment_goods_desc, container, false); 48 | ButterKnife.bind(this, view); 49 | initView(); 50 | return view; 51 | } 52 | 53 | private void initView() { 54 | Activity activity = getActivity(); 55 | 56 | recyclerView.setLayoutManager(new GridLayoutManager(activity, 1)); 57 | recyclerView.setAdapter(new GoodsDescAdapter(activity.getApplicationContext(), activity, list)); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/presenter/HomePresenter.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.presenter; 2 | 3 | import android.content.Context; 4 | 5 | import com.smile.taobaodemo.model.HomeLoadModel; 6 | import com.smile.taobaodemo.model.entity.HomeBottom; 7 | import com.smile.taobaodemo.model.entity.HomeTop; 8 | import com.smile.taobaodemo.model.impl.HomeModelImpl; 9 | import com.smile.taobaodemo.contract.HomeContract; 10 | 11 | /** 12 | * @author Smile Wei 13 | * @since 2017/03/01. 14 | */ 15 | 16 | public class HomePresenter implements HomeContract.Presenter { 17 | private HomeContract.View view; 18 | private HomeLoadModel loadModel; 19 | private Context context; 20 | 21 | public void init(HomeContract.View view, Context context) { 22 | loadModel = new HomeModelImpl(); 23 | this.view = view; 24 | this.context = context; 25 | this.view.initView(); 26 | } 27 | 28 | @Override 29 | public void start(int type) { 30 | view.loading(); 31 | loadModel.load(new OnLoadListener() { 32 | @Override 33 | public void onSuccess(HomeTop bean) { 34 | view.show(bean); 35 | } 36 | 37 | @Override 38 | public void onError(String state, String msg) { 39 | view.error(msg); 40 | } 41 | 42 | @Override 43 | public void networkError() { 44 | view.networkError(); 45 | } 46 | }, context, type); 47 | 48 | } 49 | 50 | @Override 51 | public void start(int type, int page, int pageSize) { 52 | view.loading(); 53 | loadModel.load(new OnLoadListener() { 54 | @Override 55 | public void onSuccess(HomeBottom success) { 56 | view.show(success); 57 | } 58 | 59 | @Override 60 | public void onError(String state, String msg) { 61 | view.error(msg); 62 | } 63 | 64 | @Override 65 | public void networkError() { 66 | view.networkError(); 67 | } 68 | }, context, type, page, pageSize); 69 | } 70 | 71 | @Override 72 | public void start() { 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | defaultConfig { 6 | applicationId "com.smile.taobaodemo" 7 | minSdkVersion 14 8 | targetSdkVersion 25 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | 13 | multiDexEnabled true 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | ext { 24 | supportLibVersion = '25.2.0' 25 | } 26 | 27 | dependencies { 28 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 29 | compile fileTree(dir: 'libs', include: ['*.jar']) 30 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 31 | exclude group: 'com.android.support', module: 'support-annotations' 32 | }) 33 | testCompile 'junit:junit:4.12' 34 | 35 | compile "com.android.support:cardview-v7:${supportLibVersion}" 36 | compile "com.android.support:appcompat-v7:${supportLibVersion}" 37 | compile "com.android.support:recyclerview-v7:${supportLibVersion}" 38 | compile "com.android.support:support-v4:${supportLibVersion}" 39 | compile "com.android.support:design:${supportLibVersion}" 40 | compile 'com.aurelhubert:ahbottomnavigation:1.3.3' 41 | compile 'com.jakewharton:butterknife:8.2.1' 42 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.2.1' 43 | compile 'com.squareup.okhttp3:okhttp:3.4.1' 44 | compile('cn.trinea.android.view.autoscrollviewpager:android-auto-scroll-view-pager:1.1.2') { 45 | exclude module: 'support-v4' 46 | } 47 | compile 'cn.trinea.android.common:trinea-android-common:4.2.15' 48 | compile 'com.oushangfeng:MarqueeLayout:1.0.4' 49 | compile 'com.github.bumptech.glide:glide:3.7.0' 50 | compile 'com.github.hotchemi:permissionsdispatcher:2.1.3' 51 | annotationProcessor 'com.github.hotchemi:permissionsdispatcher-processor:2.1.3' 52 | compile 'com.google.code.gson:gson:2.4' 53 | 54 | android { 55 | useLibrary 'org.apache.http.legacy' 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/adapter/ImageHomeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.adapter; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.smile.taobaodemo.R; 11 | import com.smile.taobaodemo.model.entity.HomeTop; 12 | import com.smile.taobaodemo.utils.GlideUtil; 13 | 14 | import java.util.List; 15 | 16 | import cn.trinea.android.common.util.ListUtils; 17 | 18 | public class ImageHomeAdapter extends RecyclingPagerAdapter { 19 | 20 | private Context context; 21 | private Activity activity; 22 | private List list; 23 | 24 | private int size; 25 | private boolean isInfiniteLoop; 26 | 27 | public ImageHomeAdapter(Context context, Activity activity, List list) { 28 | this.context = context; 29 | this.activity = activity; 30 | this.list = list; 31 | this.size = ListUtils.getSize(list); 32 | isInfiniteLoop = false; 33 | } 34 | 35 | @Override 36 | public int getCount() { 37 | return isInfiniteLoop ? Integer.MAX_VALUE : ListUtils.getSize(list); 38 | } 39 | 40 | private int getPosition(int position) { 41 | return isInfiniteLoop ? position % size : position; 42 | } 43 | 44 | @Override 45 | public View getView(final int position, View view, ViewGroup container) { 46 | ViewHolder holder; 47 | if (view == null) { 48 | holder = new ViewHolder(); 49 | view = holder.imageView = new ImageView(context); 50 | view.setTag(R.string.app_name, holder); 51 | } else { 52 | holder = (ViewHolder) view.getTag(R.string.app_name); 53 | } 54 | holder.imageView.setScaleType(ImageView.ScaleType.FIT_XY); 55 | GlideUtil.load(activity, list.get(getPosition(position)).getUrl(), holder.imageView); 56 | return view; 57 | } 58 | 59 | private static class ViewHolder { 60 | 61 | ImageView imageView; 62 | } 63 | 64 | /** 65 | * @return the isInfiniteLoop 66 | */ 67 | public boolean isInfiniteLoop() { 68 | return isInfiniteLoop; 69 | } 70 | 71 | /** 72 | * @param isInfiniteLoop the isInfiniteLoop to set 73 | */ 74 | public ImageHomeAdapter setInfiniteLoop(boolean isInfiniteLoop) { 75 | this.isInfiniteLoop = isInfiniteLoop; 76 | return this; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/utils/NetWorkUtil.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.utils; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | /** 8 | * 检测网络工具类 9 | * 包含检测网络的相关方法 10 | * 11 | * @author Smile Wei 12 | * @since 2014.4.4 13 | */ 14 | public class NetWorkUtil { 15 | /** 16 | * 检测当的网络(WIFI、4G/3G/2G)状态 17 | * 18 | * @param context context 19 | * @return boolean 20 | */ 21 | public static boolean isNetworkAvailable(Context context) { 22 | ConnectivityManager connectivityManager = (ConnectivityManager) context 23 | .getSystemService(Context.CONNECTIVITY_SERVICE); 24 | if (connectivityManager == null) { 25 | return false; 26 | } 27 | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); 28 | return !(networkInfo == null || !networkInfo.isConnected()) && networkInfo.getState() == NetworkInfo.State.CONNECTED; 29 | } 30 | 31 | /** 32 | * 检测当的网络(4G/3G/2G)状态 33 | * 34 | * @param context context 35 | * @return boolean 36 | */ 37 | public static boolean isGprsAvailable(Context context) { 38 | ConnectivityManager connectivityManager = (ConnectivityManager) context 39 | .getSystemService(Context.CONNECTIVITY_SERVICE); 40 | if (connectivityManager == null) 41 | return false; 42 | if (connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) { 43 | return false; 44 | } 45 | NetworkInfo.State state = connectivityManager.getNetworkInfo( 46 | ConnectivityManager.TYPE_MOBILE).getState(); 47 | return NetworkInfo.State.CONNECTED == state; 48 | } 49 | 50 | /** 51 | * 检测当的网络(WIFI)状态 52 | * 53 | * @param context context 54 | * @return boolean 55 | */ 56 | public static boolean isWifiAvailable(Context context) { 57 | ConnectivityManager connectivityManager = (ConnectivityManager) context 58 | .getSystemService(Context.CONNECTIVITY_SERVICE); 59 | if (connectivityManager == null) 60 | return false; 61 | if (connectivityManager 62 | .getNetworkInfo(ConnectivityManager.TYPE_WIFI) == null) { 63 | return false; 64 | } 65 | NetworkInfo.State state = connectivityManager.getNetworkInfo( 66 | ConnectivityManager.TYPE_WIFI).getState(); 67 | return NetworkInfo.State.CONNECTED == state; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/fragment/GoodsCommentFragment.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.fragment; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.os.Parcelable; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | 14 | 15 | import com.smile.taobaodemo.R; 16 | import com.smile.taobaodemo.base.Type; 17 | import com.smile.taobaodemo.model.entity.CommentBase; 18 | import com.smile.taobaodemo.ui.adapter.GoodsCommentAdapter; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import butterknife.BindView; 24 | import butterknife.ButterKnife; 25 | 26 | public class GoodsCommentFragment extends Fragment { 27 | public static final String ARGS_DATA = "args_data"; 28 | @BindView(R.id.recycler_view) 29 | RecyclerView recyclerView; 30 | 31 | private Context context; 32 | private Activity activity; 33 | private GoodsCommentAdapter adapter; 34 | private List list = new ArrayList<>(); 35 | private CommentBase footerItem = new CommentBase(); 36 | 37 | public static GoodsCommentFragment newInstance(List list) { 38 | GoodsCommentFragment fragment = new GoodsCommentFragment(); 39 | Bundle args = new Bundle(); 40 | args.putParcelableArrayList(ARGS_DATA, (ArrayList) list); 41 | fragment.setArguments(args); 42 | return fragment; 43 | } 44 | 45 | @Override 46 | public void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | list = getArguments().getParcelableArrayList(ARGS_DATA); 49 | } 50 | 51 | @Override 52 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 53 | Bundle savedInstanceState) { 54 | View view = inflater.inflate(R.layout.fragment_goods_comment, container, false); 55 | ButterKnife.bind(this, view); 56 | 57 | initView(); 58 | return view; 59 | } 60 | 61 | public void initView() { 62 | activity = getActivity(); 63 | context = activity.getApplicationContext(); 64 | footerItem.setType(Type.TYPE_FOOTER_FULL); 65 | list.add(footerItem); 66 | recyclerView.setLayoutManager(new LinearLayoutManager(activity)); 67 | adapter = new GoodsCommentAdapter(context, activity, list); 68 | recyclerView.setAdapter(adapter); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/utils/DateFormatUtil.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.utils; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.text.ParseException; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Calendar; 8 | import java.util.Date; 9 | import java.util.Locale; 10 | 11 | public class DateFormatUtil { 12 | 13 | /** 14 | * 常用时间格式 15 | */ 16 | public final static String FORMAT_yyyyMMdd_HHmmss = "yyyy-MM-dd HH:mm:ss"; 17 | public final static String FORMAT_yyyyMMdd_HHmm = "yyyy-MM-dd HH:mm"; 18 | public final static String FORMAT_yyyyMMdd = "yyyy-MM-dd"; 19 | public final static String FORMAT_yyyy_S_MM_S_dd_HHmm = "yyyy/MM/dd HH:mm"; 20 | public final static String FORMAT_yyyy_S_MM_dd = "yyyy/MM/dd"; 21 | public final static String FORMAT_MMdd_HHmm = "MM-dd HH:mm"; 22 | public final static String FORMAT_yyyy = "yyyy"; 23 | public final static String FORMAT_M = "M"; 24 | public final static String FORMAT_dd = "dd"; 25 | public final static String FORMAT_HHmmss = "HH:mm:ss"; 26 | public final static String FORMAT_HHMM = "HH:mm"; 27 | public final static String FORMAT_MMddHHmmss = "MM-dd HH:mm:ss"; 28 | 29 | /** 30 | * 时间戳单位(毫秒/秒)大于该值则为毫秒否则为秒 31 | */ 32 | private final static long SECOND_TIME = 9999999999L; 33 | 34 | /** 35 | * 根据时间戳获得指定格式日期 36 | * 37 | * @param format 时间格式 38 | * @param time 时间戳 秒 39 | * @return 日期 40 | */ 41 | public static String formatDate(final String format, final long time) { 42 | SimpleDateFormat sdf = new SimpleDateFormat(!TextUtils.isEmpty(format) ? format : FORMAT_yyyyMMdd, Locale.getDefault()); 43 | return sdf.format(new Date(SECOND_TIME < time ? time : time * 1000)); 44 | } 45 | 46 | /** 47 | * 时间字符串转换成long字符 48 | * 49 | * @param time 时间字符串,如2015/01/01 50 | */ 51 | public static long formatDate(String format, String time) { 52 | SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault()); 53 | try { 54 | Date date = sdf.parse(time); 55 | return date.getTime(); 56 | } catch (ParseException e) { 57 | e.printStackTrace(); 58 | return 0L; 59 | } 60 | } 61 | 62 | 63 | public static String getNowDateStr(int days) { 64 | SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_yyyyMMdd, 65 | Locale.getDefault()); 66 | Date dt = new Date(System.currentTimeMillis()); 67 | Calendar calendar = Calendar.getInstance(); 68 | calendar.setTime(dt); 69 | calendar.add(Calendar.DAY_OF_MONTH, days); 70 | 71 | return sdf.format(calendar.getTime()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_goods_comment.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 22 | 23 | 32 | 33 | 43 | 44 | 45 | 46 | 54 | 55 | 63 | 64 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /app/src/main/res/values/vpi_defaults.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | true 19 | #FFFFFFFF 20 | #00000000 21 | 0 22 | 3dp 23 | false 24 | #FFDDDDDD 25 | 1dp 26 | 27 | 12dp 28 | 4dp 29 | 1dp 30 | #FF33B5E5 31 | #FFBBBBBB 32 | true 33 | 34 | 4dp 35 | #FF33B5E5 36 | 2dp 37 | 2 38 | 4dp 39 | 20dp 40 | 7dp 41 | 0 42 | #FFFFFFFF 43 | true 44 | #BBFFFFFF 45 | 15dp 46 | 5dp 47 | 7dp 48 | 49 | true 50 | 300 51 | 400 52 | #FF33B5E5 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/model/entity/CommentBase.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.model.entity; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import com.smile.taobaodemo.base.Type; 7 | 8 | /** 9 | * @author Smile Wei 10 | * @since 2016/11/19. 11 | */ 12 | 13 | public class CommentBase implements Parcelable { 14 | 15 | private int type = Type.TYPE_SHOW; 16 | private String content; 17 | private int product_score; 18 | private String user_id; 19 | private long create_date; 20 | private String picture; 21 | private String user_name; 22 | 23 | public int getType() { 24 | return type; 25 | } 26 | 27 | public void setType(int type) { 28 | this.type = type; 29 | } 30 | 31 | public String getContent() { 32 | return content; 33 | } 34 | 35 | public void setContent(String content) { 36 | this.content = content; 37 | } 38 | 39 | public int getProduct_score() { 40 | return product_score; 41 | } 42 | 43 | public void setProduct_score(int product_score) { 44 | this.product_score = product_score; 45 | } 46 | 47 | public String getUser_id() { 48 | return user_id; 49 | } 50 | 51 | public void setUser_id(String user_id) { 52 | this.user_id = user_id; 53 | } 54 | 55 | public long getCreate_date() { 56 | return create_date; 57 | } 58 | 59 | public void setCreate_date(long create_date) { 60 | this.create_date = create_date; 61 | } 62 | 63 | public String getPicture() { 64 | return picture; 65 | } 66 | 67 | public void setPicture(String picture) { 68 | this.picture = picture; 69 | } 70 | 71 | public String getUser_name() { 72 | return user_name; 73 | } 74 | 75 | public void setUser_name(String user_name) { 76 | this.user_name = user_name; 77 | } 78 | 79 | @Override 80 | public int describeContents() { 81 | return 0; 82 | } 83 | 84 | @Override 85 | public void writeToParcel(Parcel dest, int flags) { 86 | dest.writeInt(this.type); 87 | dest.writeString(this.content); 88 | dest.writeInt(this.product_score); 89 | dest.writeString(this.user_id); 90 | dest.writeLong(this.create_date); 91 | dest.writeString(this.picture); 92 | dest.writeString(this.user_name); 93 | } 94 | 95 | public CommentBase() { 96 | } 97 | 98 | protected CommentBase(Parcel in) { 99 | this.type = in.readInt(); 100 | this.content = in.readString(); 101 | this.product_score = in.readInt(); 102 | this.user_id = in.readString(); 103 | this.create_date = in.readLong(); 104 | this.picture = in.readString(); 105 | this.user_name = in.readString(); 106 | } 107 | 108 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 109 | @Override 110 | public CommentBase createFromParcel(Parcel source) { 111 | return new CommentBase(source); 112 | } 113 | 114 | @Override 115 | public CommentBase[] newArray(int size) { 116 | return new CommentBase[size]; 117 | } 118 | }; 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/okhttp/OkCallback.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.okhttp; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | 7 | import org.json.JSONException; 8 | import org.json.JSONObject; 9 | 10 | import java.io.IOException; 11 | 12 | import okhttp3.Call; 13 | import okhttp3.Callback; 14 | import okhttp3.Response; 15 | 16 | /** 17 | * @author Smile Wei 18 | * @since 2016/8/2. 19 | */ 20 | public abstract class OkCallback implements Callback { 21 | private static final String SUCCESS_OK = "0000"; 22 | public static final String ERROR_0014 = "500014"; 23 | private static final String ERROR_0011 = "500011"; 24 | private static final String ERROR_1000 = "1000"; 25 | private static final String ERROR_1001 = "1001"; 26 | private static final String ERROR = "connect error"; 27 | private static final String STATE = "state"; 28 | private static final String MSG = "msg"; 29 | private static Handler handler = new Handler(Looper.getMainLooper()); 30 | 31 | @Override 32 | public void onFailure(Call call, final IOException e) { 33 | handler.post(new Runnable() { 34 | @Override 35 | public void run() { 36 | onFailure(ERROR_1000, e.getMessage()); 37 | } 38 | }); 39 | } 40 | 41 | 42 | private Context context; 43 | private boolean isJumpLogin = true; 44 | 45 | public void setContext(Context context) { 46 | this.context = context; 47 | } 48 | 49 | void setJumpLogin(boolean jumpLogin) { 50 | isJumpLogin = jumpLogin; 51 | } 52 | 53 | @Override 54 | public void onResponse(Call call, final Response response) throws IOException { 55 | try { 56 | final String res = response.body().string(); 57 | final JSONObject jsonObject = new JSONObject(res); 58 | final String status = jsonObject.getString(STATE); 59 | 60 | if (status.equals(SUCCESS_OK)) { 61 | handler.post(new Runnable() { 62 | @Override 63 | public void run() { 64 | onResponse(res); 65 | } 66 | }); 67 | return; 68 | } 69 | //如果state=0011,则是token失效,需要重新跳转到登录界面 70 | final String msg = jsonObject.getString(MSG); 71 | if (status.equals(ERROR_0011) && isJumpLogin) { 72 | handler.post(new Runnable() { 73 | @Override 74 | public void run() { 75 | onFailure(status, msg); 76 | } 77 | }); 78 | 79 | return; 80 | } 81 | handler.post(new Runnable() { 82 | @Override 83 | public void run() { 84 | onFailure(status, msg); 85 | } 86 | }); 87 | } catch (JSONException e) { 88 | handler.post(new Runnable() { 89 | @Override 90 | public void run() { 91 | //onFailure(ERROR_1001, ERROR); 92 | } 93 | }); 94 | e.printStackTrace(); 95 | } 96 | } 97 | 98 | public abstract void onResponse(String response); 99 | 100 | public abstract void onFailure(String state, String msg); 101 | 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/utils/GlideUtil.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Color; 6 | import android.widget.ImageView; 7 | 8 | import com.bumptech.glide.Glide; 9 | import com.smile.taobaodemo.R; 10 | import com.smile.taobaodemo.widget.glide.GlideCircleTransform; 11 | import com.smile.taobaodemo.widget.glide.GlideRoundTransform; 12 | 13 | /** 14 | * @author Smile Wei 15 | * @since 2016/6/7. 16 | */ 17 | public class GlideUtil { 18 | 19 | private static GlideCircleTransform circleTransform; 20 | private static GlideRoundTransform roundTransform; 21 | 22 | /** 23 | * 初始化transform 24 | * 25 | * @param context context 26 | * @return transform 27 | */ 28 | private static GlideCircleTransform transform(Context context) { 29 | if (circleTransform == null) { 30 | circleTransform = new GlideCircleTransform(context); 31 | } 32 | return circleTransform; 33 | } 34 | 35 | /** 36 | * 初始化transform 37 | * 38 | * @param context context 39 | * @return transform 40 | */ 41 | private static GlideRoundTransform transform(Context context, int dp) { 42 | if (roundTransform == null) { 43 | roundTransform = new GlideRoundTransform(context, dp); 44 | } 45 | return roundTransform; 46 | } 47 | 48 | /** 49 | * 加载圆角缩略图 50 | * 51 | * @param activity activity 52 | * @param url 头像url 53 | * @param imageView 头像view 54 | * @param dp 圆角dp 55 | */ 56 | public static void load(Context context, Activity activity, String url, ImageView imageView, int dp) { 57 | Glide.with(activity).load(url == null ? "" : url).error(R.color.bg_main_color) 58 | .placeholder(R.color.bg_main_color) 59 | .transform(transform(context, dp)) 60 | .into(imageView); 61 | } 62 | 63 | /** 64 | * 加载头像url 65 | * 66 | * @param context context 67 | * @param activity activity 68 | * @param url 头像url 69 | * @param imageView 头像view 70 | */ 71 | public static void load(Context context, Activity activity, String url, ImageView imageView) { 72 | Glide.with(activity).load(url == null ? "" : url).error(R.color.bg_main_color) 73 | .placeholder(R.color.bg_main_color) 74 | .transform(transform(context)) 75 | .into(imageView); 76 | } 77 | 78 | /** 79 | * 加载缩略图 80 | * 81 | * @param activity activity 82 | * @param url 头像url 83 | * @param imageView 头像view 84 | */ 85 | public static void load(Activity activity, String url, ImageView imageView) { 86 | Glide.with(activity).load(url == null ? "" : url).error(R.color.bg_main_color) 87 | .placeholder(R.color.bg_main_color) 88 | .into(imageView); 89 | } 90 | 91 | /** 92 | * 加载缩略图 93 | * 94 | * @param activity activity 95 | * @param url 头像url 96 | * @param imageView 头像view 97 | */ 98 | public static void loadCategory(Activity activity, String url, ImageView imageView) { 99 | Glide.with(activity).load(url == null ? "" : url).error(Color.WHITE) 100 | .placeholder(Color.WHITE) 101 | .into(imageView); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/adapter/GoodsDescAdapter.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.adapter; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.smile.taobaodemo.R; 13 | import com.smile.taobaodemo.model.entity.DescBase; 14 | import com.smile.taobaodemo.utils.GlideUtil; 15 | 16 | import java.util.List; 17 | 18 | import butterknife.BindView; 19 | import butterknife.ButterKnife; 20 | 21 | /** 22 | * @author Smile Wei 23 | * @since 2016/8/12. 24 | */ 25 | public class GoodsDescAdapter extends RecyclerView.Adapter { 26 | private Context context; 27 | private Activity activity; 28 | private List list; 29 | 30 | public GoodsDescAdapter(Context context, Activity activity, List list) { 31 | this.context = context; 32 | this.activity = activity; 33 | this.list = list; 34 | } 35 | 36 | @Override 37 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 38 | View view; 39 | switch (viewType) { 40 | case DescBase.TYPE_PICTURE: 41 | view = LayoutInflater.from(context).inflate(R.layout.item_goods_desc_picture, parent, false); 42 | return new ViewHolder(view); 43 | default: 44 | view = LayoutInflater.from(context).inflate(R.layout.item_goods_desc, parent, false); 45 | return new DescHolder(view); 46 | } 47 | } 48 | 49 | @Override 50 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 51 | DescBase bean = list.get(position); 52 | if (holder instanceof DescHolder) { 53 | ((DescHolder) holder).tvDesc.setText(bean.getName()); 54 | } else if (holder instanceof ViewHolder) { 55 | GlideUtil.load(activity, bean.getUrl(), ((ViewHolder) holder).ivPicture); 56 | } 57 | } 58 | 59 | @Override 60 | public int getItemViewType(int position) { 61 | return list.get(position).getType(); 62 | } 63 | 64 | @Override 65 | public int getItemCount() { 66 | return list.size(); 67 | } 68 | 69 | public interface OnItemClickListener { 70 | void onItemClick(int position); 71 | } 72 | 73 | private OnItemClickListener listener; 74 | 75 | public void setOnItemClickListener(OnItemClickListener listener) { 76 | this.listener = listener; 77 | } 78 | 79 | 80 | class ViewHolder extends RecyclerView.ViewHolder { 81 | @BindView(R.id.iv_picture) 82 | ImageView ivPicture; 83 | 84 | 85 | public ViewHolder(View itemView) { 86 | super(itemView); 87 | itemView.setOnClickListener(new View.OnClickListener() { 88 | @Override 89 | public void onClick(View v) { 90 | if (listener != null) 91 | listener.onItemClick(getLayoutPosition()); 92 | } 93 | }); 94 | ButterKnife.bind(this, itemView); 95 | } 96 | 97 | } 98 | 99 | class DescHolder extends RecyclerView.ViewHolder { 100 | @BindView(R.id.tv_desc) 101 | TextView tvDesc; 102 | 103 | 104 | public DescHolder(View itemView) { 105 | super(itemView); 106 | ButterKnife.bind(this, itemView); 107 | } 108 | 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/model/entity/HomeBase.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.model.entity; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | /** 7 | * @author Smile Wei 8 | * @since 2016/8/10. 9 | */ 10 | public class HomeBase implements Parcelable { 11 | public static final String NULL_STRING = ""; 12 | public static final double ZERO = 0; 13 | public static final int TYPE_PLACE = -1; 14 | public static final int TYPE_HEADER = 0; 15 | public static final int TYPE_CAROUSEL = 3; 16 | public static final int TYPE_CATEGORY = 4; 17 | public static final int TYPE_HEADLINE = 5; 18 | public static final int TYPE_DIVIDER = 6; 19 | public static final int TYPE_LIVE = 7; 20 | public static final int TYPE_HOT = 9; 21 | public static final int TYPE_RECOMMEND = 12; 22 | 23 | 24 | private long id; 25 | private String name; 26 | private String url; 27 | private double price; 28 | private int type = TYPE_RECOMMEND; 29 | private int spanCount = 150; 30 | 31 | public HomeBase() { 32 | } 33 | 34 | public HomeBase(long id, double price, String url, String name, int type, int spanCount) { 35 | this.id = id; 36 | this.price = price; 37 | this.url = url; 38 | this.name = name; 39 | this.type = type; 40 | this.spanCount = spanCount; 41 | } 42 | 43 | public long getId() { 44 | return id; 45 | } 46 | 47 | public void setId(long id) { 48 | this.id = id; 49 | } 50 | 51 | public double getPrice() { 52 | return price; 53 | } 54 | 55 | public void setPrice(double price) { 56 | this.price = price; 57 | } 58 | 59 | public String getUrl() { 60 | return url == null ? "" : url; 61 | } 62 | 63 | public void setUrl(String url) { 64 | this.url = url; 65 | } 66 | 67 | public String getName() { 68 | return name == null ? "" : name; 69 | } 70 | 71 | public void setName(String name) { 72 | this.name = name; 73 | } 74 | 75 | public String getCurrency() { 76 | return "¥"; 77 | } 78 | 79 | public int getType() { 80 | return type; 81 | } 82 | 83 | public void setType(int type) { 84 | this.type = type; 85 | } 86 | 87 | public int getSpanCount() { 88 | return spanCount; 89 | } 90 | 91 | public void setSpanCount(int spanCount) { 92 | this.spanCount = spanCount; 93 | } 94 | 95 | @Override 96 | public int describeContents() { 97 | return 0; 98 | } 99 | 100 | @Override 101 | public void writeToParcel(Parcel dest, int flags) { 102 | dest.writeLong(this.id); 103 | dest.writeString(this.name); 104 | dest.writeString(this.url); 105 | dest.writeDouble(this.price); 106 | dest.writeInt(this.type); 107 | dest.writeInt(this.spanCount); 108 | } 109 | 110 | protected HomeBase(Parcel in) { 111 | this.id = in.readLong(); 112 | this.name = in.readString(); 113 | this.url = in.readString(); 114 | this.price = in.readDouble(); 115 | this.type = in.readInt(); 116 | this.spanCount = in.readInt(); 117 | } 118 | 119 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 120 | @Override 121 | public HomeBase createFromParcel(Parcel source) { 122 | return new HomeBase(source); 123 | } 124 | 125 | @Override 126 | public HomeBase[] newArray(int size) { 127 | return new HomeBase[size]; 128 | } 129 | }; 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/adapter/GoodsDetailPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.adapter; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentPagerAdapter; 6 | 7 | import com.smile.taobaodemo.base.Type; 8 | import com.smile.taobaodemo.model.entity.CommentBase; 9 | import com.smile.taobaodemo.model.entity.DescBase; 10 | import com.smile.taobaodemo.ui.fragment.GoodsCommentFragment; 11 | import com.smile.taobaodemo.ui.fragment.GoodsDescFragment; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @author Smile Wei 18 | * @since 2016/8/6. 19 | */ 20 | public class GoodsDetailPagerAdapter extends FragmentPagerAdapter { 21 | private String[] title; 22 | 23 | public GoodsDetailPagerAdapter(FragmentManager fm, String[] title) { 24 | super(fm); 25 | this.title = title; 26 | } 27 | 28 | @Override 29 | public Fragment getItem(int position) { 30 | switch (position) { 31 | case 0: { 32 | List list = new ArrayList<>(); 33 | DescBase bean = new DescBase(DescBase.TYPE_DESC, "这件不买你就真的太傻了\n" + 34 | "一点不怕告诉你们\n" + 35 | "这件衣服是我做了所有衣服以来\n" + 36 | "被周围人拿走最多的一件\n" + 37 | "我怕我再不上架,都被拿空了\n" + 38 | "管它男的女的都来要\n" + 39 | "女的买回去男的来要\n" + 40 | "店里小姑娘穿回去舍友来要\n" + 41 | "连快递来拿件看了他们穿的也要\n" + 42 | "人见人爱 波及范围相当广\n" + 43 | "可能它的确太实用太保暖质量太喜人吧\n" + 44 | "显瘦死了保暖死了 全用的今年最好的鸭绒\n" + 45 | "我的羽绒系列绝对是闭眼入\n" + 46 | "废话不说 明晚来抢\n" + 47 | "之前说错了,是均码,男女都能穿", ""); 48 | list.add(bean); 49 | list.add(new DescBase(DescBase.TYPE_PICTURE, "", "https://img.alicdn.com/bao/uploaded/i1/TB1sDqKLXXXXXanXXXXXXXXXXXX_!!0-item_pic.jpg_800x800.jpg")); 50 | list.add(new DescBase(DescBase.TYPE_PICTURE, "", "https://img.alicdn.com/bao/uploaded/i2/2171322350/TB2SqaTaNaJ.eBjSsziXXaJ_XXa_!!2171322350.jpg_800x800.jpg")); 51 | list.add(new DescBase(DescBase.TYPE_PICTURE, "", "https://img.alicdn.com/bao/uploaded/i4/TB1Ke9CJpXXXXa9XpXXXXXXXXXX_!!0-item_pic.jpg_800x800.jpg")); 52 | list.add(new DescBase(DescBase.TYPE_PICTURE, "", "https://asearch.alicdn.com/bao/uploaded/i2/159530341092325317/TB2mMMbaHBnpuFjSZFGXXX51pXa_!!0-saturn_solar.jpg_800x800.jpg")); 53 | list.add(new DescBase(DescBase.TYPE_PICTURE, "", "https://img.alicdn.com/bao/uploaded/i3/20821802/TB2S7E9abVkpuFjSspcXXbSMVXa_!!20821802.jpg_800x800.jpg")); 54 | return GoodsDescFragment.newInstance(list); 55 | } 56 | default: { 57 | List list = new ArrayList<>(); 58 | for (int i = 0; i < 20; i++) { 59 | CommentBase bean = new CommentBase(); 60 | bean.setContent("废话不说 明晚来抢"); 61 | bean.setPicture("https://cdn.56come.cn/upload/6571/2016/0428/8uxd63yvy4umfwuprwhsuqb5g.thumb.jpg"); 62 | bean.setProduct_score(5); 63 | bean.setType(Type.TYPE_SHOW); 64 | bean.setCreate_date(System.currentTimeMillis() - 10000000 * i); 65 | bean.setUser_name("Smile" + i); 66 | list.add(bean); 67 | } 68 | return GoodsCommentFragment.newInstance(list); 69 | } 70 | } 71 | } 72 | 73 | @Override 74 | public int getCount() { 75 | return title.length; 76 | } 77 | 78 | @Override 79 | public CharSequence getPageTitle(int position) { 80 | return title[position]; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 33 | 34 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/adapter/GoodsCommentAdapter.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.adapter; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | import android.widget.RatingBar; 11 | import android.widget.TextView; 12 | 13 | 14 | import com.smile.taobaodemo.R; 15 | import com.smile.taobaodemo.base.Type; 16 | import com.smile.taobaodemo.model.entity.CommentBase; 17 | import com.smile.taobaodemo.utils.DateFormatUtil; 18 | import com.smile.taobaodemo.utils.GlideUtil; 19 | import com.smile.taobaodemo.widget.FooterLoading; 20 | 21 | import java.util.List; 22 | 23 | import butterknife.BindView; 24 | import butterknife.ButterKnife; 25 | 26 | /** 27 | * @author Smile Wei 28 | * @since 2016/8/12. 29 | */ 30 | public class GoodsCommentAdapter extends RecyclerView.Adapter { 31 | private Context context; 32 | private Activity activity; 33 | private List list; 34 | private LayoutInflater inflate; 35 | 36 | public GoodsCommentAdapter(Context context, Activity activity, List list) { 37 | this.context = context; 38 | this.activity = activity; 39 | this.list = list; 40 | inflate = LayoutInflater.from(context); 41 | } 42 | 43 | @Override 44 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 45 | View view; 46 | switch (viewType) { 47 | case Type.TYPE_SHOW: 48 | view = inflate.inflate(R.layout.item_goods_comment, parent, false); 49 | return new ViewHolder(view); 50 | default: 51 | view = inflate.inflate(R.layout.item_footer_loading, parent, false); 52 | return new FooterHolder(view); 53 | } 54 | } 55 | 56 | @Override 57 | public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) { 58 | if (viewHolder instanceof ViewHolder) { 59 | ViewHolder holder = (ViewHolder) viewHolder; 60 | CommentBase bean = list.get(position); 61 | GlideUtil.load(context, activity, bean.getPicture(), holder.ivUser); 62 | holder.tvName.setText(bean.getUser_name()); 63 | holder.tvTime.setText(DateFormatUtil.formatDate(DateFormatUtil.FORMAT_yyyyMMdd_HHmm, bean.getCreate_date())); 64 | holder.ratingBar.setNumStars(bean.getProduct_score()); 65 | holder.ratingBar.setRating(bean.getProduct_score()); 66 | holder.tvComment.setText(bean.getContent()); 67 | } else if (viewHolder instanceof FooterHolder) { 68 | FooterHolder holder = (FooterHolder) viewHolder; 69 | holder.footerLoading.onLoad(Type.TYPE_FOOTER_FULL == list.get(position).getType()); 70 | } 71 | 72 | } 73 | 74 | @Override 75 | public int getItemCount() { 76 | return list.size(); 77 | } 78 | 79 | @Override 80 | public int getItemViewType(int position) { 81 | return list.get(position).getType(); 82 | } 83 | 84 | class ViewHolder extends RecyclerView.ViewHolder { 85 | @BindView(R.id.iv_user) 86 | ImageView ivUser; 87 | @BindView(R.id.tv_name) 88 | TextView tvName; 89 | @BindView(R.id.tv_time) 90 | TextView tvTime; 91 | @BindView(R.id.rating_bar) 92 | RatingBar ratingBar; 93 | @BindView(R.id.tv_comment) 94 | TextView tvComment; 95 | 96 | public ViewHolder(View itemView) { 97 | super(itemView); 98 | ButterKnife.bind(this, itemView); 99 | } 100 | } 101 | 102 | class FooterHolder extends RecyclerView.ViewHolder { 103 | @BindView(R.id.footer) 104 | FooterLoading footerLoading; 105 | 106 | FooterHolder(View itemView) { 107 | super(itemView); 108 | ButterKnife.bind(this, itemView); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/model/entity/LivePlay.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.model.entity; 2 | 3 | import com.smile.taobaodemo.base.Type; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author Smile Wei 9 | * @since 2016/10/8. 10 | */ 11 | 12 | public class LivePlay { 13 | 14 | private String state; 15 | private String msg; 16 | 17 | private int totalPage; 18 | 19 | private List data; 20 | 21 | public String getState() { 22 | return state; 23 | } 24 | 25 | public void setState(String state) { 26 | this.state = state; 27 | } 28 | 29 | public String getMsg() { 30 | return msg; 31 | } 32 | 33 | public void setMsg(String msg) { 34 | this.msg = msg; 35 | } 36 | 37 | public int getTotalPage() { 38 | return totalPage; 39 | } 40 | 41 | public void setTotalPage(int totalPage) { 42 | this.totalPage = totalPage; 43 | } 44 | 45 | public List getData() { 46 | return data; 47 | } 48 | 49 | public void setData(List data) { 50 | this.data = data; 51 | } 52 | 53 | public static class Data { 54 | 55 | private int type = Type.TYPE_SHOW; 56 | private String livePlayId; 57 | private String flvPlayUrl; 58 | private String rtmpPlayUrl; 59 | private String hlsPlayUrl; 60 | private String title; 61 | private String picture; 62 | private String groupId; 63 | private String photo; 64 | private String name; 65 | private int watchNumber; 66 | private int likeNumber; 67 | 68 | public int getType() { 69 | return type; 70 | } 71 | 72 | public void setType(int type) { 73 | this.type = type; 74 | } 75 | 76 | public String getRtmpPlayUrl() { 77 | return rtmpPlayUrl; 78 | } 79 | 80 | public void setRtmpPlayUrl(String rtmpPlayUrl) { 81 | this.rtmpPlayUrl = rtmpPlayUrl; 82 | } 83 | 84 | public String getLivePlayId() { 85 | return livePlayId; 86 | } 87 | 88 | public void setLivePlayId(String livePlayId) { 89 | this.livePlayId = livePlayId; 90 | } 91 | 92 | public String getFlvPlayUrl() { 93 | return flvPlayUrl; 94 | } 95 | 96 | public void setFlvPlayUrl(String flvPlayUrl) { 97 | this.flvPlayUrl = flvPlayUrl; 98 | } 99 | 100 | public String getHlsPlayUrl() { 101 | return hlsPlayUrl; 102 | } 103 | 104 | public void setHlsPlayUrl(String hlsPlayUrl) { 105 | this.hlsPlayUrl = hlsPlayUrl; 106 | } 107 | 108 | public String getTitle() { 109 | return title; 110 | } 111 | 112 | public void setTitle(String title) { 113 | this.title = title; 114 | } 115 | 116 | public String getPicture() { 117 | return picture; 118 | } 119 | 120 | public void setPicture(String picture) { 121 | this.picture = picture; 122 | } 123 | 124 | public int getWatchNumber() { 125 | return watchNumber; 126 | } 127 | 128 | public void setWatchNumber(int watchNumber) { 129 | this.watchNumber = watchNumber; 130 | } 131 | 132 | public int getLikeNumber() { 133 | return likeNumber; 134 | } 135 | 136 | public void setLikeNumber(int likeNumber) { 137 | this.likeNumber = likeNumber; 138 | } 139 | 140 | public String getName() { 141 | return name; 142 | } 143 | 144 | public void setName(String name) { 145 | this.name = name; 146 | } 147 | 148 | public String getGroupId() { 149 | return groupId; 150 | } 151 | 152 | public void setGroupId(String groupId) { 153 | this.groupId = groupId; 154 | } 155 | 156 | public String getPhoto() { 157 | return photo; 158 | } 159 | 160 | public void setPhoto(String photo) { 161 | this.photo = photo; 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/activity/DetailActivity.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.activity; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.support.design.widget.TabLayout; 8 | import android.support.v4.view.ViewPager; 9 | import android.support.v7.app.ActionBar; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.support.v7.widget.Toolbar; 12 | import android.view.View; 13 | import android.widget.TextView; 14 | 15 | import com.smile.taobaodemo.R; 16 | import com.smile.taobaodemo.base.BundleKey; 17 | import com.smile.taobaodemo.model.entity.HomeBase; 18 | import com.smile.taobaodemo.model.entity.HomeTop; 19 | import com.smile.taobaodemo.ui.adapter.GoodsDetailPagerAdapter; 20 | import com.smile.taobaodemo.ui.adapter.ImageHomeAdapter; 21 | import com.smile.taobaodemo.utils.StatusBarUtil; 22 | import com.smile.taobaodemo.widget.CirclePageIndicator; 23 | import com.smile.taobaodemo.widget.GradientScrollView; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import butterknife.BindView; 29 | import butterknife.ButterKnife; 30 | import cn.trinea.android.view.autoscrollviewpager.AutoScrollViewPager; 31 | 32 | public class DetailActivity extends AppCompatActivity { 33 | @BindView(R.id.toolbar) 34 | Toolbar toolbar; 35 | @BindView(R.id.status_bar) 36 | View statusBar; 37 | @BindView(R.id.scroll_view) 38 | GradientScrollView scrollView; 39 | @BindView(R.id.auto_view_pager) 40 | AutoScrollViewPager autoViewPager; 41 | @BindView(R.id.indicator) 42 | CirclePageIndicator indicator; 43 | @BindView(R.id.tv_name) 44 | TextView tvName; 45 | @BindView(R.id.tv_price) 46 | TextView tvPrice; 47 | @BindView(R.id.tab_layout) 48 | TabLayout tabLayout; 49 | @BindView(R.id.view_pager) 50 | ViewPager viewPager; 51 | 52 | private Activity activity; 53 | private Context context; 54 | 55 | @Override 56 | protected void onCreate(Bundle savedInstanceState) { 57 | super.onCreate(savedInstanceState); 58 | 59 | setContentView(R.layout.activity_detail); 60 | 61 | ButterKnife.bind(this); 62 | 63 | activity = this; 64 | context = getApplicationContext(); 65 | 66 | initView(); 67 | } 68 | 69 | private void initView() { 70 | toolbar.setTitle("商品详情"); 71 | setSupportActionBar(toolbar); 72 | ActionBar actionBar = getSupportActionBar(); 73 | if (actionBar != null) 74 | actionBar.setDisplayHomeAsUpEnabled(true); 75 | toolbar.setNavigationOnClickListener(new View.OnClickListener() { 76 | @Override 77 | public void onClick(View view) { 78 | onBackPressed(); 79 | } 80 | }); 81 | 82 | toolbar.setTitleTextColor(Color.argb(0, 255, 255, 255)); 83 | toolbar.getBackground().mutate().setAlpha(0); 84 | statusBar.getBackground().mutate().setAlpha(0); 85 | scrollView.setHeader(toolbar, statusBar); 86 | StatusBarUtil.setTransparentForImageView(this, tvName); 87 | 88 | HomeBase bean = getIntent().getParcelableExtra(BundleKey.PARCELABLE); 89 | 90 | tvName.setText(bean.getName()); 91 | tvPrice.setText("¥" + bean.getPrice()); 92 | List list = new ArrayList<>(); 93 | list.add(new HomeTop.Carousel(1, "https://img.alicdn.com/bao/uploaded/i1/TB1sDqKLXXXXXanXXXXXXXXXXXX_!!0-item_pic.jpg_800x800.jpg")); 94 | list.add(new HomeTop.Carousel(2, "https://img.alicdn.com/bao/uploaded/i2/2171322350/TB2SqaTaNaJ.eBjSsziXXaJ_XXa_!!2171322350.jpg_800x800.jpg")); 95 | list.add(new HomeTop.Carousel(3, "https://img.alicdn.com/bao/uploaded/i4/TB1Ke9CJpXXXXa9XpXXXXXXXXXX_!!0-item_pic.jpg_800x800.jpg")); 96 | list.add(new HomeTop.Carousel(4, "https://asearch.alicdn.com/bao/uploaded/i2/159530341092325317/TB2mMMbaHBnpuFjSZFGXXX51pXa_!!0-saturn_solar.jpg_800x800.jpg")); 97 | list.add(new HomeTop.Carousel(5, "https://img.alicdn.com/bao/uploaded/i3/20821802/TB2S7E9abVkpuFjSspcXXbSMVXa_!!20821802.jpg_800x800.jpg")); 98 | 99 | autoViewPager.setAdapter(new ImageHomeAdapter(context, activity, list)); 100 | indicator.setViewPager(autoViewPager); 101 | autoViewPager.setInterval(4000); 102 | autoViewPager.setSlideBorderMode(AutoScrollViewPager.SLIDE_BORDER_MODE_TO_PARENT); 103 | 104 | GoodsDetailPagerAdapter adapter = new GoodsDetailPagerAdapter(getSupportFragmentManager(), 105 | new String[]{"商品描述", "评论(20)"}); 106 | viewPager.setAdapter(adapter); 107 | tabLayout.setupWithViewPager(viewPager); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/adapter/RecyclingPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.adapter; 2 | 3 | import android.support.v4.view.PagerAdapter; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.AdapterView; 7 | 8 | import com.smile.taobaodemo.widget.RecycleBin; 9 | 10 | /** 11 | * A {@link PagerAdapter} which behaves like an {@link android.widget.Adapter} with view types and 12 | * view recycling. 13 | */ 14 | public abstract class RecyclingPagerAdapter extends PagerAdapter { 15 | static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE; 16 | 17 | private final RecycleBin recycleBin; 18 | 19 | public RecyclingPagerAdapter() { 20 | this(new RecycleBin()); 21 | } 22 | 23 | RecyclingPagerAdapter(RecycleBin recycleBin) { 24 | this.recycleBin = recycleBin; 25 | recycleBin.setViewTypeCount(getViewTypeCount()); 26 | } 27 | 28 | @Override 29 | public void notifyDataSetChanged() { 30 | recycleBin.scrapActiveViews(); 31 | super.notifyDataSetChanged(); 32 | } 33 | 34 | @Override 35 | public final Object instantiateItem(ViewGroup container, int position) { 36 | int viewType = getItemViewType(position); 37 | View view = null; 38 | if (viewType != IGNORE_ITEM_VIEW_TYPE) { 39 | view = recycleBin.getScrapView(position, viewType); 40 | } 41 | view = getView(position, view, container); 42 | container.addView(view); 43 | return view; 44 | } 45 | 46 | @Override 47 | public final void destroyItem(ViewGroup container, int position, Object object) { 48 | View view = (View) object; 49 | container.removeView(view); 50 | int viewType = getItemViewType(position); 51 | if (viewType != IGNORE_ITEM_VIEW_TYPE) { 52 | recycleBin.addScrapView(view, position, viewType); 53 | } 54 | } 55 | 56 | @Override 57 | public final boolean isViewFromObject(View view, Object object) { 58 | return view == object; 59 | } 60 | 61 | /** 62 | *

63 | * Returns the number of types of Views that will be created by 64 | * {@link #getView}. Each type represents a set of views that can be 65 | * converted in {@link #getView}. If the adapter always returns the same 66 | * type of View for all items, this method should return 1. 67 | *

68 | *

69 | * This method will only be called when when the adapter is set on the 70 | * the {@link AdapterView}. 71 | *

72 | * 73 | * @return The number of types of Views that will be created by this adapter 74 | */ 75 | public int getViewTypeCount() { 76 | return 1; 77 | } 78 | 79 | /** 80 | * Get the type of View that will be created by {@link #getView} for the specified item. 81 | * 82 | * @param position The position of the item within the adapter's data set whose view type we 83 | * want. 84 | * @return An integer representing the type of View. Two views should share the same type if one 85 | * can be converted to the other in {@link #getView}. Note: Integers must be in the 86 | * range 0 to {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can 87 | * also be returned. 88 | * @see #IGNORE_ITEM_VIEW_TYPE 89 | */ 90 | @SuppressWarnings("UnusedParameters") // Argument potentially used by subclasses. 91 | public int getItemViewType(int position) { 92 | return 0; 93 | } 94 | 95 | /** 96 | * Get a View that displays the data at the specified position in the data set. You can either 97 | * create a View manually or inflate it from an XML layout file. When the View is inflated, the 98 | * parent View (GridView, ListView...) will apply default layout parameters unless you use 99 | * {@link android.view.LayoutInflater#inflate(int, ViewGroup, boolean)} 100 | * to specify a root view and to prevent attachment to the root. 101 | * 102 | * @param position The position of the item within the adapter's data set of the item whose view 103 | * we want. 104 | * @param convertView The old view to reuse, if possible. Note: You should check that this view 105 | * is non-null and of an appropriate type before using. If it is not possible to convert 106 | * this view to display the correct data, this method can create a new view. 107 | * Heterogeneous lists can specify their number of view types, so that this View is 108 | * always of the right type (see {@link #getViewTypeCount()} and 109 | * {@link #getItemViewType(int)}). 110 | * @param parent The parent that this view will eventually be attached to 111 | * @return A View corresponding to the data at the specified position. 112 | */ 113 | public abstract View getView(int position, View convertView, ViewGroup container); 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 23 | 24 | 32 | 33 | 43 | 44 | 47 | 48 | 49 | 59 | 60 | 68 | 69 | 70 | 71 | 72 | 77 | 78 | 79 | 80 | 87 | 88 | 95 | 96 | 97 | 98 | 99 | 100 | 106 | 107 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.activity; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.os.CountDownTimer; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.widget.TextView; 10 | 11 | import com.aurelhubert.ahbottomnavigation.AHBottomNavigation; 12 | import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem; 13 | import com.aurelhubert.ahbottomnavigation.AHBottomNavigationViewPager; 14 | import com.smile.taobaodemo.R; 15 | import com.smile.taobaodemo.ui.adapter.ViewPagerAdapter; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.Random; 20 | 21 | import butterknife.BindView; 22 | import butterknife.ButterKnife; 23 | 24 | /** 25 | * @author Smile Wei 26 | * @since 2017/03/01. 27 | */ 28 | 29 | public class MainActivity extends AppCompatActivity { 30 | 31 | @BindView(R.id.view_pager) 32 | AHBottomNavigationViewPager viewPager; 33 | @BindView(R.id.bottom_navigation) 34 | AHBottomNavigation bottomNavigation; 35 | @BindView(R.id.toolbar) 36 | Toolbar toolbar; 37 | @BindView(R.id.tv_search_tips) 38 | TextView tvSearchTips; 39 | 40 | private CountDownTimer timer; 41 | 42 | private ArrayList bottomNavigationItems = new ArrayList<>(); 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | setContentView(R.layout.activity_main); 48 | ButterKnife.bind(this); 49 | initView(); 50 | } 51 | 52 | @Override 53 | protected void onNewIntent(Intent intent) { 54 | super.onNewIntent(intent); 55 | } 56 | 57 | public void initView() { 58 | toolbar.setTitle(""); 59 | setSupportActionBar(toolbar); 60 | AHBottomNavigationItem item1 = new AHBottomNavigationItem(R.string.bottom_navigation_item_home, R.drawable.navtab_home, R.color.colorBottomNavigationActiveColored); 61 | AHBottomNavigationItem item2 = new AHBottomNavigationItem(R.string.bottom_navigation_item_we, R.drawable.navtab_we, R.color.colorBottomNavigationActiveColored); 62 | AHBottomNavigationItem item3 = new AHBottomNavigationItem(R.string.bottom_navigation_item_help, R.drawable.navtab_help, R.color.colorBottomNavigationActiveColored); 63 | AHBottomNavigationItem item4 = new AHBottomNavigationItem(R.string.bottom_navigation_item_cart, R.drawable.navtab_cart, R.color.colorBottomNavigationActiveColored); 64 | AHBottomNavigationItem item5 = new AHBottomNavigationItem(R.string.bottom_navigation_item_user, R.drawable.navtab_user, R.color.colorBottomNavigationActiveColored); 65 | 66 | bottomNavigationItems.add(item1); 67 | bottomNavigationItems.add(item2); 68 | bottomNavigationItems.add(item3); 69 | bottomNavigationItems.add(item4); 70 | bottomNavigationItems.add(item5); 71 | 72 | bottomNavigation.addItems(bottomNavigationItems); 73 | bottomNavigation.setForceTitlesDisplay(true); 74 | bottomNavigation.setDefaultBackgroundColor(Color.parseColor("#FEFEFE")); 75 | bottomNavigation.setAccentColor(Color.parseColor("#1DA1F2")); 76 | bottomNavigation.setInactiveColor(Color.parseColor("#949494")); 77 | 78 | bottomNavigation.setOnTabSelectedListener(new AHBottomNavigation.OnTabSelectedListener() { 79 | @Override 80 | public boolean onTabSelected(int position, boolean wasSelected) { 81 | viewPager.setCurrentItem(position, false); 82 | return true; 83 | } 84 | }); 85 | viewPager.setOffscreenPageLimit(5); 86 | viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager())); 87 | 88 | /** 89 | * 顶部搜索框内容定时更新,简单的采用倒计时功能 90 | */ 91 | final List tips = new ArrayList<>(); 92 | tips.add("AndroidNexus"); 93 | tips.add("EasyToForget"); 94 | tips.add("zhiye.wei@gmail.com"); 95 | 96 | timer = new CountDownTimer(3000000, 5000) { 97 | @Override 98 | public void onTick(long millisUntilFinished) { 99 | tvSearchTips.setText(tips.get(new Random().nextInt(2))); 100 | } 101 | 102 | @Override 103 | public void onFinish() { 104 | 105 | } 106 | }; 107 | } 108 | 109 | @Override 110 | protected void onResume() { 111 | super.onResume(); 112 | } 113 | 114 | @Override 115 | protected void onStart() { 116 | super.onStart(); 117 | timer.start(); 118 | } 119 | 120 | @Override 121 | protected void onStop() { 122 | super.onStop(); 123 | timer.cancel(); 124 | } 125 | 126 | @Override 127 | public void onBackPressed() { 128 | moveTaskToBack(false); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 31 | 32 | 33 | 38 | 39 | 51 | 52 | 56 | 57 | 69 | 70 | 74 | 75 | 87 | 88 | 89 | 99 | 100 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 120 | 121 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/widget/RecycleBin.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.widget; 2 | 3 | import android.os.Build; 4 | import android.util.SparseArray; 5 | import android.view.View; 6 | 7 | /** 8 | * The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of 9 | * storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the 10 | * start of a layout. By construction, they are displaying current information. At the end of 11 | * layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that 12 | * could potentially be used by the adapter to avoid allocating views unnecessarily. 13 | *

14 | * This class was taken from Android's implementation of {@link android.widget.AbsListView} which 15 | * is copyrighted 2006 The Android Open Source Project. 16 | */ 17 | public class RecycleBin { 18 | /** 19 | * Views that were on screen at the start of layout. This array is populated at the start of 20 | * layout, and at the end of layout all view in activeViews are moved to scrapViews. 21 | * Views in activeViews represent a contiguous range of Views, with position of the first 22 | * view store in mFirstActivePosition. 23 | */ 24 | private View[] activeViews = new View[0]; 25 | private int[] activeViewTypes = new int[0]; 26 | 27 | /** Unsorted views that can be used by the adapter as a convert view. */ 28 | private SparseArray[] scrapViews; 29 | 30 | private int viewTypeCount; 31 | 32 | private SparseArray currentScrapViews; 33 | 34 | public void setViewTypeCount(int viewTypeCount) { 35 | if (viewTypeCount < 1) { 36 | throw new IllegalArgumentException("Can't have a viewTypeCount < 1"); 37 | } 38 | //noinspection unchecked 39 | SparseArray[] scrapViews = new SparseArray[viewTypeCount]; 40 | for (int i = 0; i < viewTypeCount; i++) { 41 | scrapViews[i] = new SparseArray(); 42 | } 43 | this.viewTypeCount = viewTypeCount; 44 | currentScrapViews = scrapViews[0]; 45 | this.scrapViews = scrapViews; 46 | } 47 | 48 | protected boolean shouldRecycleViewType(int viewType) { 49 | return viewType >= 0; 50 | } 51 | 52 | /** @return A view from the ScrapViews collection. These are unordered. */ 53 | public View getScrapView(int position, int viewType) { 54 | if (viewTypeCount == 1) { 55 | return retrieveFromScrap(currentScrapViews, position); 56 | } else if (viewType >= 0 && viewType < scrapViews.length) { 57 | return retrieveFromScrap(scrapViews[viewType], position); 58 | } 59 | return null; 60 | } 61 | 62 | /** 63 | * Put a view into the ScrapViews list. These views are unordered. 64 | * 65 | * @param scrap The view to add 66 | */ 67 | public void addScrapView(View scrap, int position, int viewType) { 68 | if (viewTypeCount == 1) { 69 | currentScrapViews.put(position, scrap); 70 | } else { 71 | scrapViews[viewType].put(position, scrap); 72 | } 73 | 74 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 75 | scrap.setAccessibilityDelegate(null); 76 | } 77 | } 78 | 79 | /** Move all views remaining in activeViews to scrapViews. */ 80 | public void scrapActiveViews() { 81 | final View[] activeViews = this.activeViews; 82 | final int[] activeViewTypes = this.activeViewTypes; 83 | final boolean multipleScraps = viewTypeCount > 1; 84 | 85 | SparseArray scrapViews = currentScrapViews; 86 | final int count = activeViews.length; 87 | for (int i = count - 1; i >= 0; i--) { 88 | final View victim = activeViews[i]; 89 | if (victim != null) { 90 | int whichScrap = activeViewTypes[i]; 91 | 92 | activeViews[i] = null; 93 | activeViewTypes[i] = -1; 94 | 95 | if (!shouldRecycleViewType(whichScrap)) { 96 | continue; 97 | } 98 | 99 | if (multipleScraps) { 100 | scrapViews = this.scrapViews[whichScrap]; 101 | } 102 | scrapViews.put(i, victim); 103 | 104 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 105 | victim.setAccessibilityDelegate(null); 106 | } 107 | } 108 | } 109 | 110 | pruneScrapViews(); 111 | } 112 | 113 | /** 114 | * Makes sure that the size of scrapViews does not exceed the size of activeViews. 115 | * (This can happen if an adapter does not recycle its views). 116 | */ 117 | private void pruneScrapViews() { 118 | final int maxViews = activeViews.length; 119 | final int viewTypeCount = this.viewTypeCount; 120 | final SparseArray[] scrapViews = this.scrapViews; 121 | for (int i = 0; i < viewTypeCount; ++i) { 122 | final SparseArray scrapPile = scrapViews[i]; 123 | int size = scrapPile.size(); 124 | final int extras = size - maxViews; 125 | size--; 126 | for (int j = 0; j < extras; j++) { 127 | scrapPile.remove(scrapPile.keyAt(size--)); 128 | } 129 | } 130 | } 131 | 132 | static View retrieveFromScrap(SparseArray scrapViews, int position) { 133 | int size = scrapViews.size(); 134 | if (size > 0) { 135 | // See if we still have a view for this position. 136 | for (int i = 0; i < size; i++) { 137 | int fromPosition = scrapViews.keyAt(i); 138 | View view = scrapViews.get(fromPosition); 139 | if (fromPosition == position) { 140 | scrapViews.remove(fromPosition); 141 | return view; 142 | } 143 | } 144 | int index = size - 1; 145 | View r = scrapViews.valueAt(index); 146 | scrapViews.remove(scrapViews.keyAt(index)); 147 | return r; 148 | } else { 149 | return null; 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_navigation_home_category.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | 13 | 24 | 25 | 36 | 37 | 48 | 49 | 60 | 61 | 72 | 73 | 74 | 75 | 82 | 83 | 94 | 95 | 106 | 107 | 118 | 119 | 130 | 131 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/fragment/NavHomeFragment.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.fragment; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v4.widget.SwipeRefreshLayout; 9 | import android.support.v7.widget.GridLayoutManager; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | 14 | import com.smile.taobaodemo.R; 15 | import com.smile.taobaodemo.base.BundleKey; 16 | import com.smile.taobaodemo.base.Type; 17 | import com.smile.taobaodemo.model.entity.HomeBase; 18 | import com.smile.taobaodemo.model.entity.HomeBottom; 19 | import com.smile.taobaodemo.model.entity.HomeTop; 20 | import com.smile.taobaodemo.presenter.HomePresenter; 21 | import com.smile.taobaodemo.ui.activity.DetailActivity; 22 | import com.smile.taobaodemo.ui.adapter.HomeAdapter; 23 | import com.smile.taobaodemo.contract.HomeContract; 24 | import com.smile.taobaodemo.utils.ToastUtil; 25 | import com.smile.taobaodemo.widget.LoadMoreRecyclerView; 26 | 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | 30 | import butterknife.BindView; 31 | import butterknife.ButterKnife; 32 | 33 | /** 34 | * @author Smile Wei 35 | * @since 2017/03/01. 36 | */ 37 | 38 | public class NavHomeFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, 39 | LoadMoreRecyclerView.OnLoadMoreListener, HomeContract.View, HomeAdapter.OnItemClickListener { 40 | private final static int HOME_TOP = 1; 41 | private final static int HOME_BOTTOM = 2; 42 | @BindView(R.id.refresh_layout) 43 | SwipeRefreshLayout refreshLayout; 44 | @BindView(R.id.recycler_view) 45 | LoadMoreRecyclerView recyclerView; 46 | private Context context; 47 | private Activity activity; 48 | 49 | private List list = new ArrayList<>(); 50 | 51 | private HomeAdapter adapter; 52 | private HomePresenter presenter; 53 | private int page = 1; 54 | private int pageSize = 10; 55 | private HomeBase footerItem = new HomeBase(); 56 | 57 | public static NavHomeFragment newInstance() { 58 | NavHomeFragment fragment = new NavHomeFragment(); 59 | Bundle args = new Bundle(); 60 | fragment.setArguments(args); 61 | return fragment; 62 | } 63 | 64 | @Override 65 | public void onCreate(Bundle savedInstanceState) { 66 | super.onCreate(savedInstanceState); 67 | } 68 | 69 | @Override 70 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 71 | Bundle savedInstanceState) { 72 | View view = inflater.inflate(R.layout.fragment_navigation_home, container, false); 73 | ButterKnife.bind(this, view); 74 | 75 | activity = getActivity(); 76 | context = activity.getApplicationContext(); 77 | 78 | presenter = new HomePresenter(); 79 | presenter.init(this, context); 80 | return view; 81 | } 82 | 83 | @Override 84 | public void initView() { 85 | refreshLayout.setColorSchemeResources(R.color.font_orange_color); 86 | refreshLayout.setOnRefreshListener(this); 87 | int spanCount = getResources().getInteger(R.integer.grid_span_count); 88 | 89 | GridLayoutManager layoutManager = new GridLayoutManager(activity, spanCount); 90 | recyclerView.setLayoutManager(layoutManager); 91 | adapter = new HomeAdapter(context, activity, list); 92 | adapter.setOnItemClickListener(this); 93 | layoutManager.setSpanSizeLookup(adapter.getSpanSizeLookup()); 94 | recyclerView.setAdapter(adapter); 95 | recyclerView.setOnLoadMoreListener(this); 96 | 97 | footerItem.setType(Type.TYPE_FOOTER_LOAD); 98 | footerItem.setSpanCount(spanCount); 99 | presenter.start(HOME_TOP); 100 | } 101 | 102 | @Override 103 | public void onRefresh() { 104 | setRefreshLoading(false); 105 | presenter.start(HOME_TOP); 106 | page = 1; 107 | } 108 | 109 | @Override 110 | public void onLoadMore() { 111 | setRefreshLoading(true); 112 | page++; 113 | presenter.start(HOME_BOTTOM, page, pageSize); 114 | } 115 | 116 | //轮播、分类、头条、直播回调 117 | @Override 118 | public void show(HomeTop bean) { 119 | list.clear(); 120 | adapter.setLoopList(bean.getCarousel()); 121 | adapter.setHeadlineList(bean.getHeadlines()); 122 | 123 | list.addAll(bean.getList()); 124 | list.add(footerItem); 125 | adapter.notifyDataSetChanged(); 126 | 127 | presenter.start(HOME_BOTTOM, page, pageSize); 128 | } 129 | 130 | 131 | //猜你喜欢模块回调 132 | @Override 133 | public void show(HomeBottom bean) { 134 | recyclerView.setPage(page, bean.getTotalPage()); 135 | footerItem.setType(page < bean.getTotalPage() ? Type.TYPE_FOOTER_LOAD : Type.TYPE_FOOTER_FULL); 136 | list.addAll(list.size() - 1, bean.getData()); 137 | adapter.notifyDataSetChanged(); 138 | setRefreshLoading(false); 139 | } 140 | 141 | @Override 142 | public void loading() { 143 | 144 | } 145 | 146 | @Override 147 | public void networkError() { 148 | setRefreshLoading(false); 149 | ToastUtil.showShortToast(context, R.string.toast_network_error); 150 | 151 | } 152 | 153 | @Override 154 | public void error(String msg) { 155 | setRefreshLoading(false); 156 | ToastUtil.showShortToast(context, msg); 157 | } 158 | 159 | @Override 160 | public void showFailed(String msg) { 161 | setRefreshLoading(false); 162 | ToastUtil.showShortToast(context, msg); 163 | } 164 | 165 | /** 166 | * 设置刷新和加载更多的状态 167 | * 168 | * @param isLoading 加载更多状态 169 | */ 170 | private void setRefreshLoading(boolean isLoading) { 171 | if (!isLoading) { 172 | recyclerView.setLoading(false); 173 | refreshLayout.setRefreshing(false); 174 | } 175 | } 176 | 177 | @Override 178 | public void onItemClick(int position) { 179 | Intent intent = new Intent(); 180 | intent.setClass(getActivity(), DetailActivity.class); 181 | intent.putExtra(BundleKey.PARCELABLE, list.get(position)); 182 | startActivity(intent); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/okhttp/OkHttp.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.okhttp; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import java.io.File; 7 | import java.net.URLEncoder; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import okhttp3.Call; 14 | import okhttp3.FormBody; 15 | import okhttp3.MultipartBody; 16 | import okhttp3.OkHttpClient; 17 | import okhttp3.Request; 18 | import okhttp3.RequestBody; 19 | 20 | /** 21 | * @author Smile Wei 22 | * @since 2016/8/2. 23 | */ 24 | public class OkHttp { 25 | private static OkHttpClient client; 26 | 27 | private static OkHttpClient init() { 28 | synchronized (OkHttp.class) { 29 | if (client == null) { 30 | client = new OkHttpClient.Builder() 31 | .readTimeout(30, TimeUnit.SECONDS) 32 | .writeTimeout(30, TimeUnit.SECONDS) 33 | .connectTimeout(30, TimeUnit.SECONDS) 34 | .build(); 35 | } 36 | } 37 | return client; 38 | } 39 | 40 | private static OkHttpClient getInstance() { 41 | return client == null ? init() : client; 42 | } 43 | 44 | /** 45 | * get方法 46 | * 47 | * @param url url 48 | * @param params 参数 49 | * @param callback 回调函数 50 | * @return call 51 | */ 52 | public static Call get(Context context, String url, Map params, OkCallback callback) { 53 | return get(context, url, params, null, callback); 54 | } 55 | 56 | /** 57 | * get方法 58 | * 59 | * @param url url 60 | * @param params 参数 61 | * @param callback 回调函数 62 | * @return call 63 | */ 64 | public static Call get(Context context, String url, Map params, boolean isJumpLogin, OkCallback callback) { 65 | return get(context, url, params, null, isJumpLogin, callback); 66 | } 67 | 68 | 69 | /** 70 | * get方法 71 | * 72 | * @param url url 73 | * @param params 参数 74 | * @param tag 标记位 75 | * @param callback 回调函数 76 | * @return call 77 | */ 78 | public static Call get(Context context, String url, Map params, Object tag, OkCallback callback) { 79 | callback.setContext(context); 80 | String endUrl = url + "?" + encodeParameters(context, params); 81 | Log.d("url", endUrl); 82 | Request.Builder builder = new Request.Builder().url(endUrl); 83 | if (tag != null) { 84 | builder.tag(tag); 85 | } 86 | Request request = builder.build(); 87 | Call call = getInstance().newCall(request); 88 | call.enqueue(callback); 89 | return call; 90 | } 91 | 92 | /** 93 | * get方法 94 | * 95 | * @param url url 96 | * @param params 参数 97 | * @param tag 标记位 98 | * @param callback 回调函数 99 | * @return call 100 | */ 101 | public static Call get(Context context, String url, Map params, Object tag, boolean isJumpLogin, OkCallback callback) { 102 | callback.setContext(context); 103 | callback.setJumpLogin(isJumpLogin); 104 | String endUrl = url + "?" + encodeParameters(context, params); 105 | Log.d("url", endUrl); 106 | Request.Builder builder = new Request.Builder().url(endUrl); 107 | if (tag != null) { 108 | builder.tag(tag); 109 | } 110 | Request request = builder.build(); 111 | Call call = getInstance().newCall(request); 112 | call.enqueue(callback); 113 | return call; 114 | } 115 | 116 | 117 | /** 118 | * post方法 119 | * 120 | * @param url url 121 | * @param params 参数 122 | * @param callback 回调函数 123 | * @return call 124 | */ 125 | public static Call post(Context context, String url, Map params, OkCallback callback) { 126 | return post(context, url, params, null, callback); 127 | } 128 | 129 | /** 130 | * post方法 131 | * 132 | * @param url url 133 | * @param params 参数 134 | * @param tag 标记位 135 | * @param callback 回调函数 136 | * @return call 137 | */ 138 | public static Call post(Context context, String url, Map params, Object tag, OkCallback callback) { 139 | callback.setContext(context); 140 | Request.Builder builder = new Request.Builder().url(url); 141 | if (tag != null) { 142 | builder.tag(tag); 143 | } 144 | FormBody.Builder formBuilder = new FormBody.Builder(); 145 | if (params != null && params.size() > 0) { 146 | for (String key : params.keySet()) { 147 | formBuilder.add(key, params.get(key)); 148 | } 149 | } 150 | builder.post(formBuilder.build()); 151 | 152 | Request request = builder.build(); 153 | Call call = getInstance().newCall(request); 154 | call.enqueue(callback); 155 | return call; 156 | } 157 | 158 | 159 | /** 160 | * 上传文件方法 161 | * 162 | * @param url url 163 | * @param params 参数 164 | * @param paths 文件路径 165 | * @param callback 回调函数 166 | * @return call 167 | */ 168 | public static Call upload(Context context, String url, Map params, List paths, OkCallback callback) { 169 | MultipartBody.Builder builder = new MultipartBody.Builder(); 170 | builder.setType(MultipartBody.FORM); 171 | if (params != null && params.size() > 0) { 172 | for (String key : params.keySet()) { 173 | builder.addFormDataPart(key, params.get(key)); 174 | } 175 | } 176 | if (paths != null && paths.size() > 0) { 177 | if (paths.size() == 1) { 178 | File file = new File(paths.get(0)); 179 | builder.addFormDataPart("file", file.getName(), RequestBody.create(null, file)); 180 | } else { 181 | for (int i = 0; i < paths.size(); i++) { 182 | File file = new File(paths.get(i)); 183 | builder.addFormDataPart("file[" + i + "]", file.getName(), RequestBody.create(null, file)); 184 | } 185 | } 186 | } 187 | RequestBody body = builder.build(); 188 | Request request = new Request.Builder().url(url).post(body).build(); 189 | Call call = getInstance().newCall(request); 190 | call.enqueue(callback); 191 | return call; 192 | } 193 | 194 | 195 | /** 196 | * 添加参数 197 | * 198 | * @param params 参数值 199 | * @return 参数字符串 200 | */ 201 | private static String encodeParameters(Context context, Map params) { 202 | if (params == null) { 203 | params = new HashMap<>(); 204 | } 205 | StringBuilder sb = new StringBuilder(""); 206 | try { 207 | for (Map.Entry entry : params.entrySet()) { 208 | sb.append(URLEncoder.encode(entry.getKey(), 209 | "UTF-8")); 210 | sb.append('='); 211 | sb.append(URLEncoder.encode(entry.getValue(), 212 | "UTF-8")); 213 | sb.append('&'); 214 | } 215 | return sb.toString(); 216 | } catch (Exception e) { 217 | } 218 | return sb.toString(); 219 | } 220 | 221 | } 222 | -------------------------------------------------------------------------------- /app/src/main/java/com/smile/taobaodemo/ui/adapter/HomeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.smile.taobaodemo.ui.adapter; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.v7.widget.GridLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import com.oushangfeng.marqueelayout.MarqueeLayout; 14 | import com.oushangfeng.marqueelayout.MarqueeLayoutAdapter; 15 | import com.smile.taobaodemo.R; 16 | import com.smile.taobaodemo.base.Type; 17 | import com.smile.taobaodemo.model.entity.HomeBase; 18 | import com.smile.taobaodemo.model.entity.HomeTop; 19 | import com.smile.taobaodemo.utils.GlideUtil; 20 | import com.smile.taobaodemo.widget.CirclePageIndicator; 21 | import com.smile.taobaodemo.widget.FooterLoading; 22 | 23 | import java.util.List; 24 | import java.util.Random; 25 | 26 | import butterknife.BindView; 27 | import butterknife.ButterKnife; 28 | import cn.trinea.android.view.autoscrollviewpager.AutoScrollViewPager; 29 | 30 | /** 31 | * @author Smile Wei 32 | * @since 2017/03/01. 33 | */ 34 | 35 | public class HomeAdapter extends RecyclerView.Adapter { 36 | private Context context; 37 | private Activity activity; 38 | private List list; 39 | private List loopList; 40 | private List headlineList; 41 | private final SpanSizeLookup spanSizeLookup = new SpanSizeLookup(); 42 | private LayoutInflater inflater; 43 | 44 | public HomeAdapter(Context context, Activity activity, List list) { 45 | this.context = context; 46 | this.activity = activity; 47 | this.list = list; 48 | inflater = LayoutInflater.from(context); 49 | } 50 | 51 | public void setLoopList(List loopList) { 52 | this.loopList = loopList; 53 | } 54 | 55 | public void setHeadlineList(List headlineList) { 56 | this.headlineList = headlineList; 57 | } 58 | 59 | public GridLayoutManager.SpanSizeLookup getSpanSizeLookup() { 60 | return spanSizeLookup; 61 | } 62 | 63 | @Override 64 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 65 | View view; 66 | switch (viewType) { 67 | case HomeBase.TYPE_CAROUSEL: 68 | view = inflater.inflate(R.layout.item_home_type_carousel, parent, false); 69 | return new CarouselHolder(view); 70 | case HomeBase.TYPE_CATEGORY: 71 | view = inflater.inflate(R.layout.fragment_navigation_home_category, parent, false); 72 | return new CategoryHolder(view); 73 | case HomeBase.TYPE_HEADLINE: 74 | view = inflater.inflate(R.layout.item_home_type_headline, parent, false); 75 | return new HeadlineHolder(view); 76 | case HomeBase.TYPE_HEADER: 77 | view = inflater.inflate(R.layout.item_home_type_header, parent, false); 78 | return new HeaderHolder(view); 79 | case HomeBase.TYPE_DIVIDER: 80 | view = inflater.inflate(R.layout.item_home_type_divider, parent, false); 81 | return new PlaceHolder(view); 82 | case HomeBase.TYPE_LIVE: 83 | view = inflater.inflate(R.layout.item_home_type_live, parent, false); 84 | return new LiveHolder(view); 85 | case HomeBase.TYPE_HOT: 86 | view = inflater.inflate(R.layout.item_home_type_hot, parent, false); 87 | return new CommonHolder(view); 88 | case HomeBase.TYPE_RECOMMEND: 89 | view = inflater.inflate(R.layout.item_home_type_recommend, parent, false); 90 | return new RecommendHolder(view); 91 | case HomeBase.TYPE_PLACE: 92 | view = inflater.inflate(R.layout.item_place, parent, false); 93 | return new PlaceHolder(view); 94 | default: 95 | view = inflater.inflate(R.layout.item_footer_loading, parent, false); 96 | return new FooterHolder(view); 97 | } 98 | } 99 | 100 | @Override 101 | public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { 102 | HomeBase bean = list.get(position); 103 | if (viewHolder instanceof CarouselHolder) { 104 | CarouselHolder holder = (CarouselHolder) viewHolder; 105 | holder.viewPager.setAdapter(new ImageHomeAdapter(context, activity, loopList)); 106 | holder.indicator.setViewPager(holder.viewPager); 107 | holder.viewPager.setInterval(4000); 108 | holder.viewPager.setSlideBorderMode(AutoScrollViewPager.SLIDE_BORDER_MODE_TO_PARENT); 109 | holder.viewPager.startAutoScroll(); 110 | } else if (viewHolder instanceof HeadlineHolder) { 111 | HeadlineHolder holder = (HeadlineHolder) viewHolder; 112 | MarqueeLayoutAdapter topAdapter = new MarqueeLayoutAdapter(headlineList) { 113 | @Override 114 | protected int getItemLayoutId() { 115 | return R.layout.item_marquee; 116 | } 117 | 118 | @Override 119 | protected void initView(View view, int position, HomeBase item) { 120 | ((TextView) view).setText(item.getName()); 121 | 122 | } 123 | }; 124 | holder.marqueeLayout.setAdapter(topAdapter); 125 | holder.marqueeLayout.start(); 126 | } else if (viewHolder instanceof HeaderHolder) { 127 | HeaderHolder holder = (HeaderHolder) viewHolder; 128 | holder.tvTitle.setText(bean.getName()); 129 | } else if (viewHolder instanceof LiveHolder) { 130 | LiveHolder holder = (LiveHolder) viewHolder; 131 | GlideUtil.load(activity, bean.getUrl(), holder.ivHome); 132 | holder.tvTitle.setText(bean.getName()); 133 | } else if (viewHolder instanceof CommonHolder) { 134 | CommonHolder holder = (CommonHolder) viewHolder; 135 | GlideUtil.load(activity, bean.getUrl(), holder.ivHome); 136 | holder.tvTitle.setText(bean.getName()); 137 | holder.tvPrice.setText(String.format("%s%s", bean.getCurrency(), bean.getPrice())); 138 | } else if (viewHolder instanceof RecommendHolder) { 139 | RecommendHolder holder = (RecommendHolder) viewHolder; 140 | GlideUtil.load(activity, bean.getUrl(), holder.ivHome); 141 | holder.tvTitle.setText(bean.getName()); 142 | holder.tvPrice.setText(String.format("%s%s", bean.getCurrency(), bean.getPrice())); 143 | holder.tvCount.setText(String.format("%d人付款", new Random().nextInt(10000))); 144 | 145 | } else if (viewHolder instanceof FooterHolder) { 146 | FooterHolder holder = (FooterHolder) viewHolder; 147 | holder.footerLoading.onLoad(Type.TYPE_FOOTER_FULL == list.get(position).getType()); 148 | } 149 | } 150 | 151 | @Override 152 | public int getItemViewType(int position) { 153 | return list.get(position).getType(); 154 | } 155 | 156 | @Override 157 | public int getItemCount() { 158 | return list.size(); 159 | } 160 | 161 | class CarouselHolder extends RecyclerView.ViewHolder { 162 | @BindView(R.id.view_pager) 163 | AutoScrollViewPager viewPager; 164 | @BindView(R.id.indicator) 165 | CirclePageIndicator indicator; 166 | 167 | CarouselHolder(View itemView) { 168 | super(itemView); 169 | ButterKnife.bind(this, itemView); 170 | } 171 | } 172 | 173 | class HeadlineHolder extends RecyclerView.ViewHolder { 174 | @BindView(R.id.marquee_layout) 175 | MarqueeLayout marqueeLayout; 176 | 177 | HeadlineHolder(View itemView) { 178 | super(itemView); 179 | ButterKnife.bind(this, itemView); 180 | } 181 | } 182 | 183 | 184 | class CommonHolder extends RecyclerView.ViewHolder { 185 | @BindView(R.id.iv_home) 186 | ImageView ivHome; 187 | @BindView(R.id.tv_title) 188 | TextView tvTitle; 189 | @BindView(R.id.tv_price) 190 | TextView tvPrice; 191 | 192 | 193 | CommonHolder(View itemView) { 194 | super(itemView); 195 | ButterKnife.bind(this, itemView); 196 | } 197 | 198 | } 199 | 200 | public interface OnItemClickListener { 201 | void onItemClick(int position); 202 | } 203 | 204 | private OnItemClickListener listener; 205 | 206 | public void setOnItemClickListener(OnItemClickListener listener) { 207 | this.listener = listener; 208 | } 209 | 210 | class RecommendHolder extends RecyclerView.ViewHolder { 211 | @BindView(R.id.iv_home) 212 | ImageView ivHome; 213 | @BindView(R.id.tv_title) 214 | TextView tvTitle; 215 | @BindView(R.id.tv_price) 216 | TextView tvPrice; 217 | @BindView(R.id.tv_count) 218 | TextView tvCount; 219 | 220 | RecommendHolder(View itemView) { 221 | super(itemView); 222 | ButterKnife.bind(this, itemView); 223 | 224 | itemView.setOnClickListener(new View.OnClickListener() { 225 | @Override 226 | public void onClick(View v) { 227 | if (listener != null) 228 | listener.onItemClick(getLayoutPosition()); 229 | } 230 | }); 231 | } 232 | 233 | } 234 | 235 | class LiveHolder extends RecyclerView.ViewHolder { 236 | @BindView(R.id.iv_home) 237 | ImageView ivHome; 238 | @BindView(R.id.tv_title) 239 | TextView tvTitle; 240 | 241 | LiveHolder(View itemView) { 242 | super(itemView); 243 | ButterKnife.bind(this, itemView); 244 | } 245 | 246 | } 247 | 248 | class HeaderHolder extends RecyclerView.ViewHolder { 249 | @BindView(R.id.tv_title) 250 | TextView tvTitle; 251 | 252 | HeaderHolder(View itemView) { 253 | super(itemView); 254 | ButterKnife.bind(this, itemView); 255 | } 256 | } 257 | 258 | private class PlaceHolder extends RecyclerView.ViewHolder { 259 | PlaceHolder(View itemView) { 260 | super(itemView); 261 | } 262 | } 263 | 264 | 265 | private class SpanSizeLookup extends GridLayoutManager.SpanSizeLookup { 266 | @Override 267 | public int getSpanSize(int position) { 268 | return list.get(position).getSpanCount(); 269 | } 270 | } 271 | 272 | class CategoryHolder extends RecyclerView.ViewHolder { 273 | 274 | CategoryHolder(View view) { 275 | super(view); 276 | ButterKnife.bind(this, view); 277 | } 278 | } 279 | 280 | class FooterHolder extends RecyclerView.ViewHolder { 281 | @BindView(R.id.footer) 282 | FooterLoading footerLoading; 283 | 284 | FooterHolder(View itemView) { 285 | super(itemView); 286 | ButterKnife.bind(this, itemView); 287 | } 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_goods_detail_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 17 | 18 | 22 | 23 | 30 | 31 | 32 | 33 | 42 | 43 | 53 | 54 | 55 | 62 | 63 | 64 | 69 | 70 | 77 | 78 | 79 | 80 | 84 | 85 | 90 | 91 | 97 | 98 | 106 | 107 | 115 | 116 | 124 | 125 | 132 | 133 | 139 | 140 | 141 | 142 | 146 | 147 | 154 | 155 | 163 | 164 | 172 | 173 | 174 | 175 | 182 | 183 | 191 | 192 | 200 | 201 | 202 | 203 | 210 | 211 | 219 | 220 | 227 | 228 | 229 | 230 | 235 | 236 | 245 | 246 | 247 | 251 | 252 | 260 | 261 | 269 | 270 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | --------------------------------------------------------------------------------