├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jarRepositories.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── AppGradle └── appBuild.gradle ├── GalleryBannerLib ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yc │ │ └── gallerybannerlib │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── yc │ │ └── gallerybannerlib │ │ ├── GalleryLayoutManager.java │ │ ├── GalleryLinearSnapHelper.java │ │ ├── GalleryRecyclerView.java │ │ ├── GalleryScaleTransformer.java │ │ └── GallerySmoothScroller.java │ └── test │ └── java │ └── com │ └── yc │ └── gallerybannerlib │ └── ExampleUnitTest.java ├── LICENSE ├── README.md ├── SnapBannerLib ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── yc │ └── snapbannerlib │ ├── ScrollLinearHelper.java │ ├── ScrollPageHelper.java │ └── ScrollSnapHelper.java ├── YCBannerLib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── yc │ │ └── cn │ │ └── ycbannerlib │ │ ├── LibUtils.java │ │ ├── banner │ │ ├── adapter │ │ │ ├── AbsDynamicPagerAdapter.java │ │ │ ├── AbsLoopPagerAdapter.java │ │ │ └── AbsStaticPagerAdapter.java │ │ ├── hintview │ │ │ ├── ColorPointHintView.java │ │ │ ├── IconHintView.java │ │ │ ├── ShapeHintView.java │ │ │ └── TextHintView.java │ │ ├── inter │ │ │ ├── BaseHintView.java │ │ │ └── HintViewDelegate.java │ │ └── view │ │ │ ├── BannerConstant.java │ │ │ ├── BannerView.java │ │ │ └── BannerViewPager.java │ │ └── marquee │ │ └── MarqueeView.java │ └── res │ ├── anim │ ├── anim_marquee_in.xml │ └── anim_marquee_out.xml │ └── values │ ├── attrs.xml │ ├── ids.xml │ └── strings.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── yc │ │ └── cn │ │ └── ycbanner │ │ ├── EightActivity.java │ │ ├── FirstActivity.java │ │ ├── FourActivity.java │ │ ├── ImageBitmapUtils.java │ │ ├── MainActivity.java │ │ ├── NightActivity.java │ │ ├── SecondActivity.java │ │ ├── SevenActivity.java │ │ ├── SixActivity.java │ │ ├── Snap2Adapter.java │ │ ├── Snap3Adapter.java │ │ ├── SnapAdapter.java │ │ ├── SplashActivity.java │ │ └── ThirdActivity.java │ └── res │ ├── drawable-xhdpi │ ├── bg_autumn_tree_min.jpg │ ├── bg_kites_min.png │ ├── bg_lake_min.jpg │ ├── bg_leaves_min.jpg │ ├── bg_magnolia_trees_min.jpg │ ├── point_focus.png │ └── point_normal.png │ ├── drawable-xxhdpi │ ├── beauty1.jpg │ ├── beauty10.jpg │ ├── beauty11.jpg │ ├── beauty12.jpg │ ├── beauty13.jpg │ ├── beauty2.jpg │ ├── beauty3.jpg │ ├── beauty4.jpg │ ├── beauty5.jpg │ ├── beauty6.jpg │ ├── beauty7.jpg │ ├── beauty8.jpg │ └── beauty9.jpg │ ├── layout │ ├── activity_eight.xml │ ├── activity_first.xml │ ├── activity_five.xml │ ├── activity_four.xml │ ├── activity_main.xml │ ├── activity_night.xml │ ├── activity_second.xml │ ├── activity_seven.xml │ ├── activity_third.xml │ ├── item_snap.xml │ └── item_snap2.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── array.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image ├── 1.png ├── 2.png ├── 4.jpg ├── 4.mp4 ├── 5.jpg └── 6.jpg └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | # External native build folder generated in Android Studio 2.2 and later 47 | .externalNativeBuild 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 47 | 48 | 49 | 50 | 51 | 1.8 52 | 53 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AppGradle/appBuild.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | 3 | androidBuildToolsVersion = "29.0.0" 4 | androidMinSdkVersion = 17 5 | androidTargetSdkVersion = 29 6 | androidCompileSdkVersion = 29 7 | 8 | 9 | constraintLayoutVersion = '1.1.3' 10 | appcompatVersion = '1.2.0' 11 | annotationVersion = '1.1.0' 12 | cardviewVersion = '1.0.0' 13 | mediaVersion = '1.0.1' 14 | recyclerviewVersion = '1.0.0' 15 | 16 | /**主app-start*/ 17 | AppDependencies = [ 18 | constraintLayout : "androidx.constraintlayout:constraintlayout:${constraintLayoutVersion}", 19 | appcompat : "androidx.appcompat:appcompat:${appcompatVersion}", 20 | annotation : "androidx.annotation:annotation:${annotationVersion}", 21 | cardview : "androidx.cardview:cardview:${cardviewVersion}", 22 | media : "androidx.media:media:${mediaVersion}", 23 | recyclerview : "androidx.recyclerview:recyclerview:${recyclerviewVersion}", 24 | ] 25 | 26 | } -------------------------------------------------------------------------------- /GalleryBannerLib/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /GalleryBannerLib/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | } 4 | apply from: rootProject.projectDir.absolutePath + "/AppGradle/appBuild.gradle" 5 | apply plugin: 'com.github.dcendents.android-maven' 6 | 7 | android { 8 | compileSdkVersion project.ext.androidCompileSdkVersion 9 | //buildToolsVersion project.ext.androidBuildToolsVersion 10 | 11 | defaultConfig { 12 | minSdkVersion project.ext.androidMinSdkVersion 13 | targetSdkVersion project.ext.androidTargetSdkVersion 14 | versionCode 2 15 | versionName "1.0.2" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: "libs", include: ["*.jar"]) 28 | implementation project.ext.AppDependencies['appcompat'] 29 | implementation project.ext.AppDependencies['recyclerview'] 30 | } -------------------------------------------------------------------------------- /GalleryBannerLib/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/GalleryBannerLib/consumer-rules.pro -------------------------------------------------------------------------------- /GalleryBannerLib/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 -------------------------------------------------------------------------------- /GalleryBannerLib/src/androidTest/java/com/yc/gallerybannerlib/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.yc.gallerybannerlib; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.yc.gallerybannerlib.test", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /GalleryBannerLib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /GalleryBannerLib/src/main/java/com/yc/gallerybannerlib/GalleryLinearSnapHelper.java: -------------------------------------------------------------------------------- 1 | package com.yc.gallerybannerlib; 2 | 3 | import android.graphics.PointF; 4 | import android.util.DisplayMetrics; 5 | import android.util.Log; 6 | import android.view.View; 7 | 8 | import androidx.annotation.Nullable; 9 | import androidx.recyclerview.widget.LinearSmoothScroller; 10 | import androidx.recyclerview.widget.LinearSnapHelper; 11 | import androidx.recyclerview.widget.OrientationHelper; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | 14 | /** 15 | *
 16 |  *     @author yangchong
 17 |  *     blog  : https://github.com/yangchong211
 18 |  *     time  : 2018/3/18
 19 |  *     desc  : 自定义SnapHelper
 20 |  *     revise: 关于SnapHelper源码分析可以看我博客:https://blog.csdn.net/m0_37700275/article/details/83901677
 21 |  * 
