├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── linshao.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── turn_left_icon.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── banner_1.png │ │ │ │ ├── banner_2.png │ │ │ │ ├── banner_3.png │ │ │ │ ├── banner_4.png │ │ │ │ ├── banner_5.png │ │ │ │ └── banner_default.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── color │ │ │ │ └── selector_banner_anim_color.xml │ │ │ ├── drawable │ │ │ │ ├── shape_anim_selected.xml │ │ │ │ ├── shape_anim_default.xml │ │ │ │ ├── shape_indicator_bg.xml │ │ │ │ ├── selector_banner_anim_tab.xml │ │ │ │ ├── shape_common_bg.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ ├── merge_banner_view.xml │ │ │ │ ├── banner_amin_flow_tab.xml │ │ │ │ ├── activity_banner_mz.xml │ │ │ │ ├── activity_banner_view.xml │ │ │ │ ├── banner_item_second_pager.xml │ │ │ │ ├── activity_show_anim.xml │ │ │ │ ├── activity_base_use.xml │ │ │ │ ├── activity_banner_indicator.xml │ │ │ │ ├── activity_banner_data.xml │ │ │ │ └── activity_main.xml │ │ │ ├── values │ │ │ │ ├── styles.xml │ │ │ │ ├── attrs.xml │ │ │ │ ├── colors.xml │ │ │ │ └── strings.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── test │ │ │ │ └── banner │ │ │ │ ├── widget │ │ │ │ ├── Default.java │ │ │ │ ├── flowlayout │ │ │ │ │ ├── TagView.java │ │ │ │ │ ├── TagAdapter.java │ │ │ │ │ ├── FlowLayout.java │ │ │ │ │ └── TagFlowLayout.java │ │ │ │ └── BannerView.java │ │ │ │ ├── bean │ │ │ │ └── BannerItem.java │ │ │ │ ├── utils │ │ │ │ ├── PixelUtils.java │ │ │ │ ├── DateUtils.java │ │ │ │ └── ScreenUtils.java │ │ │ │ ├── application │ │ │ │ └── AppContext.java │ │ │ │ ├── MainActivity.java │ │ │ │ └── banner │ │ │ │ ├── BannerMzActivity.java │ │ │ │ ├── BaseUseActivity.java │ │ │ │ ├── BannerViewActivity.java │ │ │ │ ├── BannerIndicatorActivity.java │ │ │ │ └── BannerDataActivity.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── test │ │ │ └── banner │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── test │ │ └── banner │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── banner ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── arrays.xml │ │ │ │ └── attr.xml │ │ │ ├── drawable-xxxhdpi │ │ │ │ └── no_banner.png │ │ │ ├── drawable │ │ │ │ ├── shape_banner_default_indicator.xml │ │ │ │ └── shape_banner_select_indicator.xml │ │ │ └── layout │ │ │ │ └── merge_banner.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── geek │ │ │ └── banner │ │ │ ├── constant │ │ │ └── BannerConfig.java │ │ │ ├── transformer │ │ │ ├── simple │ │ │ │ ├── ScaleInOutTransformer.java │ │ │ │ ├── StackTransformer.java │ │ │ │ ├── DefaultTransformer.java │ │ │ │ ├── AccordionTransformer.java │ │ │ │ ├── CubeOutTransformer.java │ │ │ │ ├── CubeInTransformer.java │ │ │ │ ├── ZoomInTransformer.java │ │ │ │ ├── ZoomOutTranformer.java │ │ │ │ ├── RotateUpTransformer.java │ │ │ │ ├── RotateDownTransformer.java │ │ │ │ ├── BackgroundToForegroundTransformer.java │ │ │ │ ├── ForegroundToBackgroundTransformer.java │ │ │ │ ├── FlipVerticalTransformer.java │ │ │ │ ├── DepthPageTransformer.java │ │ │ │ ├── FlipHorizontalTransformer.java │ │ │ │ ├── ZoomOutSlideTransformer.java │ │ │ │ ├── TabletTransformer.java │ │ │ │ └── ABaseTransformer.java │ │ │ └── complex │ │ │ │ ├── NonPageTransformer.java │ │ │ │ ├── BasePageTransformer.java │ │ │ │ ├── ScaleYTransformer.java │ │ │ │ ├── AlphaPageTransformer.java │ │ │ │ ├── RotateYTransformer.java │ │ │ │ ├── RotateDownPageTransformer.java │ │ │ │ ├── RotateUpPageTransformer.java │ │ │ │ └── ScaleInTransformer.java │ │ │ ├── loader │ │ │ ├── BannerEntry.java │ │ │ ├── ImageLoader.java │ │ │ └── BannerLoader.java │ │ │ └── widget │ │ │ ├── BannerScroller.java │ │ │ └── BannerViewPager.java │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── geek │ │ │ └── banner │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── geek │ │ └── banner │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── banner.jks ├── banner1.png ├── banner2.png ├── banner3.png ├── banner4.png ├── banner5.png ├── banner6.png ├── linshao.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── gradlew.bat ├── gradlew └── README.md /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /banner/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':banner' 2 | -------------------------------------------------------------------------------- /banner.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/banner.jks -------------------------------------------------------------------------------- /banner1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/banner1.png -------------------------------------------------------------------------------- /banner2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/banner2.png -------------------------------------------------------------------------------- /banner3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/banner3.png -------------------------------------------------------------------------------- /banner4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/banner4.png -------------------------------------------------------------------------------- /banner5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/banner5.png -------------------------------------------------------------------------------- /banner6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/banner6.png -------------------------------------------------------------------------------- /linshao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/linshao.png -------------------------------------------------------------------------------- /banner/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/linshao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-xxhdpi/linshao.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/banner_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/drawable-xxxhdpi/banner_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/banner_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/drawable-xxxhdpi/banner_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/banner_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/drawable-xxxhdpi/banner_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/banner_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/drawable-xxxhdpi/banner_4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/banner_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/drawable-xxxhdpi/banner_5.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/turn_left_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-xxhdpi/turn_left_icon.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /banner/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /banner/src/main/res/drawable-xxxhdpi/no_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/banner/src/main/res/drawable-xxxhdpi/no_banner.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/banner_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/drawable-xxxhdpi/banner_default.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlpsDog/Banner/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /banner/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/color/selector_banner_anim_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_anim_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jul 31 16:34:00 CST 2019 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-5.1.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_anim_default.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_indicator_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/widget/Default.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.widget; 2 | 3 | /** 4 | * @Project: Banner 5 | * @Package: com.test.banner.widget 6 | * @Author: HSL 7 | * @Time: 2019/08/07 10:26 8 | * @E-mail: xxx@163.com 9 | * @Description: 这个人太懒,没留下什么踪迹~ 10 | */ 11 | public class Default { 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_banner_anim_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /banner/src/main/res/drawable/shape_banner_default_indicator.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /banner/src/main/res/drawable/shape_banner_select_indicator.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_common_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/merge_banner_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/test/java/com/test/banner/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.test.banner; 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() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /banner/src/test/java/com/geek/banner/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner; 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() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/constant/BannerConfig.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.constant; 2 | 3 | /** 4 | * @Author: HSL 5 | * @Time: 2018/12/13 14:00 6 | * @E-mail: xxx@163.com 7 | * @Description: Banner常量 8 | */ 9 | public interface BannerConfig { 10 | 11 | boolean CAN_AUTO_PLAY = true; 12 | int SINGLE = 1; 13 | int MULTI = 2; 14 | int MZ_EFFECT = 3; 15 | int INTERVAL_TIME = 3000; 16 | int SCROLL_TIME = 800; 17 | int EXPOSE_WIDTH = 40; 18 | int PAGE_SPACING = 10; 19 | int PAGER_TRANSFORM = 0; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/ScaleInOutTransformer.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.transformer.simple; 2 | 3 | import android.view.View; 4 | 5 | public class ScaleInOutTransformer extends ABaseTransformer { 6 | 7 | @Override 8 | protected void onTransform(View view, float position) { 9 | view.setPivotX(position < 0 ? 0 : view.getWidth()); 10 | view.setPivotY(view.getHeight() / 2f); 11 | float scale = position < 0 ? 1f + position : 1f - position; 12 | view.setScaleX(scale); 13 | view.setScaleY(scale); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/complex/NonPageTransformer.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.transformer.complex; 2 | 3 | import android.support.v4.view.ViewPager; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by zhy on 16/5/7. 8 | */ 9 | public class NonPageTransformer implements ViewPager.PageTransformer { 10 | @Override 11 | public void transformPage(View page, float position) { 12 | page.setScaleX(0.999f); 13 | } 14 | 15 | public static final ViewPager.PageTransformer INSTANCE = new NonPageTransformer(); 16 | } 17 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/loader/BannerEntry.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.loader; 2 | 3 | /** 4 | * @Project: Banner 5 | * @Package: com.geek.banner.loader 6 | * @Author: HSL 7 | * @Time: 2019/08/07 16:08 8 | * @E-mail: xxx@163.com 9 | * @Description: 这个人太懒,没留下什么踪迹~ 10 | */ 11 | public interface BannerEntry { 12 | 13 | /** 14 | * 获取Banner数据源 15 | * 16 | * @return 17 | */ 18 | T getBannerPath(); 19 | 20 | /** 21 | * 获取指示器文本 22 | * 23 | * @return 24 | */ 25 | String getIndicatorText(); 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | #f8f8f8 8 | #efefef 9 | 10 | #ffffff 11 | #333333 12 | #999999 13 | #efefef 14 | #666666 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/banner_amin_flow_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/loader/ImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.loader; 2 | 3 | import android.content.Context; 4 | import android.widget.ImageView; 5 | 6 | /** 7 | * @Author: HSL 8 | * @Time: 2018/12/13 14:01 9 | * @E-mail: xxx@163.com 10 | * @Description: ImageView加载器~ 11 | */ 12 | public abstract class ImageLoader implements BannerLoader { 13 | 14 | @Override 15 | public ImageView createView(Context context, int position) { 16 | ImageView imageView = new ImageView(context); 17 | imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); 18 | return imageView; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/loader/BannerLoader.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.loader; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | 6 | /** 7 | * @Author: HSL 8 | * @Time: 2018/12/13 14:01 9 | * @E-mail: xxx@163.com 10 | * @Description: Banner加载器~ 11 | */ 12 | public interface BannerLoader { 13 | 14 | /** 15 | * 加载VIEW 16 | * 17 | * @param context 18 | * @param entry 19 | * @param position 显示的位置 20 | * @param imageView 21 | */ 22 | void loadView(Context context, BannerEntry entry, int position, V imageView); 23 | 24 | /** 25 | * 创建View 26 | * 27 | * @param context 28 | * @param position 29 | * @return 30 | */ 31 | V createView(Context context, int position); 32 | } 33 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /banner/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/test/banner/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.test.banner; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.geek.myapplication", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /banner/src/androidTest/java/com/geek/banner/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.geek.banner.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /banner/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | 6 | defaultConfig { 7 | minSdkVersion 15 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | } 22 | 23 | dependencies { 24 | implementation fileTree(dir: 'libs', include: ['*.jar']) 25 | compileOnly 'com.android.support:appcompat-v7:28.0.0' 26 | testCompileOnly 'junit:junit:4.12' 27 | androidTestCompileOnly 'com.android.support.test:runner:1.0.2' 28 | androidTestCompileOnly 'com.android.support.test.espresso:espresso-core:3.0.2' 29 | } 30 | -------------------------------------------------------------------------------- /banner/src/main/res/layout/merge_banner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 17 | 18 | 24 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/complex/BasePageTransformer.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.transformer.complex; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.support.v4.view.ViewPager.PageTransformer; 6 | import android.view.View; 7 | 8 | /** 9 | * Created by zhy on 16/5/7. 10 | */ 11 | public abstract class BasePageTransformer implements PageTransformer { 12 | protected PageTransformer mPageTransformer = NonPageTransformer.INSTANCE; 13 | public static final float DEFAULT_CENTER = 0.5f; 14 | 15 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 16 | public void transformPage(View view, float position) { 17 | if (mPageTransformer != null) { 18 | mPageTransformer.transformPage(view, position); 19 | } 20 | 21 | pageTransform(view, position); 22 | } 23 | 24 | protected abstract void pageTransform(View view, float position); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/StackTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class StackTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | view.setTranslationX(position < 0 ? 0f : -view.getWidth() * position); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/DefaultTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class DefaultTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | } 26 | 27 | @Override 28 | public boolean isPagingEnabled() { 29 | return true; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/complex/ScaleYTransformer.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.transformer.complex; 2 | 3 | import android.support.v4.view.ViewPager; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by zhouwei on 17/5/26. 8 | */ 9 | 10 | public class ScaleYTransformer implements ViewPager.PageTransformer { 11 | private static final float MIN_SCALE = 0.9F; 12 | @Override 13 | public void transformPage(View page, float position) { 14 | 15 | if(position < -1){ 16 | page.setScaleY(MIN_SCALE); 17 | }else if(position<= 1){ 18 | // 19 | float scale = Math.max(MIN_SCALE,1 - Math.abs(position)); 20 | page.setScaleY(scale); 21 | /*page.setScaleX(scale); 22 | 23 | if(position<0){ 24 | page.setTranslationX(width * (1 - scale) /2); 25 | }else{ 26 | page.setTranslationX(-width * (1 - scale) /2); 27 | }*/ 28 | 29 | }else{ 30 | page.setScaleY(MIN_SCALE); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/AccordionTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class AccordionTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | view.setPivotX(position < 0 ? 0 : view.getWidth()); 26 | view.setScaleX(position < 0 ? 1f + position : 1f - position); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/bean/BannerItem.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.bean; 2 | 3 | import com.geek.banner.loader.BannerEntry; 4 | 5 | /** 6 | * @Project: Banner 7 | * @Package: com.test.banner 8 | * @Author: HSL 9 | * @Time: 2019/08/07 16:25 10 | * @E-mail: xxx@163.com 11 | * @Description: 这个人太懒,没留下什么踪迹~ 12 | */ 13 | public class BannerItem implements BannerEntry { 14 | 15 | private Object path; 16 | private String indicatorText; 17 | 18 | public BannerItem() { 19 | } 20 | 21 | public BannerItem(Object path, String indicatorText) { 22 | this.path = path; 23 | this.indicatorText = indicatorText; 24 | } 25 | 26 | @Override 27 | public Object getBannerPath() { 28 | return path; 29 | } 30 | 31 | @Override 32 | public String getIndicatorText() { 33 | return indicatorText; 34 | } 35 | 36 | public Object getPath() { 37 | return path; 38 | } 39 | 40 | public void setPath(Object path) { 41 | this.path = path; 42 | } 43 | 44 | public void setIndicatorText(String indicatorText) { 45 | this.indicatorText = indicatorText; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/CubeOutTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class CubeOutTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | view.setPivotX(position < 0f ? view.getWidth() : 0f); 26 | view.setPivotY(view.getHeight() * 0.5f); 27 | view.setRotationY(90f * position); 28 | } 29 | 30 | @Override 31 | public boolean isPagingEnabled() { 32 | return true; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/CubeInTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class CubeInTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | // Rotate the fragment on the left or right edge 26 | view.setPivotX(position > 0 ? 0 : view.getWidth()); 27 | view.setPivotY(0); 28 | view.setRotationY(-90f * position); 29 | } 30 | 31 | @Override 32 | public boolean isPagingEnabled() { 33 | return true; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/ZoomInTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class ZoomInTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float scale = position < 0 ? position + 1f : Math.abs(1f - position); 26 | view.setScaleX(scale); 27 | view.setScaleY(scale); 28 | view.setPivotX(view.getWidth() * 0.5f); 29 | view.setPivotY(view.getHeight() * 0.5f); 30 | view.setAlpha(position < -1f || position > 1f ? 0f : 1f - (scale - 1f)); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/ZoomOutTranformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class ZoomOutTranformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float scale = 1f + Math.abs(position); 26 | view.setScaleX(scale); 27 | view.setScaleY(scale); 28 | view.setPivotX(view.getWidth() * 0.5f); 29 | view.setPivotY(view.getHeight() * 0.5f); 30 | view.setAlpha(position < -1f || position > 1f ? 0f : 1f - (scale - 1f)); 31 | if(position == -1){ 32 | view.setTranslationX(view.getWidth() * -1); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/RotateUpTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class RotateUpTransformer extends ABaseTransformer { 22 | 23 | private static final float ROT_MOD = -15f; 24 | 25 | @Override 26 | protected void onTransform(View view, float position) { 27 | final float width = view.getWidth(); 28 | final float rotation = ROT_MOD * position; 29 | 30 | view.setPivotX(width * 0.5f); 31 | view.setPivotY(0f); 32 | view.setTranslationX(0f); 33 | view.setRotation(rotation); 34 | } 35 | 36 | @Override 37 | protected boolean isPagingEnabled() { 38 | return true; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/RotateDownTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class RotateDownTransformer extends ABaseTransformer { 22 | 23 | private static final float ROT_MOD = -15f; 24 | 25 | @Override 26 | protected void onTransform(View view, float position) { 27 | final float width = view.getWidth(); 28 | final float height = view.getHeight(); 29 | final float rotation = ROT_MOD * position * -1.25f; 30 | 31 | view.setPivotX(width * 0.5f); 32 | view.setPivotY(height); 33 | view.setRotation(rotation); 34 | } 35 | 36 | @Override 37 | protected boolean isPagingEnabled() { 38 | return true; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/BackgroundToForegroundTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class BackgroundToForegroundTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float height = view.getHeight(); 26 | final float width = view.getWidth(); 27 | final float scale = min(position < 0 ? 1f : Math.abs(1f - position), 0.5f); 28 | 29 | view.setScaleX(scale); 30 | view.setScaleY(scale); 31 | view.setPivotX(width * 0.5f); 32 | view.setPivotY(height * 0.5f); 33 | view.setTranslationX(position < 0 ? width * position : -width * position * 0.25f); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/ForegroundToBackgroundTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class ForegroundToBackgroundTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float height = view.getHeight(); 26 | final float width = view.getWidth(); 27 | final float scale = min(position > 0 ? 1f : Math.abs(1f + position), 0.5f); 28 | 29 | view.setScaleX(scale); 30 | view.setScaleY(scale); 31 | view.setPivotX(width * 0.5f); 32 | view.setPivotY(height * 0.5f); 33 | view.setTranslationX(position > 0 ? width * position : -width * position * 0.25f); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/utils/PixelUtils.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.utils; 2 | 3 | import android.content.Context; 4 | 5 | public class PixelUtils { 6 | 7 | /** 8 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素) 9 | */ 10 | public static int dip2px(Context context, float dpValue) { 11 | final float scale = context.getResources().getDisplayMetrics().density; 12 | return (int) (dpValue * scale + 0.5f); 13 | } 14 | 15 | /** 16 | * 根据手机的分辨率从 px(像素)的单位 转成为 dp 17 | */ 18 | public static int px2dip(Context context, float pxValue) { 19 | final float scale = context.getResources().getDisplayMetrics().density; 20 | return (int) (pxValue / scale + 0.5f); 21 | } 22 | 23 | /** 24 | * 将px值转换为sp值 25 | * 26 | * @param pxValue 27 | * @param fontScale 28 | * (DisplayMetrics类中属性scaledDensity) 29 | * @return 30 | */ 31 | public static int px2sp(Context context, float pxValue) { 32 | float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 33 | return (int) (pxValue / fontScale + 0.5f); 34 | } 35 | 36 | /** 37 | * 将sp值转换为px值 38 | * 39 | * @param spValue 40 | * @param fontScale 41 | * (DisplayMetrics类中属性scaledDensity) 42 | * @return 43 | */ 44 | public static int sp2px(Context context, float spValue) { 45 | float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 46 | return (int) (spValue * fontScale + 0.5f); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /banner/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/widget/BannerScroller.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.widget; 2 | 3 | import android.content.Context; 4 | import android.view.animation.Interpolator; 5 | import android.widget.Scroller; 6 | 7 | import com.geek.banner.constant.BannerConfig; 8 | 9 | /** 10 | * @Author: HSL 11 | * @Time: 2018/12/13 14:12 12 | * @E-mail: xxx@163.com 13 | * @Description: 控制ViewPager翻页的时间~ 14 | */ 15 | public class BannerScroller extends Scroller { 16 | 17 | //ViewPager翻页的时间 18 | private int mDuration = BannerConfig.SCROLL_TIME; 19 | 20 | public BannerScroller(Context context) { 21 | super(context); 22 | } 23 | 24 | public BannerScroller(Context context, Interpolator interpolator) { 25 | super(context, interpolator); 26 | } 27 | 28 | public BannerScroller(Context context, Interpolator interpolator, boolean flywheel) { 29 | super(context, interpolator, flywheel); 30 | } 31 | 32 | @Override 33 | public void startScroll(int startX, int startY, int dx, int dy, int duration) { 34 | super.startScroll(startX, startY, dx, dy, mDuration); 35 | } 36 | 37 | @Override 38 | public void startScroll(int startX, int startY, int dx, int dy) { 39 | super.startScroll(startX, startY, dx, dy, mDuration); 40 | } 41 | 42 | /** 43 | * 设置翻页时间 44 | * 45 | * @param duration 46 | */ 47 | public void setDuration(int duration) { 48 | mDuration = duration; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/FlipVerticalTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class FlipVerticalTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float rotation = -180f * position; 26 | 27 | view.setAlpha(rotation > 90f || rotation < -90f ? 0f : 1f); 28 | view.setPivotX(view.getWidth() * 0.5f); 29 | view.setPivotY(view.getHeight() * 0.5f); 30 | view.setRotationX(rotation); 31 | } 32 | 33 | @Override 34 | protected void onPostTransform(View page, float position) { 35 | super.onPostTransform(page, position); 36 | 37 | if (position > -0.5f && position < 0.5f) { 38 | page.setVisibility(View.VISIBLE); 39 | } else { 40 | page.setVisibility(View.INVISIBLE); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_banner_mz.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 24 | 25 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_banner_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 25 | 26 | 36 | 37 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/DepthPageTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class DepthPageTransformer extends ABaseTransformer { 22 | 23 | private static final float MIN_SCALE = 0.75f; 24 | 25 | @Override 26 | protected void onTransform(View view, float position) { 27 | if (position <= 0f) { 28 | view.setTranslationX(0f); 29 | view.setScaleX(1f); 30 | view.setScaleY(1f); 31 | } else if (position <= 1f) { 32 | final float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); 33 | view.setAlpha(1 - position); 34 | view.setPivotY(0.5f * view.getHeight()); 35 | view.setTranslationX(view.getWidth() * -position); 36 | view.setScaleX(scaleFactor); 37 | view.setScaleY(scaleFactor); 38 | } 39 | } 40 | 41 | @Override 42 | protected boolean isPagingEnabled() { 43 | return true; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/banner_item_second_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 29 | 30 | 39 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/FlipHorizontalTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class FlipHorizontalTransformer extends ABaseTransformer { 22 | 23 | @Override 24 | protected void onTransform(View view, float position) { 25 | final float rotation = 180f * position; 26 | 27 | view.setAlpha(rotation > 90f || rotation < -90f ? 0 : 1); 28 | view.setPivotX(view.getWidth() * 0.5f); 29 | view.setPivotY(view.getHeight() * 0.5f); 30 | view.setRotationY(rotation); 31 | } 32 | 33 | @Override 34 | protected void onPostTransform(View page, float position) { 35 | super.onPostTransform(page, position); 36 | 37 | //resolve problem: new page can't handle click event! 38 | if (position > -0.5f && position < 0.5f) { 39 | page.setVisibility(View.VISIBLE); 40 | } else { 41 | page.setVisibility(View.INVISIBLE); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/widget/flowlayout/TagView.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.widget.flowlayout; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.widget.Checkable; 6 | import android.widget.FrameLayout; 7 | 8 | /** 9 | * @Description:https://github.com/hongyangAndroid/FlowLayout 10 | */ 11 | public class TagView extends FrameLayout implements Checkable { 12 | private boolean isChecked; 13 | private static final int[] CHECK_STATE = new int[]{android.R.attr.state_checked}; 14 | 15 | public TagView(Context context) { 16 | super(context); 17 | } 18 | 19 | public View getTagView() { 20 | return getChildAt(0); 21 | } 22 | 23 | @Override 24 | public int[] onCreateDrawableState(int extraSpace) { 25 | int[] states = super.onCreateDrawableState(extraSpace + 1); 26 | if (isChecked()) { 27 | mergeDrawableStates(states, CHECK_STATE); 28 | } 29 | return states; 30 | } 31 | 32 | 33 | /** 34 | * Change the checked state of the view 35 | * 36 | * @param checked The new checked state 37 | */ 38 | @Override 39 | public void setChecked(boolean checked) { 40 | if (this.isChecked != checked) { 41 | this.isChecked = checked; 42 | refreshDrawableState(); 43 | } 44 | } 45 | 46 | /** 47 | * @return The current checked state of the view 48 | */ 49 | @Override 50 | public boolean isChecked() { 51 | return isChecked; 52 | } 53 | 54 | /** 55 | * Change the checked state of the view to the inverse of its current state 56 | */ 57 | @Override 58 | public void toggle() { 59 | setChecked(!isChecked); 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/complex/AlphaPageTransformer.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.transformer.complex; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.support.v4.view.ViewPager; 6 | import android.view.View; 7 | /** 8 | * @Author: HSL 9 | * @Time: 2018/12/13 14:05 10 | * @E-mail: xxx@163.com 11 | * @Description: 透明 12 | * 来自https://github.com/hongyangAndroid/MagicViewPager 13 | */ 14 | public class AlphaPageTransformer extends BasePageTransformer { 15 | private static final float DEFAULT_MIN_ALPHA = 0.5f; 16 | private float mMinAlpha = DEFAULT_MIN_ALPHA; 17 | 18 | public AlphaPageTransformer() { 19 | 20 | } 21 | 22 | public AlphaPageTransformer(float minAlpha) { 23 | this(minAlpha, NonPageTransformer.INSTANCE); 24 | } 25 | 26 | public AlphaPageTransformer(ViewPager.PageTransformer pageTransformer) { 27 | this(DEFAULT_MIN_ALPHA, pageTransformer); 28 | } 29 | 30 | public AlphaPageTransformer(float minAlpha, ViewPager.PageTransformer pageTransformer) { 31 | mMinAlpha = minAlpha; 32 | mPageTransformer = pageTransformer; 33 | } 34 | 35 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 36 | public void pageTransform(View view, float position) { 37 | view.setScaleX(0.999f); 38 | if (position < -1) { 39 | view.setAlpha(mMinAlpha); 40 | } else if (position <= 1) { 41 | if (position < 0) { 42 | float factor = mMinAlpha + (1 - mMinAlpha) * (1 + position); 43 | view.setAlpha(factor); 44 | } else { 45 | float factor = mMinAlpha + (1 - mMinAlpha) * (1 - position); 46 | view.setAlpha(factor); 47 | } 48 | } else { 49 | view.setAlpha(mMinAlpha); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/ZoomOutSlideTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.view.View; 20 | 21 | public class ZoomOutSlideTransformer extends ABaseTransformer { 22 | 23 | private static final float MIN_SCALE = 0.85f; 24 | private static final float MIN_ALPHA = 0.5f; 25 | 26 | @Override 27 | protected void onTransform(View view, float position) { 28 | if (position >= -1 || position <= 1) { 29 | // Modify the default slide transition to shrink the page as well 30 | final float height = view.getHeight(); 31 | final float width = view.getWidth(); 32 | final float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); 33 | final float vertMargin = height * (1 - scaleFactor) / 2; 34 | final float horzMargin = width * (1 - scaleFactor) / 2; 35 | 36 | // Center vertically 37 | view.setPivotY(0.5f * height); 38 | view.setPivotX(0.5f * width); 39 | 40 | if (position < 0) { 41 | view.setTranslationX(horzMargin - vertMargin / 2); 42 | } else { 43 | view.setTranslationX(-horzMargin + vertMargin / 2); 44 | } 45 | 46 | // Scale the page down (between MIN_SCALE and 1) 47 | view.setScaleX(scaleFactor); 48 | view.setScaleY(scaleFactor); 49 | 50 | // Fade the page relative to its size. 51 | view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/widget/BannerView.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.RelativeLayout; 6 | 7 | import com.bumptech.glide.Glide; 8 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 9 | import com.bumptech.glide.request.RequestOptions; 10 | import com.test.banner.R; 11 | 12 | import cn.jzvd.Jzvd; 13 | import cn.jzvd.JzvdStd; 14 | 15 | /** 16 | * @Project: Banner 17 | * @Package: com.test.banner.widget 18 | * @Author: HSL 19 | * @Time: 2019/08/07 14:19 20 | * @E-mail: xxx@163.com 21 | * @Description: 这个人太懒,没留下什么踪迹~ 22 | */ 23 | public class BannerView extends RelativeLayout { 24 | 25 | private JzvdStd mVideo; 26 | 27 | public BannerView(Context context) { 28 | this(context, null); 29 | } 30 | 31 | public BannerView(Context context, AttributeSet attrs) { 32 | this(context, attrs, 0); 33 | } 34 | 35 | public BannerView(Context context, AttributeSet attrs, int defStyleAttr) { 36 | super(context, attrs, defStyleAttr); 37 | inflate(context, R.layout.merge_banner_view, this); 38 | mVideo = findViewById(R.id.jz_video); 39 | mVideo.setUp("http://jzvd.nathen.cn/c6e3dc12a1154626b3476d9bf3bd7266/6b56c5f0dc31428083757a45764763b0-5287d2089db37e62345123a1be272f8b.mp4" 40 | , "饺子闭眼睛"); 41 | RequestOptions requestOptions = new RequestOptions() 42 | .placeholder(R.drawable.banner_default) 43 | .error(R.drawable.banner_default) 44 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); 45 | Glide.with(context) 46 | .load("http://p.qpic.cn/videoyun/0/2449_43b6f696980311e59ed467f22794e792_1/640") 47 | .apply(requestOptions) 48 | .into(mVideo.thumbImageView); 49 | } 50 | 51 | public void startPlay() { 52 | if (mVideo != null) { 53 | mVideo.startVideo(); 54 | } 55 | } 56 | 57 | public void stopPlay() { 58 | Jzvd.releaseAllVideos(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/complex/RotateYTransformer.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.transformer.complex; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.support.v4.view.ViewPager; 6 | import android.view.View; 7 | 8 | public class RotateYTransformer extends BasePageTransformer { 9 | 10 | private static final float DEFAULT_MAX_ROTATE = 35f; 11 | private float mMaxRotate = DEFAULT_MAX_ROTATE; 12 | 13 | public RotateYTransformer() { 14 | } 15 | 16 | public RotateYTransformer(float maxRotate) { 17 | this(maxRotate, NonPageTransformer.INSTANCE); 18 | } 19 | 20 | public RotateYTransformer(ViewPager.PageTransformer pageTransformer) { 21 | this(DEFAULT_MAX_ROTATE, pageTransformer); 22 | } 23 | 24 | public RotateYTransformer(float maxRotate, ViewPager.PageTransformer pageTransformer) { 25 | mMaxRotate = maxRotate; 26 | mPageTransformer = pageTransformer; 27 | } 28 | 29 | 30 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 31 | public void pageTransform(View view, float position) { 32 | view.setPivotY(view.getHeight() / 2); 33 | if (position < -1) { 34 | // This page is way off-screen to the left. 35 | view.setRotationY(-1 * mMaxRotate); 36 | view.setPivotX(view.getWidth()); 37 | } else if (position <= 1) { 38 | // Modify the default slide transition to shrink the page as well 39 | view.setRotationY(position * mMaxRotate); 40 | if (position < 0) { 41 | view.setPivotX(view.getWidth() * (DEFAULT_CENTER + DEFAULT_CENTER * (-position))); 42 | view.setPivotX(view.getWidth()); 43 | } else { 44 | view.setPivotX(view.getWidth() * DEFAULT_CENTER * (1 - position)); 45 | view.setPivotX(0); 46 | } 47 | // Scale the page down (between MIN_SCALE and 1) 48 | } else { 49 | // This page is way off-screen to the right. 50 | view.setRotationY(1 * mMaxRotate); 51 | view.setPivotX(0); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/TabletTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.graphics.Camera; 20 | import android.graphics.Matrix; 21 | import android.view.View; 22 | 23 | public class TabletTransformer extends ABaseTransformer { 24 | 25 | private static final Matrix OFFSET_MATRIX = new Matrix(); 26 | private static final Camera OFFSET_CAMERA = new Camera(); 27 | private static final float[] OFFSET_TEMP_FLOAT = new float[2]; 28 | 29 | @Override 30 | protected void onTransform(View view, float position) { 31 | final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position); 32 | 33 | view.setTranslationX(getOffsetXForRotation(rotation, view.getWidth(), view.getHeight())); 34 | view.setPivotX(view.getWidth() * 0.5f); 35 | view.setPivotY(0); 36 | view.setRotationY(rotation); 37 | } 38 | 39 | protected static final float getOffsetXForRotation(float degrees, int width, int height) { 40 | OFFSET_MATRIX.reset(); 41 | OFFSET_CAMERA.save(); 42 | OFFSET_CAMERA.rotateY(Math.abs(degrees)); 43 | OFFSET_CAMERA.getMatrix(OFFSET_MATRIX); 44 | OFFSET_CAMERA.restore(); 45 | 46 | OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f); 47 | OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f); 48 | OFFSET_TEMP_FLOAT[0] = width; 49 | OFFSET_TEMP_FLOAT[1] = height; 50 | OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT); 51 | return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/complex/RotateDownPageTransformer.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.transformer.complex; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.support.v4.view.ViewPager; 6 | import android.view.View; 7 | 8 | public class RotateDownPageTransformer extends BasePageTransformer { 9 | private static final float DEFAULT_MAX_ROTATE = 15.0f; 10 | private float mMaxRotate = DEFAULT_MAX_ROTATE; 11 | 12 | public RotateDownPageTransformer() { 13 | } 14 | 15 | public RotateDownPageTransformer(float maxRotate) { 16 | this(maxRotate, NonPageTransformer.INSTANCE); 17 | } 18 | 19 | public RotateDownPageTransformer(ViewPager.PageTransformer pageTransformer) { 20 | this(DEFAULT_MAX_ROTATE, pageTransformer); 21 | } 22 | 23 | public RotateDownPageTransformer(float maxRotate, ViewPager.PageTransformer pageTransformer) { 24 | mPageTransformer = pageTransformer; 25 | mMaxRotate = maxRotate; 26 | } 27 | 28 | 29 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 30 | public void pageTransform(View view, float position) { 31 | if (position < -1) { 32 | // This page is way off-screen to the left. 33 | view.setRotation(mMaxRotate * -1); 34 | view.setPivotX(view.getWidth()); 35 | view.setPivotY(view.getHeight()); 36 | 37 | } else if (position <= 1) { 38 | 39 | if (position < 0) { 40 | view.setPivotX(view.getWidth() * (DEFAULT_CENTER + DEFAULT_CENTER * (-position))); 41 | view.setPivotY(view.getHeight()); 42 | view.setRotation(mMaxRotate * position); 43 | } else { 44 | view.setPivotX(view.getWidth() * DEFAULT_CENTER * (1 - position)); 45 | view.setPivotY(view.getHeight()); 46 | view.setRotation(mMaxRotate * position); 47 | } 48 | } else { 49 | // This page is way off-screen to the right. 50 | view.setRotation(mMaxRotate); 51 | view.setPivotX(view.getWidth() * 0); 52 | view.setPivotY(view.getHeight()); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/complex/RotateUpPageTransformer.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.transformer.complex; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.support.v4.view.ViewPager; 6 | import android.view.View; 7 | 8 | public class RotateUpPageTransformer extends BasePageTransformer { 9 | 10 | private static final float DEFAULT_MAX_ROTATE = 15.0f; 11 | private float mMaxRotate = DEFAULT_MAX_ROTATE; 12 | 13 | public RotateUpPageTransformer() { 14 | } 15 | 16 | public RotateUpPageTransformer(float maxRotate) { 17 | this(maxRotate, NonPageTransformer.INSTANCE); 18 | } 19 | 20 | public RotateUpPageTransformer(ViewPager.PageTransformer pageTransformer) { 21 | this(DEFAULT_MAX_ROTATE, pageTransformer); 22 | } 23 | 24 | public RotateUpPageTransformer(float maxRotate, ViewPager.PageTransformer pageTransformer) { 25 | mMaxRotate = maxRotate; 26 | mPageTransformer = pageTransformer; 27 | } 28 | 29 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 30 | public void pageTransform(View view, float position) { 31 | if (position < -1) { 32 | // This page is way off-screen to the left. 33 | view.setRotation(mMaxRotate); 34 | view.setPivotX(view.getWidth()); 35 | view.setPivotY(0); 36 | 37 | } else if (position <= 1) { 38 | // Modify the default slide transition to shrink the page as well 39 | if (position < 0) { 40 | view.setPivotX(view.getWidth() * (0.5f + 0.5f * (-position))); 41 | view.setPivotY(0); 42 | view.setRotation(-mMaxRotate * position); 43 | } else { 44 | view.setPivotX(view.getWidth() * 0.5f * (1 - position)); 45 | view.setPivotY(0); 46 | view.setRotation(-mMaxRotate * position); 47 | } 48 | } else { 49 | // This page is way off-screen to the right. 50 | // ViewHelper.setRotation(view, ROT_MAX); 51 | view.setRotation(-mMaxRotate); 52 | view.setPivotX(0); 53 | view.setPivotY(0); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Banner示例 3 | Banner属性说明 4 | \n 5 | \n banner_auto_play : 能否自动轮播 6 | \n banner_show_model : 显示模式(一屏一页、一屏三页、仿魅族Banner) 7 | \n banner_interval_time : 轮播间隔 8 | \n banner_scroll_time : 翻页时长(决定翻页的速度) 9 | \n banner_single_anim : 一屏一页动画 10 | \n banner_default_image : 数据为空时,默认显示图 11 | \n banner_expose_width : 一屏三页,左右两页露出的宽度 12 | \n banner_page_spacing : 一屏三页,页间距 13 | \n banner_mz_overlap : 仿魅族Banner时,中间Page压着左右两边page的宽度(与左右banner重叠的宽度) 14 | \n banner_mz_anim : 仿魅族Banner动画 15 | \n banner_multi_anim : 一屏三页动画 16 | \n banner_show_indicator : 是否显示指示器 17 | \n indicator_select_width : 选中的指示器宽度 18 | \n indicator_select_height : 选中的指示器高度 19 | \n indicator_default_width : 未选中指示器宽度 20 | \n indicator_default_height : 未选中指示器高度 21 | \n indicator_space : 指示器间隔 22 | \n indicator_margin_bottom : 指示器距底部距离 23 | \n indicator_select_drawable : 指示器选中的样式 24 | \n indicator_default_drawable : 指示器未选中样式 25 | 26 | 这里加载的banner view有视频View 27 | \n 因为没法准确定位当前bannerItem是不是不可见, 28 | \n 致使无法准确控制视频播放的生命周期 29 | \n 仅供自定义加载bannerItem做参考 30 | 31 | 1. Banner本身为RelativeLayout 32 | \n 2. 所以指示器你可以随便定义 33 | \n 3. 结合setBannerPagerChangedListener()设置页数指示器 34 | \n 4. 调用setBannerText()设置Banner摘要 35 | \n 5. 详情见Demo 36 | 37 | 这真是一个还凑合的Banner 38 | \n 轮播页面内部做了缓存 39 | \n 支持一屏三页 40 | \n 支持自定义BANNER显示的View 41 | \n 支持自定义显示器 42 | \n 反正用其来还凑合,大家多多指正! 43 | 44 | 45 | Banner新增属性说明(仿魅族) 46 | \n 47 | \n banner_show_model : 显示模式(一屏一页、一屏三页、仿魅族Banner) 48 | \n banner_mz_overlap : 仿魅族Banner时,中间Page压着左右两边page的宽度(与左右banner重叠的宽度) 49 | \n banner_mz_anim : 仿魅族Banner动画 50 | \n banner_expose_width : 仿魅族Banner,左右两页可见的宽度(不包括被中间page压着的,整个长度得加上banner_mz_overlap) 51 | 52 | 53 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/complex/ScaleInTransformer.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.transformer.complex; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.support.v4.view.ViewPager; 6 | import android.view.View; 7 | 8 | public class ScaleInTransformer extends BasePageTransformer { 9 | 10 | private static final float DEFAULT_MIN_SCALE = 0.85f; 11 | private float mMinScale = DEFAULT_MIN_SCALE; 12 | 13 | public ScaleInTransformer() { 14 | 15 | } 16 | 17 | public ScaleInTransformer(float minScale) { 18 | this(minScale, NonPageTransformer.INSTANCE); 19 | } 20 | 21 | public ScaleInTransformer(ViewPager.PageTransformer pageTransformer) { 22 | this(DEFAULT_MIN_SCALE, pageTransformer); 23 | } 24 | 25 | public ScaleInTransformer(float minScale, ViewPager.PageTransformer pageTransformer) { 26 | mMinScale = minScale; 27 | mPageTransformer = pageTransformer; 28 | } 29 | 30 | 31 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 32 | public void pageTransform(View view, float position) { 33 | int pageWidth = view.getWidth(); 34 | int pageHeight = view.getHeight(); 35 | 36 | view.setPivotY(pageHeight / 2); 37 | view.setPivotX(pageWidth / 2); 38 | if (position < -1) { 39 | // This page is way off-screen to the left. 40 | view.setScaleX(mMinScale); 41 | view.setScaleY(mMinScale); 42 | view.setPivotX(pageWidth); 43 | } else if (position <= 1) { 44 | // Modify the default slide transition to shrink the page as well 45 | if (position < 0) { 46 | float scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale; 47 | view.setScaleX(scaleFactor); 48 | view.setScaleY(scaleFactor); 49 | view.setPivotX(pageWidth * (DEFAULT_CENTER + (DEFAULT_CENTER * -position))); 50 | } else { 51 | float scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale; 52 | view.setScaleX(scaleFactor); 53 | view.setScaleY(scaleFactor); 54 | view.setPivotX(pageWidth * ((1 - position) * DEFAULT_CENTER)); 55 | } 56 | } else { 57 | view.setPivotX(0); 58 | view.setScaleX(mMinScale); 59 | view.setScaleY(mMinScale); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.geek.myapplication" 7 | minSdkVersion 16 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | signingConfigs { 14 | debug { 15 | keyAlias 'banner' 16 | keyPassword 'wl2019' 17 | storeFile file('../banner.jks') 18 | storePassword 'wl2019' 19 | } 20 | release { 21 | keyAlias 'banner' 22 | keyPassword 'wl2019' 23 | storeFile file('../banner.jks') 24 | storePassword 'wl2019' 25 | } 26 | } 27 | lintOptions { 28 | abortOnError false 29 | disable 'GoogleAppIndexingWarning' 30 | } 31 | buildTypes { 32 | release { 33 | minifyEnabled false 34 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 35 | } 36 | } 37 | compileOptions { 38 | sourceCompatibility = '1.8' 39 | targetCompatibility = '1.8' 40 | } 41 | } 42 | 43 | dependencies { 44 | implementation fileTree(include: ['*.jar'], dir: 'libs') 45 | implementation 'com.android.support:appcompat-v7:28.0.0' 46 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 47 | testImplementation 'junit:junit:4.12' 48 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 49 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 50 | implementation 'com.jakewharton:butterknife:9.0.0-rc1' 51 | annotationProcessor 'com.jakewharton:butterknife-compiler:9.0.0-rc1' 52 | implementation 'com.github.bumptech.glide:glide:4.8.0' 53 | annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' 54 | implementation 'com.android.support:cardview-v7:28.0.0' 55 | implementation 'com.android.support:design:28.0.0' 56 | implementation 'com.github.iwgang:countdownview:2.1.6' 57 | implementation 'cn.jzvd:jiaozivideoplayer:7.0.5' 58 | implementation "com.hanks:htextview-rainbow:0.1.6" 59 | implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-28' 60 | implementation project(':banner') 61 | // implementation 'com.github.AlpsDog:Banner:v1.0.5' 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/widget/flowlayout/TagAdapter.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.widget.flowlayout; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.HashSet; 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | public abstract class TagAdapter { 13 | private List mTagDatas; 14 | private OnDataChangedListener mOnDataChangedListener; 15 | @Deprecated 16 | private HashSet mCheckedPosList = new HashSet(); 17 | 18 | public TagAdapter(List datas) { 19 | mTagDatas = datas; 20 | } 21 | 22 | @Deprecated 23 | public TagAdapter(T[] datas) { 24 | mTagDatas = new ArrayList(Arrays.asList(datas)); 25 | } 26 | 27 | interface OnDataChangedListener { 28 | void onChanged(); 29 | } 30 | 31 | void setOnDataChangedListener(OnDataChangedListener listener) { 32 | mOnDataChangedListener = listener; 33 | } 34 | 35 | @Deprecated 36 | public void setSelectedList(int... poses) { 37 | Set set = new HashSet<>(); 38 | for (int pos : poses) { 39 | set.add(pos); 40 | } 41 | setSelectedList(set); 42 | } 43 | 44 | @Deprecated 45 | public void setSelectedList(Set set) { 46 | mCheckedPosList.clear(); 47 | if (set != null) { 48 | mCheckedPosList.addAll(set); 49 | } 50 | notifyDataChanged(); 51 | } 52 | 53 | @Deprecated 54 | HashSet getPreCheckedList() { 55 | return mCheckedPosList; 56 | } 57 | 58 | 59 | public int getCount() { 60 | return mTagDatas == null ? 0 : mTagDatas.size(); 61 | } 62 | 63 | public void notifyDataChanged() { 64 | if (mOnDataChangedListener != null) 65 | mOnDataChangedListener.onChanged(); 66 | } 67 | 68 | public T getItem(int position) { 69 | return mTagDatas.get(position); 70 | } 71 | 72 | public abstract View getView(FlowLayout parent, int position, T t); 73 | 74 | 75 | public void onSelected(int position, View view){ 76 | Log.d("zhy","onSelected " + position); 77 | } 78 | 79 | public void unSelected(int position, View view){ 80 | Log.d("zhy","unSelected " + position); 81 | } 82 | 83 | public boolean setSelected(int position, T t) { 84 | return false; 85 | } 86 | 87 | 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/application/AppContext.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.application; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.support.annotation.NonNull; 6 | 7 | import com.scwang.smartrefresh.layout.SmartRefreshLayout; 8 | import com.scwang.smartrefresh.layout.api.DefaultRefreshHeaderCreator; 9 | import com.scwang.smartrefresh.layout.api.DefaultRefreshInitializer; 10 | import com.scwang.smartrefresh.layout.api.RefreshHeader; 11 | import com.scwang.smartrefresh.layout.api.RefreshLayout; 12 | import com.scwang.smartrefresh.layout.header.ClassicsHeader; 13 | 14 | /** 15 | * @Author: HSL 16 | * @Time: 2018/12/13 14:29 17 | * @E-mail: xxx@163.com 18 | * @Description: 这个人太懒,没留下什么踪迹~ 19 | */ 20 | public class AppContext extends Application { 21 | 22 | private static AppContext instance; 23 | 24 | /** 25 | * 获取全局上下文 26 | * 27 | * @return 28 | */ 29 | public static AppContext getInstance() { 30 | return instance; 31 | } 32 | 33 | static { 34 | ////刷新控件配置 35 | ////刷新控件配置 36 | //设置全局默认配置(优先级最低,会被其他设置覆盖) 37 | SmartRefreshLayout.setDefaultRefreshInitializer(new DefaultRefreshInitializer() { 38 | @Override 39 | public void initialize(@NonNull Context context, @NonNull RefreshLayout layout) { 40 | //全局设置(优先级最低) 41 | layout.setEnableLoadMore(false); 42 | layout.setEnableAutoLoadMore(false); 43 | layout.setEnableOverScrollDrag(false); 44 | layout.setEnableOverScrollBounce(true); 45 | //全局设置主题颜色 46 | // layout.setPrimaryColorsId(R.color.c_fdfdfd, R.color.c_333333); 47 | } 48 | }); 49 | //设置全局头部 50 | SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() { 51 | @NonNull 52 | @Override 53 | public RefreshHeader createRefreshHeader(@NonNull Context context, @NonNull RefreshLayout layout) { 54 | ClassicsHeader classicsHeader = new ClassicsHeader(context); 55 | classicsHeader.setTextSizeTitle(14); 56 | return classicsHeader; 57 | } 58 | }); 59 | } 60 | 61 | @Override 62 | public void onCreate() { 63 | super.onCreate(); 64 | instance = this; 65 | //初始化工作 66 | //初始化工作 67 | //初始化工作 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.test.banner; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.widget.TextView; 6 | 7 | import com.test.banner.banner.BannerDataActivity; 8 | import com.test.banner.banner.BannerIndicatorActivity; 9 | import com.test.banner.banner.BannerMzActivity; 10 | import com.test.banner.banner.BannerViewActivity; 11 | import com.test.banner.banner.BaseUseActivity; 12 | import com.test.banner.banner.ShowAnimActivity; 13 | 14 | import butterknife.BindView; 15 | import butterknife.ButterKnife; 16 | import butterknife.OnClick; 17 | 18 | /** 19 | * @Author: HSL 20 | * @Time: 2019/8/5 11:30 21 | * @E-mail: xxx@163.com 22 | * @Description: 主页~ 23 | */ 24 | public class MainActivity extends AppCompatActivity { 25 | 26 | @BindView(R.id.banner_base_use) 27 | TextView bannerBaseUse; 28 | @BindView(R.id.banner_empty_use) 29 | TextView bannerEmptyUse; 30 | @BindView(R.id.banner_mz_use) 31 | TextView bannerMzUse; 32 | @BindView(R.id.banner_anim_show) 33 | TextView bannerAnimShow; 34 | @BindView(R.id.banner_view_show) 35 | TextView bannerViewShow; 36 | @BindView(R.id.banner_indicator_show) 37 | TextView bannerIndicatorShow; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_main); 43 | ButterKnife.bind(this); 44 | } 45 | 46 | /** 47 | * 基本使用 48 | */ 49 | @OnClick(R.id.banner_base_use) 50 | public void onBaseUseClicked() { 51 | BaseUseActivity.start(this); 52 | } 53 | 54 | /** 55 | * 空数据、刷新 56 | */ 57 | @OnClick(R.id.banner_empty_use) 58 | public void onBannerEmptyUseClicked() { 59 | BannerDataActivity.start(this); 60 | } 61 | 62 | /** 63 | * 仿魅族Banner 64 | */ 65 | @OnClick(R.id.banner_mz_use) 66 | public void onBannerMzClicked() { 67 | BannerMzActivity.start(this); 68 | } 69 | 70 | /** 71 | * 动画展示 72 | */ 73 | @OnClick(R.id.banner_anim_show) 74 | public void onAnimShowClicked() { 75 | ShowAnimActivity.start(this); 76 | } 77 | 78 | /** 79 | * 自定义展示VIEW 80 | */ 81 | @OnClick(R.id.banner_view_show) 82 | public void onBannerViewClicked() { 83 | BannerViewActivity.start(this); 84 | } 85 | 86 | /** 87 | * Banner指示器 88 | */ 89 | @OnClick(R.id.banner_indicator_show) 90 | public void onIndicatorClicked() { 91 | BannerIndicatorActivity.start(this); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 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 | -------------------------------------------------------------------------------- /banner/src/main/res/values/attr.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 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_show_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 27 | 28 | 34 | 35 | 42 | 43 | 58 | 59 | 65 | 66 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_base_use.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 29 | 30 | 45 | 46 | 55 | 56 | 57 | 58 | 67 | 68 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/widget/BannerViewPager.java: -------------------------------------------------------------------------------- 1 | package com.geek.banner.widget; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | import android.util.SparseArray; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collections; 12 | 13 | /** 14 | * @Author: HSL 15 | * @Time: 2018/11/30 10:34 16 | * @E-mail: xxx@163.com 17 | * @Description: 控制ViewPager能否滚动,控制是否仿魅族效果的绘制 18 | */ 19 | public class BannerViewPager extends ViewPager { 20 | 21 | private ArrayList childCenterXAbs = new ArrayList<>(); 22 | private SparseArray childIndex = new SparseArray<>(); 23 | /** 24 | * 能否滚动 25 | */ 26 | private boolean mScrollable = true; 27 | /** 28 | * 能否仿魅族效果 29 | */ 30 | private boolean mEnableMzEffects = false; 31 | 32 | public BannerViewPager(Context context) { 33 | super(context); 34 | } 35 | 36 | public BannerViewPager(Context context, AttributeSet attrs) { 37 | super(context, attrs); 38 | } 39 | 40 | @Override 41 | public boolean onTouchEvent(MotionEvent ev) { 42 | if (mScrollable) 43 | return super.onTouchEvent(ev); 44 | else 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean onInterceptTouchEvent(MotionEvent ev) { 50 | if (mScrollable) 51 | return super.onInterceptTouchEvent(ev); 52 | else 53 | return false; 54 | 55 | } 56 | 57 | /** 58 | * @param childCount 59 | * @param n 60 | * @return 第n个位置的child 的绘制索引 61 | *

62 | * 重写这个方法来控制字View的绘制顺序 63 | * 让中间View压着左右两边View,出现仿魅族效果 64 | */ 65 | @Override 66 | protected int getChildDrawingOrder(int childCount, int n) { 67 | if (mEnableMzEffects) { 68 | if (n == 0 || childIndex.size() != childCount) { 69 | childCenterXAbs.clear(); 70 | childIndex.clear(); 71 | int viewCenterX = getViewCenterX(this); 72 | for (int i = 0; i < childCount; ++i) { 73 | int indexAbs = Math.abs(viewCenterX - getViewCenterX(getChildAt(i))); 74 | //两个距离相同,后来的那个做自增,从而保持abs不同 75 | if (childIndex.get(indexAbs) != null) { 76 | ++indexAbs; 77 | } 78 | childCenterXAbs.add(indexAbs); 79 | childIndex.append(indexAbs, i); 80 | } 81 | //1,0,2 0,1,2 82 | Collections.sort(childCenterXAbs); 83 | } 84 | //那个item距离中心点远一些,就先draw它。(最近的就是中间放大的item,最后draw) 85 | return childIndex.get(childCenterXAbs.get(childCount - 1 - n)); 86 | } else { 87 | return super.getChildDrawingOrder(childCount, n); 88 | } 89 | } 90 | 91 | private int getViewCenterX(View view) { 92 | int[] array = new int[2]; 93 | view.getLocationOnScreen(array); 94 | return array[0] + view.getWidth() / 2; 95 | } 96 | 97 | /** 98 | * 设置能否滚动 99 | * 100 | * @param scrollable 101 | */ 102 | public void setScrollable(boolean scrollable) { 103 | mScrollable = scrollable; 104 | } 105 | 106 | /** 107 | * 仿魅族Banner 108 | * 控制绘制顺序,让中间View覆盖左右两View 109 | * 110 | * @param enableMzEffects 111 | */ 112 | public void setEnableMzEffects(boolean enableMzEffects) { 113 | mEnableMzEffects = enableMzEffects; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/banner/BannerMzActivity.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.banner; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.Toast; 11 | 12 | import com.bumptech.glide.Glide; 13 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 14 | import com.bumptech.glide.request.RequestOptions; 15 | import com.geek.banner.Banner; 16 | import com.geek.banner.loader.BannerEntry; 17 | import com.geek.banner.loader.ImageLoader; 18 | import com.test.banner.R; 19 | import com.test.banner.bean.BannerItem; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | import butterknife.BindView; 25 | import butterknife.ButterKnife; 26 | 27 | /** 28 | * @Author: HSL 29 | * @Time: 2019/8/23 11:54 30 | * @E-mail: xxx@163.com 31 | * @Description: 仿魅族Banner~ 32 | */ 33 | public class BannerMzActivity extends AppCompatActivity { 34 | 35 | @BindView(R.id.banner_mz) 36 | Banner bannerMz; 37 | 38 | private List mData = new ArrayList<>(); 39 | 40 | public static void start(Context context) { 41 | Intent starter = new Intent(context, BannerMzActivity.class); 42 | context.startActivity(starter); 43 | } 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | setContentView(R.layout.activity_banner_mz); 49 | ButterKnife.bind(this); 50 | initData(); 51 | initBannerMZ(); 52 | } 53 | 54 | @Override 55 | protected void onResume() { 56 | super.onResume(); 57 | bannerMz.startAutoPlay(); 58 | } 59 | 60 | @Override 61 | protected void onPause() { 62 | super.onPause(); 63 | bannerMz.stopAutoPlay(); 64 | } 65 | 66 | private void initData() { 67 | mData.add(new BannerItem(R.drawable.banner_1, "")); 68 | mData.add(new BannerItem(R.drawable.banner_2, "")); 69 | mData.add(new BannerItem(R.drawable.banner_3, "")); 70 | mData.add(new BannerItem(R.drawable.banner_4, "")); 71 | mData.add(new BannerItem(R.drawable.banner_5, "")); 72 | } 73 | 74 | private void initBannerMZ() { 75 | // 1. 创建设置BannerLoader 76 | bannerMz.setBannerLoader(new ImageLoader() { 77 | @Override 78 | public void loadView(Context context, BannerEntry entry, int position, View imageView) { 79 | RequestOptions requestOptions = new RequestOptions() 80 | .placeholder(R.drawable.banner_default) 81 | .error(R.drawable.banner_default) 82 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); 83 | Glide.with(context).load(entry.getBannerPath()).apply(requestOptions).into((ImageView) imageView); 84 | } 85 | }); 86 | 87 | // 2. 设置页面点击事件 88 | bannerMz.setOnBannerClickListener(new Banner.OnBannerClickListener() { 89 | @Override 90 | public void onBannerClick(int position) { 91 | Toast.makeText(BannerMzActivity.this, "点击了:" + position, Toast.LENGTH_SHORT).show(); 92 | } 93 | }); 94 | 95 | // 3. 翻页事件 96 | bannerMz.setBannerPagerChangedListener(new Banner.OnBannerSimplePagerListener() { 97 | @Override 98 | public void onPageSelected(int position) { 99 | Log.d("hsl777", "onPageSelected: ==>" + position); 100 | } 101 | }); 102 | 103 | // 4. 最重要一步,加载数据 104 | bannerMz.loadImagePaths(mData); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_banner_indicator.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 22 | 23 | 35 | 36 | 47 | 48 | 49 | 64 | 65 | 78 | 79 | 91 | 92 | 93 | 103 | 104 | -------------------------------------------------------------------------------- /banner/src/main/java/com/geek/banner/transformer/simple/ABaseTransformer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Toxic Bakery 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.geek.banner.transformer.simple; 18 | 19 | import android.support.v4.view.ViewPager.PageTransformer; 20 | import android.view.View; 21 | 22 | public abstract class ABaseTransformer implements PageTransformer { 23 | 24 | /** 25 | * Called each {@link #transformPage(View, float)}. 26 | * 27 | * @param page 28 | * Apply the transformation to this page 29 | * @param position 30 | * Position of page relative to the current front-and-center position of the pager. 0 is front and 31 | * center. 1 is one full page position to the right, and -1 is one page position to the left. 32 | */ 33 | protected abstract void onTransform(View page, float position); 34 | 35 | /** 36 | * Apply a property transformation to the given page. For most use cases, this method should not be overridden. 37 | * Instead use {@link #transformPage(View, float)} to perform typical transformations. 38 | * 39 | * @param page 40 | * Apply the transformation to this page 41 | * @param position 42 | * Position of page relative to the current front-and-center position of the pager. 0 is front and 43 | * center. 1 is one full page position to the right, and -1 is one page position to the left. 44 | */ 45 | @Override 46 | public void transformPage(View page, float position) { 47 | onPreTransform(page, position); 48 | onTransform(page, position); 49 | onPostTransform(page, position); 50 | } 51 | 52 | /** 53 | * If the position offset of a fragment is less than negative one or greater than one, returning true will set the 54 | * fragment alpha to 0f. Otherwise fragment alpha is always defaulted to 1f. 55 | * 56 | * @return 57 | */ 58 | protected boolean hideOffscreenPages() { 59 | return true; 60 | } 61 | 62 | /** 63 | * Indicates if the default animations of the view pager should be used. 64 | * 65 | * @return 66 | */ 67 | protected boolean isPagingEnabled() { 68 | return false; 69 | } 70 | 71 | /** 72 | * Called each {@link #transformPage(View, float)} before {{@link #onTransform(View, float)}. 73 | *

74 | * The default implementation attempts to reset all view properties. This is useful when toggling transforms that do 75 | * not modify the same page properties. For instance changing from a transformation that applies rotation to a 76 | * transformation that fades can inadvertently leave a fragment stuck with a rotation or with some degree of applied 77 | * alpha. 78 | * 79 | * @param page 80 | * Apply the transformation to this page 81 | * @param position 82 | * Position of page relative to the current front-and-center position of the pager. 0 is front and 83 | * center. 1 is one full page position to the right, and -1 is one page position to the left. 84 | */ 85 | protected void onPreTransform(View page, float position) { 86 | final float width = page.getWidth(); 87 | 88 | page.setRotationX(0); 89 | page.setRotationY(0); 90 | page.setRotation(0); 91 | page.setScaleX(1); 92 | page.setScaleY(1); 93 | page.setPivotX(0); 94 | page.setPivotY(0); 95 | page.setTranslationY(0); 96 | page.setTranslationX(isPagingEnabled() ? 0f : -width * position); 97 | 98 | if (hideOffscreenPages()) { 99 | page.setAlpha(position <= -1f || position >= 1f ? 0f : 1f); 100 | // page.setEnabled(false); 101 | } else { 102 | // page.setEnabled(true); 103 | page.setAlpha(1f); 104 | } 105 | } 106 | 107 | /** 108 | * Called each {@link #transformPage(View, float)} after {@link #onTransform(View, float)}. 109 | * 110 | * @param page 111 | * Apply the transformation to this page 112 | * @param position 113 | * Position of page relative to the current front-and-center position of the pager. 0 is front and 114 | * center. 1 is one full page position to the right, and -1 is one page position to the left. 115 | */ 116 | protected void onPostTransform(View page, float position) { 117 | } 118 | 119 | /** 120 | * Same as {@link Math#min(double, double)} without double casting, zero closest to infinity handling, or NaN support. 121 | * 122 | * @param val 123 | * @param min 124 | * @return 125 | */ 126 | protected static final float min(float val, float min) { 127 | return val < min ? min : val; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_banner_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 18 | 19 | 31 | 32 | 44 | 45 | 46 | 61 | 62 | 74 | 75 | 76 | 90 | 91 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/banner/BaseUseActivity.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.banner; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.Toast; 11 | 12 | import com.bumptech.glide.Glide; 13 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 14 | import com.bumptech.glide.request.RequestOptions; 15 | import com.geek.banner.Banner; 16 | import com.geek.banner.loader.BannerEntry; 17 | import com.geek.banner.loader.ImageLoader; 18 | import com.test.banner.R; 19 | import com.test.banner.bean.BannerItem; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | import butterknife.BindView; 25 | import butterknife.ButterKnife; 26 | 27 | /** 28 | * @Author: HSL 29 | * @Time: 2019/8/5 15:38 30 | * @E-mail: xxx@163.com 31 | * @Description: 基本使用~ 32 | */ 33 | public class BaseUseActivity extends AppCompatActivity { 34 | 35 | @BindView(R.id.banner) 36 | Banner banner; 37 | @BindView(R.id.banner_2) 38 | Banner banner2; 39 | 40 | private List mData = new ArrayList<>(); 41 | 42 | public static void start(Context context) { 43 | Intent starter = new Intent(context, BaseUseActivity.class); 44 | context.startActivity(starter); 45 | } 46 | 47 | @Override 48 | protected void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | setContentView(R.layout.activity_base_use); 51 | ButterKnife.bind(this); 52 | initData(); 53 | initBanner(); 54 | initBanner2(); 55 | } 56 | 57 | private void initData() { 58 | mData.add(new BannerItem(R.drawable.banner_1, "")); 59 | mData.add(new BannerItem(R.drawable.banner_2, "")); 60 | mData.add(new BannerItem(R.drawable.banner_3, "")); 61 | mData.add(new BannerItem(R.drawable.banner_4, "")); 62 | mData.add(new BannerItem(R.drawable.banner_5, "")); 63 | } 64 | 65 | private void initBanner() { 66 | // 1. 创建设置BannerLoader 67 | banner.setBannerLoader(new ImageLoader() { 68 | @Override 69 | public void loadView(Context context, BannerEntry entry, int position, View imageView) { 70 | RequestOptions requestOptions = new RequestOptions() 71 | .placeholder(R.drawable.banner_default) 72 | .error(R.drawable.banner_default) 73 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); 74 | Glide.with(context).load(entry.getBannerPath()).apply(requestOptions).into((ImageView) imageView); 75 | } 76 | }); 77 | 78 | // 2 设置页面点击事件 79 | banner.setOnBannerClickListener(new Banner.OnBannerClickListener() { 80 | @Override 81 | public void onBannerClick(int position) { 82 | Toast.makeText(BaseUseActivity.this, "点击了:" + position, Toast.LENGTH_SHORT).show(); 83 | } 84 | }); 85 | 86 | // 3 翻页事件 87 | banner.setBannerPagerChangedListener(new Banner.OnBannerSimplePagerListener() { 88 | @Override 89 | public void onPageSelected(int position) { 90 | Log.d("hsl777", "onPageSelected: ==>" + position); 91 | } 92 | }); 93 | 94 | // 4 最重要一步,加载数据 95 | banner.loadImagePaths(mData); 96 | } 97 | 98 | private void initBanner2() { 99 | // 1. 创建设置BannerLoader 100 | banner2.setBannerLoader(new ImageLoader() { 101 | @Override 102 | public void loadView(Context context, BannerEntry entry, int position, View imageView) { 103 | RequestOptions requestOptions = new RequestOptions() 104 | .placeholder(R.drawable.banner_default) 105 | .error(R.drawable.banner_default) 106 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); 107 | Glide.with(context).load(entry.getBannerPath()).apply(requestOptions).into((ImageView) imageView); 108 | } 109 | }); 110 | 111 | // 2. 设置页面点击事件 112 | banner2.setOnBannerClickListener(new Banner.OnBannerClickListener() { 113 | @Override 114 | public void onBannerClick(int position) { 115 | Toast.makeText(BaseUseActivity.this, "点击了:" + position, Toast.LENGTH_SHORT).show(); 116 | } 117 | }); 118 | 119 | // 3. 翻页事件 120 | banner2.setBannerPagerChangedListener(new Banner.OnBannerSimplePagerListener() { 121 | @Override 122 | public void onPageSelected(int position) { 123 | Log.d("hsl777", "onPageSelected: ==>" + position); 124 | } 125 | }); 126 | 127 | // 4. 最重要一步,加载数据 128 | banner2.loadImagePaths(mData); 129 | } 130 | 131 | 132 | @Override 133 | protected void onResume() { 134 | super.onResume(); 135 | banner.startAutoPlay(); 136 | banner2.startAutoPlay(); 137 | } 138 | 139 | @Override 140 | protected void onPause() { 141 | super.onPause(); 142 | banner.stopAutoPlay(); 143 | banner2.stopAutoPlay(); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 26 | 27 | 36 | 37 | 43 | 44 | 53 | 54 | 60 | 61 | 70 | 71 | 77 | 78 | 87 | 88 | 94 | 95 | 104 | 105 | 111 | 112 | 116 | 117 | 127 | 128 | 134 | 135 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/banner/BannerViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.banner; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.widget.ImageView; 11 | import android.widget.Toast; 12 | 13 | import com.bumptech.glide.Glide; 14 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 15 | import com.bumptech.glide.request.RequestOptions; 16 | import com.geek.banner.Banner; 17 | import com.geek.banner.loader.BannerEntry; 18 | import com.geek.banner.loader.BannerLoader; 19 | import com.test.banner.R; 20 | import com.test.banner.bean.BannerItem; 21 | import com.test.banner.widget.BannerView; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | import butterknife.BindView; 27 | import butterknife.ButterKnife; 28 | import cn.iwgang.countdownview.CountdownView; 29 | import cn.jzvd.Jzvd; 30 | 31 | /** 32 | * @Author: HSL 33 | * @Time: 2019/8/7 13:44 34 | * @E-mail: xxx@163.com 35 | * @Description: 自定义BannerView~ 36 | */ 37 | public class BannerViewActivity extends AppCompatActivity { 38 | 39 | @BindView(R.id.banner) 40 | Banner banner; 41 | 42 | private List mData = new ArrayList<>(); 43 | 44 | public static void start(Context context) { 45 | Intent starter = new Intent(context, BannerViewActivity.class); 46 | context.startActivity(starter); 47 | } 48 | 49 | @Override 50 | protected void onCreate(Bundle savedInstanceState) { 51 | super.onCreate(savedInstanceState); 52 | setContentView(R.layout.activity_banner_view); 53 | ButterKnife.bind(this); 54 | initData(); 55 | initBanner(); 56 | } 57 | 58 | private void initData() { 59 | mData.add(new BannerItem(R.drawable.banner_1, "")); 60 | mData.add(new BannerItem("", "")); 61 | mData.add(new BannerItem(R.drawable.banner_3, "")); 62 | mData.add(new BannerItem("", "")); 63 | mData.add(new BannerItem(R.drawable.banner_5, "")); 64 | } 65 | 66 | private void initBanner() { 67 | //First 创建BannerLoader 68 | /** 69 | * 加载器 70 | * 第一个泛型:图片的URL FILE res...等 71 | * 第二个泛型:banner显示的View,可以是任意View 72 | */ 73 | BannerLoader mBannerLoader = new BannerLoader() { 74 | 75 | /** 76 | * 如何加载图片资源,由自己决定 77 | * @param context 78 | * @param path 79 | * @param view 80 | */ 81 | @Override 82 | public void loadView(Context context, BannerEntry path, int position, View view) { 83 | if (position == 1) { 84 | CountdownView countdownView = view.findViewById(R.id.time_cdv); 85 | countdownView.start(995550000); 86 | } else if (position == 3) { 87 | ((BannerView) view).startPlay(); 88 | } else { 89 | RequestOptions requestOptions = new RequestOptions() 90 | .placeholder(R.drawable.banner_default) 91 | .error(R.drawable.banner_default) 92 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); 93 | Glide.with(context).load(path.getBannerPath()).apply(requestOptions).into((ImageView) view); 94 | } 95 | } 96 | 97 | /** 98 | * 怎样创建View,也由自己决定 99 | * @param context 100 | * @return 101 | */ 102 | @Override 103 | public View createView(Context context, int position) { 104 | View bannerView = null; 105 | if (position == 1) { 106 | bannerView = LayoutInflater.from(context).inflate(R.layout.banner_item_second_pager, null); 107 | } else if (position == 3) { 108 | bannerView = new BannerView(context); 109 | } else { 110 | ImageView imageView = new ImageView(context); 111 | imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); 112 | bannerView = imageView; 113 | } 114 | return bannerView; 115 | } 116 | }; 117 | 118 | //second 设置BannerLoader 119 | banner.setBannerLoader(mBannerLoader); 120 | 121 | //third 设置页面点击事件 122 | banner.setOnBannerClickListener(new Banner.OnBannerClickListener() { 123 | @Override 124 | public void onBannerClick(int position) { 125 | Toast.makeText(BannerViewActivity.this, "点击了:" + position, Toast.LENGTH_SHORT).show(); 126 | } 127 | }); 128 | 129 | //four 翻页事件 130 | banner.setBannerPagerChangedListener(new Banner.OnBannerSimplePagerListener() { 131 | @Override 132 | public void onPageSelected(int position) { 133 | Log.d("hsl777", "onPageSelected: ==>" + position); 134 | } 135 | }); 136 | //last 最重要一步,加载数据 137 | banner.loadImagePaths(mData); 138 | } 139 | 140 | @Override 141 | protected void onResume() { 142 | super.onResume(); 143 | banner.startAutoPlay(); 144 | } 145 | 146 | @Override 147 | protected void onPause() { 148 | super.onPause(); 149 | banner.stopAutoPlay(); 150 | Jzvd.releaseAllVideos(); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/banner/BannerIndicatorActivity.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.banner; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | import android.widget.Toast; 12 | 13 | import com.bumptech.glide.Glide; 14 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 15 | import com.bumptech.glide.request.RequestOptions; 16 | import com.geek.banner.Banner; 17 | import com.geek.banner.loader.BannerEntry; 18 | import com.geek.banner.loader.ImageLoader; 19 | import com.test.banner.R; 20 | import com.test.banner.bean.BannerItem; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import butterknife.BindView; 26 | import butterknife.ButterKnife; 27 | 28 | public class BannerIndicatorActivity extends AppCompatActivity { 29 | 30 | @BindView(R.id.pager_tv) 31 | TextView pagerTv; 32 | @BindView(R.id.title_tv) 33 | TextView titleTv; 34 | @BindView(R.id.banner) 35 | Banner banner; 36 | @BindView(R.id.pager_2_tv) 37 | TextView pager2Tv; 38 | @BindView(R.id.title_2_tv) 39 | TextView title2Tv; 40 | @BindView(R.id.banner_2) 41 | Banner banner2; 42 | 43 | private List mData = new ArrayList<>(); 44 | 45 | public static void start(Context context) { 46 | Intent starter = new Intent(context, BannerIndicatorActivity.class); 47 | context.startActivity(starter); 48 | } 49 | 50 | @Override 51 | protected void onCreate(Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | setContentView(R.layout.activity_banner_indicator); 54 | ButterKnife.bind(this); 55 | initData(); 56 | initBanner(); 57 | initBanner2(); 58 | } 59 | 60 | private void initData() { 61 | mData.add(new BannerItem(R.drawable.banner_1, "《悯农》 白居易")); 62 | mData.add(new BannerItem(R.drawable.banner_2, "锄禾日当午")); 63 | mData.add(new BannerItem(R.drawable.banner_3, "汗滴禾下午")); 64 | mData.add(new BannerItem(R.drawable.banner_4, "谁知盘中餐")); 65 | mData.add(new BannerItem(R.drawable.banner_5, "粒粒皆辛苦")); 66 | } 67 | 68 | private void initBanner() { 69 | // 1. 创建设置BannerLoader 70 | banner.setBannerLoader(new ImageLoader() { 71 | @Override 72 | public void loadView(Context context, BannerEntry entry, int position, View imageView) { 73 | RequestOptions requestOptions = new RequestOptions() 74 | .placeholder(R.drawable.banner_default) 75 | .error(R.drawable.banner_default) 76 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); 77 | Glide.with(context).load(entry.getBannerPath()).apply(requestOptions).into((ImageView) imageView); 78 | } 79 | }); 80 | 81 | // 2 设置页面点击事件 82 | banner.setOnBannerClickListener(new Banner.OnBannerClickListener() { 83 | @Override 84 | public void onBannerClick(int position) { 85 | Toast.makeText(BannerIndicatorActivity.this, "点击了:" + position, Toast.LENGTH_SHORT).show(); 86 | } 87 | }); 88 | 89 | // 3 翻页事件 90 | banner.setBannerPagerChangedListener(new Banner.OnBannerSimplePagerListener() { 91 | @Override 92 | public void onPageSelected(int position) { 93 | Log.d("hsl777", "onPageSelected: ==>" + position); 94 | pagerTv.setText(String.format("%s/5", position + 1)); 95 | } 96 | }); 97 | //额外功能设置banner摘要 98 | banner.setBannerText(titleTv); 99 | // 4 最重要一步,加载数据 100 | banner.loadImagePaths(mData); 101 | } 102 | 103 | private void initBanner2() { 104 | // 1. 创建设置BannerLoader 105 | banner2.setBannerLoader(new ImageLoader() { 106 | @Override 107 | public void loadView(Context context, BannerEntry entry, int position, View imageView) { 108 | RequestOptions requestOptions = new RequestOptions() 109 | .placeholder(R.drawable.banner_default) 110 | .error(R.drawable.banner_default) 111 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); 112 | Glide.with(context).load(entry.getBannerPath()).apply(requestOptions).into((ImageView) imageView); 113 | } 114 | }); 115 | 116 | // 2. 设置页面点击事件 117 | banner2.setOnBannerClickListener(new Banner.OnBannerClickListener() { 118 | @Override 119 | public void onBannerClick(int position) { 120 | Toast.makeText(BannerIndicatorActivity.this, "点击了:" + position, Toast.LENGTH_SHORT).show(); 121 | } 122 | }); 123 | 124 | // 3. 翻页事件 125 | banner2.setBannerPagerChangedListener(new Banner.OnBannerSimplePagerListener() { 126 | @Override 127 | public void onPageSelected(int position) { 128 | Log.d("hsl777", "onPageSelected: ==>" + position); 129 | pager2Tv.setText(String.format("%s/5", position + 1)); 130 | } 131 | }); 132 | //额外功能设置banner摘要 133 | banner2.setBannerText(title2Tv); 134 | // 4. 最重要一步,加载数据 135 | banner2.loadImagePaths(mData); 136 | } 137 | 138 | @Override 139 | protected void onResume() { 140 | super.onResume(); 141 | banner.startAutoPlay(); 142 | banner2.startAutoPlay(); 143 | } 144 | 145 | @Override 146 | protected void onPause() { 147 | super.onPause(); 148 | banner.stopAutoPlay(); 149 | banner2.stopAutoPlay(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/banner/BannerDataActivity.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.banner; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | import android.widget.Toast; 13 | 14 | import com.bumptech.glide.Glide; 15 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 16 | import com.bumptech.glide.request.RequestOptions; 17 | import com.geek.banner.Banner; 18 | import com.geek.banner.loader.BannerEntry; 19 | import com.geek.banner.loader.ImageLoader; 20 | import com.scwang.smartrefresh.layout.SmartRefreshLayout; 21 | import com.scwang.smartrefresh.layout.api.RefreshLayout; 22 | import com.scwang.smartrefresh.layout.listener.OnRefreshListener; 23 | import com.test.banner.R; 24 | import com.test.banner.bean.BannerItem; 25 | import com.test.banner.utils.DateUtils; 26 | 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | import java.util.Random; 30 | 31 | import butterknife.BindView; 32 | import butterknife.ButterKnife; 33 | 34 | /** 35 | * @Author: HSL 36 | * @Time: 2019/8/23 15:35 37 | * @E-mail: xxx@163.com 38 | * @Description: 数据展示~ 39 | */ 40 | public class BannerDataActivity extends AppCompatActivity { 41 | 42 | @BindView(R.id.pager_tv) 43 | TextView pagerTv; 44 | @BindView(R.id.banner) 45 | Banner banner; 46 | @BindView(R.id.pager_tv_2) 47 | TextView pagerTv2; 48 | @BindView(R.id.banner_2) 49 | Banner banner2; 50 | @BindView(R.id.pager_tv_3) 51 | TextView pagerTv3; 52 | @BindView(R.id.banner_mz) 53 | Banner bannerMz; 54 | @BindView(R.id.refresh_srl) 55 | SmartRefreshLayout refreshSrl; 56 | 57 | private List mData = new ArrayList<>(); 58 | 59 | public static void start(Context context) { 60 | Intent starter = new Intent(context, BannerDataActivity.class); 61 | context.startActivity(starter); 62 | } 63 | 64 | @Override 65 | protected void onCreate(Bundle savedInstanceState) { 66 | super.onCreate(savedInstanceState); 67 | setContentView(R.layout.activity_banner_data); 68 | ButterKnife.bind(this); 69 | initData(); 70 | initBanner(banner); 71 | initBanner(banner2); 72 | initBanner(bannerMz); 73 | refreshSrl.setOnRefreshListener(new OnRefreshListener() { 74 | @Override 75 | public void onRefresh(@NonNull RefreshLayout refreshLayout) { 76 | refreshSrl.finishRefresh(); 77 | int max = new Random().nextInt(5); 78 | List data = new ArrayList<>(); 79 | for (int i = 0; i < mData.size(); i++) { 80 | if (i > max || max == 0) break; 81 | data.add(mData.get(i)); 82 | } 83 | pagerTv.setText(data.size() + "张"); 84 | banner.loadImagePaths(data); 85 | if (max < 2) { 86 | banner2.loadImagePaths(data); 87 | pagerTv2.setText(data.size() + "张"); 88 | } else { 89 | bannerMz.loadImagePaths(data); 90 | pagerTv3.setText(data.size() + "张"); 91 | } 92 | } 93 | }); 94 | } 95 | 96 | private void initData() { 97 | mData.add(new BannerItem(R.drawable.banner_1, "")); 98 | mData.add(new BannerItem(R.drawable.banner_2, "")); 99 | mData.add(new BannerItem(R.drawable.banner_3, "")); 100 | mData.add(new BannerItem(R.drawable.banner_4, "")); 101 | mData.add(new BannerItem(R.drawable.banner_5, "")); 102 | pagerTv.setText("5张"); 103 | pagerTv2.setText("5张"); 104 | pagerTv3.setText("5张"); 105 | } 106 | 107 | private void initBanner(Banner banner) { 108 | // 1. 创建设置BannerLoader 109 | banner.setBannerLoader(new ImageLoader() { 110 | @Override 111 | public void loadView(Context context, BannerEntry entry, int position, View imageView) { 112 | RequestOptions requestOptions = new RequestOptions() 113 | .placeholder(R.drawable.banner_default) 114 | .error(R.drawable.banner_default) 115 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); 116 | Glide.with(context).load(entry.getBannerPath()).apply(requestOptions).into((ImageView) imageView); 117 | } 118 | }); 119 | 120 | // 2 设置页面点击事件 121 | banner.setOnBannerClickListener(new Banner.OnBannerClickListener() { 122 | @Override 123 | public void onBannerClick(int position) { 124 | Toast.makeText(BannerDataActivity.this, "点击了:" + position, Toast.LENGTH_SHORT).show(); 125 | } 126 | }); 127 | 128 | // 3 翻页事件 129 | banner.setBannerPagerChangedListener(new Banner.OnBannerSimplePagerListener() { 130 | @Override 131 | public void onPageSelected(int position) { 132 | Log.d("hsl777", "onPageSelected: ==>" 133 | + position 134 | + "\n" + banner); 135 | } 136 | }); 137 | 138 | // 4 最重要一步,加载数据 139 | banner.loadImagePaths(mData); 140 | } 141 | 142 | @Override 143 | protected void onResume() { 144 | super.onResume(); 145 | banner.startAutoPlay(); 146 | banner2.startAutoPlay(); 147 | bannerMz.startAutoPlay(); 148 | } 149 | 150 | @Override 151 | protected void onPause() { 152 | super.onPause(); 153 | banner.stopAutoPlay(); 154 | banner2.stopAutoPlay(); 155 | bannerMz.stopAutoPlay(); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/widget/flowlayout/FlowLayout.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.widget.flowlayout; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.test.banner.R; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * @Description: 流式布局 16 | * https://github.com/hongyangAndroid/FlowLayout 17 | */ 18 | public class FlowLayout extends ViewGroup { 19 | private static final String TAG = "FlowLayout"; 20 | private static final int LEFT = -1; 21 | private static final int CENTER = 0; 22 | private static final int RIGHT = 1; 23 | 24 | protected List> mAllViews = new ArrayList>(); 25 | protected List mLineHeight = new ArrayList(); 26 | protected List mLineWidth = new ArrayList(); 27 | private int mGravity; 28 | private List lineViews = new ArrayList<>(); 29 | 30 | public FlowLayout(Context context) { 31 | this(context, null); 32 | } 33 | 34 | public FlowLayout(Context context, AttributeSet attrs) { 35 | this(context, attrs, 0); 36 | } 37 | 38 | public FlowLayout(Context context, AttributeSet attrs, int defStyle) { 39 | super(context, attrs, defStyle); 40 | TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout); 41 | mGravity = ta.getInt(R.styleable.TagFlowLayout_tag_gravity, LEFT); 42 | ta.recycle(); 43 | } 44 | 45 | @Override 46 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 47 | int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); 48 | int modeWidth = MeasureSpec.getMode(widthMeasureSpec); 49 | int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); 50 | int modeHeight = MeasureSpec.getMode(heightMeasureSpec); 51 | 52 | // wrap_content 53 | int width = 0; 54 | int height = 0; 55 | 56 | int lineWidth = 0; 57 | int lineHeight = 0; 58 | 59 | int cCount = getChildCount(); 60 | 61 | for (int i = 0; i < cCount; i++) { 62 | View child = getChildAt(i); 63 | if (child.getVisibility() == View.GONE) { 64 | if (i == cCount - 1) { 65 | width = Math.max(lineWidth, width); 66 | height += lineHeight; 67 | } 68 | continue; 69 | 70 | 71 | } 72 | measureChild(child, widthMeasureSpec, heightMeasureSpec); 73 | MarginLayoutParams lp = (MarginLayoutParams) child 74 | .getLayoutParams(); 75 | 76 | int childWidth = child.getMeasuredWidth() + lp.leftMargin 77 | + lp.rightMargin; 78 | int childHeight = child.getMeasuredHeight() + lp.topMargin 79 | + lp.bottomMargin; 80 | 81 | if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) { 82 | width = Math.max(width, lineWidth); 83 | lineWidth = childWidth; 84 | height += lineHeight; 85 | lineHeight = childHeight; 86 | } else { 87 | lineWidth += childWidth; 88 | lineHeight = Math.max(lineHeight, childHeight); 89 | } 90 | if (i == cCount - 1) { 91 | width = Math.max(lineWidth, width); 92 | height += lineHeight; 93 | } 94 | } 95 | setMeasuredDimension( 96 | modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(), 97 | modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom() 98 | ); 99 | 100 | } 101 | 102 | 103 | @Override 104 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 105 | mAllViews.clear(); 106 | mLineHeight.clear(); 107 | mLineWidth.clear(); 108 | lineViews.clear(); 109 | 110 | int width = getWidth(); 111 | 112 | int lineWidth = 0; 113 | int lineHeight = 0; 114 | 115 | int cCount = getChildCount(); 116 | 117 | for (int i = 0; i < cCount; i++) { 118 | View child = getChildAt(i); 119 | if (child.getVisibility() == View.GONE) continue; 120 | MarginLayoutParams lp = (MarginLayoutParams) child 121 | .getLayoutParams(); 122 | 123 | int childWidth = child.getMeasuredWidth(); 124 | int childHeight = child.getMeasuredHeight(); 125 | 126 | if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width - getPaddingLeft() - getPaddingRight()) { 127 | mLineHeight.add(lineHeight); 128 | mAllViews.add(lineViews); 129 | mLineWidth.add(lineWidth); 130 | 131 | lineWidth = 0; 132 | lineHeight = childHeight + lp.topMargin + lp.bottomMargin; 133 | lineViews = new ArrayList(); 134 | } 135 | lineWidth += childWidth + lp.leftMargin + lp.rightMargin; 136 | lineHeight = Math.max(lineHeight, childHeight + lp.topMargin 137 | + lp.bottomMargin); 138 | lineViews.add(child); 139 | 140 | } 141 | mLineHeight.add(lineHeight); 142 | mLineWidth.add(lineWidth); 143 | mAllViews.add(lineViews); 144 | 145 | 146 | int left = getPaddingLeft(); 147 | int top = getPaddingTop(); 148 | 149 | int lineNum = mAllViews.size(); 150 | 151 | for (int i = 0; i < lineNum; i++) { 152 | lineViews = mAllViews.get(i); 153 | lineHeight = mLineHeight.get(i); 154 | 155 | // set gravity 156 | int currentLineWidth = this.mLineWidth.get(i); 157 | switch (this.mGravity) { 158 | case LEFT: 159 | left = getPaddingLeft(); 160 | break; 161 | case CENTER: 162 | left = (width - currentLineWidth) / 2 + getPaddingLeft(); 163 | break; 164 | case RIGHT: 165 | left = width - currentLineWidth + getPaddingLeft(); 166 | break; 167 | } 168 | 169 | for (int j = 0; j < lineViews.size(); j++) { 170 | View child = lineViews.get(j); 171 | if (child.getVisibility() == View.GONE) { 172 | continue; 173 | } 174 | 175 | MarginLayoutParams lp = (MarginLayoutParams) child 176 | .getLayoutParams(); 177 | 178 | int lc = left + lp.leftMargin; 179 | int tc = top + lp.topMargin; 180 | int rc = lc + child.getMeasuredWidth(); 181 | int bc = tc + child.getMeasuredHeight(); 182 | 183 | child.layout(lc, tc, rc, bc); 184 | 185 | left += child.getMeasuredWidth() + lp.leftMargin 186 | + lp.rightMargin; 187 | } 188 | top += lineHeight; 189 | } 190 | 191 | } 192 | 193 | @Override 194 | public LayoutParams generateLayoutParams(AttributeSet attrs) { 195 | return new MarginLayoutParams(getContext(), attrs); 196 | } 197 | 198 | @Override 199 | protected LayoutParams generateDefaultLayoutParams() { 200 | return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 201 | } 202 | 203 | @Override 204 | protected LayoutParams generateLayoutParams(LayoutParams p) { 205 | return new MarginLayoutParams(p); 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android轮播图 - Banner 2 | 3 | 纵观Android古今,轮播图已然泛滥成灾!大神们各显神通大兴土木,所起楼台之高让后来者心生膜拜,纷纷Star!但不法分子也是层出不穷,为求"大神"的桂冠,挂羊头卖狗肉,一个镜像就试图去名满天下,鄙人正是此等不法分子!虽有点盗窃[youth5201314](https://github.com/youth5201314/banner)前辈的劳动成果,但也算是实实在在在前辈的肩膀上干了点实在事——帮前辈梳了梳头,整理了一下发型。毕竟盲仔说过:头可断,发型不能乱。但是在下还是得由衷感谢[youth5201314](https://github.com/youth5201314/banner)前辈,您造的法拉利我至少给您保养了一番! 4 | 5 | ## 功能特点 6 | - 支持一屏三页 7 | - 支持任意View显示在Banner上 8 | - 支持自定义显示器 9 | - 支持多种Banner动画 10 | - 支持仿魅族Banner 11 | - 空数据、两条数据优化处理 12 | - 创建的View内部已做缓存,性能更佳 13 | - 一句话:更加精简,更加智能,更加好用!!! 14 | 15 | ## 有图有真相 16 | ![Banner1](https://github.com/AlpsDog/Banner/blob/master/banner1.png) 17 | ![Banner2](https://github.com/AlpsDog/Banner/blob/master/banner2.png) 18 | ![Banner3](https://github.com/AlpsDog/Banner/blob/master/banner3.png) 19 | ![Banner4](https://github.com/AlpsDog/Banner/blob/master/banner4.png) 20 | ![Banner6](https://github.com/AlpsDog/Banner/blob/master/banner6.png) 21 | 22 | ### 新增仿魅族Banner 23 | ![Banner5](https://github.com/AlpsDog/Banner/blob/master/banner5.png) 24 | 25 | ## 简单用法 26 | #### 1.添加依赖: 27 | ``` 28 | 1.1 工程的build.gradle下添加: 29 | maven { url 'https://jitpack.io' } 30 | 1.2 模块的build.gradle下添加: 31 | implementation 'com.github.AlpsDog:Banner:v1.0.6' 32 | ``` 33 | > 如果你的项目为: **AndroidX** 34 | ``` 35 | 请在 gradle.properties 中添加:(如果已经添加请忽略) 36 | 37 | android.useAndroidX=true 38 | android.enableJetifier=true 39 | 40 | ``` 41 | #### 2.XML布局文件 42 | ``` 43 | 58 | ``` 59 | #### 3.在Activity/Fragment中 60 | ``` 61 | // 1. 创建设置BannerLoader 62 | banner.setBannerLoader(new ImageLoader() { 63 | @Override 64 | public void loadView(Context context, BannerEntry entry, int position, View imageView) { 65 | RequestOptions requestOptions = new RequestOptions() 66 | .placeholder(R.drawable.banner_default) 67 | .error(R.drawable.banner_default) 68 | .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC); 69 | Glide.with(context).load(entry.getBannerPath()).apply(requestOptions).into((ImageView) imageView); 70 | } 71 | }); 72 | 73 | // 2 设置页面点击事件 74 | banner.setOnBannerClickListener(new Banner.OnBannerClickListener() { 75 | @Override 76 | public void onBannerClick(int position) { 77 | Toast.makeText(BaseUseActivity.this, "点击了:" + position, Toast.LENGTH_SHORT).show(); 78 | } 79 | }); 80 | 81 | // 3 翻页事件 82 | banner.setBannerPagerChangedListener(new Banner.OnBannerSimplePagerListener() { 83 | @Override 84 | public void onPageSelected(int position) { 85 | Log.d("hsl777", "onPageSelected: ==>" + position); 86 | } 87 | }); 88 | 89 | // 4 最重要一步,加载数据 90 | banner.loadImagePaths(mData); 91 | ``` 92 | 93 | >非常重要之处 94 | ``` 95 | 此处添加可以优化Banner体验 96 | 但是一旦启用自动轮播,必须调用 banner.stopAutoPlay(); 97 | 可以在onResume()、也可以在onDestory(), 98 | 这样才能确保轮播任务停止 99 | 防止内存泄漏 100 | 101 | @Override 102 | protected void onResume() { 103 | super.onResume(); 104 | banner.startAutoPlay(); 105 | } 106 | 107 | @Override 108 | protected void onPause() { 109 | super.onPause(); 110 | banner.stopAutoPlay(); 111 | } 112 | ``` 113 | 114 | #### 4.数据源说明 115 | ``` 116 | // Banner内部定义的数据接口 117 | public interface BannerEntry { 118 | 119 | /** 120 | * 获取Banner数据源 121 | * 122 | * @return 123 | */ 124 | T getBannerPath(); 125 | 126 | /** 127 | * 获取指示器文本 128 | * 129 | * @return 130 | */ 131 | String getIndicatorText(); 132 | } 133 | 134 | // 实体类继承此接口 135 | // getBannerPath()返回图片加载的源 136 | // getIndicatorText()返回Banner摘要,非必须 137 | public class BannerItem implements BannerEntry { 138 | 139 | private Object path; 140 | private String indicatorText; 141 | 142 | public BannerItem() { 143 | } 144 | 145 | public BannerItem(Object path, String indicatorText) { 146 | this.path = path; 147 | this.indicatorText = indicatorText; 148 | } 149 | 150 | @Override 151 | public Object getBannerPath() { 152 | //此处返回图片加载的源,可以是 URL RES FILE... 153 | return path; 154 | } 155 | 156 | @Override 157 | public String getIndicatorText() { 158 | //此处返回Banner摘要,非必须 159 | return indicatorText; 160 | } 161 | 162 | public Object getPath() { 163 | return path; 164 | } 165 | 166 | public void setPath(Object path) { 167 | this.path = path; 168 | } 169 | 170 | public void setIndicatorText(String indicatorText) { 171 | this.indicatorText = indicatorText; 172 | } 173 | } 174 | ``` 175 | #### 5.加载器说明 176 | ``` 177 | //自定义Banner显示的View时,可用此加载器 178 | public interface BannerLoader { 179 | 180 | /** 181 | * 加载VIEW 182 | * 183 | * @param context 184 | * @param entry 185 | * @param position 显示的位置 186 | * @param imageView 187 | */ 188 | void loadView(Context context, BannerEntry entry, int position, V imageView); 189 | 190 | /** 191 | * 创建View 192 | * 193 | * @param context 194 | * @param position 195 | * @return 196 | */ 197 | V createView(Context context, int position); 198 | } 199 | 200 | //简化版加载器 201 | public abstract class ImageLoader implements BannerLoader { 202 | 203 | @Override 204 | public ImageView createView(Context context, int position) { 205 | ImageView imageView = new ImageView(context); 206 | imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); 207 | return imageView; 208 | } 209 | } 210 | 211 | //关于怎样自定义Banner显示的View,可参考Demo 212 | ``` 213 | #### 6.自定义属性说明 214 | ``` 215 | banner_auto_play : 能否自动轮播 216 | banner_show_model : 显示模式(一屏一页、一屏三页、仿魅族Banner) 217 | banner_interval_time : 轮播间隔 218 | banner_scroll_time : 翻页时长(决定翻页的速度) 219 | banner_single_anim : 一屏一页动画 220 | banner_default_image : 数据为空时,默认显示图 221 | banner_expose_width : 一屏三页,左右两页露出的宽度 222 | banner_page_spacing : 一屏三页,页间距 223 | banner_multi_anim : 一屏三页动画 224 | banner_mz_overlap : 仿魅族Banner时,中间Page压着左右两边page的宽度 225 | banner_mz_anim : 仿魅族Banner动画 226 | banner_show_indicator : 是否显示指示器 227 | indicator_select_width : 选中的指示器宽度 228 | indicator_select_height : 选中的指示器高度 229 | indicator_default_width : 未选中指示器宽度 230 | indicator_default_height : 未选中指示器高度 231 | indicator_space : 指示器间隔 232 | indicator_margin_bottom : 指示器距底部距离 233 | indicator_select_drawable : 指示器选中的样式 234 | indicator_default_drawable : 指示器未选中样式 235 | ``` 236 | ## 版本说明 237 | ##### v1.0.6正式版 238 | ``` 239 | 1.修复一张图刷新为多张图是时,显示问题 240 | 2.修复多张图刷为一张图时,崩溃问题 241 | ``` 242 | ##### v1.0.4正式版 243 | ``` 244 | 1.修复一张图时,使用glide崩溃问题 245 | ``` 246 | ##### v1.0.3正式版 247 | ``` 248 | 1.空数据优化 249 | 2.频繁刷新优化 250 | ``` 251 | ##### v1.0.2正式版 252 | ``` 253 | 新增仿魅族Banner 254 | ``` 255 | ##### v1.0.1正式版 256 | ``` 257 | 1.对内部结构进行了优化 258 | 2.增加数据源接口,规范使用 259 | ``` 260 | ##### V1.0.0正式版 261 | ``` 262 | 1.轮播图使用示例 263 | 2.轮播图LIB源码 264 | ``` 265 | ## 鸣谢 266 | 感谢[youth5201314](https://github.com/youth5201314/banner)前辈的Banner 267 | 268 | 感谢[张鸿洋](https://github.com/hongyangAndroid/MagicViewPager)大师的ViewPager一屏三页动画 269 | 270 | **感谢大家对鄙人的支持** 271 | 272 | ![HEAD](https://github.com/AlpsDog/Banner/blob/master/linshao.png) 273 | 274 | 275 | 276 | 277 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/widget/flowlayout/TagFlowLayout.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.widget.flowlayout; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.os.Bundle; 6 | import android.os.Parcelable; 7 | import android.text.TextUtils; 8 | import android.util.AttributeSet; 9 | import android.util.Log; 10 | import android.view.View; 11 | 12 | import com.test.banner.R; 13 | 14 | import java.util.HashSet; 15 | import java.util.Iterator; 16 | import java.util.Set; 17 | 18 | /** 19 | * @Description:带选中的流式布局 20 | */ 21 | public class TagFlowLayout extends FlowLayout 22 | implements TagAdapter.OnDataChangedListener { 23 | 24 | private TagAdapter mTagAdapter; 25 | //-1为不限制数量 26 | private int mSelectedMax = -1; 27 | private static final String TAG = "TagFlowLayout"; 28 | 29 | private Set mSelectedView = new HashSet(); 30 | 31 | private OnSelectListener mOnSelectListener; 32 | private OnTagClickListener mOnTagClickListener; 33 | 34 | public interface OnSelectListener { 35 | void onSelected(Set selectPosSet); 36 | } 37 | 38 | public interface OnTagClickListener { 39 | boolean onTagClick(View view, int position, FlowLayout parent); 40 | } 41 | 42 | public TagFlowLayout(Context context, AttributeSet attrs, int defStyle) { 43 | super(context, attrs, defStyle); 44 | TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout); 45 | mSelectedMax = ta.getInt(R.styleable.TagFlowLayout_max_select, -1); 46 | ta.recycle(); 47 | } 48 | 49 | public TagFlowLayout(Context context, AttributeSet attrs) { 50 | this(context, attrs, 0); 51 | } 52 | 53 | public TagFlowLayout(Context context) { 54 | this(context, null); 55 | } 56 | 57 | 58 | @Override 59 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 60 | int cCount = getChildCount(); 61 | for (int i = 0; i < cCount; i++) { 62 | TagView tagView = (TagView) getChildAt(i); 63 | if (tagView.getVisibility() == View.GONE) { 64 | continue; 65 | } 66 | if (tagView.getTagView().getVisibility() == View.GONE) { 67 | tagView.setVisibility(View.GONE); 68 | } 69 | } 70 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 71 | } 72 | 73 | 74 | public void setOnSelectListener(OnSelectListener onSelectListener) { 75 | mOnSelectListener = onSelectListener; 76 | } 77 | 78 | 79 | public void setOnTagClickListener(OnTagClickListener onTagClickListener) { 80 | mOnTagClickListener = onTagClickListener; 81 | } 82 | 83 | public void setAdapter(TagAdapter adapter) { 84 | mTagAdapter = adapter; 85 | mTagAdapter.setOnDataChangedListener(this); 86 | mSelectedView.clear(); 87 | changeAdapter(); 88 | } 89 | 90 | @SuppressWarnings("ResourceType") 91 | private void changeAdapter() { 92 | removeAllViews(); 93 | TagAdapter adapter = mTagAdapter; 94 | TagView tagViewContainer = null; 95 | HashSet preCheckedList = mTagAdapter.getPreCheckedList(); 96 | for (int i = 0; i < adapter.getCount(); i++) { 97 | View tagView = adapter.getView(this, i, adapter.getItem(i)); 98 | 99 | tagViewContainer = new TagView(getContext()); 100 | tagView.setDuplicateParentStateEnabled(true); 101 | if (tagView.getLayoutParams() != null) { 102 | tagViewContainer.setLayoutParams(tagView.getLayoutParams()); 103 | 104 | 105 | } else { 106 | MarginLayoutParams lp = new MarginLayoutParams( 107 | LayoutParams.WRAP_CONTENT, 108 | LayoutParams.WRAP_CONTENT); 109 | lp.setMargins(dip2px(getContext(), 5), 110 | dip2px(getContext(), 5), 111 | dip2px(getContext(), 5), 112 | dip2px(getContext(), 5)); 113 | tagViewContainer.setLayoutParams(lp); 114 | } 115 | LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 116 | tagView.setLayoutParams(lp); 117 | tagViewContainer.addView(tagView); 118 | addView(tagViewContainer); 119 | 120 | if (preCheckedList.contains(i)) { 121 | setChildChecked(i, tagViewContainer); 122 | } 123 | 124 | if (mTagAdapter.setSelected(i, adapter.getItem(i))) { 125 | setChildChecked(i, tagViewContainer); 126 | } 127 | tagView.setClickable(false); 128 | final TagView finalTagViewContainer = tagViewContainer; 129 | final int position = i; 130 | tagViewContainer.setOnClickListener(new OnClickListener() { 131 | @Override 132 | public void onClick(View v) { 133 | doSelect(finalTagViewContainer, position); 134 | if (mOnTagClickListener != null) { 135 | mOnTagClickListener.onTagClick(finalTagViewContainer, position, 136 | TagFlowLayout.this); 137 | } 138 | } 139 | }); 140 | } 141 | mSelectedView.addAll(preCheckedList); 142 | } 143 | 144 | public void setMaxSelectCount(int count) { 145 | if (mSelectedView.size() > count) { 146 | Log.w(TAG, "you has already select more than " + count + " views , so it will be clear ."); 147 | mSelectedView.clear(); 148 | } 149 | mSelectedMax = count; 150 | } 151 | 152 | public Set getSelectedList() { 153 | return new HashSet(mSelectedView); 154 | } 155 | 156 | private void setChildChecked(int position, TagView view) { 157 | view.setChecked(true); 158 | mTagAdapter.onSelected(position, view.getTagView()); 159 | } 160 | 161 | private void setChildUnChecked(int position, TagView view) { 162 | view.setChecked(false); 163 | mTagAdapter.unSelected(position, view.getTagView()); 164 | } 165 | 166 | private void doSelect(TagView child, int position) { 167 | if (!child.isChecked()) { 168 | //处理max_select=1的情况 169 | if (mSelectedMax == 1 && mSelectedView.size() == 1) { 170 | Iterator iterator = mSelectedView.iterator(); 171 | Integer preIndex = iterator.next(); 172 | TagView pre = (TagView) getChildAt(preIndex); 173 | setChildUnChecked(preIndex, pre); 174 | setChildChecked(position, child); 175 | 176 | mSelectedView.remove(preIndex); 177 | mSelectedView.add(position); 178 | } else { 179 | if (mSelectedMax > 0 && mSelectedView.size() >= mSelectedMax) { 180 | return; 181 | } 182 | setChildChecked(position, child); 183 | mSelectedView.add(position); 184 | } 185 | } else { 186 | setChildUnChecked(position, child); 187 | mSelectedView.remove(position); 188 | } 189 | if (mOnSelectListener != null) { 190 | mOnSelectListener.onSelected(new HashSet(mSelectedView)); 191 | } 192 | } 193 | 194 | public TagAdapter getAdapter() { 195 | return mTagAdapter; 196 | } 197 | 198 | 199 | private static final String KEY_CHOOSE_POS = "key_choose_pos"; 200 | private static final String KEY_DEFAULT = "key_default"; 201 | 202 | 203 | @Override 204 | protected Parcelable onSaveInstanceState() { 205 | Bundle bundle = new Bundle(); 206 | bundle.putParcelable(KEY_DEFAULT, super.onSaveInstanceState()); 207 | 208 | String selectPos = ""; 209 | if (mSelectedView.size() > 0) { 210 | for (int key : mSelectedView) { 211 | selectPos += key + "|"; 212 | } 213 | selectPos = selectPos.substring(0, selectPos.length() - 1); 214 | } 215 | bundle.putString(KEY_CHOOSE_POS, selectPos); 216 | return bundle; 217 | } 218 | 219 | @Override 220 | protected void onRestoreInstanceState(Parcelable state) { 221 | if (state instanceof Bundle) { 222 | Bundle bundle = (Bundle) state; 223 | String mSelectPos = bundle.getString(KEY_CHOOSE_POS); 224 | if (!TextUtils.isEmpty(mSelectPos)) { 225 | String[] split = mSelectPos.split("\\|"); 226 | for (String pos : split) { 227 | int index = Integer.parseInt(pos); 228 | mSelectedView.add(index); 229 | 230 | TagView tagView = (TagView) getChildAt(index); 231 | if (tagView != null) { 232 | setChildChecked(index, tagView); 233 | } 234 | } 235 | 236 | } 237 | super.onRestoreInstanceState(bundle.getParcelable(KEY_DEFAULT)); 238 | return; 239 | } 240 | super.onRestoreInstanceState(state); 241 | } 242 | 243 | 244 | @Override 245 | public void onChanged() { 246 | mSelectedView.clear(); 247 | changeAdapter(); 248 | } 249 | 250 | public static int dip2px(Context context, float dpValue) { 251 | final float scale = context.getResources().getDisplayMetrics().density; 252 | return (int) (dpValue * scale + 0.5f); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/utils/DateUtils.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.utils; 2 | 3 | 4 | import java.sql.Timestamp; 5 | import java.text.ParseException; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Calendar; 8 | import java.util.Date; 9 | import java.util.GregorianCalendar; 10 | import java.util.Locale; 11 | 12 | /** 13 | * Description: 对不同日期和时间的格式方法的封装 14 | */ 15 | 16 | public class DateUtils { 17 | 18 | 19 | private static DateUtils instance; 20 | 21 | private DateUtils() { 22 | 23 | } 24 | 25 | public static DateUtils getInstance() { 26 | if (instance == null) { 27 | synchronized (DateUtils.class) { 28 | if (instance == null) { 29 | instance = new DateUtils(); 30 | } 31 | } 32 | } 33 | return instance; 34 | } 35 | 36 | 37 | /** 38 | * 通过long类型的值返回当前的 星期几 39 | * 40 | * @param time 41 | * @return 42 | */ 43 | public String getWeekday(long time) { 44 | Calendar calen = Calendar.getInstance(); 45 | calen.setTimeInMillis(time); 46 | int week = calen.get(Calendar.DAY_OF_WEEK); 47 | String result = "星期一"; 48 | switch (week) { 49 | case Calendar.SUNDAY: 50 | result = "星期日"; 51 | break; 52 | case Calendar.MONDAY: 53 | result = "星期一"; 54 | break; 55 | case Calendar.TUESDAY: 56 | result = "星期二"; 57 | break; 58 | case Calendar.WEDNESDAY: 59 | result = "星期三"; 60 | break; 61 | case Calendar.THURSDAY: 62 | result = "星期四"; 63 | break; 64 | case Calendar.FRIDAY: 65 | result = "星期五"; 66 | break; 67 | case Calendar.SATURDAY: 68 | result = "星期六"; 69 | break; 70 | default: 71 | result = "星期一"; 72 | break; 73 | } 74 | return result; 75 | } 76 | 77 | /** 78 | * 判断两个时间是否属于同一天 79 | * 80 | * @param time1 81 | * @param time2 82 | * @return 83 | */ 84 | public boolean isSameDay(long time1, long time2) { 85 | Calendar calen = Calendar.getInstance(); 86 | calen.setTimeInMillis(time1); 87 | int day1 = calen.get(Calendar.DAY_OF_YEAR); 88 | calen.setTimeInMillis(time2); 89 | int day2 = calen.get(Calendar.DAY_OF_YEAR); 90 | return day1 == day2; 91 | } 92 | 93 | /** 94 | * @param time 95 | * @return 96 | * @描述: 2017-02-23 97 | */ 98 | public String getDayOrMonthOrYear(long time) { 99 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 100 | return sdf.format(new Date(time)); 101 | } 102 | 103 | /** 104 | * @param time 105 | * @return 106 | * @描述: 2017年02月23日 107 | */ 108 | public String getDayOrMonthOrYear1(long time) { 109 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy年-MM月-dd日"); 110 | return sdf.format(new Date(time)); 111 | } 112 | 113 | /** 114 | * @param time 115 | * @return 116 | * @描述: 2017年02月23日 117 | */ 118 | public String getDayOrMonthOrYear2(long time) { 119 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); 120 | return sdf.format(new Date(time)); 121 | } 122 | 123 | /** 124 | * @param time 125 | * @return 126 | * @描述: 2017/02/23 127 | */ 128 | public String getDayOrMonthOrYear3(long time) { 129 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); 130 | return sdf.format(new Date(time)); 131 | } 132 | 133 | /** 134 | * @param time 135 | * @return 136 | * @描述: 2017.02.23 137 | */ 138 | public String getDayOrMonthOrYear4(long time) { 139 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd"); 140 | return sdf.format(new Date(time)); 141 | } 142 | 143 | public String dateFormat(long time) { 144 | return new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) 145 | .format(new Date(time)); 146 | } 147 | 148 | /** 149 | * @param time 150 | * @return 151 | * @描述: 2017-02-23 06:26:12 152 | */ 153 | public String dateFormat2(long time) { 154 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) 155 | .format(new Date(time)); 156 | } 157 | 158 | /** 159 | * @param time 160 | * @return 161 | * @描述: 2017年02月23日06点26分12秒 162 | */ 163 | public String dateFormat3(long time) { 164 | return new SimpleDateFormat("yyyy年MM月dd日HH点mm分ss秒", Locale.getDefault()) 165 | .format(new Date(time)); 166 | } 167 | 168 | /** 169 | * @param 170 | * @return 171 | * @描述: 2017-02-23 06:26:12 倒计时格式 172 | */ 173 | public String dateFormat4(long mss) { 174 | long hours = mss / (1000 * 60 * 60); 175 | long minutes = (mss % (1000 * 60 * 60)) / (1000 * 60); 176 | long seconds = (mss % (1000 * 60)) / 1000; 177 | return hours + ":" + minutes + ":" 178 | + seconds; 179 | } 180 | 181 | public String dateFormat5(long mss) { 182 | long hours = mss / (1000 * 60 * 60); 183 | long minutes = (mss % (1000 * 60 * 60)) / (1000 * 60); 184 | long seconds = (mss % (1000 * 60)) / 1000; 185 | return hours + "时" + minutes + "分" 186 | + seconds + "秒"; 187 | } 188 | 189 | /** 190 | * @param time 191 | * @return 192 | * @描述: 2017-02-23 06:26:12 193 | */ 194 | public String dateFormat6(long time) { 195 | return new SimpleDateFormat("HH:mm:ss", Locale.getDefault()) 196 | .format(new Date(time)); 197 | } 198 | 199 | 200 | public String dateFormat7(long time) { 201 | return new SimpleDateFormat("MM-dd", Locale.getDefault()) 202 | .format(new Date(time)); 203 | } 204 | 205 | public String dateFormat8(long time) { 206 | return new SimpleDateFormat("HH:mm", Locale.getDefault()) 207 | .format(new Date(time)); 208 | } 209 | 210 | /** 211 | * 格式9 212 | * 213 | * @param time 214 | * @return 2019/07/11 14:51:01 215 | */ 216 | public String dateFormat9(long time) { 217 | return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault()) 218 | .format(new Date(time)); 219 | } 220 | 221 | /** 222 | * 获取本周的开始时间 223 | * 224 | * @return 225 | */ 226 | public Date getBeginDayOfWeek() { 227 | Date date = new Date(); 228 | if (date == null) { 229 | return null; 230 | } 231 | Calendar cal = Calendar.getInstance(); 232 | cal.setTime(date); 233 | int dayofweek = cal.get(Calendar.DAY_OF_WEEK); 234 | if (dayofweek == 1) { 235 | dayofweek += 7; 236 | } 237 | cal.add(Calendar.DATE, 2 - dayofweek); 238 | return getDayStartTime(cal.getTime()); 239 | } 240 | 241 | //获取本月的开始时间 242 | public Date getBeginDayOfMonth() { 243 | Calendar calendar = Calendar.getInstance(); 244 | calendar.set(getNowYear(), getNowMonth() - 1, 1); 245 | return getDayStartTime(calendar.getTime()); 246 | } 247 | 248 | //获取某个日期的开始时间 249 | public Timestamp getDayStartTime(Date d) { 250 | Calendar calendar = Calendar.getInstance(); 251 | if (null != d) calendar.setTime(d); 252 | calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0); 253 | calendar.set(Calendar.MILLISECOND, 0); 254 | return new Timestamp(calendar.getTimeInMillis()); 255 | } 256 | 257 | //转时间戳 秒 258 | public String dateToStamp(String s) throws ParseException { 259 | String res; 260 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 261 | Date date = simpleDateFormat.parse(s); 262 | long ts = date.getTime(); 263 | ts = ts / 1000; 264 | res = String.valueOf(ts); 265 | return res; 266 | } 267 | 268 | //获取今年是哪一年 269 | public Integer getNowYear() { 270 | Date date = new Date(); 271 | GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance(); 272 | gc.setTime(date); 273 | return Integer.valueOf(gc.get(1)); 274 | } 275 | 276 | //获取本月是哪一月 277 | public int getNowMonth() { 278 | Date date = new Date(); 279 | GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance(); 280 | gc.setTime(date); 281 | return gc.get(2) + 1; 282 | } 283 | 284 | 285 | // string类型转换为date类型 286 | // strTime要转换的string类型的时间,formatType要转换的格式yyyy-MM-dd HH:mm:ss//yyyy年MM月dd日 287 | // HH时mm分ss秒, 288 | // strTime的时间格式必须要与formatType的时间格式相同 289 | public Date stringToDate(String strTime, String formatType) 290 | throws ParseException, ParseException { 291 | SimpleDateFormat formatter = new SimpleDateFormat(formatType); 292 | Date date = null; 293 | date = formatter.parse(strTime); 294 | return date; 295 | } 296 | 297 | public static String getTime(int second) { 298 | if (second < 10) { 299 | return "00:00:0" + second; 300 | } 301 | if (second < 60) { 302 | return "00:00:" + second; 303 | } 304 | if (second < 3600) { 305 | int minute = second / 60; 306 | second = second - minute * 60; 307 | if (minute < 10) { 308 | if (second < 10) { 309 | return "00:0" + minute + ":0" + second; 310 | } 311 | return "00:0" + minute + ":" + second; 312 | } 313 | if (second < 10) { 314 | return "00:" + minute + ":0" + second; 315 | } 316 | return "00:" + minute + ":" + second; 317 | } 318 | int hour = second / 3600; 319 | int minute = (second - hour * 3600) / 60; 320 | second = second - hour * 3600 - minute * 60; 321 | if (hour < 10) { 322 | if (minute < 10) { 323 | if (second < 10) { 324 | return "0" + hour + ":0" + minute + ":0" + second; 325 | } 326 | return "0" + hour + ":0" + minute + ":" + second; 327 | } 328 | if (second < 10) { 329 | return "0" + hour + minute + ":0" + second; 330 | } 331 | return "0" + hour + minute + ":" + second; 332 | } 333 | if (minute < 10) { 334 | if (second < 10) { 335 | return hour + ":0" + minute + ":0" + second; 336 | } 337 | return hour + ":0" + minute + ":" + second; 338 | } 339 | if (second < 10) { 340 | return hour + minute + ":0" + second; 341 | } 342 | return hour + minute + ":" + second; 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /app/src/main/java/com/test/banner/utils/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package com.test.banner.utils; 2 | 3 | import android.app.Activity; 4 | import android.app.KeyguardManager; 5 | import android.content.Context; 6 | import android.content.pm.ActivityInfo; 7 | import android.content.res.Configuration; 8 | import android.content.res.Resources; 9 | import android.graphics.Bitmap; 10 | import android.graphics.Point; 11 | import android.os.Build; 12 | import android.provider.Settings; 13 | import android.support.annotation.NonNull; 14 | import android.support.annotation.RequiresPermission; 15 | import android.util.DisplayMetrics; 16 | import android.view.Surface; 17 | import android.view.View; 18 | import android.view.Window; 19 | import android.view.WindowManager; 20 | 21 | import com.test.banner.application.AppContext; 22 | 23 | import static android.Manifest.permission.WRITE_SETTINGS; 24 | 25 | /** 26 | * 屏幕相关工具类 27 | */ 28 | public final class ScreenUtils { 29 | 30 | private ScreenUtils() { 31 | throw new UnsupportedOperationException("u can't instantiate me..."); 32 | } 33 | 34 | /** 35 | * 获取屏幕宽度 36 | * 37 | * @return the width of screen, in pixel 38 | */ 39 | public static int getScreenWidth() { 40 | WindowManager wm = (WindowManager) AppContext.getInstance().getSystemService(Context.WINDOW_SERVICE); 41 | if (wm == null) { 42 | return AppContext.getInstance().getResources().getDisplayMetrics().widthPixels; 43 | } 44 | Point point = new Point(); 45 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 46 | wm.getDefaultDisplay().getRealSize(point); 47 | } else { 48 | wm.getDefaultDisplay().getSize(point); 49 | } 50 | return point.x; 51 | } 52 | 53 | /** 54 | * 获取屏幕高度 55 | * 56 | * @return the height of screen, in pixel 57 | */ 58 | public static int getScreenHeight() { 59 | WindowManager wm = (WindowManager) AppContext.getInstance().getSystemService(Context.WINDOW_SERVICE); 60 | if (wm == null) { 61 | return AppContext.getInstance().getResources().getDisplayMetrics().heightPixels; 62 | } 63 | Point point = new Point(); 64 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 65 | wm.getDefaultDisplay().getRealSize(point); 66 | } else { 67 | wm.getDefaultDisplay().getSize(point); 68 | } 69 | return point.y; 70 | } 71 | 72 | /** 73 | * 屏幕密度 74 | * 75 | * @return the density of screen 76 | */ 77 | public static float getScreenDensity() { 78 | return AppContext.getInstance().getResources().getDisplayMetrics().density; 79 | } 80 | 81 | /** 82 | * @return the screen density expressed as dots-per-inch 83 | */ 84 | public static int getScreenDensityDpi() { 85 | return AppContext.getInstance().getResources().getDisplayMetrics().densityDpi; 86 | } 87 | 88 | /** 89 | * 设置全屏 90 | * 91 | * @param activity The activity. 92 | */ 93 | public static void setFullScreen(@NonNull final Activity activity) { 94 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN 95 | | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 96 | } 97 | 98 | /** 99 | * 取消全屏 100 | * 101 | * @param activity The activity. 102 | */ 103 | public static void setNonFullScreen(@NonNull final Activity activity) { 104 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN 105 | | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 106 | } 107 | 108 | /** 109 | * Toggle full screen. 110 | * 111 | * @param activity The activity. 112 | */ 113 | public static void toggleFullScreen(@NonNull final Activity activity) { 114 | int fullScreenFlag = WindowManager.LayoutParams.FLAG_FULLSCREEN; 115 | Window window = activity.getWindow(); 116 | if ((window.getAttributes().flags & fullScreenFlag) == fullScreenFlag) { 117 | window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN 118 | | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 119 | } else { 120 | window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN 121 | | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 122 | } 123 | } 124 | 125 | /** 126 | * 是否全屏 127 | */ 128 | public static boolean isFullScreen(@NonNull final Activity activity) { 129 | int fullScreenFlag = WindowManager.LayoutParams.FLAG_FULLSCREEN; 130 | return (activity.getWindow().getAttributes().flags & fullScreenFlag) == fullScreenFlag; 131 | } 132 | 133 | /** 134 | * 横屏 135 | * 136 | * @param activity The activity. 137 | */ 138 | public static void setLandscape(@NonNull final Activity activity) { 139 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 140 | } 141 | 142 | /** 143 | * 竖屏 144 | * 145 | * @param activity The activity. 146 | */ 147 | public static void setPortrait(@NonNull final Activity activity) { 148 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 149 | } 150 | 151 | /** 152 | * Return whether screen is landscape. 153 | * 154 | * @return 155 | */ 156 | public static boolean isLandscape() { 157 | return AppContext.getInstance().getResources().getConfiguration().orientation 158 | == Configuration.ORIENTATION_LANDSCAPE; 159 | } 160 | 161 | /** 162 | * Return whether screen is portrait. 163 | * 164 | * @return 165 | */ 166 | public static boolean isPortrait() { 167 | return AppContext.getInstance().getResources().getConfiguration().orientation 168 | == Configuration.ORIENTATION_PORTRAIT; 169 | } 170 | 171 | /** 172 | * Return the rotation of screen. 173 | * 174 | * @param activity The activity. 175 | * @return the rotation of screen 176 | */ 177 | public static int getScreenRotation(@NonNull final Activity activity) { 178 | switch (activity.getWindowManager().getDefaultDisplay().getRotation()) { 179 | case Surface.ROTATION_0: 180 | return 0; 181 | case Surface.ROTATION_90: 182 | return 90; 183 | case Surface.ROTATION_180: 184 | return 180; 185 | case Surface.ROTATION_270: 186 | return 270; 187 | default: 188 | return 0; 189 | } 190 | } 191 | 192 | /** 193 | * 截屏 194 | * 195 | * @param activity The activity. 196 | * @return the bitmap of screen 197 | */ 198 | public static Bitmap screenShot(@NonNull final Activity activity) { 199 | return screenShot(activity, false); 200 | } 201 | 202 | /** 203 | * 截屏 204 | * 205 | * @param activity The activity. 206 | * @param isDeleteStatusBar True to delete status bar, false otherwise. 207 | * @return the bitmap of screen 208 | */ 209 | public static Bitmap screenShot(@NonNull final Activity activity, boolean isDeleteStatusBar) { 210 | View decorView = activity.getWindow().getDecorView(); 211 | decorView.setDrawingCacheEnabled(true); 212 | decorView.buildDrawingCache(); 213 | Bitmap bmp = decorView.getDrawingCache(); 214 | DisplayMetrics dm = new DisplayMetrics(); 215 | activity.getWindowManager().getDefaultDisplay().getMetrics(dm); 216 | Bitmap ret; 217 | if (isDeleteStatusBar) { 218 | Resources resources = activity.getResources(); 219 | int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); 220 | int statusBarHeight = resources.getDimensionPixelSize(resourceId); 221 | ret = Bitmap.createBitmap( 222 | bmp, 223 | 0, 224 | statusBarHeight, 225 | dm.widthPixels, 226 | dm.heightPixels - statusBarHeight 227 | ); 228 | } else { 229 | ret = Bitmap.createBitmap(bmp, 0, 0, dm.widthPixels, dm.heightPixels); 230 | } 231 | decorView.destroyDrawingCache(); 232 | return ret; 233 | } 234 | 235 | /** 236 | * Return whether screen is locked. 237 | */ 238 | public static boolean isScreenLock() { 239 | KeyguardManager km = 240 | (KeyguardManager) AppContext.getInstance().getSystemService(Context.KEYGUARD_SERVICE); 241 | return km != null && km.inKeyguardRestrictedInputMode(); 242 | } 243 | 244 | /** 245 | * Set the duration of sleep. 246 | *

Must hold {@code }

247 | * 248 | * @param duration The duration. 249 | */ 250 | @RequiresPermission(WRITE_SETTINGS) 251 | public static void setSleepDuration(final int duration) { 252 | Settings.System.putInt( 253 | AppContext.getInstance().getContentResolver(), 254 | Settings.System.SCREEN_OFF_TIMEOUT, 255 | duration 256 | ); 257 | } 258 | 259 | /** 260 | * Return the duration of sleep. 261 | * 262 | * @return the duration of sleep. 263 | */ 264 | public static int getSleepDuration() { 265 | try { 266 | return Settings.System.getInt( 267 | AppContext.getInstance().getContentResolver(), 268 | Settings.System.SCREEN_OFF_TIMEOUT 269 | ); 270 | } catch (Settings.SettingNotFoundException e) { 271 | e.printStackTrace(); 272 | return -123; 273 | } 274 | } 275 | 276 | /** 277 | * Return whether device is tablet. 278 | * 279 | * @return {@code true}: yes
{@code false}: no 280 | */ 281 | public static boolean isTablet() { 282 | return (AppContext.getInstance().getResources().getConfiguration().screenLayout 283 | & Configuration.SCREENLAYOUT_SIZE_MASK) 284 | >= Configuration.SCREENLAYOUT_SIZE_LARGE; 285 | } 286 | 287 | /** 288 | * Reference from: https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA 289 | */ 290 | private static void adaptScreen(final Activity activity, 291 | final float sizeInDp, 292 | final boolean isVerticalSlide) { 293 | final DisplayMetrics appDm = AppContext.getInstance().getResources().getDisplayMetrics(); 294 | final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics(); 295 | if (isVerticalSlide) { 296 | activityDm.density = activityDm.widthPixels / sizeInDp; 297 | } else { 298 | activityDm.density = activityDm.heightPixels / sizeInDp; 299 | } 300 | activityDm.scaledDensity = activityDm.density * (appDm.scaledDensity / appDm.density); 301 | activityDm.densityDpi = (int) (160 * activityDm.density); 302 | } 303 | } 304 | --------------------------------------------------------------------------------