22 | */ 23 | public class GalleryLinearSnapHelper extends LinearSnapHelper { 24 | 25 | private static final float INVALID_DISTANCE = 1f; 26 | private static final float MILLISECONDS_PER_INCH = 100.0f; 27 | private static final int MAX_SCROLL_ON_FLING_DURATION = 100; // ms 28 | private RecyclerView mRecyclerView; 29 | private OrientationHelper mHorizontalHelper; 30 | 31 | public GalleryLinearSnapHelper(@Nullable RecyclerView recyclerView){ 32 | mRecyclerView = recyclerView; 33 | } 34 | 35 | @Nullable 36 | protected LinearSmoothScroller createSnapScroller(final RecyclerView.LayoutManager layoutManager) { 37 | if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 38 | return null; 39 | } 40 | return new LinearSmoothScroller(mRecyclerView.getContext()) { 41 | @Override 42 | protected void onTargetFound(View targetView, RecyclerView.State state, RecyclerView.SmoothScroller.Action action) { 43 | int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), targetView); 44 | final int dx; 45 | final int dy; 46 | if (snapDistances != null) { 47 | dx = snapDistances[0]; 48 | dy = snapDistances[1]; 49 | final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy))); 50 | if (time > 0) { 51 | action.update(dx, dy, time, mDecelerateInterpolator); 52 | } 53 | } 54 | } 55 | 56 | @Override 57 | protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { 58 | //这个地方可以自己设置 59 | return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; 60 | } 61 | 62 | @Override 63 | protected int calculateTimeForScrolling(int dx) { 64 | return Math.min(MAX_SCROLL_ON_FLING_DURATION, super.calculateTimeForScrolling(dx)); 65 | } 66 | }; 67 | } 68 | 69 | /** 70 | * 提供一个用于对齐的Adapter 目标position,抽象方法,需要子类自己实现 71 | * 发现滚动时候,会滑动多个item,如果相对item个数做限制,可以在findTargetSnapPosition()方法中处理。 72 | * @param layoutManager layoutManager 73 | * @param velocityX velocityX 74 | * @param velocityY velocityY 75 | * @return 76 | */ 77 | @Override 78 | public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) { 79 | if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 80 | return RecyclerView.NO_POSITION; 81 | } 82 | 83 | final int itemCount = layoutManager.getItemCount(); 84 | if (itemCount == 0) { 85 | return RecyclerView.NO_POSITION; 86 | } 87 | 88 | final View currentView = findSnapView(layoutManager); 89 | if (currentView == null) { 90 | return RecyclerView.NO_POSITION; 91 | } 92 | 93 | final int currentPosition = layoutManager.getPosition(currentView); 94 | if (currentPosition == RecyclerView.NO_POSITION) { 95 | return RecyclerView.NO_POSITION; 96 | } 97 | 98 | RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider = 99 | (RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager; 100 | PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1); 101 | if (vectorForEnd == null) { 102 | return RecyclerView.NO_POSITION; 103 | } 104 | 105 | //在松手之后,列表最多只能滚多一屏的item数 106 | int deltaThreshold = layoutManager.getWidth() / getHorizontalHelper(layoutManager).getDecoratedMeasurement(currentView); 107 | Log.d("GalleryLinearSnapHelper", "---deltaThreshold---"+deltaThreshold+""); 108 | int hDeltaJump; 109 | if (layoutManager.canScrollHorizontally()) { 110 | hDeltaJump = estimateNextPositionDiffForFling(layoutManager, getHorizontalHelper(layoutManager), velocityX, 0); 111 | if (hDeltaJump > deltaThreshold) { 112 | hDeltaJump = deltaThreshold; 113 | } 114 | if (hDeltaJump < -deltaThreshold) { 115 | hDeltaJump = -deltaThreshold; 116 | } 117 | 118 | if (vectorForEnd.x < 0) { 119 | hDeltaJump = -hDeltaJump; 120 | } 121 | Log.d("GalleryLinearSnapHelper", "+++-hDeltaJump-+++"+hDeltaJump+""); 122 | } else { 123 | hDeltaJump = 0; 124 | } 125 | 126 | if (hDeltaJump == 0) { 127 | return RecyclerView.NO_POSITION; 128 | } 129 | Log.d("GalleryLinearSnapHelper", "---hDeltaJump---"+hDeltaJump+""); 130 | int targetPos = currentPosition + hDeltaJump; 131 | if (targetPos < 0) { 132 | targetPos = 0; 133 | } 134 | Log.d("GalleryLinearSnapHelper", "+++targetPos+++"+targetPos+""); 135 | if (targetPos >= itemCount) { 136 | targetPos = itemCount - 1; 137 | } 138 | Log.d("GalleryLinearSnapHelper", "---targetPos---"+targetPos+""); 139 | return targetPos; 140 | } 141 | 142 | 143 | private int estimateNextPositionDiffForFling(RecyclerView.LayoutManager layoutManager, 144 | OrientationHelper helper, int velocityX, int velocityY) { 145 | int[] distances = calculateScrollDistance(velocityX, velocityY); 146 | float distancePerChild = computeDistancePerChild(layoutManager, helper); 147 | if (distancePerChild <= 0) { 148 | return 0; 149 | } 150 | int distance = distances[0]; 151 | if (distance > 0) { 152 | return (int) Math.floor(distance / distancePerChild); 153 | } else { 154 | return (int) Math.ceil(distance / distancePerChild); 155 | } 156 | } 157 | 158 | 159 | private float computeDistancePerChild(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) { 160 | View minPosView = null; 161 | View maxPosView = null; 162 | int minPos = Integer.MAX_VALUE; 163 | int maxPos = Integer.MIN_VALUE; 164 | int childCount = layoutManager.getChildCount(); 165 | if (childCount == 0) { 166 | return INVALID_DISTANCE; 167 | } 168 | for (int i = 0; i < childCount; i++) { 169 | View child = layoutManager.getChildAt(i); 170 | final int pos = layoutManager.getPosition(child); 171 | if (pos == RecyclerView.NO_POSITION) { 172 | continue; 173 | } 174 | if (pos < minPos) { 175 | minPos = pos; 176 | minPosView = child; 177 | } 178 | if (pos > maxPos) { 179 | maxPos = pos; 180 | maxPosView = child; 181 | } 182 | } 183 | if (minPosView == null || maxPosView == null) { 184 | return INVALID_DISTANCE; 185 | } 186 | int start = Math.min(helper.getDecoratedStart(minPosView), helper.getDecoratedStart(maxPosView)); 187 | int end = Math.max(helper.getDecoratedEnd(minPosView), helper.getDecoratedEnd(maxPosView)); 188 | int distance = end - start; 189 | if (distance == 0) {return INVALID_DISTANCE;} 190 | return 1f * distance / ((maxPos - minPos) + 1); 191 | } 192 | 193 | private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager) { 194 | if (mHorizontalHelper == null) { 195 | mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager); 196 | } 197 | return mHorizontalHelper; 198 | } 199 | 200 | } 201 | -------------------------------------------------------------------------------- /GalleryBannerLib/src/main/java/com/yc/gallerybannerlib/GalleryScaleTransformer.java: -------------------------------------------------------------------------------- 1 | package com.yc.gallerybannerlib; 2 | 3 | 4 | import android.view.View; 5 | 6 | import androidx.annotation.FloatRange; 7 | 8 | /** 9 | *
10 |  *     @author yangchong
11 |  *     blog  : https://github.com/yangchong211
12 |  *     time  : 2018/4/17
13 |  *     desc  : 自定义ItemTransformer,用于动画缩放比例,可以灵活设置
14 |  *     revise:
15 |  * 
16 | */ 17 | public class GalleryScaleTransformer implements GalleryLayoutManager.ItemTransformer { 18 | 19 | //设置缩放比例因子 20 | private float scaleDivisor = 0.2f; 21 | private int padding = 30; 22 | public GalleryScaleTransformer(@FloatRange(from = 0.0f, to = 1.0f) float scaleSize , int padding) { 23 | this.scaleDivisor = scaleSize; 24 | this.padding = padding; 25 | } 26 | 27 | @Override 28 | public void transformItem(GalleryLayoutManager layoutManager, View item, float fraction) { 29 | item.setPivotX(item.getWidth() / 2.0f); 30 | item.setPivotY(item.getHeight()/ 2.0f); 31 | if (scaleDivisor==0.0f){ 32 | int measuredWidth = item.getMeasuredWidth(); 33 | //Log.d("GalleryScaleTransformer",measuredWidth+""); 34 | if (padding<0 || padding>measuredWidth){ 35 | padding = 30; 36 | } 37 | item.setPadding(padding,0,padding,0); 38 | }else { 39 | float scale = 1 - scaleDivisor * Math.abs(fraction); 40 | //可以在这里对view设置动画效果 41 | item.setScaleX(scale); 42 | item.setScaleY(scale); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /GalleryBannerLib/src/main/java/com/yc/gallerybannerlib/GallerySmoothScroller.java: -------------------------------------------------------------------------------- 1 | package com.yc.gallerybannerlib; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.view.View; 6 | 7 | import androidx.recyclerview.widget.LinearSmoothScroller; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | /** 11 | *
12 |  *     @author yangchong
13 |  *     blog  : https://github.com/yangchong211
14 |  *     time  : 2018/4/17
15 |  *     desc  : 自定义LinearSmoothScroller
16 |  *     revise:
17 |  * 
18 | */ 19 | public class GallerySmoothScroller extends LinearSmoothScroller { 20 | 21 | private static final float MILLISECONDS_PER_INCH = 100f; 22 | 23 | GallerySmoothScroller(Context context) { 24 | super(context); 25 | } 26 | 27 | //This returns the milliseconds it takes to 28 | //scroll one pixel. 29 | @Override 30 | protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { 31 | // 返回:滑过1px时经历的时间(ms)。 32 | //return MILLISECONDS_PER_INCH / displayMetrics.density; 33 | return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; 34 | //返回滑动一个pixel需要多少毫秒 35 | } 36 | 37 | 38 | @Override 39 | protected void onTargetFound(View targetView, RecyclerView.State state, Action action) { 40 | final int dx = calculateDxToMakeCentral(targetView); 41 | final int dy = calculateDyToMakeCentral(targetView); 42 | final int distance = (int) Math.sqrt(dx * dx + dy * dy); 43 | final int time = calculateTimeForDeceleration(distance); 44 | if (time > 0) { 45 | action.update(-dx, -dy, time, mDecelerateInterpolator); 46 | } 47 | } 48 | 49 | 50 | private int calculateDxToMakeCentral(View view) { 51 | final RecyclerView.LayoutManager layoutManager = getLayoutManager(); 52 | if (layoutManager == null || !layoutManager.canScrollHorizontally()) { 53 | return 0; 54 | } 55 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams(); 56 | final int left = layoutManager.getDecoratedLeft(view) - params.leftMargin; 57 | final int right = layoutManager.getDecoratedRight(view) + params.rightMargin; 58 | final int start = layoutManager.getPaddingLeft(); 59 | final int end = layoutManager.getWidth() - layoutManager.getPaddingRight(); 60 | final int childCenter = left + (int) ((right - left) / 2.0f); 61 | final int containerCenter = (int) ((end - start) / 2.f); 62 | return containerCenter - childCenter; 63 | } 64 | 65 | private int calculateDyToMakeCentral(View view) { 66 | final RecyclerView.LayoutManager layoutManager = getLayoutManager(); 67 | if (layoutManager == null || !layoutManager.canScrollVertically()) { 68 | return 0; 69 | } 70 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams(); 71 | final int top = layoutManager.getDecoratedTop(view) - params.topMargin; 72 | final int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin; 73 | final int start = layoutManager.getPaddingTop(); 74 | final int end = layoutManager.getHeight() - layoutManager.getPaddingBottom(); 75 | final int childCenter = top + (int) ((bottom - top) / 2.0f); 76 | final int containerCenter = (int) ((end - start) / 2.f); 77 | return containerCenter - childCenter; 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /GalleryBannerLib/src/test/java/com/yc/gallerybannerlib/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.yc.gallerybannerlib; 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 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## YCBanner轮播图 2 | - 主要引导界面滑动导航 + 大于1页时无限轮播 + 自定义指示器 3 | - 项目地址:https://github.com/yangchong211/YCBanner 4 | 5 | 6 | 7 | ### 目录介绍 8 | - 1.功能说明 9 | - 2.ViewPager轮播图使用说明 10 | - 3.跑马灯使用说明 11 | - 4.RecyclerView轮播图 12 | - 5.图片展示 13 | - 6.其他介绍 14 | 15 | 16 | ### 1.功能说明 17 | #### 1.1 基础功能介绍 18 | - 1.1 自定义轮播图,可以设置轮播红点或者轮播数字,多种指示器,并且灵活设置位置 19 | - 1.2 支持多种轮播图适配器,无限轮播adapter,静态管理adapter,和动态管理adapter。支持多种场合使用。 20 | - 1.3 支持自定义hintView,十分灵活,拓展性强 21 | - 1.4 无限循环自动轮播、手指按下暂停轮播、抬起手指开始轮播 22 | - 1.5 优化:在页面onPause中调用停止轮播,在页面onResume中调用开始轮播 23 | - 1.6 支持监听item点击事件,支持轮播图中ViewPager的滑动监听事件 24 | - 1.7 不仅支持轮播图,还支持引导页面,十分方便 25 | - 1.8 后期增加使用recyclerView设置轮播图。已经封装到GalleryRecyclerView中,链式调用十分方便 26 | - 1.9 GalleryRecyclerView轮播图支持设置轮播间隔时间,设置滑动速度,设置缩放比例因子 27 | - 如何引用:直接在项目build文件中添加库即可:compile 'cn.yc:YCBannerLib:1.3.9' 28 | 29 | 30 | #### 1.2 该库的优势 31 | 32 | 33 | ### 2.ViewPager轮播图使用说明 34 | - 2.1 关于具体的使用方法,可以直接参考代码 35 | - 2.2 在布局中写,可以设置选择的属性值 36 | 37 | ``` 38 | 47 | ``` 48 | 49 | 50 | - 2.3 在代码中,自定义adapter适配器,继承自己合适的adapter。目前支持继承动态管理adapter,静态管理adapter,和无限轮播adapter 51 | 52 | ``` 53 | private void initBanner() { 54 | banner = (BannerView) findViewById(R.id.banner); 55 | //设置轮播时间 56 | banner.setPlayDelay(2000); 57 | //设置轮播图适配器,必须 58 | banner.setAdapter(new ImageNormalAdapter()); 59 | //设置位置 60 | banner.setHintGravity(1); 61 | //设置指示器样式 62 | banner.setHintMode(BannerView.HintMode.TEXT_HINT); 63 | //判断轮播是否进行 64 | boolean playing = banner.isPlaying(); 65 | //轮播图点击事件 66 | banner.setOnBannerClickListener(new OnBannerClickListener() { 67 | @Override 68 | public void onItemClick(int position) { 69 | Toast.makeText(FirstActivity.this,position+"被点击呢",Toast.LENGTH_SHORT).show(); 70 | } 71 | }); 72 | //轮播图滑动事件 73 | banner.setOnPageListener(new OnPageListener() { 74 | @Override 75 | public void onPageChange(int position) { 76 | 77 | } 78 | }); 79 | } 80 | 81 | 82 | private class ImageNormalAdapter extends AbsStaticPagerAdapter { 83 | 84 | @Override 85 | public View getView(ViewGroup container, int position) { 86 | ImageView view = new ImageView(container.getContext()); 87 | view.setScaleType(ImageView.ScaleType.CENTER_CROP); 88 | view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 89 | ViewGroup.LayoutParams.MATCH_PARENT)); 90 | view.setImageResource(imgs[position]); 91 | return view; 92 | } 93 | 94 | @Override 95 | public int getCount() { 96 | return imgs.length; 97 | } 98 | } 99 | ``` 100 | 101 | 102 | - **2.4 关于轮播图属性** 103 | - 关于暂停和开始轮播方法,建议加上 104 | 105 | ``` 106 | @Override 107 | protected void onPause() { 108 | super.onPause(); 109 | if(banner!=null){ 110 | //停止轮播 111 | banner.pause(); 112 | } 113 | } 114 | 115 | @Override 116 | protected void onResume() { 117 | super.onResume(); 118 | if(banner!=null){ 119 | //开始轮播 120 | banner.resume(); 121 | } 122 | } 123 | ``` 124 | 125 | 126 | - **2.5 如何显示红点,文字,自定义icon等** 127 | - **a.设置文本添加代码**: 128 | - banner.setHintView(new TextHintView(this)); 129 | - **b.设置自定义icon添加代码:** 130 | - banner.setHintView(new IconHintView(this,R.drawable.point_focus,R.drawable.point_normal)); 131 | - **c.默认不添加该方法则是显示圆点** 132 | - 请参考代码,已经做出了很详细的注释 133 | 134 | 135 | ### 3.跑马灯使用说明 136 | #### 3.1 在布局中添加代码 137 | ``` 138 | 139 | 154 | ``` 155 | 156 | #### 3.2 使用 157 | ``` 158 | List list = getMarqueeTitle(); 159 | //根据公告字符串列表启动轮播 160 | marqueeView.startWithList(list); 161 | //设置点击事件 162 | marqueeView.setOnItemClickListener(new MarqueeView.OnItemClickListener() { 163 | @Override 164 | public void onItemClick(int position, TextView textView) { 165 | 166 | } 167 | }); 168 | ``` 169 | 170 | ### 4.RecyclerView轮播图 171 | #### 4.1 RecyclerView轮播图简单使用 172 | - 在布局中 173 | ``` 174 | 179 | ``` 180 | - 代码设置 181 | ``` 182 | private void initRecyclerView() { 183 | Snap3Adapter adapter = new Snap3Adapter(this); 184 | adapter.setData(getData()); 185 | mGalleryRecyclerView.setDelayTime(3000) 186 | .setFlingSpeed(0) 187 | .setDataAdapter(adapter) 188 | .setSelectedPosition(100) 189 | .setCallbackInFling(false) 190 | .setOnItemSelectedListener(new GalleryRecyclerView.OnItemSelectedListener() { 191 | @Override 192 | public void onItemSelected(RecyclerView recyclerView, View item, int position) { 193 | Log.e("onItemSelected-----",position+""); 194 | //设置高斯模糊背景 195 | setBlurImage(true); 196 | } 197 | }) 198 | .setSize(adapter.getData().size()) 199 | .setUp(); 200 | } 201 | ``` 202 | - 注意要点:recyclerView轮播要是无限轮播,必须设置两点,很关键。 203 | - 第一处是getItemCount() 返回的是Integer.MAX_VALUE。这是因为广告轮播图是无限轮播,getItemCount()返回的是Adapter中的总项目数,这样才能使RecyclerView能一直滚动。 204 | - 第二处是onBindViewHolder()中的 position%list.size() ,表示position对图片列表list取余,这样list.get(position%list.size())才能按顺序循环展示图片。 205 | #### 4.2 RecyclerView实现平滑滚动,图片剧中效果 206 | - 如果不想设置轮播图,只想滚动。则可以直接套用GalleryLayoutManager 207 | - 类似猫眼的电影选择控件 208 | ``` 209 | GalleryLayoutManager manager = new GalleryLayoutManager(LinearLayoutManager.HORIZONTAL); 210 | manager.attach(recyclerView,100); 211 | //如果想缩放,可以直接设置缩放比例因子即可 212 | manager.setItemTransformer(new GalleryScaleTransformer( 0.2f)); 213 | recyclerView.setLayoutManager(manager); 214 | Snap3Adapter adapter = new Snap3Adapter(this); 215 | adapter.setData(getData()); 216 | recyclerView.setAdapter(adapter); 217 | ``` 218 | 219 | #### 4.3 关于自定义SnapHelper类 220 | - 有的时候原生LinearSnapHelper或者PagerSnapHelper无法满足我的需求,比如要设置滑动卡片左边对齐,或者右边对齐,或者居中模式;如果想要修改一下速率,或者一次滑动只能滑动一个item,那么就需要自定义呢 221 | - 具体实现可以看我的项目demo,看看下面的效果图 222 | - 关于SnapHelper类源码深度解析,可以看我的这篇博客:https://www.jianshu.com/p/9b8e0696802d 223 | 224 | 225 | ### 5.图片展示 226 | - 4.1 轮播图截图 227 | - ![image](https://github.com/yangchong211/YCBanner/blob/master/image/1.png) 228 | - ![image](https://github.com/yangchong211/YCBanner/blob/master/image/2.png) 229 | - ![image](https://github.com/yangchong211/YCBanner/blob/master/image/4.jpg) 230 | - ![image](https://github.com/yangchong211/YCBanner/blob/master/image/5.jpg) 231 | - ![image](https://github.com/yangchong211/YCBanner/blob/master/image/6.jpg) 232 | - 234 | - 235 | 236 | ### 6.其他介绍 237 | **5.1版本更新说明** 238 | - v1.0 16年3月23日,新芽轮播图,最简单的轮播图,无限轮播。 239 | - v1.1 5月2日 添加了动态管理adapter,和静态管理adapter,模拟多种场景轮播图 240 | - v1.2 6月12日 添加了触摸轮播图时暂停,松开手指开始轮播的功能;如果设置轮播图控件宽高都是wrap_content,那么则默认宽是match_parent,高是200dp。修改了handler内存泄漏 241 | - v1.3 17年8月22日 添加了ViewPager滑动监听接口,可以作用于引导页,十分简单 242 | - v1.3.2 17年10月21日 添加跑马灯轮播到该lib库中 243 | - v1.3.6 18年9月15日 同行提议更新API方法说明 244 | - v1.3.7 18年4月到6月17日 抽取项目中代码增加了recyclerView轮播图 245 | - v1.4.0 18年12月10日 修改了recyclerView轮播图滑动卡顿现象 246 | 247 | 248 | #### 关于其他内容介绍 249 | ![image](https://upload-images.jianshu.io/upload_images/4432347-7100c8e5a455c3ee.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 250 | 251 | 252 | #### 关于博客汇总链接 253 | - 1.[技术博客汇总](https://www.jianshu.com/p/614cb839182c) 254 | - 2.[开源项目汇总](https://blog.csdn.net/m0_37700275/article/details/80863574) 255 | - 3.[生活博客汇总](https://blog.csdn.net/m0_37700275/article/details/79832978) 256 | - 4.[喜马拉雅音频汇总](https://www.jianshu.com/p/f665de16d1eb) 257 | - 5.[其他汇总](https://www.jianshu.com/p/53017c3fc75d) 258 | 259 | 260 | 261 | 262 | #### 于LICENSE 263 | ``` 264 | Licensed under the Apache License, Version 2.0 (the "License"); 265 | you may not use this file except in compliance with the License. 266 | You may obtain a copy of the License at 267 | 268 | http://www.apache.org/licenses/LICENSE-2.0 269 | 270 | Unless required by applicable law or agreed to in writing, software 271 | distributed under the License is distributed on an "AS IS" BASIS, 272 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 273 | See the License for the specific language governing permissions and 274 | limitations under the License. 275 | ``` 276 | 277 | -------------------------------------------------------------------------------- /SnapBannerLib/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /SnapBannerLib/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | } 4 | apply from: rootProject.projectDir.absolutePath + "/AppGradle/appBuild.gradle" 5 | apply plugin: 'com.github.dcendents.android-maven' 6 | 7 | android { 8 | compileSdkVersion project.ext.androidCompileSdkVersion 9 | //buildToolsVersion project.ext.androidBuildToolsVersion 10 | 11 | defaultConfig { 12 | minSdkVersion project.ext.androidMinSdkVersion 13 | targetSdkVersion project.ext.androidTargetSdkVersion 14 | versionCode 2 15 | versionName "1.0.2" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: "libs", include: ["*.jar"]) 28 | implementation project.ext.AppDependencies['appcompat'] 29 | implementation project.ext.AppDependencies['recyclerview'] 30 | } -------------------------------------------------------------------------------- /SnapBannerLib/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/SnapBannerLib/consumer-rules.pro -------------------------------------------------------------------------------- /SnapBannerLib/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 -------------------------------------------------------------------------------- /SnapBannerLib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /SnapBannerLib/src/main/java/com/yc/snapbannerlib/ScrollLinearHelper.java: -------------------------------------------------------------------------------- 1 | package com.yc.snapbannerlib; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | import androidx.recyclerview.widget.LinearLayoutManager; 6 | import androidx.recyclerview.widget.LinearSmoothScroller; 7 | import androidx.recyclerview.widget.LinearSnapHelper; 8 | import androidx.recyclerview.widget.OrientationHelper; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | import android.util.DisplayMetrics; 11 | import android.view.View; 12 | 13 | /** 14 | *
 15 |  *     @author yangchong
 16 |  *     blog  : https://github.com/yangchong211
 17 |  *     time  : 2018/3/18
 18 |  *     desc  : 自定义SnapHelper,设置左对齐,滑动时候会滑动多个item
 19 |  *     revise: 关于SnapHelper源码分析可以看我博客:https://blog.csdn.net/m0_37700275/article/details/83901677
 20 |  * 
21 | */ 22 | public class ScrollLinearHelper extends LinearSnapHelper { 23 | 24 | private OrientationHelper mHorizontalHelper, mVerticalHelper; 25 | private RecyclerView mRecyclerView; 26 | private static final float MILLISECONDS_PER_INCH = 40f; 27 | 28 | @Override 29 | public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException { 30 | mRecyclerView = recyclerView; 31 | super.attachToRecyclerView(recyclerView); 32 | } 33 | 34 | @Nullable 35 | @Override 36 | public int[] calculateDistanceToFinalSnap(RecyclerView.LayoutManager layoutManager, View targetView) { 37 | int[] out = new int[2]; 38 | if (layoutManager.canScrollHorizontally()) { 39 | out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager)); 40 | } else { 41 | out[0] = 0; 42 | } 43 | if (layoutManager.canScrollVertically()) { 44 | out[1] = distanceToStart(targetView, getVerticalHelper(layoutManager)); 45 | } else { 46 | out[1] = 0; 47 | } 48 | return out; 49 | } 50 | 51 | private int distanceToStart(View targetView, OrientationHelper helper) { 52 | return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding(); 53 | } 54 | 55 | @Nullable 56 | @Override 57 | public View findSnapView(RecyclerView.LayoutManager layoutManager) { 58 | if (layoutManager instanceof LinearLayoutManager) { 59 | if (layoutManager.canScrollHorizontally()) { 60 | return findStartView(layoutManager, getHorizontalHelper(layoutManager)); 61 | } else { 62 | return findStartView(layoutManager, getVerticalHelper(layoutManager)); 63 | } 64 | } 65 | return super.findSnapView(layoutManager); 66 | } 67 | 68 | private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) { 69 | if (layoutManager instanceof LinearLayoutManager) { 70 | int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); 71 | //需要判断是否是最后一个Item,如果是最后一个则不让对齐,以免出现最后一个显示不完全。 72 | boolean isLastItem = ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition() 73 | == layoutManager.getItemCount() - 1; 74 | if (firstChild == RecyclerView.NO_POSITION || isLastItem) { 75 | return null; 76 | } 77 | View child = layoutManager.findViewByPosition(firstChild); 78 | if (helper.getDecoratedEnd(child) >= helper.getDecoratedMeasurement(child) / 2 79 | && helper.getDecoratedEnd(child) > 0) { 80 | return child; 81 | } else { 82 | if (((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition() 83 | == layoutManager.getItemCount() - 1) { 84 | return null; 85 | } else { 86 | return layoutManager.findViewByPosition(firstChild + 1); 87 | } 88 | } 89 | } 90 | return super.findSnapView(layoutManager); 91 | } 92 | 93 | @Nullable 94 | protected LinearSmoothScroller createSnapScroller(final RecyclerView.LayoutManager layoutManager) { 95 | if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 96 | return null; 97 | } 98 | return new LinearSmoothScroller(mRecyclerView.getContext()) { 99 | @Override 100 | protected void onTargetFound(View targetView, RecyclerView.State state, RecyclerView.SmoothScroller.Action action) { 101 | int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), targetView); 102 | final int dx; 103 | final int dy; 104 | if (snapDistances != null) { 105 | dx = snapDistances[0]; 106 | dy = snapDistances[1]; 107 | final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy))); 108 | if (time > 0) { 109 | action.update(dx, dy, time, mDecelerateInterpolator); 110 | } 111 | } 112 | } 113 | 114 | @Override 115 | protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { 116 | //这个地方可以自己设置 117 | return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; 118 | } 119 | }; 120 | } 121 | 122 | @NonNull 123 | private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) { 124 | if (mVerticalHelper == null) { 125 | mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager); 126 | } 127 | return mVerticalHelper; 128 | } 129 | 130 | @NonNull 131 | private OrientationHelper getHorizontalHelper( 132 | @NonNull RecyclerView.LayoutManager layoutManager) { 133 | if (mHorizontalHelper == null) { 134 | mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager); 135 | } 136 | return mHorizontalHelper; 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /SnapBannerLib/src/main/java/com/yc/snapbannerlib/ScrollPageHelper.java: -------------------------------------------------------------------------------- 1 | package com.yc.snapbannerlib; 2 | 3 | import android.os.Build; 4 | import androidx.annotation.NonNull; 5 | import androidx.annotation.Nullable; 6 | import androidx.recyclerview.widget.GridLayoutManager; 7 | import androidx.recyclerview.widget.LinearLayoutManager; 8 | import androidx.recyclerview.widget.LinearSmoothScroller; 9 | import androidx.recyclerview.widget.OrientationHelper; 10 | import androidx.recyclerview.widget.PagerSnapHelper; 11 | import androidx.recyclerview.widget.RecyclerView; 12 | import androidx.recyclerview.widget.SnapHelper; 13 | import android.text.TextUtils; 14 | import android.view.Gravity; 15 | import android.view.View; 16 | 17 | import java.util.Locale; 18 | 19 | /** 20 | *
 21 |  *     @author yangchong
 22 |  *     blog  : https://github.com/yangchong211
 23 |  *     time  : 2018/3/18
 24 |  *     desc  : 自定义SnapHelper,设置左对齐,滑动时候会限制item只滑动一个。可以设置gravity位置对齐
 25 |  *     revise: 关于SnapHelper源码分析可以看我博客:https://blog.csdn.net/m0_37700275/article/details/83901677
 26 |  * 
27 | */ 28 | public class ScrollPageHelper extends PagerSnapHelper { 29 | 30 | private OrientationHelper mHorizontalHelper, mVerticalHelper; 31 | private int gravity; 32 | private boolean snapLastItem; 33 | private boolean isRtlHorizontal; 34 | 35 | public ScrollPageHelper(int gravity, boolean enableSnapLast){ 36 | this.snapLastItem = enableSnapLast; 37 | this.gravity = gravity; 38 | } 39 | 40 | @Override 41 | public void attachToRecyclerView(@Nullable RecyclerView recyclerView) 42 | throws IllegalStateException { 43 | if (recyclerView != null && (!(recyclerView.getLayoutManager() instanceof LinearLayoutManager) 44 | || recyclerView.getLayoutManager() instanceof GridLayoutManager)) { 45 | throw new IllegalStateException("ScrollPageHelper needs a RecyclerView with a LinearLayoutManager"); 46 | } 47 | if (recyclerView != null) { 48 | recyclerView.setOnFlingListener(null); 49 | if ((gravity == Gravity.START || gravity == Gravity.END)) { 50 | isRtlHorizontal = isRtl(); 51 | } 52 | } 53 | super.attachToRecyclerView(recyclerView); 54 | } 55 | 56 | 57 | @Nullable 58 | @Override 59 | public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) { 60 | int[] out = new int[2]; 61 | if (layoutManager.canScrollHorizontally()) { 62 | if (gravity == Gravity.START) { 63 | out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager), false); 64 | } else { // END 65 | out[0] = distanceToEnd(targetView, getHorizontalHelper(layoutManager), false); 66 | } 67 | } else { 68 | out[0] = 0; 69 | } 70 | if (layoutManager.canScrollVertically()) { 71 | if (gravity == Gravity.TOP) { 72 | out[1] = distanceToStart(targetView, getVerticalHelper(layoutManager), false); 73 | } else { // BOTTOM 74 | out[1] = distanceToEnd(targetView, getVerticalHelper(layoutManager), false); 75 | } 76 | } else { 77 | out[1] = 0; 78 | } 79 | return out; 80 | } 81 | 82 | @Nullable 83 | @Override 84 | public View findSnapView(RecyclerView.LayoutManager layoutManager) { 85 | View snapView = null; 86 | if (layoutManager instanceof LinearLayoutManager) { 87 | switch (gravity) { 88 | case Gravity.START: 89 | snapView = findStartView(layoutManager, getHorizontalHelper(layoutManager)); 90 | break; 91 | case Gravity.END: 92 | snapView = findEndView(layoutManager, getHorizontalHelper(layoutManager)); 93 | break; 94 | case Gravity.TOP: 95 | snapView = findStartView(layoutManager, getVerticalHelper(layoutManager)); 96 | break; 97 | case Gravity.BOTTOM: 98 | snapView = findEndView(layoutManager, getVerticalHelper(layoutManager)); 99 | break; 100 | } 101 | } 102 | return snapView; 103 | } 104 | 105 | 106 | private boolean isRtl() { 107 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { 108 | return false; 109 | } 110 | return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL; 111 | } 112 | 113 | 114 | @NonNull 115 | private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) { 116 | if (mVerticalHelper == null) { 117 | mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager); 118 | } 119 | return mVerticalHelper; 120 | } 121 | 122 | @NonNull 123 | private OrientationHelper getHorizontalHelper( 124 | @NonNull RecyclerView.LayoutManager layoutManager) { 125 | if (mHorizontalHelper == null) { 126 | mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager); 127 | } 128 | return mHorizontalHelper; 129 | } 130 | 131 | 132 | private int distanceToStart(View targetView, @NonNull OrientationHelper helper, boolean fromEnd) { 133 | if (isRtlHorizontal && !fromEnd) { 134 | return distanceToEnd(targetView, helper, true); 135 | } 136 | 137 | return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding(); 138 | } 139 | 140 | private int distanceToEnd(View targetView, @NonNull OrientationHelper helper, boolean fromStart) { 141 | if (isRtlHorizontal && !fromStart) { 142 | return distanceToStart(targetView, helper, true); 143 | } 144 | 145 | return helper.getDecoratedEnd(targetView) - helper.getEndAfterPadding(); 146 | } 147 | 148 | 149 | @Nullable 150 | private View findStartView(RecyclerView.LayoutManager layoutManager, 151 | @NonNull OrientationHelper helper) { 152 | 153 | if (layoutManager instanceof LinearLayoutManager) { 154 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; 155 | boolean reverseLayout = linearLayoutManager.getReverseLayout(); 156 | int firstChild = reverseLayout ? linearLayoutManager.findLastVisibleItemPosition() 157 | : linearLayoutManager.findFirstVisibleItemPosition(); 158 | int offset = 1; 159 | 160 | if (layoutManager instanceof GridLayoutManager) { 161 | offset += ((GridLayoutManager) layoutManager).getSpanCount() - 1; 162 | } 163 | 164 | if (firstChild == RecyclerView.NO_POSITION) { 165 | return null; 166 | } 167 | 168 | View child = layoutManager.findViewByPosition(firstChild); 169 | 170 | float visibleWidth; 171 | if (isRtlHorizontal) { 172 | visibleWidth = (float) (helper.getTotalSpace() - helper.getDecoratedStart(child)) 173 | / helper.getDecoratedMeasurement(child); 174 | } else { 175 | visibleWidth = (float) helper.getDecoratedEnd(child) 176 | / helper.getDecoratedMeasurement(child); 177 | } 178 | boolean endOfList; 179 | if (!reverseLayout) { 180 | endOfList = ((LinearLayoutManager) layoutManager) 181 | .findLastCompletelyVisibleItemPosition() 182 | == layoutManager.getItemCount() - 1; 183 | } else { 184 | endOfList = ((LinearLayoutManager) layoutManager) 185 | .findFirstCompletelyVisibleItemPosition() 186 | == 0; 187 | } 188 | 189 | if (visibleWidth > 0.5f && !endOfList) { 190 | return child; 191 | } else if (snapLastItem && endOfList) { 192 | return child; 193 | } else if (endOfList) { 194 | return null; 195 | } else { 196 | return reverseLayout ? layoutManager.findViewByPosition(firstChild - offset) 197 | : layoutManager.findViewByPosition(firstChild + offset); 198 | } 199 | } 200 | 201 | return null; 202 | } 203 | 204 | @Nullable 205 | private View findEndView(RecyclerView.LayoutManager layoutManager, 206 | @NonNull OrientationHelper helper) { 207 | 208 | if (layoutManager instanceof LinearLayoutManager) { 209 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; 210 | boolean reverseLayout = linearLayoutManager.getReverseLayout(); 211 | int lastChild = reverseLayout ? linearLayoutManager.findFirstVisibleItemPosition() 212 | : linearLayoutManager.findLastVisibleItemPosition(); 213 | int offset = 1; 214 | 215 | if (layoutManager instanceof GridLayoutManager) { 216 | offset += ((GridLayoutManager) layoutManager).getSpanCount() - 1; 217 | } 218 | 219 | if (lastChild == RecyclerView.NO_POSITION) { 220 | return null; 221 | } 222 | 223 | View child = layoutManager.findViewByPosition(lastChild); 224 | 225 | float visibleWidth; 226 | 227 | if (isRtlHorizontal) { 228 | visibleWidth = (float) helper.getDecoratedEnd(child) 229 | / helper.getDecoratedMeasurement(child); 230 | } else { 231 | visibleWidth = (float) (helper.getTotalSpace() - helper.getDecoratedStart(child)) 232 | / helper.getDecoratedMeasurement(child); 233 | } 234 | 235 | boolean startOfList; 236 | if (!reverseLayout) { 237 | startOfList = ((LinearLayoutManager) layoutManager) 238 | .findFirstCompletelyVisibleItemPosition() == 0; 239 | } else { 240 | startOfList = ((LinearLayoutManager) layoutManager) 241 | .findLastCompletelyVisibleItemPosition() 242 | == layoutManager.getItemCount() - 1; 243 | } 244 | 245 | if (visibleWidth > 0.5f && !startOfList) { 246 | return child; 247 | } else if (snapLastItem && startOfList) { 248 | return child; 249 | } else if (startOfList) { 250 | return null; 251 | } else { 252 | return reverseLayout ? layoutManager.findViewByPosition(lastChild + offset) 253 | : layoutManager.findViewByPosition(lastChild - offset); 254 | } 255 | } 256 | return null; 257 | } 258 | 259 | 260 | } 261 | -------------------------------------------------------------------------------- /SnapBannerLib/src/main/java/com/yc/snapbannerlib/ScrollSnapHelper.java: -------------------------------------------------------------------------------- 1 | package com.yc.snapbannerlib; 2 | 3 | import android.graphics.PointF; 4 | import android.util.DisplayMetrics; 5 | import android.view.View; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | import androidx.recyclerview.widget.LinearLayoutManager; 10 | import androidx.recyclerview.widget.LinearSmoothScroller; 11 | import androidx.recyclerview.widget.OrientationHelper; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | import androidx.recyclerview.widget.SnapHelper; 14 | 15 | 16 | /** 17 | *
 18 |  *     @author yangchong
 19 |  *     blog  : https://github.com/yangchong211
 20 |  *     time  : 2018/3/18
 21 |  *     desc  : 自定义SnapHelper
 22 |  *     revise: 关于SnapHelper源码分析可以看我博客:https://blog.csdn.net/m0_37700275/article/details/83901677
 23 |  * 
24 | */ 25 | public class ScrollSnapHelper extends SnapHelper { 26 | 27 | private static final float INVALID_DISTANCE = 1f; 28 | private static final float MILLISECONDS_PER_INCH = 40f; 29 | private OrientationHelper mHorizontalHelper; 30 | private RecyclerView mRecyclerView; 31 | 32 | 33 | @Override 34 | public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException { 35 | mRecyclerView = recyclerView; 36 | super.attachToRecyclerView(recyclerView); 37 | } 38 | 39 | @Override 40 | public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) { 41 | int[] out = new int[2]; 42 | if (layoutManager.canScrollHorizontally()) { 43 | out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager)); 44 | } else { 45 | out[0] = 0; 46 | } 47 | return out; 48 | } 49 | 50 | private int distanceToStart(View targetView, OrientationHelper helper) { 51 | return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding(); 52 | } 53 | 54 | @Nullable 55 | protected LinearSmoothScroller createSnapScroller(final RecyclerView.LayoutManager layoutManager) { 56 | if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 57 | return null; 58 | } 59 | return new LinearSmoothScroller(mRecyclerView.getContext()) { 60 | @Override 61 | protected void onTargetFound(View targetView, RecyclerView.State state, Action action) { 62 | int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), targetView); 63 | final int dx; 64 | final int dy; 65 | if (snapDistances != null) { 66 | dx = snapDistances[0]; 67 | dy = snapDistances[1]; 68 | final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy))); 69 | if (time > 0) { 70 | action.update(dx, dy, time, mDecelerateInterpolator); 71 | } 72 | } 73 | } 74 | 75 | @Override 76 | protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { 77 | return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; 78 | } 79 | }; 80 | } 81 | 82 | @Override 83 | public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) { 84 | if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 85 | return RecyclerView.NO_POSITION; 86 | } 87 | final int itemCount = layoutManager.getItemCount(); 88 | if (itemCount == 0) { 89 | return RecyclerView.NO_POSITION; 90 | } 91 | final View currentView = findSnapView(layoutManager); 92 | if (currentView == null) { 93 | return RecyclerView.NO_POSITION; 94 | } 95 | final int currentPosition = layoutManager.getPosition(currentView); 96 | if (currentPosition == RecyclerView.NO_POSITION) { 97 | return RecyclerView.NO_POSITION; 98 | } 99 | RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider = 100 | (RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager; 101 | PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1); 102 | if (vectorForEnd == null) { 103 | // cannot get a vector for the given position. 104 | return RecyclerView.NO_POSITION; 105 | } 106 | 107 | //在松手之后,列表最多只能滚多一屏的item数 108 | int deltaThreshold = layoutManager.getWidth() / getHorizontalHelper(layoutManager).getDecoratedMeasurement(currentView); 109 | 110 | int hDeltaJump; 111 | if (layoutManager.canScrollHorizontally()) { 112 | hDeltaJump = estimateNextPositionDiffForFling(layoutManager, getHorizontalHelper(layoutManager), velocityX, 0); 113 | if (hDeltaJump > deltaThreshold) { 114 | hDeltaJump = deltaThreshold; 115 | } 116 | if (hDeltaJump < -deltaThreshold) { 117 | hDeltaJump = -deltaThreshold; 118 | } 119 | if (vectorForEnd.x < 0) { 120 | hDeltaJump = -hDeltaJump; 121 | } 122 | } else { 123 | hDeltaJump = 0; 124 | } 125 | if (hDeltaJump == 0) { 126 | return RecyclerView.NO_POSITION; 127 | } 128 | 129 | int targetPos = currentPosition + hDeltaJump; 130 | if (targetPos < 0) { 131 | targetPos = 0; 132 | } 133 | if (targetPos >= itemCount) { 134 | targetPos = itemCount - 1; 135 | } 136 | return targetPos; 137 | } 138 | 139 | @Override 140 | public View findSnapView(RecyclerView.LayoutManager layoutManager) { 141 | return findStartView(layoutManager, getHorizontalHelper(layoutManager)); 142 | } 143 | 144 | 145 | private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) { 146 | if (layoutManager instanceof LinearLayoutManager) { 147 | int firstChildPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); 148 | if (firstChildPosition == RecyclerView.NO_POSITION) { 149 | return null; 150 | } 151 | if (((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition() == layoutManager.getItemCount() - 1) { 152 | return null; 153 | } 154 | View firstChildView = layoutManager.findViewByPosition(firstChildPosition); 155 | if (helper.getDecoratedEnd(firstChildView) >= helper.getDecoratedMeasurement(firstChildView) / 2 && helper.getDecoratedEnd(firstChildView) > 0) { 156 | return firstChildView; 157 | } else { 158 | return layoutManager.findViewByPosition(firstChildPosition + 1); 159 | } 160 | } else { 161 | return null; 162 | } 163 | } 164 | 165 | 166 | private int estimateNextPositionDiffForFling(RecyclerView.LayoutManager layoutManager, OrientationHelper helper, int velocityX, int velocityY) { 167 | int[] distances = calculateScrollDistance(velocityX, velocityY); 168 | float distancePerChild = computeDistancePerChild(layoutManager, helper); 169 | if (distancePerChild <= 0) { 170 | return 0; 171 | } 172 | int distance = distances[0]; 173 | if (distance > 0) { 174 | return (int) Math.floor(distance / distancePerChild); 175 | } else { 176 | return (int) Math.ceil(distance / distancePerChild); 177 | } 178 | } 179 | 180 | private float computeDistancePerChild(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) { 181 | View minPosView = null; 182 | View maxPosView = null; 183 | int minPos = Integer.MAX_VALUE; 184 | int maxPos = Integer.MIN_VALUE; 185 | int childCount = layoutManager.getChildCount(); 186 | if (childCount == 0) { 187 | return INVALID_DISTANCE; 188 | } 189 | for (int i = 0; i < childCount; i++) { 190 | View child = layoutManager.getChildAt(i); 191 | final int pos = layoutManager.getPosition(child); 192 | if (pos == RecyclerView.NO_POSITION) { 193 | continue; 194 | } 195 | if (pos < minPos) { 196 | minPos = pos; 197 | minPosView = child; 198 | } 199 | if (pos > maxPos) { 200 | maxPos = pos; 201 | maxPosView = child; 202 | } 203 | } 204 | if (minPosView == null || maxPosView == null) { 205 | return INVALID_DISTANCE; 206 | } 207 | int start = Math.min(helper.getDecoratedStart(minPosView), helper.getDecoratedStart(maxPosView)); 208 | int end = Math.max(helper.getDecoratedEnd(minPosView), helper.getDecoratedEnd(maxPosView)); 209 | int distance = end - start; 210 | if (distance == 0) { 211 | return INVALID_DISTANCE; 212 | } 213 | return 1f * distance / ((maxPos - minPos) + 1); 214 | } 215 | 216 | 217 | private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager) { 218 | if (mHorizontalHelper == null) { 219 | mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager); 220 | } 221 | return mHorizontalHelper; 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /YCBannerLib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /YCBannerLib/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | } 4 | apply from: rootProject.projectDir.absolutePath + "/AppGradle/appBuild.gradle" 5 | apply plugin: 'com.github.dcendents.android-maven' 6 | 7 | android { 8 | compileSdkVersion project.ext.androidCompileSdkVersion 9 | //buildToolsVersion project.ext.androidBuildToolsVersion 10 | 11 | defaultConfig { 12 | minSdkVersion project.ext.androidMinSdkVersion 13 | targetSdkVersion project.ext.androidTargetSdkVersion 14 | versionCode 2 15 | versionName "1.0.2" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: "libs", include: ["*.jar"]) 28 | implementation project.ext.AppDependencies['appcompat'] 29 | implementation project.ext.AppDependencies['recyclerview'] 30 | } -------------------------------------------------------------------------------- /YCBannerLib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\PC\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/LibUtils.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib; 2 | 3 | 4 | import android.content.Context; 5 | 6 | /** 7 | *
 8 |  *     @author yangchong
 9 |  *     blog  : https://github.com/yangchong211
10 |  *     time  : 2018/4/17
11 |  *     desc  : 工具类
12 |  *     revise:
13 |  * 
14 | */ 15 | public class LibUtils { 16 | 17 | public static int dip2px(Context ctx, float dpValue) { 18 | final float scale = ctx.getResources().getDisplayMetrics().density; 19 | return (int) (dpValue * scale + 0.5f); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/adapter/AbsDynamicPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.adapter; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.fragment.app.FragmentPagerAdapter; 8 | import androidx.viewpager.widget.PagerAdapter; 9 | 10 | 11 | /** 12 | *
13 |  *     @author yangchong
14 |  *     blog  : https://github.com/yangchong211
15 |  *     time  : 2016/3/18
16 |  *     desc  : 动态管理的Adapter。概念参照{@link FragmentPagerAdapter}
17 |  *             每次都会创建新view,销毁旧View。节省内存消耗性能
18 |  *     revise: 比如使用场景是启动引导页
19 |  * 
20 | */ 21 | public abstract class AbsDynamicPagerAdapter extends PagerAdapter { 22 | 23 | @Override 24 | public boolean isViewFromObject(@NonNull View arg0, @NonNull Object arg1) { 25 | return arg0==arg1; 26 | } 27 | 28 | @Override 29 | public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { 30 | container.removeView((View) object); 31 | } 32 | 33 | @Override 34 | public int getItemPosition(@NonNull Object object) { 35 | return super.getItemPosition(object); 36 | } 37 | 38 | @NonNull 39 | @Override 40 | public Object instantiateItem(@NonNull ViewGroup container, int position) { 41 | View itemView = getView(container,position); 42 | container.addView(itemView); 43 | return itemView; 44 | } 45 | 46 | /** 47 | * 创建view 48 | * @param container container 49 | * @param position 索引 50 | * @return 51 | */ 52 | public abstract View getView(ViewGroup container, int position); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/adapter/AbsLoopPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.adapter; 2 | 3 | import android.annotation.TargetApi; 4 | import android.database.DataSetObserver; 5 | import android.os.Build; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import androidx.annotation.NonNull; 11 | import androidx.viewpager.widget.PagerAdapter; 12 | import androidx.viewpager.widget.ViewPager; 13 | 14 | import com.yc.cn.ycbannerlib.banner.inter.BaseHintView; 15 | import com.yc.cn.ycbannerlib.banner.inter.HintViewDelegate; 16 | import com.yc.cn.ycbannerlib.banner.view.BannerView; 17 | 18 | import java.lang.reflect.Field; 19 | import java.util.ArrayList; 20 | 21 | /** 22 | *
 23 |  *     @author yangchong
 24 |  *     blog  : https://github.com/yangchong211
 25 |  *     time  : 2016/3/18
 26 |  *     desc  : AbsLoopPagerAdapter
 27 |  *     revise: 如果是自动轮播图的话就用这一个
 28 |  * 
29 | */ 30 | public abstract class AbsLoopPagerAdapter extends PagerAdapter { 31 | 32 | 33 | private BannerView mViewPager; 34 | /** 35 | * 用来存放View的集合 36 | */ 37 | private ArrayList mViewList = new ArrayList<>(); 38 | 39 | private class LoopHintViewDelegate implements HintViewDelegate { 40 | @Override 41 | public void setCurrentPosition(int position, BaseHintView hintView) { 42 | if (hintView!=null&&getRealCount()>0){ 43 | hintView.setCurrent(position%getRealCount()); 44 | } 45 | } 46 | 47 | @Override 48 | public void initView(int length, int gravity, BaseHintView hintView) { 49 | if (hintView!=null){ 50 | hintView.initView(getRealCount(),gravity); 51 | } 52 | } 53 | } 54 | 55 | /** 56 | * 刷新全部 57 | */ 58 | @Override 59 | public void notifyDataSetChanged() { 60 | mViewList.clear(); 61 | initPosition(); 62 | super.notifyDataSetChanged(); 63 | } 64 | 65 | /** 66 | * 获取item索引 67 | * 68 | * POSITION_UNCHANGED表示位置没有变化,即在添加或移除一页或多页之后该位置的页面保持不变, 69 | * 可以用于一个ViewPager中最后几页的添加或移除时,保持前几页仍然不变; 70 | * 71 | * POSITION_NONE,表示当前页不再作为ViewPager的一页数据,将被销毁,可以用于无视View缓存的刷新; 72 | * 根据传过来的参数Object来判断这个key所指定的新的位置 73 | * @param object objcet 74 | * @return 75 | */ 76 | @Override 77 | public int getItemPosition(@NonNull Object object) { 78 | return POSITION_NONE; 79 | } 80 | 81 | /** 82 | * 注册数据观察者监听 83 | * @param observer observer 84 | */ 85 | @Override 86 | public void registerDataSetObserver(@NonNull DataSetObserver observer) { 87 | super.registerDataSetObserver(observer); 88 | initPosition(); 89 | } 90 | 91 | private void initPosition(){ 92 | if (getRealCount()>1){ 93 | if (mViewPager.getViewPager().getCurrentItem() == 0&&getRealCount()>0){ 94 | int half = Integer.MAX_VALUE/2; 95 | int start = half - half%getRealCount(); 96 | setCurrent(start); 97 | } 98 | } 99 | } 100 | 101 | /** 102 | * 设置位置,利用反射实现 103 | * @param index 索引 104 | */ 105 | @TargetApi(Build.VERSION_CODES.KITKAT) 106 | private void setCurrent(int index){ 107 | try { 108 | Field field = ViewPager.class.getDeclaredField("mCurItem"); 109 | field.setAccessible(true); 110 | field.set(mViewPager.getViewPager(),index); 111 | } catch (NoSuchFieldException | IllegalAccessException e) { 112 | e.printStackTrace(); 113 | } 114 | } 115 | 116 | public AbsLoopPagerAdapter(BannerView viewPager){ 117 | this.mViewPager = viewPager; 118 | viewPager.setHintViewDelegate(new LoopHintViewDelegate()); 119 | } 120 | 121 | @Override 122 | public boolean isViewFromObject(@NonNull View arg0, @NonNull Object arg1) { 123 | return arg0==arg1; 124 | } 125 | 126 | /** 127 | * 如果页面不是当前显示的页面也不是要缓存的页面,会调用这个方法,将页面销毁。 128 | * @param container container 129 | * @param position 索引 130 | * @param object object 131 | */ 132 | @Override 133 | public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { 134 | container.removeView((View) object); 135 | Log.d("PagerAdapter","销毁的方法"); 136 | } 137 | 138 | /** 139 | * 要显示的页面或需要缓存的页面,会调用这个方法进行布局的初始化。 140 | * @param container container 141 | * @param position 索引 142 | * @return 143 | */ 144 | @NonNull 145 | @Override 146 | public Object instantiateItem(@NonNull ViewGroup container, int position) { 147 | int realPosition = position%getRealCount(); 148 | View itemView = findViewByPosition(container,realPosition); 149 | container.addView(itemView); 150 | Log.d("PagerAdapter","创建的方法"); 151 | return itemView; 152 | } 153 | 154 | /** 155 | * 这个是避免重复创建,如果集合中有,则取集合中的 156 | * @param container container 157 | * @param position 索引 158 | * @return 159 | */ 160 | private View findViewByPosition(ViewGroup container, int position){ 161 | for (View view : mViewList) { 162 | if (((int)view.getTag()) == position&&view.getParent()==null){ 163 | return view; 164 | } 165 | } 166 | View view = getView(container,position); 167 | view.setTag(position); 168 | mViewList.add(view); 169 | return view; 170 | } 171 | 172 | 173 | @Deprecated 174 | @Override 175 | public final int getCount() { 176 | //设置最大轮播图数量 ,如果是1那么就是1,不轮播;如果大于1则设置一个最大值,可以轮播 177 | //return getRealCount(); 178 | return getRealCount()<=1?getRealCount(): Integer.MAX_VALUE; 179 | } 180 | 181 | /** 182 | * 获取轮播图数量 183 | * @return 数量 184 | */ 185 | public abstract int getRealCount(); 186 | 187 | /** 188 | * 创建view 189 | * @param container viewGroup 190 | * @param position 索引 191 | * @return 192 | */ 193 | public abstract View getView(ViewGroup container, int position); 194 | 195 | } 196 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/adapter/AbsStaticPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.adapter; 2 | 3 | 4 | import android.util.Log; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.fragment.app.FragmentStatePagerAdapter; 10 | import androidx.viewpager.widget.PagerAdapter; 11 | 12 | import com.yc.cn.ycbannerlib.LibUtils; 13 | 14 | import java.util.ArrayList; 15 | 16 | 17 | 18 | /** 19 | *
20 |  *     @author yangchong
21 |  *     blog  : https://github.com/yangchong211
22 |  *     time  : 2016/3/18
23 |  *     desc  : 静态存储的Adapter,概念参照{@link FragmentStatePagerAdapter}
24 |  *             view添加进去就不管了,View长在,内存不再
25 |  *     revise: 如果是静态轮播图就用这个
26 |  * 
27 | */ 28 | public abstract class AbsStaticPagerAdapter extends PagerAdapter { 29 | 30 | private ArrayList mViewList = new ArrayList<>(); 31 | 32 | @Override 33 | public boolean isViewFromObject(@NonNull View arg0, @NonNull Object arg1) { 34 | return arg0==arg1; 35 | } 36 | 37 | @Override 38 | public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { 39 | container.removeView((View) object); 40 | Log.d("PagerAdapter","销毁的方法"); 41 | } 42 | 43 | @Override 44 | public void notifyDataSetChanged() { 45 | mViewList.clear(); 46 | super.notifyDataSetChanged(); 47 | } 48 | 49 | @Override 50 | public int getItemPosition(@NonNull Object object) { 51 | return POSITION_NONE; 52 | } 53 | 54 | @NonNull 55 | @Override 56 | public Object instantiateItem(@NonNull ViewGroup container, int position) { 57 | View itemView = findViewByPosition(container,position); 58 | container.addView(itemView); 59 | onBind(itemView,position); 60 | Log.d("PagerAdapter","创建的方法"); 61 | return itemView; 62 | } 63 | 64 | private View findViewByPosition(ViewGroup container, int position){ 65 | for (View view : mViewList) { 66 | if (((int)view.getTag()) == position&&view.getParent()==null){ 67 | return view; 68 | } 69 | } 70 | View view = getView(container,position); 71 | view.setTag(position); 72 | mViewList.add(view); 73 | return view; 74 | } 75 | 76 | 77 | public void onBind(View view, int position){} 78 | 79 | public abstract View getView(ViewGroup container, int position); 80 | 81 | } 82 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/hintview/ColorPointHintView.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.hintview; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.drawable.Drawable; 6 | import android.graphics.drawable.GradientDrawable; 7 | 8 | import com.yc.cn.ycbannerlib.LibUtils; 9 | 10 | /** 11 | *
12 |  *     @author yangchong
13 |  *     blog  : https://github.com/yangchong211
14 |  *     time  : 2016/3/18
15 |  *     desc  : color
16 |  *     revise:
17 |  * 
18 | */ 19 | @SuppressLint("ViewConstructor") 20 | public class ColorPointHintView extends ShapeHintView { 21 | 22 | private int focusColor; 23 | private int normalColor; 24 | 25 | public ColorPointHintView(Context context, int focusColor, int normalColor) { 26 | super(context); 27 | this.focusColor = focusColor; 28 | this.normalColor = normalColor; 29 | } 30 | 31 | @Override 32 | public Drawable makeFocusDrawable() { 33 | GradientDrawable dotFocus = new GradientDrawable(); 34 | dotFocus.setColor(focusColor); 35 | dotFocus.setCornerRadius(LibUtils.dip2px(getContext(), 4)); 36 | dotFocus.setSize(LibUtils.dip2px(getContext(), 8), 37 | LibUtils.dip2px(getContext(), 8)); 38 | return dotFocus; 39 | } 40 | 41 | @Override 42 | public Drawable makeNormalDrawable() { 43 | GradientDrawable dotNormal = new GradientDrawable(); 44 | dotNormal.setColor(normalColor); 45 | dotNormal.setCornerRadius(LibUtils.dip2px(getContext(), 4)); 46 | dotNormal.setSize(LibUtils.dip2px(getContext(), 8), 47 | LibUtils.dip2px(getContext(), 8)); 48 | return dotNormal; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/hintview/IconHintView.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.hintview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Matrix; 7 | import android.graphics.PixelFormat; 8 | import android.graphics.drawable.BitmapDrawable; 9 | import android.graphics.drawable.Drawable; 10 | 11 | import androidx.annotation.DrawableRes; 12 | 13 | import com.yc.cn.ycbannerlib.LibUtils; 14 | 15 | /** 16 | *
17 |  *     @author yangchong
18 |  *     blog  : https://github.com/yangchong211
19 |  *     time  : 2016/3/18
20 |  *     desc  : icon
21 |  *     revise:
22 |  * 
23 | */ 24 | public class IconHintView extends ShapeHintView { 25 | 26 | private int focusResId; 27 | private int normalResId; 28 | private int size; 29 | 30 | 31 | public IconHintView(Context context, @DrawableRes int focusResId, @DrawableRes int normalResId) { 32 | this(context, focusResId, normalResId, LibUtils.dip2px(context,32)); 33 | } 34 | 35 | public IconHintView(Context context, @DrawableRes int focusResId, 36 | @DrawableRes int normalResId, int size) { 37 | super(context); 38 | this.focusResId = focusResId; 39 | this.normalResId = normalResId; 40 | this.size = size; 41 | } 42 | 43 | @Override 44 | public Drawable makeFocusDrawable() { 45 | Drawable drawable = getContext().getResources().getDrawable(focusResId); 46 | if (size>0){ 47 | drawable = zoomDrawable(drawable,size,size); 48 | } 49 | return drawable; 50 | } 51 | 52 | @Override 53 | public Drawable makeNormalDrawable() { 54 | Drawable drawable = getContext().getResources().getDrawable(normalResId); 55 | if (size>0){ 56 | drawable = zoomDrawable(drawable,size,size); 57 | } 58 | return drawable; 59 | } 60 | 61 | private Drawable zoomDrawable(Drawable drawable, int w, int h) { 62 | int width = drawable.getIntrinsicWidth(); 63 | int height = drawable.getIntrinsicHeight(); 64 | Bitmap oldBmp = drawableToBitmap(drawable); 65 | Matrix matrix = new Matrix(); 66 | float scaleWidth = ((float) w / width); 67 | float scaleHeight = ((float) h / height); 68 | matrix.postScale(scaleWidth, scaleHeight); 69 | Bitmap newBmp = Bitmap.createBitmap(oldBmp, 0, 0, width, height, matrix, true); 70 | return new BitmapDrawable(null, newBmp); 71 | } 72 | 73 | private Bitmap drawableToBitmap(Drawable drawable) { 74 | int width = drawable.getIntrinsicWidth(); 75 | int height = drawable.getIntrinsicHeight(); 76 | Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? 77 | Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 78 | Bitmap bitmap = Bitmap.createBitmap(width, height, config); 79 | Canvas canvas = new Canvas(bitmap); 80 | drawable.setBounds(0, 0, width, height); 81 | drawable.draw(canvas); 82 | return bitmap; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/hintview/ShapeHintView.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.hintview; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.util.AttributeSet; 6 | import android.view.Gravity; 7 | import android.widget.ImageView; 8 | import android.widget.LinearLayout; 9 | 10 | import com.yc.cn.ycbannerlib.banner.inter.BaseHintView; 11 | 12 | /** 13 | *
14 |  *     @author yangchong
15 |  *     blog  : https://github.com/yangchong211
16 |  *     time  : 2016/3/18
17 |  *     desc  : shape图形
18 |  *     revise:
19 |  * 
20 | */ 21 | public abstract class ShapeHintView extends LinearLayout implements BaseHintView { 22 | 23 | private ImageView[] mDots; 24 | private int length = 0; 25 | private int lastPosition = 0; 26 | 27 | private Drawable dotNormal; 28 | private Drawable dotFocus; 29 | 30 | public ShapeHintView(Context context){ 31 | super(context); 32 | } 33 | 34 | public ShapeHintView(Context context, AttributeSet attrs) { 35 | super(context, attrs); 36 | } 37 | 38 | 39 | public abstract Drawable makeFocusDrawable(); 40 | 41 | public abstract Drawable makeNormalDrawable(); 42 | 43 | @Override 44 | public void initView(int length, int gravity) { 45 | removeAllViews(); 46 | lastPosition = 0; 47 | setOrientation(HORIZONTAL); 48 | switch (gravity) { 49 | case 0: 50 | setGravity(Gravity.START| Gravity.CENTER_VERTICAL); 51 | break; 52 | case 1: 53 | setGravity(Gravity.CENTER); 54 | break; 55 | case 2: 56 | setGravity(Gravity.END| Gravity.CENTER_VERTICAL); 57 | break; 58 | default: 59 | break; 60 | } 61 | 62 | this.length = length; 63 | mDots = new ImageView[length]; 64 | 65 | dotFocus = makeFocusDrawable(); 66 | dotNormal = makeNormalDrawable(); 67 | 68 | for (int i = 0; i < length; i++) { 69 | mDots[i]=new ImageView(getContext()); 70 | LayoutParams dotLp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 71 | dotLp.setMargins(10, 0, 10, 0); 72 | mDots[i].setLayoutParams(dotLp); 73 | mDots[i].setBackgroundDrawable(dotNormal); 74 | addView(mDots[i]); 75 | } 76 | setCurrent(0); 77 | } 78 | 79 | @Override 80 | public void setCurrent(int current) { 81 | if (current < 0 || current > length - 1) { 82 | return; 83 | } 84 | mDots[lastPosition].setBackgroundDrawable(dotNormal); 85 | mDots[current].setBackgroundDrawable(dotFocus); 86 | lastPosition = current; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/hintview/TextHintView.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.hintview; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Color; 6 | import android.util.AttributeSet; 7 | import android.view.Gravity; 8 | 9 | import androidx.appcompat.widget.AppCompatTextView; 10 | 11 | import com.yc.cn.ycbannerlib.banner.inter.BaseHintView; 12 | 13 | /** 14 | *
15 |  *     @author yangchong
16 |  *     blog  : https://github.com/yangchong211
17 |  *     time  : 2016/3/18
18 |  *     desc  : 文本
19 |  *     revise:
20 |  * 
21 | */ 22 | public class TextHintView extends AppCompatTextView implements BaseHintView { 23 | 24 | private int length; 25 | public TextHintView(Context context){ 26 | super(context); 27 | } 28 | 29 | public TextHintView(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | } 32 | 33 | @Override 34 | public void initView(int length, int gravity) { 35 | this.length = length; 36 | setTextColor(Color.WHITE); 37 | switch (gravity) { 38 | case 0: 39 | setGravity(Gravity.START| Gravity.CENTER_VERTICAL); 40 | break; 41 | case 1: 42 | setGravity(Gravity.CENTER); 43 | break; 44 | case 2: 45 | setGravity(Gravity.END| Gravity.CENTER_VERTICAL); 46 | break; 47 | default: 48 | break; 49 | } 50 | 51 | setCurrent(0); 52 | } 53 | 54 | @SuppressLint("SetTextI18n") 55 | @Override 56 | public void setCurrent(int current) { 57 | setText(current+1+"/"+ length); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/inter/BaseHintView.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.inter; 2 | 3 | /** 4 | *
 5 |  *     @author yangchong
 6 |  *     blog  : https://github.com/yangchong211
 7 |  *     time  : 2016/3/18
 8 |  *     desc  : 所有指示器的接口
 9 |  *     revise:
10 |  * 
11 | */ 12 | public interface BaseHintView { 13 | 14 | void initView(int length, int gravity); 15 | 16 | void setCurrent(int current); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/inter/HintViewDelegate.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.inter; 2 | 3 | /** 4 | *
 5 |  *     @author yangchong
 6 |  *     blog  : https://github.com/yangchong211
 7 |  *     time  : 2016/3/18
 8 |  *     desc  :
 9 |  *     revise:
10 |  * 
11 | */ 12 | public interface HintViewDelegate { 13 | 14 | /** 15 | * 设置索引位置 16 | * @param position 索引 17 | * @param hintView HintView 18 | */ 19 | void setCurrentPosition(int position, BaseHintView hintView); 20 | 21 | /** 22 | * 初始化view 23 | * @param length length 24 | * @param gravity 位置 25 | * @param hintView HintView 26 | */ 27 | void initView(int length, int gravity, BaseHintView hintView); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/view/BannerConstant.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.view; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | public class BannerConstant { 7 | 8 | 9 | /** 10 | * 不建议用枚举,可以用注解替代 11 | * 轮播图红点是0,数字是1 12 | * 后期还可以加入其他的 13 | */ 14 | @Retention(RetentionPolicy.SOURCE) 15 | public @interface HintMode { 16 | int COLOR_POINT_HINT = 0; 17 | int TEXT_HINT = 1; 18 | } 19 | 20 | @Retention(RetentionPolicy.SOURCE) 21 | public @interface HintGravity { 22 | int LEFT = 1; 23 | int CENTER = 2; 24 | int RIGHT = 3; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/banner/view/BannerViewPager.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.banner.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.MotionEvent; 6 | 7 | import androidx.viewpager.widget.ViewPager; 8 | 9 | public class BannerViewPager extends ViewPager { 10 | 11 | private boolean scrollable = true; 12 | 13 | public BannerViewPager(Context context) { 14 | super(context); 15 | } 16 | 17 | public BannerViewPager(Context context, AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | @Override 22 | public boolean onTouchEvent(MotionEvent ev) { 23 | if(this.scrollable) { 24 | if (getCurrentItem() == 0 && getChildCount() == 0) { 25 | return false; 26 | } 27 | return super.onTouchEvent(ev); 28 | } else { 29 | return false; 30 | } 31 | } 32 | 33 | @Override 34 | public boolean onInterceptTouchEvent(MotionEvent ev) { 35 | if(this.scrollable) { 36 | if (getCurrentItem() == 0 && getChildCount() == 0) { 37 | return false; 38 | } 39 | return super.onInterceptTouchEvent(ev); 40 | } else { 41 | return false; 42 | } 43 | } 44 | 45 | public void setScrollable(boolean scrollable) { 46 | this.scrollable = scrollable; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/java/com/yc/cn/ycbannerlib/marquee/MarqueeView.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbannerlib.marquee; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.text.TextUtils; 7 | import android.util.AttributeSet; 8 | import android.view.Gravity; 9 | import android.view.View; 10 | import android.view.ViewTreeObserver; 11 | import android.view.animation.Animation; 12 | import android.view.animation.AnimationUtils; 13 | import android.widget.TextView; 14 | import android.widget.ViewFlipper; 15 | import com.yc.cn.ycbannerlib.R; 16 | import java.util.ArrayList; 17 | 18 | /** 19 | *
 20 |  *     @author yangchong
 21 |  *     blog  : https://github.com/yangchong211
 22 |  *     time  : 2017/1/18
 23 |  *     desc  : v1.0 17年1月18日
 24 |  *             v1.1 17年4月7日
 25 |  *     revise:
 26 |  * 
27 | */ 28 | public class MarqueeView extends ViewFlipper { 29 | 30 | private Context mContext; 31 | private ArrayList notices; 32 | private boolean isSetAnimDuration = false; 33 | private OnItemClickListener onItemClickListener; 34 | 35 | private int interval = 2000; 36 | private int animDuration = 500; 37 | private int textSize = 14; 38 | private int textColor = 0xffffffff; 39 | 40 | private boolean singleLine = false; 41 | private int gravity = Gravity.START | Gravity.CENTER_VERTICAL; 42 | private static final int TEXT_GRAVITY_LEFT = 0, TEXT_GRAVITY_CENTER = 1, TEXT_GRAVITY_RIGHT = 2; 43 | 44 | public MarqueeView(Context context, AttributeSet attrs) { 45 | super(context, attrs); 46 | init(context, attrs, 0); 47 | } 48 | 49 | private void init(Context context, AttributeSet attrs, int defStyleAttr) { 50 | this.mContext = context; 51 | if (notices == null) { 52 | notices = new ArrayList<>(); 53 | } 54 | 55 | @SuppressLint("CustomViewStyleable") 56 | TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MarqueeViewStyle, defStyleAttr, 0); 57 | interval = typedArray.getInteger(R.styleable.MarqueeViewStyle_mvInterval, interval); 58 | isSetAnimDuration = typedArray.hasValue(R.styleable.MarqueeViewStyle_mvAnimDuration); 59 | singleLine = typedArray.getBoolean(R.styleable.MarqueeViewStyle_mvSingleLine, false); 60 | animDuration = typedArray.getInteger(R.styleable.MarqueeViewStyle_mvAnimDuration, animDuration); 61 | if (typedArray.hasValue(R.styleable.MarqueeViewStyle_mvTextSize)) { 62 | textSize = (int) typedArray.getDimension(R.styleable.MarqueeViewStyle_mvTextSize, textSize); 63 | textSize = px2sp(mContext, textSize); 64 | } 65 | textColor = typedArray.getColor(R.styleable.MarqueeViewStyle_mvTextColor, textColor); 66 | int gravityType = typedArray.getInt(R.styleable.MarqueeViewStyle_mvGravity, TEXT_GRAVITY_LEFT); 67 | switch (gravityType) { 68 | case TEXT_GRAVITY_CENTER: 69 | gravity = Gravity.CENTER; 70 | break; 71 | case TEXT_GRAVITY_RIGHT: 72 | gravity = Gravity.START | Gravity.CENTER_VERTICAL; 73 | break; 74 | default: 75 | break; 76 | } 77 | typedArray.recycle(); 78 | 79 | setFlipInterval(interval); 80 | } 81 | 82 | /** 83 | * 根据公告字符串启动轮播 84 | * @param notice 公告 85 | */ 86 | public void startWithText(final String notice) { 87 | if (TextUtils.isEmpty(notice)) { 88 | return; 89 | } 90 | getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 91 | @Override 92 | public void onGlobalLayout() { 93 | getViewTreeObserver().removeGlobalOnLayoutListener(this); 94 | startWithFixedWidth(notice, getWidth()); 95 | } 96 | }); 97 | } 98 | 99 | /** 100 | * 根据公告字符串列表启动轮播 101 | * @param notices 公告集合 102 | */ 103 | public void startWithList(ArrayList notices) { 104 | setNotices(notices); 105 | start(); 106 | } 107 | 108 | /** 109 | * 根据宽度和公告字符串启动轮播 110 | * @param notice 公告 111 | * @param width width 112 | */ 113 | private void startWithFixedWidth(String notice, int width) { 114 | int noticeLength = notice.length(); 115 | int dpW = px2dip(mContext, width); 116 | int limit = dpW / textSize; 117 | if (dpW == 0) { 118 | throw new RuntimeException("Please set MarqueeView width !"); 119 | } 120 | ArrayList list = new ArrayList<>(); 121 | if (noticeLength <= limit) { 122 | list.add(notice); 123 | } else { 124 | int size = noticeLength / limit + (noticeLength % limit != 0 ? 1 : 0); 125 | for (int i = 0; i < size; i++) { 126 | int startIndex = i * limit; 127 | int endIndex = ((i + 1) * limit >= noticeLength ? noticeLength : (i + 1) * limit); 128 | list.add(notice.substring(startIndex, endIndex)); 129 | } 130 | } 131 | notices.addAll(list); 132 | start(); 133 | } 134 | 135 | /** 136 | * 启动轮播 137 | * @return 是否启动轮播 138 | */ 139 | public boolean start() { 140 | if (notices == null || notices.size() == 0) { 141 | return false; 142 | } 143 | //先移除所有view 144 | removeAllViews(); 145 | //然后重置动画 146 | resetAnimation(); 147 | 148 | //根据设置的数据集合数量创建TextView 149 | for (int i = 0; i < notices.size(); i++) { 150 | final TextView textView = createTextView(notices.get(i), i); 151 | final int finalI = i; 152 | textView.setOnClickListener(new OnClickListener() { 153 | @Override 154 | public void onClick(View v) { 155 | if (onItemClickListener != null) { 156 | onItemClickListener.onItemClick(finalI, textView); 157 | } 158 | } 159 | }); 160 | addView(textView); 161 | } 162 | 163 | //如果集合数目大于1,则开始;否则停止 164 | if (notices.size() > 1) { 165 | startFlipping(); 166 | } else { 167 | stopFlipping(); 168 | } 169 | return true; 170 | } 171 | 172 | 173 | /** 174 | * 重置动画 175 | */ 176 | private void resetAnimation(){ 177 | clearAnimation(); 178 | //设置进入的动画 179 | Animation animIn = AnimationUtils.loadAnimation(mContext, R.anim.anim_marquee_in); 180 | if (isSetAnimDuration) { 181 | animIn.setDuration(animDuration); 182 | } 183 | setInAnimation(animIn); 184 | 185 | //设置结束的动画 186 | Animation animOut = AnimationUtils.loadAnimation(mContext, R.anim.anim_marquee_out); 187 | if (isSetAnimDuration) { 188 | animOut.setDuration(animDuration); 189 | } 190 | setOutAnimation(animOut); 191 | } 192 | 193 | /** 194 | * 创建ViewFlipper下的TextView 195 | * @param text text 196 | * @param position position 197 | * @return TextView 198 | */ 199 | private TextView createTextView(CharSequence text, int position) { 200 | TextView tv = new TextView(mContext); 201 | tv.setGravity(gravity); 202 | tv.setText(text); 203 | tv.setTextColor(textColor); 204 | tv.setTextSize(textSize); 205 | tv.setSingleLine(singleLine); 206 | tv.setTag(position); 207 | return tv; 208 | } 209 | 210 | /** 211 | * 获取当前索引位置 212 | * @return 索引 213 | */ 214 | public int getPosition() { 215 | return (int) getCurrentView().getTag(); 216 | } 217 | 218 | public ArrayList getNotices() { 219 | return notices; 220 | } 221 | 222 | /** 223 | * 设置数据集合 224 | * @param notices 数据 225 | */ 226 | public void setNotices(ArrayList notices) { 227 | this.notices = notices; 228 | } 229 | 230 | /** 231 | * 设置点击事件 232 | * @param onItemClickListener 点击事件listener 233 | */ 234 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 235 | this.onItemClickListener = onItemClickListener; 236 | } 237 | public interface OnItemClickListener { 238 | void onItemClick(int position, TextView textView); 239 | } 240 | 241 | 242 | public static int px2sp(Context context, float pxValue) { 243 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 244 | return (int) (pxValue / fontScale + 0.5f); 245 | } 246 | 247 | public static int px2dip(Context ctx, float pxValue) { 248 | final float scale = ctx.getResources().getDisplayMetrics().density; 249 | return (int) (pxValue / scale + 0.5f); 250 | } 251 | 252 | } 253 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/res/anim/anim_marquee_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/res/anim/anim_marquee_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /YCBannerLib/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | YCBannerLib 3 | 4 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply from: rootProject.projectDir.absolutePath + "/AppGradle/appBuild.gradle" 3 | 4 | android { 5 | compileSdkVersion project.ext.androidCompileSdkVersion 6 | //buildToolsVersion project.ext.androidBuildToolsVersion 7 | defaultConfig { 8 | applicationId "com.yc.cn.ycbanner" 9 | minSdkVersion project.ext.androidMinSdkVersion 10 | targetSdkVersion project.ext.androidTargetSdkVersion 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | implementation project.ext.AppDependencies['appcompat'] 25 | implementation project.ext.AppDependencies['recyclerview'] 26 | implementation project.ext.AppDependencies['media'] 27 | compile project(':YCBannerLib') 28 | compile project(':GalleryBannerLib') 29 | compile project(':SnapBannerLib') 30 | // compile 'cn.yc:YCBannerLib:1.4.0' //轮播图 31 | compile 'cn.yc:YCStatusBarLib:1.4.0' 32 | compile 'cn.yc:YCBaseAdapterLib:1.3.4' 33 | compile 'cn.yc:YCUtilsLib:1.6.2' 34 | compile 'cn.yc:YCStatusBarLib:1.4.0' 35 | } 36 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\PC\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/EightActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.content.res.TypedArray; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.graphics.drawable.Drawable; 8 | import android.graphics.drawable.TransitionDrawable; 9 | import android.os.Bundle; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.widget.FrameLayout; 13 | 14 | 15 | import androidx.annotation.Nullable; 16 | import androidx.appcompat.app.AppCompatActivity; 17 | import androidx.recyclerview.widget.LinearLayoutManager; 18 | import androidx.recyclerview.widget.RecyclerView; 19 | 20 | import com.ns.yc.ycutilslib.blurView.blur.CustomBlur; 21 | import com.yc.gallerybannerlib.GalleryLayoutManager; 22 | import com.yc.gallerybannerlib.GalleryRecyclerView; 23 | import com.yc.gallerybannerlib.GalleryScaleTransformer; 24 | 25 | import java.util.ArrayList; 26 | import java.util.HashMap; 27 | import java.util.Map; 28 | 29 | import cn.ycbjie.ycstatusbarlib.bar.StateAppBar; 30 | 31 | public class EightActivity extends AppCompatActivity { 32 | 33 | private GalleryRecyclerView mRecyclerView; 34 | private RecyclerView recyclerView2; 35 | private ArrayList data = new ArrayList<>(); 36 | private FrameLayout fl_container; 37 | 38 | @Override 39 | protected void onDestroy() { 40 | super.onDestroy(); 41 | if (mRecyclerView!=null){ 42 | mRecyclerView.release(); 43 | } 44 | } 45 | 46 | @Override 47 | protected void onStart() { 48 | super.onStart(); 49 | if (mRecyclerView!=null){ 50 | mRecyclerView.onStart(); 51 | } 52 | } 53 | 54 | @Override 55 | protected void onStop() { 56 | super.onStop(); 57 | if (mRecyclerView!=null){ 58 | mRecyclerView.onStop(); 59 | } 60 | } 61 | 62 | @Override 63 | protected void onCreate(@Nullable Bundle savedInstanceState) { 64 | super.onCreate(savedInstanceState); 65 | setContentView(R.layout.activity_eight); 66 | StateAppBar.translucentStatusBar(this,true); 67 | mRecyclerView = findViewById(R.id.recyclerView); 68 | recyclerView2 = findViewById(R.id.recyclerView2); 69 | fl_container = findViewById(R.id.fl_container); 70 | initRecyclerView(); 71 | initRecyclerView2(); 72 | } 73 | 74 | private void initRecyclerView() { 75 | Snap3Adapter adapter = new Snap3Adapter(this); 76 | adapter.setData(getData()); 77 | mRecyclerView.setDelayTime(3000) 78 | .setFlingSpeed(10000) 79 | .setDataAdapter(adapter) 80 | .setSelectedPosition(100) 81 | .setCallbackInFling(false) 82 | .setOnItemSelectedListener(new GalleryRecyclerView.OnItemSelectedListener() { 83 | @Override 84 | public void onItemSelected(RecyclerView recyclerView, View item, int position) { 85 | Log.e("onItemSelected-----",position+""); 86 | //设置高斯模糊背景 87 | setBlurImage(true); 88 | } 89 | }) 90 | .setSize(adapter.getData().size()) 91 | .setUp(); 92 | } 93 | 94 | 95 | private void initRecyclerView2() { 96 | GalleryLayoutManager manager = new GalleryLayoutManager(this, LinearLayoutManager.HORIZONTAL); 97 | manager.attach(recyclerView2,100); 98 | manager.setItemTransformer(new GalleryScaleTransformer( 0.2f,30)); 99 | recyclerView2.setLayoutManager(manager); 100 | Snap3Adapter adapter = new Snap3Adapter(this); 101 | adapter.setData(getData()); 102 | recyclerView2.setAdapter(adapter); 103 | } 104 | 105 | 106 | private ArrayList getData(){ 107 | TypedArray bannerImage = getResources().obtainTypedArray(R.array.banner_image); 108 | for (int i = 0; i < 12 ; i++) { 109 | int image = bannerImage.getResourceId(i, R.drawable.beauty1); 110 | data.add(image); 111 | } 112 | bannerImage.recycle(); 113 | return data; 114 | } 115 | 116 | 117 | /** 118 | * 获取虚化背景的位置 119 | */ 120 | private int mLastDraPosition = -1; 121 | private Map mTSDraCacheMap = new HashMap<>(); 122 | private static final String KEY_PRE_DRAW = "key_pre_draw"; 123 | /** 124 | * 设置背景高斯模糊 125 | */ 126 | public void setBlurImage(boolean forceUpdate) { 127 | final Snap3Adapter adapter = (Snap3Adapter) mRecyclerView.getAdapter(); 128 | final int mCurViewPosition = mRecyclerView.getCurrentItem(); 129 | 130 | boolean isSamePosAndNotUpdate = (mCurViewPosition == mLastDraPosition) && !forceUpdate; 131 | 132 | if (adapter == null || mRecyclerView == null || isSamePosAndNotUpdate) { 133 | return; 134 | } 135 | mRecyclerView.post(new Runnable() { 136 | @Override 137 | public void run() { 138 | // 获取当前位置的图片资源ID 139 | int resourceId = adapter.getData().get(mCurViewPosition%adapter.getData().size()); 140 | // 将该资源图片转为Bitmap 141 | Bitmap resBmp = BitmapFactory.decodeResource(getResources(), resourceId); 142 | // 将该Bitmap高斯模糊后返回到resBlurBmp 143 | Bitmap resBlurBmp = CustomBlur.apply(mRecyclerView.getContext(), resBmp, 10); 144 | // 再将resBlurBmp转为Drawable 145 | Drawable resBlurDrawable = new BitmapDrawable(resBlurBmp); 146 | // 获取前一页的Drawable 147 | Drawable preBlurDrawable = mTSDraCacheMap.get(KEY_PRE_DRAW) == null ? resBlurDrawable : mTSDraCacheMap.get(KEY_PRE_DRAW); 148 | 149 | /* 以下为淡入淡出效果 */ 150 | Drawable[] drawableArr = {preBlurDrawable, resBlurDrawable}; 151 | TransitionDrawable transitionDrawable = new TransitionDrawable(drawableArr); 152 | fl_container.setBackgroundDrawable(transitionDrawable); 153 | transitionDrawable.startTransition(500); 154 | 155 | // 存入到cache中 156 | mTSDraCacheMap.put(KEY_PRE_DRAW, resBlurDrawable); 157 | // 记录上一次高斯模糊的位置 158 | mLastDraPosition = mCurViewPosition; 159 | } 160 | }); 161 | } 162 | 163 | 164 | 165 | } 166 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/FirstActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.Toast; 10 | 11 | import androidx.annotation.Nullable; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | 14 | import com.yc.cn.ycbannerlib.banner.view.BannerConstant; 15 | import com.yc.cn.ycbannerlib.banner.view.BannerView; 16 | import com.yc.cn.ycbannerlib.banner.adapter.AbsLoopPagerAdapter; 17 | 18 | 19 | /** 20 | * Created by PC on 2017/11/21. 21 | * 作者:PC 22 | */ 23 | 24 | public class FirstActivity extends AppCompatActivity { 25 | 26 | 27 | private int[] imgs = { 28 | R.drawable.bg_kites_min, 29 | R.drawable.bg_autumn_tree_min, 30 | R.drawable.bg_lake_min, 31 | R.drawable.bg_leaves_min, 32 | R.drawable.bg_magnolia_trees_min, 33 | }; 34 | private BannerView banner; 35 | 36 | @Override 37 | protected void onDestroy() { 38 | super.onDestroy(); 39 | } 40 | 41 | @Override 42 | protected void onPause() { 43 | super.onPause(); 44 | if(banner!=null){ 45 | //停止轮播 46 | banner.pause(); 47 | } 48 | } 49 | 50 | @Override 51 | protected void onResume() { 52 | super.onResume(); 53 | if(banner!=null){ 54 | //开始轮播 55 | banner.resume(); 56 | } 57 | } 58 | 59 | @Override 60 | protected void onCreate(@Nullable Bundle savedInstanceState) { 61 | super.onCreate(savedInstanceState); 62 | setContentView(R.layout.activity_first); 63 | 64 | initBanner(); 65 | } 66 | 67 | private void initBanner() { 68 | banner = (BannerView) findViewById(R.id.banner); 69 | //设置轮播时间 70 | banner.setPlayDelay(2000); 71 | //设置轮播图适配器,必须 72 | banner.setAdapter(new ImageNormalAdapter(banner)); 73 | //设置位置 74 | banner.setHintGravity(1); 75 | banner.setHintPadding(20,0, 20,20); 76 | //判断轮播是否进行 77 | boolean playing = banner.isPlaying(); 78 | //轮播图点击事件 79 | banner.setOnBannerClickListener(new BannerView.OnBannerClickListener() { 80 | @Override 81 | public void onItemClick(int position) { 82 | Toast.makeText(FirstActivity.this,position+"被点击呢",Toast.LENGTH_SHORT).show(); 83 | } 84 | }); 85 | //轮播图滑动事件 86 | banner.setOnPageListener(new BannerView.OnPageListener() { 87 | @Override 88 | public void onPageChange(int position) { 89 | 90 | } 91 | }); 92 | } 93 | 94 | 95 | private class ImageNormalAdapter extends AbsLoopPagerAdapter { 96 | 97 | public ImageNormalAdapter(BannerView viewPager) { 98 | super(viewPager); 99 | } 100 | 101 | @Override 102 | public View getView(ViewGroup container, int position) { 103 | ImageView view = new ImageView(container.getContext()); 104 | view.setScaleType(ImageView.ScaleType.CENTER_CROP); 105 | view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 106 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs[position]); 107 | Bitmap bitmap1 = ImageBitmapUtils.compressByQuality(bitmap, 50, false); 108 | view.setImageBitmap(bitmap1); 109 | return view; 110 | } 111 | 112 | @Override 113 | public int getRealCount() { 114 | return imgs.length; 115 | } 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/FourActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.Toast; 10 | 11 | import androidx.annotation.Nullable; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | 14 | import com.yc.cn.ycbannerlib.banner.adapter.AbsStaticPagerAdapter; 15 | import com.yc.cn.ycbannerlib.banner.view.BannerView; 16 | import com.yc.cn.ycbannerlib.banner.adapter.AbsLoopPagerAdapter; 17 | import com.yc.cn.ycbannerlib.banner.hintview.TextHintView; 18 | 19 | /** 20 | * Created by PC on 2017/11/21. 21 | * 作者:PC 22 | */ 23 | 24 | public class FourActivity extends AppCompatActivity { 25 | 26 | private int[] imgs = { 27 | R.drawable.bg_kites_min, 28 | R.drawable.bg_autumn_tree_min, 29 | R.drawable.bg_lake_min, 30 | R.drawable.bg_leaves_min, 31 | R.drawable.bg_magnolia_trees_min, 32 | }; 33 | private BannerView banner; 34 | 35 | @Override 36 | protected void onDestroy() { 37 | super.onDestroy(); 38 | } 39 | 40 | @Override 41 | protected void onPause() { 42 | super.onPause(); 43 | if(banner!=null){ 44 | banner.pause(); 45 | } 46 | } 47 | 48 | @Override 49 | protected void onResume() { 50 | super.onResume(); 51 | if(banner!=null){ 52 | banner.resume(); 53 | } 54 | } 55 | 56 | @Override 57 | protected void onCreate(@Nullable Bundle savedInstanceState) { 58 | super.onCreate(savedInstanceState); 59 | setContentView(R.layout.activity_four); 60 | 61 | initBanner(); 62 | } 63 | 64 | private void initBanner() { 65 | banner = (BannerView) findViewById(R.id.banner); 66 | banner.setHintPadding(0, 20, 20,20); 67 | banner.setHintView(new TextHintView(this)); 68 | banner.setAdapter(new ImageNormalAdapter()); 69 | banner.setOnBannerClickListener(new BannerView.OnBannerClickListener() { 70 | @Override 71 | public void onItemClick(int position) { 72 | Toast.makeText(FourActivity.this, 73 | position+"被点击呢",Toast.LENGTH_SHORT).show(); 74 | } 75 | }); 76 | } 77 | 78 | 79 | 80 | private class ImageNormalAdapter extends AbsStaticPagerAdapter { 81 | 82 | @Override 83 | public View getView(ViewGroup container, int position) { 84 | ImageView view = new ImageView(container.getContext()); 85 | view.setScaleType(ImageView.ScaleType.CENTER_CROP); 86 | view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 87 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs[position]); 88 | Bitmap bitmap1 = ImageBitmapUtils.compressByQuality(bitmap, 50, false); 89 | view.setImageBitmap(bitmap1); 90 | return view; 91 | } 92 | 93 | @Override 94 | public int getCount() { 95 | return imgs.length; 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/ImageBitmapUtils.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.Matrix; 8 | import android.util.Log; 9 | 10 | import androidx.annotation.IntRange; 11 | 12 | import java.io.ByteArrayOutputStream; 13 | 14 | /** 15 | *
 16 |  *     @author 杨充
 17 |  *     blog  : https://github.com/yangchong211
 18 |  *     time  : 2017/11/26
 19 |  *     desc  : bitmap优化压缩工具类
 20 |  *     revise: 针对每个工具类,方法以及参数必须标注清晰
 21 |  * 
22 | */ 23 | public class ImageBitmapUtils { 24 | 25 | /* 26 | 质量压缩方法:在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的: 27 | 1、bitmap图片的大小不会改变 28 | 2、bytes.length是随着quality变小而变小的。 29 | 这样适合去传递二进制的图片数据,比如分享图片,要传入二进制数据过去,限制500kb之内。 30 | */ 31 | /** 32 | * 第一种:质量压缩法 33 | * @param image 目标原图 34 | * @param maxSize 最大的图片大小 35 | * @return bitmap,注意可以测试以下压缩前后bitmap的大小值 36 | */ 37 | public static Bitmap compressImage(Bitmap image , long maxSize) { 38 | int byteCount = image.getByteCount(); 39 | Log.i("yc压缩图片","压缩前大小"+byteCount); 40 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 41 | // 把ByteArrayInputStream数据生成图片 42 | Bitmap bitmap = null; 43 | // 质量压缩方法,options的值是0-100,这里100表示原来图片的质量,不压缩,把压缩后的数据存放到baos中 44 | image.compress(Bitmap.CompressFormat.JPEG, 100, baos); 45 | int options = 90; 46 | // 循环判断如果压缩后图片是否大于maxSize,大于继续压缩 47 | while (baos.toByteArray().length > maxSize) { 48 | // 重置baos即清空baos 49 | baos.reset(); 50 | // 这里压缩options%,把压缩后的数据存放到baos中 51 | image.compress(Bitmap.CompressFormat.JPEG, options, baos); 52 | // 每次都减少10,当为1的时候停止,options<10的时候,递减1 53 | if(options == 1){ 54 | break; 55 | }else if (options <= 10) { 56 | options -= 1; 57 | } else { 58 | options -= 10; 59 | } 60 | } 61 | byte[] bytes = baos.toByteArray(); 62 | if (bytes.length != 0) { 63 | // 把压缩后的数据baos存放到bytes中 64 | bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 65 | int byteCount1 = bitmap.getByteCount(); 66 | Log.i("yc压缩图片","压缩后大小"+byteCount1); 67 | } 68 | return bitmap; 69 | } 70 | 71 | 72 | /** 73 | * 第一种:质量压缩法 74 | * 75 | * @param src 源图片 76 | * @param maxByteSize 允许最大值字节数 77 | * @param recycle 是否回收 78 | * @return 质量压缩压缩过的图片 79 | */ 80 | public static Bitmap compressByQuality1(final Bitmap src, long maxByteSize, final boolean recycle) { 81 | if (src == null || src.getWidth() == 0 || src.getHeight() == 0 || maxByteSize <= 0) { 82 | return null; 83 | } 84 | Log.i("yc压缩图片","压缩前大小"+src.getByteCount()); 85 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 86 | src.compress(Bitmap.CompressFormat.JPEG, 100, baos); 87 | byte[] bytes; 88 | if (baos.size() <= maxByteSize) {// 最好质量的不大于最大字节,则返回最佳质量 89 | bytes = baos.toByteArray(); 90 | } else { 91 | baos.reset(); 92 | src.compress(Bitmap.CompressFormat.JPEG, 0, baos); 93 | if (baos.size() >= maxByteSize) { // 最差质量不小于最大字节,则返回最差质量 94 | bytes = baos.toByteArray(); 95 | } else { 96 | // 二分法寻找最佳质量 97 | int st = 0; 98 | int end = 100; 99 | int mid = 0; 100 | while (st < end) { 101 | mid = (st + end) / 2; 102 | baos.reset(); 103 | src.compress(Bitmap.CompressFormat.JPEG, mid, baos); 104 | int len = baos.size(); 105 | if (len == maxByteSize) { 106 | break; 107 | } else if (len > maxByteSize) { 108 | end = mid - 1; 109 | } else { 110 | st = mid + 1; 111 | } 112 | } 113 | if (end == mid - 1) { 114 | baos.reset(); 115 | src.compress(Bitmap.CompressFormat.JPEG, st, baos); 116 | } 117 | bytes = baos.toByteArray(); 118 | } 119 | } 120 | if (recycle && !src.isRecycled()){ 121 | src.recycle(); 122 | } 123 | Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 124 | Log.i("yc压缩图片","压缩后大小"+bitmap.getByteCount()); 125 | return bitmap; 126 | } 127 | 128 | 129 | /** 130 | * 第一种:质量压缩法 131 | * 132 | * @param src 源图片 133 | * @param quality 质量 134 | * @param recycle 是否回收 135 | * @return 质量压缩后的图片 136 | */ 137 | public static Bitmap compressByQuality(final Bitmap src, @IntRange(from = 0, to = 100) final int quality, final boolean recycle) { 138 | if (src == null || src.getWidth() == 0 || src.getHeight() == 0) { 139 | return null; 140 | } 141 | Log.i("yc压缩图片","压缩前大小"+src.getByteCount()); 142 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 143 | src.compress(Bitmap.CompressFormat.JPEG, quality, baos); 144 | byte[] bytes = baos.toByteArray(); 145 | if (recycle && !src.isRecycled()) { 146 | src.recycle(); 147 | } 148 | Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 149 | Log.i("yc压缩图片","压缩后大小"+bitmap.getByteCount()); 150 | return bitmap; 151 | } 152 | 153 | 154 | 155 | /** 156 | * 第二种:按采样大小压缩 157 | * 158 | * @param src 源图片 159 | * @param sampleSize 采样率大小 160 | * @param recycle 是否回收 161 | * @return 按采样率压缩后的图片 162 | */ 163 | public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize, final boolean recycle) { 164 | if (src == null || src.getWidth() == 0 || src.getHeight() == 0) { 165 | return null; 166 | } 167 | Log.i("yc压缩图片","压缩前大小"+src.getByteCount()); 168 | BitmapFactory.Options options = new BitmapFactory.Options(); 169 | options.inSampleSize = sampleSize; 170 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 171 | src.compress(Bitmap.CompressFormat.JPEG, 100, baos); 172 | byte[] bytes = baos.toByteArray(); 173 | if (recycle && !src.isRecycled()) { 174 | src.recycle(); 175 | } 176 | Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); 177 | Log.i("yc压缩图片","压缩后大小"+bitmap.getByteCount()); 178 | return bitmap; 179 | } 180 | 181 | 182 | /** 183 | * 第二种:按采样大小压缩 184 | * 185 | * @param src 源图片 186 | * @param maxWidth 最大宽度 187 | * @param maxHeight 最大高度 188 | * @param recycle 是否回收 189 | * @return 按采样率压缩后的图片 190 | */ 191 | public static Bitmap compressBySampleSize(final Bitmap src, final int maxWidth, final int maxHeight, final boolean recycle) { 192 | if (src == null || src.getWidth() == 0 || src.getHeight() == 0) { 193 | return null; 194 | } 195 | Log.i("yc压缩图片","压缩前大小"+src.getByteCount()); 196 | BitmapFactory.Options options = new BitmapFactory.Options(); 197 | options.inJustDecodeBounds = true; 198 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 199 | src.compress(Bitmap.CompressFormat.JPEG, 100, baos); 200 | byte[] bytes = baos.toByteArray(); 201 | BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); 202 | options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); 203 | options.inJustDecodeBounds = false; 204 | if (recycle && !src.isRecycled()) { 205 | src.recycle(); 206 | } 207 | Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); 208 | Log.i("yc压缩图片","压缩后大小"+bitmap.getByteCount()); 209 | return bitmap; 210 | } 211 | 212 | /** 213 | * 计算获取缩放比例inSampleSize 214 | */ 215 | private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 216 | final int height = options.outHeight; 217 | final int width = options.outWidth; 218 | int inSampleSize = 1; 219 | if (height > reqHeight || width > reqWidth) { 220 | final int heightRatio = Math.round((float) height / (float) reqHeight); 221 | final int widthRatio = Math.round((float) width / (float) reqWidth); 222 | inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; 223 | } 224 | final float totalPixels = width * height; 225 | final float totalReqPixelsCap = reqWidth * reqHeight * 2; 226 | while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { 227 | inSampleSize++; 228 | } 229 | return inSampleSize; 230 | } 231 | 232 | 233 | /** 234 | * 第三种:按缩放压缩 235 | * 236 | * @param src 源图片 237 | * @param newWidth 新宽度 238 | * @param newHeight 新高度 239 | * @param recycle 是否回收 240 | * @return 缩放压缩后的图片 241 | */ 242 | public static Bitmap compressByScale(final Bitmap src, final int newWidth, final int newHeight, final boolean recycle) { 243 | return scale(src, newWidth, newHeight, recycle); 244 | } 245 | 246 | /** 247 | * 第三种:按缩放压缩 248 | * 249 | * @param src 源图片 250 | * @param scaleWidth 缩放宽度倍数 251 | * @param scaleHeight 缩放高度倍数 252 | * @param recycle 是否回收 253 | * @return 缩放压缩后的图片 254 | */ 255 | public static Bitmap compressByScale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) { 256 | return scale(src, scaleWidth, scaleHeight, recycle); 257 | } 258 | 259 | /** 260 | * 缩放图片 261 | * 262 | * @param src 源图片 263 | * @param scaleWidth 缩放宽度倍数 264 | * @param scaleHeight 缩放高度倍数 265 | * @param recycle 是否回收 266 | * @return 缩放后的图片 267 | */ 268 | private static Bitmap scale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) { 269 | if (src == null || src.getWidth() == 0 || src.getHeight() == 0) { 270 | return null; 271 | } 272 | Matrix matrix = new Matrix(); 273 | matrix.setScale(scaleWidth, scaleHeight); 274 | Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); 275 | if (recycle && !src.isRecycled()) { 276 | src.recycle(); 277 | } 278 | return ret; 279 | } 280 | 281 | 282 | } 283 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Color; 7 | import android.os.Build; 8 | import android.os.Bundle; 9 | import android.text.SpannableString; 10 | import android.text.Spanned; 11 | import android.text.style.ForegroundColorSpan; 12 | import android.text.style.URLSpan; 13 | import android.util.Log; 14 | import android.view.View; 15 | import android.widget.TextView; 16 | 17 | import androidx.annotation.RequiresApi; 18 | import androidx.appcompat.app.AppCompatActivity; 19 | 20 | import com.yc.cn.ycbannerlib.marquee.MarqueeView; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.concurrent.atomic.AtomicInteger; 25 | 26 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 27 | 28 | private MarqueeView marqueeView; 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_main); 34 | 35 | findViewById(R.id.tv_1).setOnClickListener(this); 36 | findViewById(R.id.tv_2).setOnClickListener(this); 37 | findViewById(R.id.tv_3).setOnClickListener(this); 38 | findViewById(R.id.tv_4).setOnClickListener(this); 39 | findViewById(R.id.tv_5).setOnClickListener(this); 40 | findViewById(R.id.tv_6).setOnClickListener(this); 41 | findViewById(R.id.tv_7).setOnClickListener(this); 42 | findViewById(R.id.tv_8).setOnClickListener(this); 43 | findViewById(R.id.tv_9).setOnClickListener(this); 44 | marqueeView = findViewById(R.id.marqueeView); 45 | initMarqueeView(); 46 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 47 | initBitmap(); 48 | } 49 | } 50 | 51 | 52 | @RequiresApi(api = Build.VERSION_CODES.KITKAT) 53 | private void initBitmap() { 54 | BitmapFactory.Options options = new BitmapFactory.Options(); 55 | // 图片复用,这个属性必须设置; 56 | options.inMutable = true; 57 | // 手动设置缩放比例,使其取整数,方便计算、观察数据; 58 | options.inDensity = 320; 59 | options.inTargetDensity = 320; 60 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg_autumn_tree_min, options); 61 | // 对象内存地址; 62 | Log.i("ycBitmap", "bitmap = " + bitmap); 63 | Log.i("ycBitmap", "ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount()); 64 | // 使用inBitmap属性,这个属性必须设置; 65 | options.inBitmap = bitmap; options.inDensity = 320; 66 | // 设置缩放宽高为原始宽高一半; 67 | options.inTargetDensity = 160; 68 | options.inMutable = true; 69 | Bitmap bitmapReuse = BitmapFactory.decodeResource(getResources(), R.drawable.bg_kites_min, options); 70 | // 复用对象的内存地址; 71 | Log.i("ycBitmap", "bitmapReuse = " + bitmapReuse); 72 | Log.i("ycBitmap", "bitmap:ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount()); 73 | Log.i("ycBitmap", "bitmapReuse:ByteCount = " + bitmapReuse.getByteCount() + ":::bitmapReuse:AllocationByteCount = " + bitmapReuse.getAllocationByteCount()); 74 | 75 | //11-26 18:24:07.971 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap = android.graphics.Bitmap@9739bff 76 | //11-26 18:24:07.972 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 4346880:::bitmap:AllocationByteCount = 4346880 77 | //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse = android.graphics.Bitmap@9739bff 78 | //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 1228800:::bitmap:AllocationByteCount = 4346880 79 | //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse:ByteCount = 1228800:::bitmapReuse:AllocationByteCount = 4346880 80 | } 81 | 82 | @Override 83 | public void onClick(View v) { 84 | switch (v.getId()){ 85 | case R.id.tv_1: 86 | startActivity(new Intent(this, FirstActivity.class)); 87 | break; 88 | case R.id.tv_2: 89 | startActivity(new Intent(this, SecondActivity.class)); 90 | break; 91 | case R.id.tv_3: 92 | startActivity(new Intent(this, ThirdActivity.class)); 93 | break; 94 | case R.id.tv_4: 95 | startActivity(new Intent(this, FourActivity.class)); 96 | break; 97 | case R.id.tv_5: 98 | startActivity(new Intent(this, SplashActivity.class)); 99 | break; 100 | case R.id.tv_6: 101 | startActivity(new Intent(this, SixActivity.class)); 102 | break; 103 | case R.id.tv_7: 104 | startActivity(new Intent(this,SevenActivity.class)); 105 | break; 106 | case R.id.tv_8: 107 | startActivity(new Intent(this,EightActivity.class)); 108 | break; 109 | case R.id.tv_9: 110 | startActivity(new Intent(this,NightActivity.class)); 111 | break; 112 | default: 113 | break; 114 | } 115 | } 116 | 117 | 118 | private void initMarqueeView() { 119 | if (marqueeView == null) { 120 | return; 121 | } 122 | ArrayList list = getMarqueeTitle(); 123 | //根据公告字符串列表启动轮播 124 | marqueeView.startWithList(list); 125 | //设置点击事件 126 | marqueeView.setOnItemClickListener(new MarqueeView.OnItemClickListener() { 127 | @Override 128 | public void onItemClick(int position, TextView textView) { 129 | 130 | } 131 | }); 132 | } 133 | 134 | 135 | 136 | public ArrayList getMarqueeTitle() { 137 | ArrayList list = new ArrayList<>(); 138 | String[] title = getResources().getStringArray(R.array.main_marquee_title); 139 | SpannableString ss1 = new SpannableString(title[0]); 140 | ss1.setSpan(new ForegroundColorSpan(Color.BLACK), 2, title[0].length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 141 | list.add(ss1.toString()); 142 | SpannableString ss2 = new SpannableString(title[1]); 143 | ss2.setSpan(new ForegroundColorSpan(Color.BLACK), 2, title[1].length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 144 | list.add(ss2.toString()); 145 | SpannableString ss3 = new SpannableString(title[2]); 146 | ss3.setSpan(new URLSpan("http://www.ximalaya.com/zhubo/71989305/"), 2, title[2].length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 147 | list.add(ss3.toString()); 148 | return list; 149 | } 150 | 151 | 152 | } 153 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/NightActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.content.res.TypedArray; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.graphics.drawable.Drawable; 8 | import android.graphics.drawable.TransitionDrawable; 9 | import android.os.Bundle; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.widget.FrameLayout; 13 | 14 | import androidx.annotation.Nullable; 15 | import androidx.appcompat.app.AppCompatActivity; 16 | import androidx.recyclerview.widget.LinearLayoutManager; 17 | import androidx.recyclerview.widget.RecyclerView; 18 | 19 | import com.ns.yc.ycutilslib.blurView.blur.CustomBlur; 20 | import com.yc.gallerybannerlib.GalleryLayoutManager; 21 | import com.yc.gallerybannerlib.GalleryLinearSnapHelper; 22 | import com.yc.gallerybannerlib.GalleryRecyclerView; 23 | import com.yc.gallerybannerlib.GalleryScaleTransformer; 24 | 25 | import java.util.ArrayList; 26 | import java.util.HashMap; 27 | import java.util.Map; 28 | 29 | import cn.ycbjie.ycstatusbarlib.bar.StateAppBar; 30 | 31 | public class NightActivity extends AppCompatActivity { 32 | 33 | private GalleryRecyclerView mRecyclerView; 34 | private GalleryRecyclerView recyclerView2; 35 | private RecyclerView recyclerView3; 36 | private ArrayList data = new ArrayList<>(); 37 | private FrameLayout fl_container; 38 | 39 | @Override 40 | protected void onDestroy() { 41 | super.onDestroy(); 42 | mRecyclerView.release(); 43 | } 44 | 45 | @Override 46 | protected void onCreate(@Nullable Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | setContentView(R.layout.activity_night); 49 | StateAppBar.translucentStatusBar(this,true); 50 | mRecyclerView = findViewById(R.id.recyclerView); 51 | fl_container = findViewById(R.id.fl_container); 52 | recyclerView2 = findViewById(R.id.recyclerView2); 53 | recyclerView3 = findViewById(R.id.recyclerView3); 54 | initRecyclerView(); 55 | initRecyclerView2(); 56 | initRecyclerView3(); 57 | } 58 | 59 | private void initRecyclerView() { 60 | Snap3Adapter adapter = new Snap3Adapter(this); 61 | adapter.setData(getData()); 62 | mRecyclerView.setAdapter(adapter); 63 | mRecyclerView.setFlingSpeed(15000); 64 | mRecyclerView.setOnItemSelectedListener(new GalleryRecyclerView.OnItemSelectedListener() { 65 | @Override 66 | public void onItemSelected(RecyclerView recyclerView, View item, int position) { 67 | Log.e("onItemSelected-----", position + ""); 68 | //设置高斯模糊背景 69 | setBlurImage(true); 70 | } 71 | }); 72 | GalleryLayoutManager manager = new GalleryLayoutManager(this, LinearLayoutManager.HORIZONTAL); 73 | //attach,绑定recyclerView,并且设置默认选中索引的位置 74 | manager.attach(100); 75 | //设置缩放比例因子,在0到1.0之间即可 76 | manager.setItemTransformer(new GalleryScaleTransformer( 0.2f,30)); 77 | mRecyclerView.setLayoutManager(manager); 78 | GalleryLinearSnapHelper mSnapHelper = new GalleryLinearSnapHelper(mRecyclerView); 79 | mSnapHelper.attachToRecyclerView(mRecyclerView); 80 | mRecyclerView.onStart(); 81 | } 82 | 83 | private void initRecyclerView2() { 84 | Snap3Adapter adapter = new Snap3Adapter(this); 85 | adapter.setData(getData()); 86 | recyclerView2.setAdapter(adapter); 87 | recyclerView2.setFlingSpeed(8000); 88 | GalleryLayoutManager manager = new GalleryLayoutManager(this, LinearLayoutManager.HORIZONTAL); 89 | //attach,绑定recyclerView,并且设置默认选中索引的位置 90 | manager.attach(100); 91 | //设置缩放比例因子,在0到1.0之间即可 92 | manager.setItemTransformer(new GalleryScaleTransformer( 0.0f,30)); 93 | recyclerView2.setLayoutManager(manager); 94 | GalleryLinearSnapHelper mSnapHelper = new GalleryLinearSnapHelper(recyclerView2); 95 | mSnapHelper.attachToRecyclerView(recyclerView2); 96 | recyclerView2.onStart(); 97 | } 98 | 99 | 100 | private void initRecyclerView3() { 101 | GalleryLayoutManager manager = new GalleryLayoutManager(this, LinearLayoutManager.HORIZONTAL); 102 | manager.attach(recyclerView3,100); 103 | manager.setItemTransformer(new GalleryScaleTransformer( 0.0f,30)); 104 | recyclerView3.setLayoutManager(manager); 105 | Snap3Adapter adapter = new Snap3Adapter(this); 106 | adapter.setData(getData()); 107 | recyclerView3.setAdapter(adapter); 108 | } 109 | 110 | 111 | private ArrayList getData(){ 112 | data.clear(); 113 | TypedArray bannerImage = getResources().obtainTypedArray(R.array.banner_image); 114 | for (int i = 0; i < 12 ; i++) { 115 | int image = bannerImage.getResourceId(i, R.drawable.beauty1); 116 | data.add(image); 117 | } 118 | bannerImage.recycle(); 119 | return data; 120 | } 121 | 122 | 123 | /** 124 | * 获取虚化背景的位置 125 | */ 126 | private int mLastDraPosition = -1; 127 | private Map mTSDraCacheMap = new HashMap<>(); 128 | private static final String KEY_PRE_DRAW = "key_pre_draw"; 129 | /** 130 | * 设置背景高斯模糊 131 | */ 132 | public void setBlurImage(boolean forceUpdate) { 133 | final Snap3Adapter adapter = (Snap3Adapter) mRecyclerView.getAdapter(); 134 | final int mCurViewPosition = mRecyclerView.getCurrentItem(); 135 | 136 | boolean isSamePosAndNotUpdate = (mCurViewPosition == mLastDraPosition) && !forceUpdate; 137 | 138 | if (adapter == null || mRecyclerView == null || isSamePosAndNotUpdate) { 139 | return; 140 | } 141 | mRecyclerView.post(new Runnable() { 142 | @Override 143 | public void run() { 144 | // 获取当前位置的图片资源ID 145 | int resourceId = adapter.getData().get(mCurViewPosition%adapter.getData().size()); 146 | // 将该资源图片转为Bitmap 147 | Bitmap resBmp = BitmapFactory.decodeResource(getResources(), resourceId); 148 | // 将该Bitmap高斯模糊后返回到resBlurBmp 149 | Bitmap resBlurBmp = CustomBlur.apply(mRecyclerView.getContext(), resBmp, 10); 150 | // 再将resBlurBmp转为Drawable 151 | Drawable resBlurDrawable = new BitmapDrawable(resBlurBmp); 152 | // 获取前一页的Drawable 153 | Drawable preBlurDrawable = mTSDraCacheMap.get(KEY_PRE_DRAW) == null ? resBlurDrawable : mTSDraCacheMap.get(KEY_PRE_DRAW); 154 | 155 | /* 以下为淡入淡出效果 */ 156 | Drawable[] drawableArr = {preBlurDrawable, resBlurDrawable}; 157 | TransitionDrawable transitionDrawable = new TransitionDrawable(drawableArr); 158 | fl_container.setBackgroundDrawable(transitionDrawable); 159 | transitionDrawable.startTransition(500); 160 | 161 | // 存入到cache中 162 | mTSDraCacheMap.put(KEY_PRE_DRAW, resBlurDrawable); 163 | // 记录上一次高斯模糊的位置 164 | mLastDraPosition = mCurViewPosition; 165 | } 166 | }); 167 | } 168 | 169 | 170 | 171 | } 172 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/SecondActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import androidx.annotation.Nullable; 11 | import androidx.appcompat.app.AppCompatActivity; 12 | 13 | import com.yc.cn.ycbannerlib.banner.view.BannerView; 14 | import com.yc.cn.ycbannerlib.banner.adapter.AbsLoopPagerAdapter; 15 | 16 | /** 17 | * Created by PC on 2017/11/21. 18 | * 作者:PC 19 | */ 20 | 21 | public class SecondActivity extends AppCompatActivity { 22 | 23 | private int[] imgs = { 24 | R.drawable.bg_kites_min, 25 | R.drawable.bg_autumn_tree_min, 26 | R.drawable.bg_lake_min, 27 | R.drawable.bg_leaves_min, 28 | R.drawable.bg_magnolia_trees_min, 29 | }; 30 | private BannerView banner; 31 | 32 | @Override 33 | protected void onDestroy() { 34 | super.onDestroy(); 35 | } 36 | 37 | @Override 38 | protected void onPause() { 39 | super.onPause(); 40 | if(banner!=null){ 41 | banner.pause(); 42 | } 43 | } 44 | 45 | @Override 46 | protected void onResume() { 47 | super.onResume(); 48 | if(banner!=null){ 49 | banner.resume(); 50 | } 51 | } 52 | 53 | @Override 54 | protected void onCreate(@Nullable Bundle savedInstanceState) { 55 | super.onCreate(savedInstanceState); 56 | setContentView(R.layout.activity_second); 57 | 58 | initBanner(); 59 | } 60 | 61 | private void initBanner() { 62 | banner = (BannerView) findViewById(R.id.banner); 63 | banner.setAdapter(new ImageNormalAdapter(banner)); 64 | banner.setHintGravity(1); 65 | banner.setPlayDelay(2000); 66 | banner.setHintPadding(20,0, 20,20); 67 | banner.setOnBannerClickListener(new BannerView.OnBannerClickListener() { 68 | @Override 69 | public void onItemClick(int position) { 70 | 71 | } 72 | }); 73 | } 74 | 75 | 76 | private class ImageNormalAdapter extends AbsLoopPagerAdapter { 77 | 78 | public ImageNormalAdapter(BannerView viewPager) { 79 | super(viewPager); 80 | } 81 | 82 | @Override 83 | public View getView(ViewGroup container, int position) { 84 | ImageView view = new ImageView(container.getContext()); 85 | view.setScaleType(ImageView.ScaleType.CENTER_CROP); 86 | view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 87 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs[position]); 88 | Bitmap bitmap1 = ImageBitmapUtils.compressByQuality(bitmap, 50, false); 89 | view.setImageBitmap(bitmap1); 90 | return view; 91 | } 92 | 93 | @Override 94 | public int getRealCount() { 95 | return imgs.length; 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/SevenActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.os.Bundle; 4 | import android.view.Gravity; 5 | 6 | import androidx.annotation.Nullable; 7 | import androidx.appcompat.app.AppCompatActivity; 8 | import androidx.recyclerview.widget.LinearLayoutManager; 9 | import androidx.recyclerview.widget.LinearSnapHelper; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | 12 | import com.yc.snapbannerlib.ScrollLinearHelper; 13 | import com.yc.snapbannerlib.ScrollPageHelper; 14 | import com.yc.snapbannerlib.ScrollSnapHelper; 15 | 16 | import java.util.ArrayList; 17 | 18 | 19 | public class SevenActivity extends AppCompatActivity { 20 | 21 | private RecyclerView mRecyclerView; 22 | private RecyclerView mRecyclerView2; 23 | private RecyclerView mRecyclerView3; 24 | private RecyclerView mRecyclerView4; 25 | private ArrayList data = new ArrayList<>(); 26 | 27 | @Override 28 | protected void onCreate(@Nullable Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_seven); 31 | mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); 32 | mRecyclerView2 = (RecyclerView) findViewById(R.id.recyclerView2); 33 | mRecyclerView3 = (RecyclerView) findViewById(R.id.recyclerView3); 34 | mRecyclerView4 = (RecyclerView) findViewById(R.id.recyclerView4); 35 | initRecyclerView(); 36 | initRecyclerView2(); 37 | initRecyclerView3(); 38 | initRecyclerView4(); 39 | } 40 | 41 | private void initRecyclerView() { 42 | LinearLayoutManager manager = new LinearLayoutManager(this); 43 | manager.setOrientation(LinearLayoutManager.HORIZONTAL); 44 | mRecyclerView.setLayoutManager(manager); 45 | ScrollLinearHelper snapHelper = new ScrollLinearHelper(); 46 | snapHelper.attachToRecyclerView(mRecyclerView); 47 | SnapAdapter adapter = new SnapAdapter(this); 48 | mRecyclerView.setAdapter(adapter); 49 | adapter.addAll(getData()); 50 | } 51 | 52 | private void initRecyclerView2() { 53 | LinearLayoutManager manager = new LinearLayoutManager(this); 54 | manager.setOrientation(LinearLayoutManager.HORIZONTAL); 55 | mRecyclerView2.setLayoutManager(manager); 56 | LinearSnapHelper snapHelper = new LinearSnapHelper(); 57 | snapHelper.attachToRecyclerView(mRecyclerView2); 58 | SnapAdapter adapter = new SnapAdapter(this); 59 | mRecyclerView2.setAdapter(adapter); 60 | adapter.addAll(getData()); 61 | } 62 | 63 | 64 | private void initRecyclerView3() { 65 | LinearLayoutManager manager = new LinearLayoutManager(this); 66 | manager.setOrientation(LinearLayoutManager.HORIZONTAL); 67 | mRecyclerView3.setLayoutManager(manager); 68 | ScrollPageHelper snapHelper = new ScrollPageHelper(Gravity.START,false); 69 | snapHelper.attachToRecyclerView(mRecyclerView3); 70 | SnapAdapter adapter = new SnapAdapter(this); 71 | mRecyclerView3.setAdapter(adapter); 72 | adapter.addAll(getData()); 73 | } 74 | 75 | 76 | private void initRecyclerView4() { 77 | LinearLayoutManager manager = new LinearLayoutManager(this); 78 | manager.setOrientation(LinearLayoutManager.HORIZONTAL); 79 | mRecyclerView4.setLayoutManager(manager); 80 | ScrollSnapHelper snapHelper = new ScrollSnapHelper(); 81 | snapHelper.attachToRecyclerView(mRecyclerView4); 82 | SnapAdapter adapter = new SnapAdapter(this); 83 | mRecyclerView4.setAdapter(adapter); 84 | adapter.addAll(getData()); 85 | } 86 | 87 | 88 | 89 | private ArrayList getData(){ 90 | for (int a=0 ; a<20 ; a++){ 91 | data.add("测试数据"+a); 92 | } 93 | return data; 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/SixActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.Toast; 10 | 11 | import androidx.annotation.Nullable; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | 14 | import com.yc.cn.ycbannerlib.banner.view.BannerView; 15 | import com.yc.cn.ycbannerlib.banner.adapter.AbsStaticPagerAdapter; 16 | import com.yc.cn.ycbannerlib.banner.hintview.IconHintView; 17 | 18 | /** 19 | * Created by PC on 2017/11/21. 20 | * 作者:PC 21 | */ 22 | 23 | public class SixActivity extends AppCompatActivity { 24 | 25 | private int[] imgs = { 26 | R.drawable.bg_kites_min, 27 | R.drawable.bg_autumn_tree_min, 28 | R.drawable.bg_lake_min, 29 | R.drawable.bg_leaves_min, 30 | R.drawable.bg_magnolia_trees_min, 31 | }; 32 | private BannerView banner; 33 | 34 | @Override 35 | protected void onDestroy() { 36 | super.onDestroy(); 37 | } 38 | 39 | @Override 40 | protected void onPause() { 41 | super.onPause(); 42 | if(banner!=null){ 43 | banner.pause(); 44 | } 45 | } 46 | 47 | @Override 48 | protected void onResume() { 49 | super.onResume(); 50 | if(banner!=null){ 51 | banner.resume(); 52 | } 53 | } 54 | 55 | @Override 56 | protected void onCreate(@Nullable Bundle savedInstanceState) { 57 | super.onCreate(savedInstanceState); 58 | setContentView(R.layout.activity_four); 59 | 60 | initBanner(); 61 | } 62 | 63 | private void initBanner() { 64 | banner = (BannerView) findViewById(R.id.banner); 65 | banner.setAnimationDuration(1000); 66 | banner.setHintGravity(1); 67 | banner.setHintPadding(0, 20,0,20); 68 | banner.setPlayDelay(2000); 69 | banner.setHintView(new IconHintView(this,R.drawable.point_focus,R.drawable.point_normal)); 70 | banner.setAdapter(new ImageNormalAdapter()); 71 | banner.setOnBannerClickListener(new BannerView.OnBannerClickListener() { 72 | @Override 73 | public void onItemClick(int position) { 74 | Toast.makeText(SixActivity.this,position+"被点击呢",Toast.LENGTH_SHORT).show(); 75 | } 76 | }); 77 | } 78 | 79 | 80 | private class ImageNormalAdapter extends AbsStaticPagerAdapter { 81 | 82 | @Override 83 | public View getView(ViewGroup container, int position) { 84 | ImageView view = new ImageView(container.getContext()); 85 | view.setScaleType(ImageView.ScaleType.CENTER_CROP); 86 | view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 87 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs[position]); 88 | Bitmap bitmap1 = ImageBitmapUtils.compressByScale(bitmap,2.0f,2.0f,false); 89 | view.setImageBitmap(bitmap1); 90 | return view; 91 | } 92 | 93 | @Override 94 | public int getCount() { 95 | return imgs.length; 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/Snap2Adapter.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | 4 | import android.content.Context; 5 | import android.util.Log; 6 | import android.view.ViewGroup; 7 | import android.widget.ImageView; 8 | import android.widget.TextView; 9 | 10 | import com.yc.cn.ycbaseadapterlib.adapter.BaseAdapter; 11 | import com.yc.cn.ycbaseadapterlib.adapter.BaseViewHolder; 12 | import com.yc.cn.ycbaseadapterlib.itemType.BaseMViewHolder; 13 | import com.yc.cn.ycbaseadapterlib.itemType.RecyclerArrayAdapter; 14 | 15 | import java.util.List; 16 | 17 | public class Snap2Adapter extends BaseAdapter { 18 | 19 | 20 | Snap2Adapter(Context context) { 21 | super(context, R.layout.item_snap2); 22 | } 23 | 24 | 25 | @Override 26 | protected void bindData(BaseViewHolder holder, Integer data) { 27 | Integer integer = getData().get(getViewPosition() % getData().size()); 28 | ImageView imageView = holder.getView(R.id.iv_image); 29 | imageView.setBackgroundResource(integer); 30 | } 31 | 32 | @Override 33 | public int getItemCount() { 34 | if (getData().size() != 1) { 35 | Log.e("getItemCount","getItemCount---------"); 36 | return Integer.MAX_VALUE; // 无限轮播 37 | } else { 38 | Log.e("getItemCount","getItemCount++++----"); 39 | return getData().size(); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/Snap3Adapter.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | 4 | import android.content.Context; 5 | import android.util.Log; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.recyclerview.widget.RecyclerView; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class Snap3Adapter extends RecyclerView.Adapter { 19 | 20 | 21 | private Context mContext; 22 | Snap3Adapter(Context context){ 23 | this.mContext =context; 24 | } 25 | 26 | private List urlList = new ArrayList<>(); 27 | public void setData(List list) { 28 | urlList.clear(); 29 | this.urlList = list; 30 | } 31 | 32 | public List getData() { 33 | return urlList; 34 | } 35 | 36 | @NonNull 37 | @Override 38 | public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 39 | View view = LayoutInflater.from(mContext).inflate(R.layout.item_snap2, parent, false); 40 | return new MyViewHolder(view); 41 | } 42 | 43 | @Override 44 | public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { 45 | if (urlList == null || urlList.isEmpty()) 46 | return; 47 | Integer url = urlList.get(position%urlList.size()); 48 | // Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), url); 49 | // Bitmap bitmap1 = ImageBitmapUtils.compressByQuality(bitmap, 60,false); 50 | // holder.imageView.setImageBitmap(bitmap1); 51 | 52 | holder.imageView.setBackgroundResource(url); 53 | } 54 | 55 | 56 | class MyViewHolder extends RecyclerView.ViewHolder{ 57 | ImageView imageView; 58 | MyViewHolder(View itemView) { 59 | super(itemView); 60 | imageView = itemView.findViewById(R.id.iv_image); 61 | } 62 | 63 | } 64 | 65 | @Override 66 | public int getItemCount() { 67 | if (urlList.size() != 1) { 68 | Log.e("getItemCount","getItemCount---------"); 69 | return Integer.MAX_VALUE; // 无限轮播 70 | } else { 71 | Log.e("getItemCount","getItemCount++++----"); 72 | return urlList.size(); 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/SnapAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | 4 | import android.content.Context; 5 | import android.view.ViewGroup; 6 | import android.widget.ImageView; 7 | import android.widget.TextView; 8 | 9 | import com.yc.cn.ycbaseadapterlib.itemType.BaseMViewHolder; 10 | import com.yc.cn.ycbaseadapterlib.itemType.RecyclerArrayAdapter; 11 | 12 | public class SnapAdapter extends RecyclerArrayAdapter{ 13 | 14 | 15 | 16 | 17 | public SnapAdapter(Context context) { 18 | super(context); 19 | } 20 | 21 | @Override 22 | public BaseMViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) { 23 | return new MyViewHolder(parent); 24 | } 25 | 26 | private class MyViewHolder extends BaseMViewHolder { 27 | 28 | private final ImageView imageView; 29 | private final TextView textView; 30 | 31 | MyViewHolder(ViewGroup parent) { 32 | super(parent, R.layout.item_snap); 33 | imageView = getView(R.id.iv_image); 34 | textView = getView(R.id.tv_title); 35 | } 36 | 37 | @Override 38 | public void setData(String data) { 39 | super.setData(data); 40 | imageView.setBackgroundResource(R.drawable.bg_kites_min); 41 | textView.setText(data); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.Button; 8 | import android.widget.ImageView; 9 | 10 | import androidx.annotation.Nullable; 11 | import androidx.appcompat.app.AppCompatActivity; 12 | 13 | import com.yc.cn.ycbannerlib.banner.view.BannerView; 14 | import com.yc.cn.ycbannerlib.banner.adapter.AbsDynamicPagerAdapter; 15 | 16 | 17 | 18 | /** 19 | * Created by yc on 2018/4/10. 20 | */ 21 | 22 | public class SplashActivity extends AppCompatActivity { 23 | 24 | private int[] imgs = { 25 | R.drawable.bg_kites_min, 26 | R.drawable.bg_autumn_tree_min, 27 | R.drawable.bg_lake_min, 28 | R.drawable.bg_leaves_min, 29 | R.drawable.bg_magnolia_trees_min, 30 | }; 31 | private BannerView banner; 32 | private Button btn; 33 | 34 | @Override 35 | protected void onCreate(@Nullable Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_five); 38 | initBanner(); 39 | initListener(); 40 | } 41 | 42 | private void initListener() { 43 | btn = (Button) findViewById(R.id.btn); 44 | btn.setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(View v) { 47 | startActivity(new Intent(SplashActivity.this, MainActivity.class)); 48 | } 49 | }); 50 | } 51 | 52 | 53 | private void initBanner() { 54 | banner = (BannerView) findViewById(R.id.banner); 55 | banner.setPlayDelay(0); 56 | banner.setAdapter(new ImageNormalAdapter()); 57 | banner.setHintGravity(1); 58 | banner.setHintPadding(20,0, 20,20); 59 | banner.setOnBannerClickListener(new BannerView.OnBannerClickListener() { 60 | @Override 61 | public void onItemClick(int position) { 62 | 63 | } 64 | }); 65 | banner.setOnPageListener(new BannerView.OnPageListener() { 66 | @Override 67 | public void onPageChange(int position) { 68 | if(position==imgs.length-1){ 69 | btn.setVisibility(View.VISIBLE); 70 | }else { 71 | btn.setVisibility(View.GONE); 72 | } 73 | } 74 | }); 75 | } 76 | 77 | 78 | 79 | private class ImageNormalAdapter extends AbsDynamicPagerAdapter { 80 | 81 | @Override 82 | public View getView(ViewGroup container, int position) { 83 | ImageView view = new ImageView(container.getContext()); 84 | view.setScaleType(ImageView.ScaleType.CENTER_CROP); 85 | view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 86 | ViewGroup.LayoutParams.MATCH_PARENT)); 87 | view.setImageResource(imgs[position]); 88 | return view; 89 | } 90 | 91 | @Override 92 | public int getCount() { 93 | return imgs.length; 94 | } 95 | } 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/yc/cn/ycbanner/ThirdActivity.java: -------------------------------------------------------------------------------- 1 | package com.yc.cn.ycbanner; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.view.Gravity; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.Toast; 12 | 13 | import androidx.annotation.Nullable; 14 | import androidx.appcompat.app.AppCompatActivity; 15 | 16 | import com.yc.cn.ycbannerlib.banner.view.BannerView; 17 | import com.yc.cn.ycbannerlib.banner.adapter.AbsLoopPagerAdapter; 18 | 19 | /** 20 | * Created by PC on 2017/11/21. 21 | * 作者:PC 22 | */ 23 | 24 | public class ThirdActivity extends AppCompatActivity { 25 | 26 | private int[] imgs = { 27 | R.drawable.bg_kites_min, 28 | R.drawable.bg_autumn_tree_min, 29 | R.drawable.bg_lake_min, 30 | R.drawable.bg_leaves_min, 31 | R.drawable.bg_magnolia_trees_min, 32 | }; 33 | private BannerView banner; 34 | 35 | @Override 36 | protected void onDestroy() { 37 | super.onDestroy(); 38 | } 39 | 40 | @Override 41 | protected void onPause() { 42 | super.onPause(); 43 | if(banner!=null){ 44 | banner.pause(); 45 | } 46 | } 47 | 48 | @Override 49 | protected void onResume() { 50 | super.onResume(); 51 | if(banner!=null){ 52 | banner.resume(); 53 | } 54 | } 55 | 56 | @Override 57 | protected void onCreate(@Nullable Bundle savedInstanceState) { 58 | super.onCreate(savedInstanceState); 59 | setContentView(R.layout.activity_third); 60 | 61 | initBanner(); 62 | } 63 | 64 | private void initBanner() { 65 | banner = (BannerView) findViewById(R.id.banner); 66 | banner.setHintColor(Color.GRAY); 67 | banner.setHintGravity(Gravity.RIGHT); 68 | banner.setAnimationDuration(1000); 69 | banner.setHintPadding(0, 20,0,20); 70 | banner.setPlayDelay(2000); 71 | banner.setAdapter(new ImageNormalAdapter(banner)); 72 | banner.setOnBannerClickListener(new BannerView.OnBannerClickListener() { 73 | @Override 74 | public void onItemClick(int position) { 75 | Toast.makeText(ThirdActivity.this,position+"被点击呢",Toast.LENGTH_SHORT).show(); 76 | } 77 | }); 78 | } 79 | 80 | 81 | private class ImageNormalAdapter extends AbsLoopPagerAdapter { 82 | 83 | ImageNormalAdapter(BannerView viewPager) { 84 | super(viewPager); 85 | } 86 | 87 | @Override 88 | public View getView(ViewGroup container, int position) { 89 | ImageView view = new ImageView(container.getContext()); 90 | view.setScaleType(ImageView.ScaleType.CENTER_CROP); 91 | view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 92 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imgs[position]); 93 | Bitmap bitmap1 = ImageBitmapUtils.compressByQuality1(bitmap, 10240,false); 94 | view.setImageBitmap(bitmap1); 95 | return view; 96 | } 97 | 98 | 99 | @Override 100 | public int getRealCount() { 101 | return imgs.length; 102 | } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_autumn_tree_min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xhdpi/bg_autumn_tree_min.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_kites_min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xhdpi/bg_kites_min.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_lake_min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xhdpi/bg_lake_min.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_leaves_min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xhdpi/bg_leaves_min.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_magnolia_trees_min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xhdpi/bg_magnolia_trees_min.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/point_focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xhdpi/point_focus.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/point_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xhdpi/point_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty10.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty11.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty12.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty13.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty4.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty5.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty6.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty7.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty8.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/beauty9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangchong211/YCBannerView/22d2a7fe1651c097877f84e619f1a1c71179b359/app/src/main/res/drawable-xxhdpi/beauty9.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_eight.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_first.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_five.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 13 | 14 |