├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zhouwei │ │ └── mzbannerview │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ │ └── com │ │ │ └── zhouwei │ │ │ └── mzbannerview │ │ │ ├── AppConfig.java │ │ │ ├── DataEntry.java │ │ │ ├── MZApplication.java │ │ │ ├── MZModeBannerFragment.java │ │ │ ├── MZModeNotCoverFragment.java │ │ │ ├── MainActivity.java │ │ │ ├── NormalViewPagerFragment.java │ │ │ ├── StatusBarUtils.java │ │ │ ├── http │ │ │ ├── BaseResponse.java │ │ │ ├── BasicParamsInterceptor.java │ │ │ ├── Fault.java │ │ │ ├── HttpCommonInterceptor.java │ │ │ ├── ObjectLoader.java │ │ │ ├── PayLoad.java │ │ │ └── RetrofitServiceManager.java │ │ │ └── remote │ │ │ ├── DataLoader.java │ │ │ ├── Movie.java │ │ │ ├── MovieLoader.java │ │ │ ├── MovieSubject.java │ │ │ └── RemoteTestFragment.java │ └── res │ │ ├── drawable │ │ ├── dot_select_image.xml │ │ ├── dot_unselect_image.xml │ │ ├── ic_format_list_bulleted_black_24dp.xml │ │ └── ic_more_vert_black_24dp.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── banner_item.xml │ │ ├── banner_item_padding.xml │ │ ├── home_activity.xml │ │ ├── mz_mode_not_cover.xml │ │ ├── normal_banner_item.xml │ │ ├── normal_view_pager_layout.xml │ │ ├── remote_banner_item.xml │ │ └── remote_test_layout.xml │ │ ├── menu │ │ └── setting.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── banner1.png │ │ ├── banner2.png │ │ ├── banner3.png │ │ ├── banner4.png │ │ ├── banner5.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── image1.jpg │ │ ├── image2.jpeg │ │ ├── image3.jpeg │ │ ├── image4.jpeg │ │ ├── image5.jpeg │ │ ├── image6.jpeg │ │ ├── image7.jpeg │ │ └── image8.jpeg │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── zhouwei │ └── mzbannerview │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image ├── MZBannerView.gif ├── MZBanner普通ViewPager效果.gif ├── demo二维码.png ├── gzh.jpg ├── meizuappbanner.gif ├── network_data.gif ├── 仿魅族Banner效果.gif ├── 魅族Banner_fial.gif └── 魅族bannerView.gif ├── mzbanner ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zhouwei │ │ └── mzbanner │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zhouwei │ │ │ └── mzbanner │ │ │ ├── CustomViewPager.java │ │ │ ├── MZBannerView.java │ │ │ ├── holder │ │ │ ├── MZHolderCreator.java │ │ │ └── MZViewHolder.java │ │ │ └── transformer │ │ │ ├── CoverModeTransformer.java │ │ │ └── ScaleYTransformer.java │ └── res │ │ ├── drawable │ │ ├── indicator_normal.xml │ │ └── indicator_selected.xml │ │ ├── layout │ │ ├── mz_banner_effect_layout.xml │ │ └── mz_banner_normal_layout.xml │ │ └── values │ │ ├── attr.xml │ │ ├── ids.xml │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── zhouwei │ └── mzbanner │ └── ExampleUnitTest.java ├── readme.md └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Android 39 | 40 | 41 | Android > Lint > Correctness 42 | 43 | 44 | Android > Lint > Correctness > Messages 45 | 46 | 47 | Android > Lint > Performance 48 | 49 | 50 | CorrectnessLintAndroid 51 | 52 | 53 | General 54 | 55 | 56 | Java 57 | 58 | 59 | LintAndroid 60 | 61 | 62 | Numeric issuesJava 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 84 | 85 | 86 | 87 | 88 | 89 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.zhouwei.mzbannerview" 8 | minSdkVersion 16 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.3.1' 28 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 29 | testCompile 'junit:junit:4.12' 30 | //compile project(':mzbanner') 31 | //compile 'com.github.pinguo-zhouwei:MZBannerView:v1.1.1' 32 | compile 'com.github.pinguo-zhouwei:MZBannerView:v2.0.2' 33 | 34 | compile 'com.squareup.retrofit2:retrofit:2.1.0' 35 | compile 'com.google.code.gson:gson:2.6.2' 36 | compile 'io.reactivex:rxjava:1.1.0' 37 | compile 'io.reactivex:rxandroid:1.1.0' 38 | compile 'com.squareup.retrofit2:converter-gson:2.1.0' 39 | compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' 40 | 41 | compile 'com.squareup.picasso:picasso:2.5.2' 42 | 43 | compile 'com.github.anrwatchdog:anrwatchdog:1.3.0' 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/zhouwei/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/zhouwei/mzbannerview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zhouwei.mzbannerview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/AppConfig.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview; 2 | 3 | /** 4 | * Created by zhouwei on 17/6/8. 5 | */ 6 | 7 | public class AppConfig { 8 | /** 9 | * 服务器地址,应该根据 DEBUG 判断选用哪个环境 10 | */ 11 | public static final String BASE_URL = "https://api.douban.com/v2/movie/"; 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/DataEntry.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview; 2 | 3 | /** 4 | * Created by zhouwei on 17/5/31. 5 | */ 6 | 7 | public class DataEntry { 8 | public int resId; 9 | public String title; 10 | public String desc; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/MZApplication.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview; 2 | 3 | import android.app.Application; 4 | 5 | /** 6 | * Created by zhouwei on 17/6/10. 7 | */ 8 | 9 | public class MZApplication extends Application { 10 | @Override 11 | public void onCreate() { 12 | super.onCreate(); 13 | //ANR检测 14 | // new ANRWatchDog().start(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/MZModeBannerFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v4.view.ViewPager; 8 | import android.util.Log; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.ImageView; 13 | import android.widget.Toast; 14 | 15 | import com.zhouwei.mzbanner.MZBannerView; 16 | import com.zhouwei.mzbanner.holder.MZHolderCreator; 17 | import com.zhouwei.mzbanner.holder.MZViewHolder; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * Created by zhouwei on 17/5/31. 24 | */ 25 | 26 | public class MZModeBannerFragment extends Fragment{ 27 | public static final String TAG = "MZModeBannerFragment"; 28 | public static final int []RES = new int[]{R.mipmap.image5,R.mipmap.image2,R.mipmap.image3,R.mipmap.image4,R.mipmap.image6,R.mipmap.image7,R.mipmap.image8}; 29 | public static final int []BANNER = new int[]{R.mipmap.banner1,R.mipmap.banner2,R.mipmap.banner3,R.mipmap.banner4,R.mipmap.banner5}; 30 | private MZBannerView mMZBanner; 31 | private MZBannerView mNormalBanner; 32 | 33 | 34 | public static MZModeBannerFragment newInstance(){ 35 | return new MZModeBannerFragment(); 36 | } 37 | 38 | private void initView(View view) { 39 | 40 | mMZBanner = (MZBannerView) view.findViewById(R.id.banner); 41 | mMZBanner.setBannerPageClickListener(new MZBannerView.BannerPageClickListener() { 42 | @Override 43 | public void onPageClick(View view, int position) { 44 | Toast.makeText(getContext(),"click page:"+position,Toast.LENGTH_LONG).show(); 45 | } 46 | }); 47 | mMZBanner.addPageChangeListener(new ViewPager.OnPageChangeListener() { 48 | @Override 49 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 50 | Log.e(TAG,"----->addPageChangeLisnter:"+position + "positionOffset:"+positionOffset+ "positionOffsetPixels:"+positionOffsetPixels); 51 | } 52 | 53 | @Override 54 | public void onPageSelected(int position) { 55 | Log.e(TAG,"addPageChangeLisnter:"+position); 56 | } 57 | 58 | @Override 59 | public void onPageScrollStateChanged(int state) { 60 | 61 | } 62 | }); 63 | List list = new ArrayList<>(); 64 | for(int i=0;i bannerList = new ArrayList<>(); 69 | for(int i=0;i() { 77 | @Override 78 | public BannerViewHolder createViewHolder() { 79 | return new BannerViewHolder(); 80 | } 81 | }); 82 | 83 | mNormalBanner = (MZBannerView) view.findViewById(R.id.banner_normal); 84 | mNormalBanner.setPages(list, new MZHolderCreator() { 85 | @Override 86 | public BannerViewHolder createViewHolder() { 87 | return new BannerViewHolder(); 88 | } 89 | }); 90 | 91 | 92 | } 93 | 94 | public static class BannerViewHolder implements MZViewHolder { 95 | private ImageView mImageView; 96 | @Override 97 | public View createView(Context context) { 98 | // 返回页面布局文件 99 | View view = LayoutInflater.from(context).inflate(R.layout.banner_item,null); 100 | mImageView = (ImageView) view.findViewById(R.id.banner_image); 101 | return view; 102 | } 103 | 104 | @Override 105 | public void onBind(Context context, int position, Integer data) { 106 | // 数据绑定 107 | mImageView.setImageResource(data); 108 | } 109 | } 110 | @Nullable 111 | @Override 112 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 113 | View view = inflater.inflate(R.layout.activity_main,null); 114 | initView(view); 115 | return view; 116 | } 117 | 118 | @Override 119 | public void onPause() { 120 | super.onPause(); 121 | mMZBanner.pause(); 122 | mNormalBanner.pause(); 123 | } 124 | 125 | @Override 126 | public void onResume() { 127 | super.onResume(); 128 | mMZBanner.start(); 129 | mNormalBanner.start(); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/MZModeNotCoverFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v4.view.ViewPager; 8 | import android.util.Log; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.ImageView; 13 | import android.widget.Toast; 14 | 15 | import com.zhouwei.mzbanner.MZBannerView; 16 | import com.zhouwei.mzbanner.holder.MZHolderCreator; 17 | import com.zhouwei.mzbanner.holder.MZViewHolder; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * Created by zhouwei on 17/5/31. 24 | */ 25 | 26 | public class MZModeNotCoverFragment extends Fragment{ 27 | public static final String TAG = "MZModeBannerFragment"; 28 | public static final int []RES = new int[]{R.mipmap.image5,R.mipmap.image2,R.mipmap.image3,R.mipmap.image4,R.mipmap.image6,R.mipmap.image7,R.mipmap.image8}; 29 | public static final int []BANNER = new int[]{R.mipmap.banner1,R.mipmap.banner2,R.mipmap.banner3,R.mipmap.banner4,R.mipmap.banner5}; 30 | private MZBannerView mMZBanner; 31 | private MZBannerView mNormalBanner; 32 | 33 | 34 | public static MZModeNotCoverFragment newInstance(){ 35 | return new MZModeNotCoverFragment(); 36 | } 37 | 38 | private void initView(View view) { 39 | 40 | mMZBanner = (MZBannerView) view.findViewById(R.id.banner); 41 | mMZBanner.setBannerPageClickListener(new MZBannerView.BannerPageClickListener() { 42 | @Override 43 | public void onPageClick(View view, int position) { 44 | Toast.makeText(getContext(),"click page:"+position,Toast.LENGTH_LONG).show(); 45 | } 46 | }); 47 | mMZBanner.addPageChangeListener(new ViewPager.OnPageChangeListener() { 48 | @Override 49 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 50 | Log.e(TAG,"----->addPageChangeLisnter:"+position + "positionOffset:"+positionOffset+ "positionOffsetPixels:"+positionOffsetPixels); 51 | } 52 | 53 | @Override 54 | public void onPageSelected(int position) { 55 | Log.e(TAG,"addPageChangeLisnter:"+position); 56 | } 57 | 58 | @Override 59 | public void onPageScrollStateChanged(int state) { 60 | 61 | } 62 | }); 63 | List list = new ArrayList<>(); 64 | for(int i=0;i bannerList = new ArrayList<>(); 69 | for(int i=0;i() { 74 | @Override 75 | public BannerViewHolder createViewHolder() { 76 | return new BannerViewHolder(); 77 | } 78 | }); 79 | 80 | mNormalBanner = (MZBannerView) view.findViewById(R.id.banner_normal); 81 | mNormalBanner.setIndicatorRes(R.color.colorAccent,R.color.colorPrimary); 82 | mNormalBanner.setPages(list, new MZHolderCreator() { 83 | @Override 84 | public BannerPaddingViewHolder createViewHolder() { 85 | return new BannerPaddingViewHolder(); 86 | } 87 | }); 88 | 89 | 90 | } 91 | 92 | public static class BannerViewHolder implements MZViewHolder { 93 | private ImageView mImageView; 94 | @Override 95 | public View createView(Context context) { 96 | // 返回页面布局文件 97 | View view = LayoutInflater.from(context).inflate(R.layout.banner_item,null); 98 | mImageView = (ImageView) view.findViewById(R.id.banner_image); 99 | return view; 100 | } 101 | 102 | @Override 103 | public void onBind(Context context, int position, Integer data) { 104 | // 数据绑定 105 | mImageView.setImageResource(data); 106 | } 107 | } 108 | 109 | public static class BannerPaddingViewHolder implements MZViewHolder { 110 | private ImageView mImageView; 111 | @Override 112 | public View createView(Context context) { 113 | // 返回页面布局文件 114 | View view = LayoutInflater.from(context).inflate(R.layout.banner_item_padding,null); 115 | mImageView = (ImageView) view.findViewById(R.id.banner_image); 116 | return view; 117 | } 118 | 119 | @Override 120 | public void onBind(Context context, int position, Integer data) { 121 | // 数据绑定 122 | mImageView.setImageResource(data); 123 | } 124 | } 125 | @Nullable 126 | @Override 127 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 128 | View view = inflater.inflate(R.layout.mz_mode_not_cover,null); 129 | initView(view); 130 | return view; 131 | } 132 | 133 | @Override 134 | public void onPause() { 135 | super.onPause(); 136 | mMZBanner.pause(); 137 | mNormalBanner.pause(); 138 | } 139 | 140 | @Override 141 | public void onResume() { 142 | super.onResume(); 143 | mMZBanner.start(); 144 | mNormalBanner.start(); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.Toolbar; 7 | import android.view.MenuItem; 8 | 9 | import com.zhouwei.mzbannerview.remote.RemoteTestFragment; 10 | 11 | public class MainActivity extends AppCompatActivity { 12 | private Toolbar mToolbar; 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.home_activity); 17 | 18 | StatusBarUtils.setColor(this,getResources().getColor(R.color.colorPrimary),0); 19 | mToolbar = (Toolbar) findViewById(R.id.tool_bar); 20 | mToolbar.inflateMenu(R.menu.setting); 21 | mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { 22 | @Override 23 | public boolean onMenuItemClick(MenuItem item) { 24 | if(item.getItemId() ==R.id.banner_mode){ 25 | switchBannerMode(); 26 | }else if(item.getItemId() == R.id.viewPager_mode){ 27 | switchViewPagerMode(); 28 | }else if(item.getItemId() == R.id.remote_mode){ 29 | switchRemoteMode(); 30 | }else if(item.getItemId() == R.id.mz_mode_not_cover){ 31 | switchMZModeNotCover(); 32 | } 33 | return true; 34 | } 35 | }); 36 | 37 | Fragment fragment = MZModeBannerFragment.newInstance(); 38 | getSupportFragmentManager().beginTransaction().add(R.id.home_container,fragment).commit(); 39 | } 40 | 41 | /** 42 | * banner模式 43 | */ 44 | public void switchBannerMode(){ 45 | Fragment fragment = MZModeBannerFragment.newInstance(); 46 | getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit(); 47 | } 48 | 49 | /** 50 | * 普通ViewPager模式 51 | */ 52 | public void switchViewPagerMode(){ 53 | Fragment fragment = NormalViewPagerFragment.newInstance(); 54 | getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit(); 55 | } 56 | 57 | /** 58 | * 从网络获取数据 59 | */ 60 | public void switchRemoteMode(){ 61 | Fragment fragment = RemoteTestFragment.newInstance(); 62 | getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit(); 63 | } 64 | 65 | public void switchMZModeNotCover(){ 66 | Fragment fragment = MZModeNotCoverFragment.newInstance(); 67 | getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/NormalViewPagerFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import com.zhouwei.mzbanner.MZBannerView; 14 | import com.zhouwei.mzbanner.holder.MZHolderCreator; 15 | import com.zhouwei.mzbanner.holder.MZViewHolder; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import static com.zhouwei.mzbannerview.MZModeBannerFragment.RES; 21 | 22 | /** 23 | * Created by zhouwei on 17/5/31. 24 | */ 25 | 26 | public class NormalViewPagerFragment extends Fragment { 27 | private MZBannerView mMZBannerView; 28 | private MZBannerView mNormalViewPager; 29 | 30 | public static NormalViewPagerFragment newInstance(){ 31 | return new NormalViewPagerFragment(); 32 | } 33 | @Nullable 34 | @Override 35 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 36 | View view = inflater.inflate(R.layout.normal_view_pager_layout,null); 37 | initView(view); 38 | return view; 39 | } 40 | 41 | private void initView(View view){ 42 | mMZBannerView = (MZBannerView) view.findViewById(R.id.mz_view_pager); 43 | mNormalViewPager = (MZBannerView) view.findViewById(R.id.normal_viewPager); 44 | 45 | 46 | 47 | mMZBannerView.setPages(mockData(), new MZHolderCreator() { 48 | @Override 49 | public ViewPagerHolder createViewHolder() { 50 | return new ViewPagerHolder(); 51 | } 52 | }); 53 | 54 | mNormalViewPager.setIndicatorRes(R.drawable.dot_unselect_image,R.drawable.dot_select_image); 55 | mNormalViewPager.setPages(mockData(), new MZHolderCreator() { 56 | @Override 57 | public ViewPagerHolder createViewHolder() { 58 | return new ViewPagerHolder(); 59 | } 60 | }); 61 | 62 | } 63 | 64 | 65 | public static final class ViewPagerHolder implements MZViewHolder { 66 | private ImageView mImageView; 67 | private TextView mTitle; 68 | private TextView mDesc; 69 | @Override 70 | public View createView(Context context) { 71 | View view = LayoutInflater.from(context).inflate(R.layout.normal_banner_item,null); 72 | mImageView = (ImageView) view.findViewById(R.id.normal_banner_image); 73 | mDesc = (TextView) view.findViewById(R.id.page_desc); 74 | return view; 75 | } 76 | 77 | @Override 78 | public void onBind(Context context, int position, DataEntry data) { 79 | mImageView.setImageResource(data.resId); 80 | mDesc.setText(data.desc); 81 | } 82 | } 83 | 84 | private List mockData(){ 85 | List list = new ArrayList<>(); 86 | DataEntry dataEntry = null; 87 | for(int i=0;i 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) { 37 | decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); 38 | } else { 39 | //新建一个和状态栏高宽的view 40 | StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha); 41 | decorView.addView(statusView); 42 | } 43 | setRootView(activity); 44 | } 45 | 46 | public static void setTranslucentImageHeader(Activity activity, int alpha, View needOffsetView){ 47 | setFullScreen(activity); 48 | //获取windowphone下的decorView 49 | ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); 50 | int count = decorView.getChildCount(); 51 | //判断是否已经添加了statusBarView 52 | if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) { 53 | decorView.getChildAt(count - 1).setBackgroundColor(Color.argb(alpha, 0, 0, 0)); 54 | } else { 55 | //新建一个和状态栏高宽的view 56 | StatusBarView statusView = createTranslucentStatusBarView(activity, alpha); 57 | decorView.addView(statusView); 58 | } 59 | 60 | if (needOffsetView != null) { 61 | ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams(); 62 | layoutParams.setMargins(0, getStatusBarHeight(activity), 0, 0); 63 | } 64 | 65 | } 66 | 67 | 68 | 69 | private static StatusBarView createTranslucentStatusBarView(Activity activity, int alpha) { 70 | // 绘制一个和状态栏一样高的矩形 71 | StatusBarView statusBarView = new StatusBarView(activity); 72 | LinearLayout.LayoutParams params = 73 | new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); 74 | statusBarView.setLayoutParams(params); 75 | statusBarView.setBackgroundColor(Color.argb(alpha, 0, 0, 0)); 76 | return statusBarView; 77 | } 78 | 79 | /** 80 | * 设置根布局参数 81 | */ 82 | private static void setRootView(Activity activity) { 83 | ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0); 84 | //rootview不会为状态栏流出状态栏空间 85 | ViewCompat.setFitsSystemWindows(rootView,true); 86 | rootView.setClipToPadding(true); 87 | } 88 | private static StatusBarView createStatusBarView(Activity activity, int color, int alpha) { 89 | // 绘制一个和状态栏一样高的矩形 90 | StatusBarView statusBarView = new StatusBarView(activity); 91 | LinearLayout.LayoutParams params = 92 | new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); 93 | statusBarView.setLayoutParams(params); 94 | statusBarView.setBackgroundColor(calculateStatusColor(color, alpha)); 95 | return statusBarView; 96 | } 97 | 98 | /** 99 | * 获取状态栏高度 100 | * 101 | * @param context context 102 | * @return 状态栏高度 103 | */ 104 | private static int getStatusBarHeight(Context context) { 105 | // 获得状态栏高度 106 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); 107 | return context.getResources().getDimensionPixelSize(resourceId); 108 | } 109 | /** 110 | * 计算状态栏颜色 111 | * 112 | * @param color color值 113 | * @param alpha alpha值 114 | * @return 最终的状态栏颜色 115 | */ 116 | private static int calculateStatusColor(int color, int alpha) { 117 | float a = 1 - alpha / 255f; 118 | int red = color >> 16 & 0xff; 119 | int green = color >> 8 & 0xff; 120 | int blue = color & 0xff; 121 | red = (int) (red * a + 0.5); 122 | green = (int) (green * a + 0.5); 123 | blue = (int) (blue * a + 0.5); 124 | return 0xff << 24 | red << 16 | green << 8 | blue; 125 | } 126 | 127 | public static void setFullScreen(Activity activity){ 128 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 129 | Window window = activity.getWindow(); 130 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS 131 | | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); 132 | window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN| View.SYSTEM_UI_FLAG_LAYOUT_STABLE); 133 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 134 | window.setStatusBarColor(Color.TRANSPARENT); 135 | }else 136 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 137 | // 设置透明状态栏,这样才能让 ContentView 向上 138 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 139 | } 140 | } 141 | 142 | public static class StatusBarView extends View { 143 | 144 | public StatusBarView(Context context) { 145 | super(context); 146 | } 147 | 148 | public StatusBarView(Context context, AttributeSet attrs) { 149 | super(context, attrs); 150 | } 151 | 152 | public StatusBarView(Context context, AttributeSet attrs, int defStyleAttr) { 153 | super(context, attrs, defStyleAttr); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/http/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.http; 2 | 3 | /** 4 | * 5 | * 网络请求结果 基类 6 | * Created by zhouwei on 16/11/10. 7 | */ 8 | 9 | public class BaseResponse { 10 | public int status; 11 | public String message; 12 | 13 | public T data; 14 | 15 | public boolean isSuccess(){ 16 | return status == 200; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/http/BasicParamsInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.http; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.io.IOException; 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.Iterator; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | import okhttp3.FormBody; 13 | import okhttp3.Headers; 14 | import okhttp3.HttpUrl; 15 | import okhttp3.Interceptor; 16 | import okhttp3.MediaType; 17 | import okhttp3.Request; 18 | import okhttp3.RequestBody; 19 | import okhttp3.Response; 20 | import okio.Buffer; 21 | 22 | /** 23 | * 24 | * OkHttp 公共参数拦截器 25 | * from: https://github.com/jkyeo/okhttp-basicparamsinterceptor.git 26 | * Created by zhouwei on 16/11/10. 27 | */ 28 | 29 | public class BasicParamsInterceptor implements Interceptor { 30 | 31 | Map queryParamsMap = new HashMap<>(); 32 | Map paramsMap = new HashMap<>(); 33 | Map headerParamsMap = new HashMap<>(); 34 | List headerLinesList = new ArrayList<>(); 35 | 36 | private BasicParamsInterceptor() { 37 | 38 | } 39 | 40 | @Override 41 | public Response intercept(Chain chain) throws IOException { 42 | 43 | Request request = chain.request(); 44 | Request.Builder requestBuilder = request.newBuilder(); 45 | 46 | // process header params inject 47 | Headers.Builder headerBuilder = request.headers().newBuilder(); 48 | if (headerParamsMap.size() > 0) { 49 | Iterator iterator = headerParamsMap.entrySet().iterator(); 50 | while (iterator.hasNext()) { 51 | Map.Entry entry = (Map.Entry) iterator.next(); 52 | headerBuilder.add((String) entry.getKey(), (String) entry.getValue()); 53 | } 54 | } 55 | 56 | if (headerLinesList.size() > 0) { 57 | for (String line: headerLinesList) { 58 | headerBuilder.add(line); 59 | } 60 | requestBuilder.headers(headerBuilder.build()); 61 | } 62 | // process header params end 63 | 64 | 65 | // process queryParams inject whatever it's GET or POST 66 | if (queryParamsMap.size() > 0) { 67 | request = injectParamsIntoUrl(request.url().newBuilder(), requestBuilder, queryParamsMap); 68 | } 69 | 70 | // process post body inject 71 | if (paramsMap.size() > 0) { 72 | if (canInjectIntoBody(request)) { 73 | FormBody.Builder formBodyBuilder = new FormBody.Builder(); 74 | for(Map.Entry entry : paramsMap.entrySet()) { 75 | formBodyBuilder.add((String) entry.getKey(), (String) entry.getValue()); 76 | } 77 | 78 | RequestBody formBody = formBodyBuilder.build(); 79 | String postBodyString = bodyToString(request.body()); 80 | postBodyString += ((postBodyString.length() > 0) ? "&" : "") + bodyToString(formBody); 81 | requestBuilder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyString)); 82 | } 83 | } 84 | 85 | request = requestBuilder.build(); 86 | return chain.proceed(request); 87 | } 88 | private boolean canInjectIntoBody(Request request) { 89 | if (request == null) { 90 | return false; 91 | } 92 | if (!TextUtils.equals(request.method(), "POST")) { 93 | return false; 94 | } 95 | RequestBody body = request.body(); 96 | if (body == null) { 97 | return false; 98 | } 99 | MediaType mediaType = body.contentType(); 100 | if (mediaType == null) { 101 | return false; 102 | } 103 | if (!TextUtils.equals(mediaType.subtype(), "x-www-form-urlencoded")) { 104 | return false; 105 | } 106 | return true; 107 | } 108 | 109 | // func to inject params into url 110 | private Request injectParamsIntoUrl(HttpUrl.Builder httpUrlBuilder, Request.Builder requestBuilder, Map paramsMap) { 111 | if (paramsMap.size() > 0) { 112 | Iterator iterator = paramsMap.entrySet().iterator(); 113 | while (iterator.hasNext()) { 114 | Map.Entry entry = (Map.Entry) iterator.next(); 115 | httpUrlBuilder.addQueryParameter((String) entry.getKey(), (String) entry.getValue()); 116 | } 117 | requestBuilder.url(httpUrlBuilder.build()); 118 | return requestBuilder.build(); 119 | } 120 | 121 | return null; 122 | } 123 | 124 | private static String bodyToString(final RequestBody request){ 125 | try { 126 | final RequestBody copy = request; 127 | final Buffer buffer = new Buffer(); 128 | if(copy != null) 129 | copy.writeTo(buffer); 130 | else 131 | return ""; 132 | return buffer.readUtf8(); 133 | } 134 | catch (final IOException e) { 135 | return "did not work"; 136 | } 137 | } 138 | 139 | public static class Builder { 140 | 141 | BasicParamsInterceptor interceptor; 142 | 143 | public Builder() { 144 | interceptor = new BasicParamsInterceptor(); 145 | } 146 | 147 | public Builder addParam(String key, String value) { 148 | interceptor.paramsMap.put(key, value); 149 | return this; 150 | } 151 | 152 | public Builder addParamsMap(Map paramsMap) { 153 | interceptor.paramsMap.putAll(paramsMap); 154 | return this; 155 | } 156 | 157 | public Builder addHeaderParam(String key, String value) { 158 | interceptor.headerParamsMap.put(key, value); 159 | return this; 160 | } 161 | 162 | public Builder addHeaderParamsMap(Map headerParamsMap) { 163 | interceptor.headerParamsMap.putAll(headerParamsMap); 164 | return this; 165 | } 166 | 167 | public Builder addHeaderLine(String headerLine) { 168 | int index = headerLine.indexOf(":"); 169 | if (index == -1) { 170 | throw new IllegalArgumentException("Unexpected header: " + headerLine); 171 | } 172 | interceptor.headerLinesList.add(headerLine); 173 | return this; 174 | } 175 | 176 | public Builder addHeaderLinesList(List headerLinesList) { 177 | for (String headerLine: headerLinesList) { 178 | int index = headerLine.indexOf(":"); 179 | if (index == -1) { 180 | throw new IllegalArgumentException("Unexpected header: " + headerLine); 181 | } 182 | interceptor.headerLinesList.add(headerLine); 183 | } 184 | return this; 185 | } 186 | 187 | public Builder addQueryParam(String key, String value) { 188 | interceptor.queryParamsMap.put(key, value); 189 | return this; 190 | } 191 | 192 | public Builder addQueryParamsMap(Map queryParamsMap) { 193 | interceptor.queryParamsMap.putAll(queryParamsMap); 194 | return this; 195 | } 196 | 197 | public BasicParamsInterceptor build() { 198 | return interceptor; 199 | } 200 | 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/http/Fault.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.http; 2 | 3 | /** 4 | * 异常处理类,将异常包装成一个 Fault ,抛给上层统一处理 5 | * Created by zhouwei on 16/11/17. 6 | */ 7 | 8 | public class Fault extends RuntimeException { 9 | private int errorCode; 10 | 11 | public Fault(int errorCode,String message){ 12 | super(message); 13 | errorCode = errorCode; 14 | } 15 | 16 | public int getErrorCode() { 17 | return errorCode; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/http/HttpCommonInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.http; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.IOException; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import okhttp3.Interceptor; 10 | import okhttp3.Request; 11 | import okhttp3.Response; 12 | 13 | /** 14 | * 拦截器 15 | * 16 | * 向请求头里添加公共参数 17 | * Created by zhouwei on 16/11/10. 18 | */ 19 | 20 | public class HttpCommonInterceptor implements Interceptor { 21 | 22 | private Map mHeaderParamsMap = new HashMap<>(); 23 | public HttpCommonInterceptor() { 24 | 25 | } 26 | 27 | @Override 28 | public Response intercept(Chain chain) throws IOException { 29 | Log.d("HttpCommonInterceptor","add common params"); 30 | Request oldRequest = chain.request(); 31 | 32 | // 添加新的参数,添加到url 中 33 | /* HttpUrl.Builder authorizedUrlBuilder = oldRequest.url() 34 | .newBuilder() 35 | .scheme(oldRequest.url().scheme()) 36 | .host(oldRequest.url().host());*/ 37 | 38 | // 新的请求 39 | 40 | Request.Builder requestBuilder = oldRequest.newBuilder(); 41 | requestBuilder.method(oldRequest.method(), oldRequest.body()); 42 | //添加公共参数,添加到header中 43 | if(mHeaderParamsMap.size() > 0){ 44 | for(Map.Entry params:mHeaderParamsMap.entrySet()){ 45 | requestBuilder.header(params.getKey(),params.getValue()); 46 | } 47 | } 48 | 49 | Request newRequest = requestBuilder.build(); 50 | 51 | return chain.proceed(newRequest); 52 | } 53 | 54 | public static class Builder{ 55 | HttpCommonInterceptor mHttpCommonInterceptor; 56 | 57 | public Builder(){ 58 | mHttpCommonInterceptor = new HttpCommonInterceptor(); 59 | } 60 | 61 | public Builder addHeaderParams(String key, String value){ 62 | mHttpCommonInterceptor.mHeaderParamsMap.put(key,value); 63 | return this; 64 | } 65 | 66 | public Builder addHeaderParams(String key, int value){ 67 | return addHeaderParams(key, String.valueOf(value)); 68 | } 69 | 70 | public Builder addHeaderParams(String key, float value){ 71 | return addHeaderParams(key, String.valueOf(value)); 72 | } 73 | 74 | public Builder addHeaderParams(String key, long value){ 75 | return addHeaderParams(key, String.valueOf(value)); 76 | } 77 | 78 | public Builder addHeaderParams(String key, double value){ 79 | return addHeaderParams(key, String.valueOf(value)); 80 | } 81 | 82 | 83 | public HttpCommonInterceptor build(){ 84 | return mHttpCommonInterceptor; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/http/ObjectLoader.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.http; 2 | 3 | import rx.Observable; 4 | import rx.android.schedulers.AndroidSchedulers; 5 | import rx.schedulers.Schedulers; 6 | 7 | /** 8 | * 9 | * 将一些重复的操作提出来,放到父类以免Loader 里每个接口都有重复代码 10 | * Created by zhouwei on 16/11/10. 11 | * 12 | */ 13 | 14 | public class ObjectLoader { 15 | /** 16 | * 17 | * @param observable 18 | * @param 19 | * @return 20 | */ 21 | protected Observable observe(Observable observable){ 22 | return observable.subscribeOn(Schedulers.io()) 23 | .unsubscribeOn(Schedulers.io()) 24 | .observeOn(AndroidSchedulers.mainThread()); 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/http/PayLoad.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.http; 2 | 3 | import rx.functions.Func1; 4 | 5 | /** 6 | * 7 | * 剥离 最终数据 8 | * Created by zhouwei on 16/11/10. 9 | */ 10 | 11 | public class PayLoad implements Func1,T> { 12 | @Override 13 | public T call(BaseResponse tBaseResponse) {//获取数据失败时,包装一个Fault 抛给上层处理错误 14 | if(!tBaseResponse.isSuccess()){ 15 | throw new Fault(tBaseResponse.status,tBaseResponse.message); 16 | } 17 | return tBaseResponse.data; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/http/RetrofitServiceManager.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.http; 2 | 3 | 4 | 5 | import com.zhouwei.mzbannerview.AppConfig; 6 | 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import okhttp3.OkHttpClient; 10 | import retrofit2.Retrofit; 11 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 12 | import retrofit2.converter.gson.GsonConverterFactory; 13 | 14 | /** 15 | * Created by zhouwei on 16/11/9. 16 | */ 17 | 18 | public class RetrofitServiceManager { 19 | private static final int DEFAULT_TIME_OUT = 5;//超时时间 5s 20 | private static final int DEFAULT_READ_TIME_OUT = 10; 21 | private Retrofit mRetrofit; 22 | private RetrofitServiceManager(){ 23 | // 创建 OKHttpClient 24 | OkHttpClient.Builder builder = new OkHttpClient.Builder(); 25 | builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间 26 | builder.writeTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//写操作 超时时间 27 | builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读操作超时时间 28 | 29 | // 添加公共参数拦截器 30 | HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder() 31 | .addHeaderParams("paltform","android") 32 | .addHeaderParams("userToken","1234343434dfdfd3434") 33 | .addHeaderParams("userId","123445") 34 | .build(); 35 | builder.addInterceptor(commonInterceptor); 36 | 37 | 38 | // 创建Retrofit 39 | mRetrofit = new Retrofit.Builder() 40 | .client(builder.build()) 41 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 42 | .addConverterFactory(GsonConverterFactory.create()) 43 | .baseUrl(AppConfig.BASE_URL) 44 | .build(); 45 | } 46 | 47 | private static class SingletonHolder{ 48 | private static final RetrofitServiceManager INSTANCE = new RetrofitServiceManager(); 49 | } 50 | 51 | /** 52 | * 获取RetrofitServiceManager 53 | * @return 54 | */ 55 | public static RetrofitServiceManager getInstance(){ 56 | return SingletonHolder.INSTANCE; 57 | } 58 | 59 | /** 60 | * 获取对应的Service 61 | * @param service Service 的 class 62 | * @param 63 | * @return 64 | */ 65 | public T create(Class service){ 66 | return mRetrofit.create(service); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/remote/DataLoader.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.remote; 2 | 3 | /** 4 | * Created by zhouwei on 17/6/8. 5 | */ 6 | 7 | public class DataLoader { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/remote/Movie.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.remote; 2 | 3 | /** 4 | * 5 | * Created by zhouwei on 16/11/9. 6 | */ 7 | 8 | public class Movie { 9 | public Rate rating; 10 | public String title; 11 | public String collect_count; 12 | public String original_title; 13 | public String subtype; 14 | public String year; 15 | public MovieImage images; 16 | 17 | public static class Rate{ 18 | public int max; 19 | public float average; 20 | public String stars; 21 | public int min; 22 | } 23 | 24 | public static class MovieImage{ 25 | public String small; 26 | public String large; 27 | public String medium; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/remote/MovieLoader.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.remote; 2 | 3 | 4 | import com.zhouwei.mzbannerview.http.ObjectLoader; 5 | import com.zhouwei.mzbannerview.http.RetrofitServiceManager; 6 | 7 | import java.util.List; 8 | 9 | import retrofit2.http.Field; 10 | import retrofit2.http.FormUrlEncoded; 11 | import retrofit2.http.GET; 12 | import retrofit2.http.POST; 13 | import retrofit2.http.Query; 14 | import rx.Observable; 15 | import rx.functions.Func1; 16 | 17 | /** 18 | * 19 | * 20 | * Created by zhouwei on 16/11/10. 21 | */ 22 | 23 | public class MovieLoader extends ObjectLoader { 24 | private MovieService mMovieService; 25 | 26 | public MovieLoader(){ 27 | mMovieService = RetrofitServiceManager.getInstance().create(MovieService.class); 28 | } 29 | 30 | /** 31 | * 获取电影列表 32 | * @param start 33 | * @param count 34 | * @return 35 | */ 36 | public Observable> getMovie(int start, int count){ 37 | return observe(mMovieService.getTop250(start,count)) 38 | .map(new Func1>() { 39 | @Override 40 | public List call(MovieSubject movieSubject) { 41 | return movieSubject.subjects; 42 | } 43 | }); 44 | } 45 | 46 | public Observable getWeatherList(String cityId, String key){ 47 | return observe(mMovieService.getWeather(cityId,key)).map(new Func1() { 48 | @Override 49 | public String call(String s) { 50 | return null; 51 | } 52 | }); 53 | } 54 | 55 | 56 | public interface MovieService{ 57 | 58 | //获取豆瓣Top250 榜单 59 | @GET("top250") 60 | Observable getTop250(@Query("start") int start, @Query("count") int count); 61 | 62 | @FormUrlEncoded 63 | @POST("/x3/weather") 64 | Observable getWeather(@Field("cityId") String cityId, @Field("key") String key); 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/remote/MovieSubject.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.remote; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by zhouwei on 16/11/9. 7 | */ 8 | 9 | public class MovieSubject { 10 | public int count; 11 | public int start; 12 | public int total; 13 | public List subjects; 14 | public String title; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/zhouwei/mzbannerview/remote/RemoteTestFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview.remote; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v4.view.ViewPager; 9 | import android.util.Log; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.ImageView; 14 | import android.widget.TextView; 15 | 16 | import com.squareup.picasso.Picasso; 17 | import com.zhouwei.mzbanner.MZBannerView; 18 | import com.zhouwei.mzbanner.holder.MZHolderCreator; 19 | import com.zhouwei.mzbanner.holder.MZViewHolder; 20 | import com.zhouwei.mzbannerview.R; 21 | import com.zhouwei.mzbannerview.http.Fault; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | import rx.functions.Action1; 27 | 28 | /** 29 | * Created by zhouwei on 17/6/8. 30 | */ 31 | 32 | public class RemoteTestFragment extends Fragment implements View.OnClickListener{ 33 | private MovieLoader mMovieLoader; 34 | private MZBannerView mMZBannerView; 35 | private TextView mBtnChange; 36 | private List mMovies; 37 | private Handler mHandler = new Handler(); 38 | public static RemoteTestFragment newInstance(){ 39 | RemoteTestFragment fragment = new RemoteTestFragment(); 40 | return fragment; 41 | } 42 | 43 | @Nullable 44 | @Override 45 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 46 | View view = inflater.inflate(R.layout.remote_test_layout,null); 47 | mMZBannerView = (MZBannerView) view.findViewById(R.id.my_banner); 48 | mBtnChange = (TextView) view.findViewById(R.id.btn_change); 49 | mBtnChange.setOnClickListener(this); 50 | view.findViewById(R.id.btn_clear).setOnClickListener(this); 51 | mMovieLoader = new MovieLoader(); 52 | getMovieList(); 53 | return view; 54 | } 55 | 56 | 57 | /** 58 | * 获取电影列表 59 | */ 60 | private void getMovieList(){ 61 | mMovieLoader.getMovie(0,10).subscribe(new Action1>() { 62 | @Override 63 | public void call(List movies) { 64 | mMovies = movies; 65 | Log.e("zhouwei","get data suceess"); 66 | setBanner(movies); 67 | } 68 | }, new Action1() { 69 | @Override 70 | public void call(Throwable throwable) { 71 | Log.e("TAG","error message:"+throwable.getMessage()); 72 | if(throwable instanceof Fault){ 73 | Fault fault = (Fault) throwable; 74 | if(fault.getErrorCode() == 404){ 75 | //错误处理 76 | }else if(fault.getErrorCode() == 500){ 77 | //错误处理 78 | }else if(fault.getErrorCode() == 501){ 79 | //错误处理 80 | } 81 | } 82 | } 83 | }); 84 | 85 | } 86 | 87 | private void setBanner(List movies){ 88 | mMZBannerView.addPageChangeListener(new ViewPager.OnPageChangeListener() { 89 | @Override 90 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 91 | 92 | } 93 | 94 | @Override 95 | public void onPageSelected(int position) { 96 | Log.e("zw","onPageScrolled---->"+position); 97 | } 98 | 99 | @Override 100 | public void onPageScrollStateChanged(int state) { 101 | 102 | } 103 | }); 104 | mMZBannerView.setPages(movies, new MZHolderCreator() { 105 | @Override 106 | public BannerViewHolder createViewHolder() { 107 | return new BannerViewHolder(); 108 | } 109 | }); 110 | 111 | mMZBannerView.start(); 112 | 113 | } 114 | 115 | 116 | @Override 117 | public void onDestroy() { 118 | super.onDestroy(); 119 | mMZBannerView.pause(); 120 | } 121 | 122 | @Override 123 | public void onClick(View v) { 124 | if(v.getId() == R.id.btn_change){ 125 | List movies = new ArrayList(mMovies); 126 | movies.add(mMovies.get(0)); 127 | movies.add(mMovies.get(1)); 128 | if(movies.size()>2){ 129 | mMZBannerView.setCanLoop(true); 130 | }else{ 131 | mMZBannerView.setCanLoop(false); 132 | } 133 | setBanner(movies); 134 | }else if(v.getId() == R.id.btn_clear){ 135 | List movies = new ArrayList<>(); 136 | movies.add(mMovies.get(0)); 137 | movies.add(mMovies.get(1)); 138 | mMZBannerView.setCanLoop(false); 139 | setBanner(movies); 140 | 141 | } 142 | } 143 | 144 | public static class BannerViewHolder implements MZViewHolder{ 145 | private ImageView mImageView; 146 | @Override 147 | public View createView(Context context) { 148 | View view = LayoutInflater.from(context).inflate(R.layout.remote_banner_item,null); 149 | mImageView = (ImageView) view.findViewById(R.id.remote_item_image); 150 | return view; 151 | } 152 | 153 | @Override 154 | public void onBind(Context context, int i, Movie movie) { 155 | Log.e("zhouwei","current position:"+i); 156 | Picasso.with(context).load(movie.images.large).into(mImageView); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dot_select_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dot_unselect_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_format_list_bulleted_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more_vert_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 31 | 32 | 41 | 42 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/banner_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/banner_item_padding.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/home_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 15 | 16 | 17 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/mz_mode_not_cover.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 30 | 31 | 40 | 41 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/normal_banner_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | 21 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/normal_view_pager_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 14 | 15 | 20 | 30 | 36 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/remote_banner_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/remote_test_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 21 | 22 | 23 | 24 | 36 | 37 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/menu/setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/banner1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/banner1.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/banner2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/banner2.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/banner3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/banner3.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/banner4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/banner4.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/banner5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/banner5.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/image1.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/image2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/image2.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/image3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/image3.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/image4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/image4.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/image5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/image5.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/image6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/image6.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/image7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/image7.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/image8.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xhdpi/image8.jpeg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MZBannerView 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/zhouwei/mzbannerview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbannerview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.0' 9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | maven {url "https://jitpack.io"} 19 | } 20 | } 21 | 22 | task clean(type: Delete) { 23 | delete rootProject.buildDir 24 | } 25 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed May 31 15:46:39 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /image/MZBannerView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/image/MZBannerView.gif -------------------------------------------------------------------------------- /image/MZBanner普通ViewPager效果.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/image/MZBanner普通ViewPager效果.gif -------------------------------------------------------------------------------- /image/demo二维码.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/image/demo二维码.png -------------------------------------------------------------------------------- /image/gzh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/image/gzh.jpg -------------------------------------------------------------------------------- /image/meizuappbanner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/image/meizuappbanner.gif -------------------------------------------------------------------------------- /image/network_data.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/image/network_data.gif -------------------------------------------------------------------------------- /image/仿魅族Banner效果.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/image/仿魅族Banner效果.gif -------------------------------------------------------------------------------- /image/魅族Banner_fial.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/image/魅族Banner_fial.gif -------------------------------------------------------------------------------- /image/魅族bannerView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinguo-zhouwei/MZBannerView/1d18c51898df70f67dc7f510ae1e68069a83fa32/image/魅族bannerView.gif -------------------------------------------------------------------------------- /mzbanner/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /mzbanner/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | group='com.github.pinguo-zhouwei' 4 | 5 | android { 6 | compileSdkVersion 25 7 | buildToolsVersion "25.0.2" 8 | 9 | defaultConfig { 10 | minSdkVersion 16 11 | targetSdkVersion 25 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 16 | 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | compile fileTree(dir: 'libs', include: ['*.jar']) 28 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 29 | exclude group: 'com.android.support', module: 'support-annotations' 30 | }) 31 | compile 'com.android.support:appcompat-v7:25.3.1' 32 | testCompile 'junit:junit:4.12' 33 | } 34 | -------------------------------------------------------------------------------- /mzbanner/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/zhouwei/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /mzbanner/src/androidTest/java/com/zhouwei/mzbanner/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbanner; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zhouwei.mzbanner.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /mzbanner/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /mzbanner/src/main/java/com/zhouwei/mzbanner/CustomViewPager.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbanner; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | import android.util.SparseArray; 7 | import android.view.View; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | 12 | /** 13 | * Created by zhouwei on 17/8/16. 14 | */ 15 | 16 | public class CustomViewPager extends ViewPager { 17 | private ArrayList childCenterXAbs = new ArrayList<>(); 18 | private SparseArray childIndex = new SparseArray<>(); 19 | 20 | public CustomViewPager(Context context) { 21 | super(context); 22 | init(); 23 | } 24 | 25 | public CustomViewPager(Context context, AttributeSet attrs) { 26 | super(context, attrs); 27 | init(); 28 | } 29 | 30 | private void init(){ 31 | setClipToPadding(false); 32 | setOverScrollMode(OVER_SCROLL_NEVER); 33 | } 34 | 35 | 36 | /** 37 | * @param childCount 38 | * @param n 39 | * @return 第n个位置的child 的绘制索引 40 | */ 41 | @Override 42 | protected int getChildDrawingOrder(int childCount, int n) { 43 | if (n == 0 || childIndex.size() != childCount) { 44 | childCenterXAbs.clear(); 45 | childIndex.clear(); 46 | int viewCenterX = getViewCenterX(this); 47 | for (int i = 0; i < childCount; ++i) { 48 | int indexAbs = Math.abs(viewCenterX - getViewCenterX(getChildAt(i))); 49 | //两个距离相同,后来的那个做自增,从而保持abs不同 50 | if (childIndex.get(indexAbs) != null) { 51 | ++indexAbs; 52 | } 53 | childCenterXAbs.add(indexAbs); 54 | childIndex.append(indexAbs, i); 55 | } 56 | Collections.sort(childCenterXAbs);//1,0,2 0,1,2 57 | } 58 | //那个item距离中心点远一些,就先draw它。(最近的就是中间放大的item,最后draw) 59 | return childIndex.get(childCenterXAbs.get(childCount - 1 - n)); 60 | } 61 | 62 | private int getViewCenterX(View view) { 63 | int[] array = new int[2]; 64 | view.getLocationOnScreen(array); 65 | return array[0] + view.getWidth() / 2; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /mzbanner/src/main/java/com/zhouwei/mzbanner/MZBannerView.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbanner; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.content.res.TypedArray; 6 | import android.os.Build; 7 | import android.os.Handler; 8 | import android.support.annotation.AttrRes; 9 | import android.support.annotation.DrawableRes; 10 | import android.support.annotation.NonNull; 11 | import android.support.annotation.Nullable; 12 | import android.support.annotation.RequiresApi; 13 | import android.support.annotation.StyleRes; 14 | import android.support.v4.view.PagerAdapter; 15 | import android.support.v4.view.ViewPager; 16 | import android.util.AttributeSet; 17 | import android.util.DisplayMetrics; 18 | import android.util.TypedValue; 19 | import android.view.LayoutInflater; 20 | import android.view.MotionEvent; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | import android.view.animation.Interpolator; 24 | import android.widget.ImageView; 25 | import android.widget.LinearLayout; 26 | import android.widget.RelativeLayout; 27 | import android.widget.Scroller; 28 | 29 | import com.zhouwei.mzbanner.holder.MZHolderCreator; 30 | import com.zhouwei.mzbanner.holder.MZViewHolder; 31 | import com.zhouwei.mzbanner.transformer.CoverModeTransformer; 32 | import com.zhouwei.mzbanner.transformer.ScaleYTransformer; 33 | 34 | import java.lang.reflect.Field; 35 | import java.util.ArrayList; 36 | import java.util.List; 37 | 38 | /** 39 | * Created by zhouwei on 17/5/26. 40 | */ 41 | 42 | public class MZBannerView extends RelativeLayout { 43 | private static final String TAG = "MZBannerView"; 44 | private CustomViewPager mViewPager; 45 | private MZPagerAdapter mAdapter; 46 | private List mDatas; 47 | private boolean mIsAutoPlay = true;// 是否自动播放 48 | private int mCurrentItem = 0;//当前位置 49 | private Handler mHandler = new Handler(); 50 | private int mDelayedTime = 3000;// Banner 切换时间间隔 51 | private ViewPagerScroller mViewPagerScroller;//控制ViewPager滑动速度的Scroller 52 | private boolean mIsOpenMZEffect = true;// 开启魅族Banner效果 53 | private boolean mIsCanLoop = true;// 是否轮播图片 54 | private LinearLayout mIndicatorContainer;//indicator容器 55 | private ArrayList mIndicators = new ArrayList<>(); 56 | //mIndicatorRes[0] 为为选中,mIndicatorRes[1]为选中 57 | private int []mIndicatorRes= new int[]{R.drawable.indicator_normal,R.drawable.indicator_selected}; 58 | private int mIndicatorPaddingLeft = 0;// indicator 距离左边的距离 59 | private int mIndicatorPaddingRight = 0;//indicator 距离右边的距离 60 | private int mIndicatorPaddingTop = 0;//indicator 距离上边的距离 61 | private int mIndicatorPaddingBottom = 0;//indicator 距离下边的距离 62 | private int mMZModePadding = 0;//在仿魅族模式下,由于前后显示了上下一个页面的部分,因此需要计算这部分padding 63 | private int mIndicatorAlign = 1; 64 | private ViewPager.OnPageChangeListener mOnPageChangeListener; 65 | private BannerPageClickListener mBannerPageClickListener; 66 | public enum IndicatorAlign{ 67 | LEFT,//做对齐 68 | CENTER,//居中对齐 69 | RIGHT //右对齐 70 | } 71 | 72 | /** 73 | * 中间Page是否覆盖两边,默认覆盖 74 | */ 75 | private boolean mIsMiddlePageCover = true; 76 | public MZBannerView(@NonNull Context context) { 77 | super(context); 78 | init(); 79 | } 80 | 81 | public MZBannerView(@NonNull Context context, @Nullable AttributeSet attrs) { 82 | super(context, attrs); 83 | readAttrs(context,attrs); 84 | init(); 85 | } 86 | 87 | public MZBannerView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { 88 | super(context, attrs, defStyleAttr); 89 | readAttrs(context,attrs); 90 | init(); 91 | } 92 | 93 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 94 | public MZBannerView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { 95 | super(context, attrs, defStyleAttr, defStyleRes); 96 | readAttrs(context,attrs); 97 | init(); 98 | } 99 | 100 | private void readAttrs(Context context,AttributeSet attrs){ 101 | TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.MZBannerView); 102 | mIsOpenMZEffect = typedArray.getBoolean(R.styleable.MZBannerView_open_mz_mode,true); 103 | mIsMiddlePageCover = typedArray.getBoolean(R.styleable.MZBannerView_middle_page_cover,true); 104 | mIsCanLoop = typedArray.getBoolean(R.styleable.MZBannerView_canLoop,true); 105 | mIndicatorAlign = typedArray.getInt(R.styleable.MZBannerView_indicatorAlign,IndicatorAlign.CENTER.ordinal()); 106 | mIndicatorPaddingLeft = typedArray.getDimensionPixelSize(R.styleable.MZBannerView_indicatorPaddingLeft,0); 107 | mIndicatorPaddingRight = typedArray.getDimensionPixelSize(R.styleable.MZBannerView_indicatorPaddingRight,0); 108 | mIndicatorPaddingTop = typedArray.getDimensionPixelSize(R.styleable.MZBannerView_indicatorPaddingTop,0); 109 | mIndicatorPaddingBottom = typedArray.getDimensionPixelSize(R.styleable.MZBannerView_indicatorPaddingBottom,0); 110 | typedArray.recycle(); 111 | } 112 | 113 | 114 | private void init(){ 115 | View view = null; 116 | if(mIsOpenMZEffect){ 117 | view = LayoutInflater.from(getContext()).inflate(R.layout.mz_banner_effect_layout,this,true); 118 | }else{ 119 | view = LayoutInflater.from(getContext()).inflate(R.layout.mz_banner_normal_layout,this,true); 120 | } 121 | mIndicatorContainer = (LinearLayout) view.findViewById(R.id.banner_indicator_container); 122 | mViewPager = (CustomViewPager) view.findViewById(R.id.mzbanner_vp); 123 | mViewPager.setOffscreenPageLimit(4); 124 | 125 | mMZModePadding = dpToPx(30); 126 | // 初始化Scroller 127 | initViewPagerScroll(); 128 | 129 | sureIndicatorPosition(); 130 | 131 | } 132 | 133 | /** 134 | * 是否开启魅族模式 135 | */ 136 | private void setOpenMZEffect(){ 137 | // 魅族模式 138 | if(mIsOpenMZEffect){ 139 | if(mIsMiddlePageCover){ 140 | // 中间页面覆盖两边,和魅族APP 的banner 效果一样。 141 | mViewPager.setPageTransformer(true,new CoverModeTransformer(mViewPager)); 142 | }else{ 143 | // 中间页面不覆盖,页面并排,只是Y轴缩小 144 | mViewPager.setPageTransformer(false,new ScaleYTransformer()); 145 | } 146 | 147 | } 148 | } 149 | 150 | /** 151 | * make sure the indicator 152 | */ 153 | private void sureIndicatorPosition(){ 154 | if(mIndicatorAlign == IndicatorAlign.LEFT.ordinal()){ 155 | setIndicatorAlign(IndicatorAlign.LEFT); 156 | }else if(mIndicatorAlign == IndicatorAlign.CENTER.ordinal()){ 157 | setIndicatorAlign(IndicatorAlign.CENTER); 158 | }else{ 159 | setIndicatorAlign(IndicatorAlign.RIGHT); 160 | } 161 | } 162 | 163 | /** 164 | * 设置ViewPager的滑动速度 165 | * */ 166 | private void initViewPagerScroll() { 167 | try { 168 | Field mScroller = null; 169 | mScroller = ViewPager.class.getDeclaredField("mScroller"); 170 | mScroller.setAccessible(true); 171 | mViewPagerScroller = new ViewPagerScroller( 172 | mViewPager.getContext()); 173 | mScroller.set(mViewPager, mViewPagerScroller); 174 | 175 | } catch (NoSuchFieldException e) { 176 | e.printStackTrace(); 177 | } catch (IllegalArgumentException e) { 178 | e.printStackTrace(); 179 | } catch (IllegalAccessException e) { 180 | e.printStackTrace(); 181 | } 182 | } 183 | 184 | 185 | private final Runnable mLoopRunnable = new Runnable() { 186 | @Override 187 | public void run() { 188 | if(mIsAutoPlay){ 189 | mCurrentItem = mViewPager.getCurrentItem(); 190 | mCurrentItem++; 191 | if(mCurrentItem == mAdapter.getCount() - 1){ 192 | mCurrentItem = 0; 193 | mViewPager.setCurrentItem(mCurrentItem,false); 194 | mHandler.postDelayed(this,mDelayedTime); 195 | }else{ 196 | mViewPager.setCurrentItem(mCurrentItem); 197 | mHandler.postDelayed(this,mDelayedTime); 198 | } 199 | }else{ 200 | mHandler.postDelayed(this,mDelayedTime); 201 | } 202 | } 203 | }; 204 | 205 | 206 | 207 | /** 208 | * 初始化指示器Indicator 209 | */ 210 | private void initIndicator(){ 211 | mIndicatorContainer.removeAllViews(); 212 | mIndicators.clear(); 213 | for(int i=0;i= paddingLeft && touchX < getScreenWidth(getContext()) - paddingLeft){ 261 | pause(); 262 | } 263 | break; 264 | case MotionEvent.ACTION_UP: 265 | start(); 266 | break; 267 | } 268 | return super.dispatchTouchEvent(ev); 269 | } 270 | 271 | public static int getScreenWidth(Context context){ 272 | Resources resources = context.getResources(); 273 | DisplayMetrics dm = resources.getDisplayMetrics(); 274 | int width = dm.widthPixels; 275 | return width; 276 | } 277 | 278 | /******************************************************************************************************/ 279 | /** 对外API **/ 280 | /******************************************************************************************************/ 281 | /** 282 | * 开始轮播 283 | *

应该确保在调用用了{@link MZBannerView {@link #setPages(List, MZHolderCreator)}} 之后调用这个方法开始轮播

284 | */ 285 | public void start(){ 286 | // 如果Adapter为null, 说明还没有设置数据,这个时候不应该轮播Banner 287 | if(mAdapter== null){ 288 | return; 289 | } 290 | if(mIsCanLoop){ 291 | pause(); 292 | mIsAutoPlay = true; 293 | mHandler.postDelayed(mLoopRunnable,mDelayedTime); 294 | } 295 | } 296 | 297 | /** 298 | * 停止轮播 299 | */ 300 | public void pause(){ 301 | mIsAutoPlay = false; 302 | mHandler.removeCallbacks(mLoopRunnable); 303 | } 304 | 305 | /** 306 | * 设置是否可以轮播 307 | * @param canLoop 308 | */ 309 | public void setCanLoop(boolean canLoop){ 310 | mIsCanLoop = canLoop; 311 | if(!canLoop){ 312 | pause(); 313 | } 314 | } 315 | 316 | /** 317 | * 设置BannerView 的切换时间间隔 318 | * @param delayedTime 319 | */ 320 | public void setDelayedTime(int delayedTime) { 321 | mDelayedTime = delayedTime; 322 | } 323 | 324 | public void addPageChangeListener(ViewPager.OnPageChangeListener onPageChangeListener){ 325 | mOnPageChangeListener = onPageChangeListener; 326 | } 327 | 328 | /** 329 | * 添加Page点击事件 330 | * @param bannerPageClickListener {@link BannerPageClickListener} 331 | */ 332 | public void setBannerPageClickListener(BannerPageClickListener bannerPageClickListener) { 333 | mBannerPageClickListener = bannerPageClickListener; 334 | } 335 | 336 | /** 337 | * 是否显示Indicator 338 | * @param visible true 显示Indicator,否则不显示 339 | */ 340 | public void setIndicatorVisible(boolean visible){ 341 | if(visible){ 342 | mIndicatorContainer.setVisibility(VISIBLE); 343 | }else{ 344 | mIndicatorContainer.setVisibility(GONE); 345 | } 346 | } 347 | 348 | /** 349 | * set indicator padding 350 | * @param paddingLeft 351 | * @param paddingTop 352 | * @param paddingRight 353 | * @param paddingBottom 354 | */ 355 | public void setIndicatorPadding(int paddingLeft,int paddingTop,int paddingRight,int paddingBottom){ 356 | mIndicatorPaddingLeft = paddingLeft; 357 | mIndicatorPaddingTop = paddingTop; 358 | mIndicatorPaddingRight = paddingRight; 359 | mIndicatorPaddingBottom = paddingBottom; 360 | sureIndicatorPosition(); 361 | } 362 | 363 | /** 364 | * 返回ViewPager 365 | * @return {@link ViewPager} 366 | */ 367 | public ViewPager getViewPager() { 368 | return mViewPager; 369 | } 370 | 371 | /** 372 | * 设置indicator 图片资源 373 | * @param unSelectRes 未选中状态资源图片 374 | * @param selectRes 选中状态资源图片 375 | */ 376 | public void setIndicatorRes(@DrawableRes int unSelectRes, @DrawableRes int selectRes){ 377 | mIndicatorRes[0]= unSelectRes; 378 | mIndicatorRes[1] = selectRes; 379 | } 380 | 381 | /** 382 | * 设置数据,这是最重要的一个方法。 383 | *

其他的配置应该在这个方法之前调用

384 | * @param datas Banner 展示的数据集合 385 | * @param mzHolderCreator ViewHolder生成器 {@link MZHolderCreator} And {@link MZViewHolder} 386 | */ 387 | public void setPages(List datas,MZHolderCreator mzHolderCreator){ 388 | if(datas == null || mzHolderCreator == null){ 389 | return; 390 | } 391 | mDatas = datas; 392 | //如果在播放,就先让播放停止 393 | pause(); 394 | 395 | //增加一个逻辑:由于魅族模式会在一个页面展示前后页面的部分,因此,数据集合的长度至少为3,否则,自动为普通Banner模式 396 | //不管配置的:open_mz_mode 属性的值是否为true 397 | 398 | if(datas.size() < 3){ 399 | mIsOpenMZEffect = false; 400 | MarginLayoutParams layoutParams = (MarginLayoutParams) mViewPager.getLayoutParams(); 401 | layoutParams.setMargins(0,0,0,0); 402 | mViewPager.setLayoutParams(layoutParams); 403 | setClipChildren(true); 404 | mViewPager.setClipChildren(true); 405 | } 406 | setOpenMZEffect(); 407 | // 2017.7.20 fix:将Indicator初始化放在Adapter的初始化之前,解决更新数据变化更新时crush. 408 | //初始化Indicator 409 | initIndicator(); 410 | 411 | mAdapter = new MZPagerAdapter(datas,mzHolderCreator,mIsCanLoop); 412 | mAdapter.setUpViewViewPager(mViewPager); 413 | mAdapter.setPageClickListener(mBannerPageClickListener); 414 | 415 | 416 | mViewPager.clearOnPageChangeListeners(); 417 | mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 418 | @Override 419 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 420 | 421 | int realPosition = position % mIndicators.size(); 422 | if(mOnPageChangeListener!=null){ 423 | mOnPageChangeListener.onPageScrolled(realPosition,positionOffset,positionOffsetPixels); 424 | } 425 | } 426 | 427 | @Override 428 | public void onPageSelected(int position) { 429 | mCurrentItem = position; 430 | 431 | 432 | // 切换indicator 433 | int realSelectPosition = mCurrentItem % mIndicators.size(); 434 | for(int i = 0;i extends PagerAdapter{ 523 | private List mDatas; 524 | private MZHolderCreator mMZHolderCreator; 525 | private ViewPager mViewPager; 526 | private boolean canLoop; 527 | private BannerPageClickListener mPageClickListener; 528 | private final int mLooperCountFactor = 500; 529 | 530 | public MZPagerAdapter(List datas, MZHolderCreator MZHolderCreator,boolean canLoop) { 531 | if(mDatas == null){ 532 | mDatas = new ArrayList<>(); 533 | } 534 | //mDatas.add(datas.get(datas.size()-1));// 加入最后一个 535 | for(T t:datas){ 536 | mDatas.add(t); 537 | } 538 | // mDatas.add(datas.get(0));//在最后加入最前面一个 539 | mMZHolderCreator = MZHolderCreator; 540 | this.canLoop = canLoop; 541 | } 542 | 543 | public void setPageClickListener(BannerPageClickListener pageClickListener) { 544 | mPageClickListener = pageClickListener; 545 | } 546 | 547 | /** 548 | * 初始化Adapter和设置当前选中的Item 549 | * @param viewPager 550 | */ 551 | public void setUpViewViewPager(ViewPager viewPager){ 552 | mViewPager = viewPager; 553 | mViewPager.setAdapter(this); 554 | mViewPager.getAdapter().notifyDataSetChanged(); 555 | int currentItem = canLoop ? getStartSelectItem():0; 556 | //设置当前选中的Item 557 | mViewPager.setCurrentItem(currentItem); 558 | } 559 | 560 | private int getStartSelectItem(){ 561 | if(getRealCount() == 0){ 562 | return 0; 563 | } 564 | // 我们设置当前选中的位置为Integer.MAX_VALUE / 2,这样开始就能往左滑动 565 | // 但是要保证这个值与getRealPosition 的 余数为0,因为要从第一页开始显示 566 | int currentItem = getRealCount() * mLooperCountFactor / 2; 567 | if(currentItem % getRealCount() ==0 ){ 568 | return currentItem; 569 | } 570 | // 直到找到从0开始的位置 571 | while (currentItem % getRealCount() != 0){ 572 | currentItem++; 573 | } 574 | return currentItem; 575 | } 576 | 577 | public void setDatas(List datas) { 578 | mDatas = datas; 579 | } 580 | 581 | @Override 582 | public int getCount() { 583 | // 2017.6.10 bug fix 584 | // 如果getCount 的返回值为Integer.MAX_VALUE 的话,那么在setCurrentItem的时候会ANR(除了在onCreate 调用之外) 585 | return canLoop ? getRealCount() * mLooperCountFactor : getRealCount();//ViewPager返回int 最大值 586 | } 587 | 588 | @Override 589 | public boolean isViewFromObject(View view, Object object) { 590 | return view == object; 591 | } 592 | 593 | @Override 594 | public Object instantiateItem(ViewGroup container, final int position) { 595 | View view = getView(position,container); 596 | container.addView(view); 597 | return view; 598 | } 599 | 600 | @Override 601 | public void destroyItem(ViewGroup container, int position, Object object) { 602 | container.removeView((View) object); 603 | } 604 | 605 | @Override 606 | public void finishUpdate(ViewGroup container) { 607 | // 轮播模式才执行 608 | if(canLoop){ 609 | int position = mViewPager.getCurrentItem(); 610 | if (position == getCount() - 1) { 611 | position = 0; 612 | setCurrentItem(position); 613 | } 614 | } 615 | 616 | } 617 | 618 | private void setCurrentItem(int position){ 619 | try { 620 | mViewPager.setCurrentItem(position, false); 621 | }catch (IllegalStateException e){ 622 | e.printStackTrace(); 623 | } 624 | } 625 | 626 | /** 627 | * 获取真实的Count 628 | * @return 629 | */ 630 | private int getRealCount(){ 631 | return mDatas==null ? 0:mDatas.size(); 632 | } 633 | 634 | /** 635 | * 636 | * @param position 637 | * @param container 638 | * @return 639 | */ 640 | private View getView(int position,ViewGroup container){ 641 | 642 | final int realPosition = position % getRealCount(); 643 | MZViewHolder holder =null; 644 | // create holder 645 | holder = mMZHolderCreator.createViewHolder(); 646 | 647 | if(holder == null){ 648 | throw new RuntimeException("can not return a null holder"); 649 | } 650 | // create View 651 | View view = holder.createView(container.getContext()); 652 | 653 | if( mDatas!=null && mDatas.size()>0){ 654 | holder.onBind(container.getContext(),realPosition,mDatas.get(realPosition)); 655 | } 656 | 657 | // 添加点击事件 658 | view.setOnClickListener(new OnClickListener() { 659 | @Override 660 | public void onClick(View v) { 661 | if(mPageClickListener!=null){ 662 | mPageClickListener.onPageClick(v,realPosition); 663 | } 664 | } 665 | }); 666 | 667 | return view; 668 | } 669 | 670 | 671 | } 672 | 673 | /** 674 | * 675 | *由于ViewPager 默认的切换速度有点快,因此用一个Scroller 来控制切换的速度 676 | *

而实际上ViewPager 切换本来就是用的Scroller来做的,因此我们可以通过反射来

677 | *

获取取到ViewPager 的 mScroller 属性,然后替换成我们自己的Scroller

678 | */ 679 | public static class ViewPagerScroller extends Scroller{ 680 | private int mDuration = 800;// ViewPager默认的最大Duration 为600,我们默认稍微大一点。值越大越慢。 681 | private boolean mIsUseDefaultDuration = false; 682 | 683 | public ViewPagerScroller(Context context) { 684 | super(context); 685 | } 686 | 687 | public ViewPagerScroller(Context context, Interpolator interpolator) { 688 | super(context, interpolator); 689 | } 690 | 691 | public ViewPagerScroller(Context context, Interpolator interpolator, boolean flywheel) { 692 | super(context, interpolator, flywheel); 693 | } 694 | 695 | @Override 696 | public void startScroll(int startX, int startY, int dx, int dy) { 697 | super.startScroll(startX, startY, dx, dy,mDuration); 698 | } 699 | 700 | @Override 701 | public void startScroll(int startX, int startY, int dx, int dy, int duration) { 702 | super.startScroll(startX, startY, dx, dy, mIsUseDefaultDuration?duration:mDuration); 703 | } 704 | 705 | public void setUseDefaultDuration(boolean useDefaultDuration) { 706 | mIsUseDefaultDuration = useDefaultDuration; 707 | } 708 | 709 | public boolean isUseDefaultDuration() { 710 | return mIsUseDefaultDuration; 711 | } 712 | 713 | public void setDuration(int duration) { 714 | mDuration = duration; 715 | } 716 | 717 | 718 | public int getScrollDuration() { 719 | return mDuration; 720 | } 721 | } 722 | 723 | /** 724 | * Banner page 点击回调 725 | */ 726 | public interface BannerPageClickListener{ 727 | void onPageClick(View view, int position); 728 | } 729 | 730 | public static int dpToPx(int dp) { 731 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics()); 732 | } 733 | 734 | } 735 | -------------------------------------------------------------------------------- /mzbanner/src/main/java/com/zhouwei/mzbanner/holder/MZHolderCreator.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbanner.holder; 2 | 3 | /** 4 | * Created by zhouwei on 17/5/26. 5 | */ 6 | 7 | public interface MZHolderCreator { 8 | /** 9 | * 创建ViewHolder 10 | * @return 11 | */ 12 | public VH createViewHolder(); 13 | } 14 | -------------------------------------------------------------------------------- /mzbanner/src/main/java/com/zhouwei/mzbanner/holder/MZViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbanner.holder; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by zhouwei on 17/5/26. 8 | */ 9 | 10 | public interface MZViewHolder { 11 | /** 12 | * 创建View 13 | * @param context 14 | * @return 15 | */ 16 | View createView(Context context); 17 | 18 | /** 19 | * 绑定数据 20 | * @param context 21 | * @param position 22 | * @param data 23 | */ 24 | void onBind(Context context, int position, T data); 25 | } 26 | -------------------------------------------------------------------------------- /mzbanner/src/main/java/com/zhouwei/mzbanner/transformer/CoverModeTransformer.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbanner.transformer; 2 | 3 | import android.support.v4.view.ViewPager; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by zhouwei on 17/8/20. 8 | */ 9 | 10 | public class CoverModeTransformer implements ViewPager.PageTransformer { 11 | 12 | private float reduceX = 0.0f; 13 | private float itemWidth = 0; 14 | private float offsetPosition = 0f; 15 | private int mCoverWidth; 16 | private float mScaleMax = 1.0f; 17 | private float mScaleMin = 0.9f; 18 | private ViewPager mViewPager; 19 | public CoverModeTransformer(ViewPager pager){ 20 | mViewPager = pager; 21 | } 22 | 23 | @Override 24 | public void transformPage(View view, float position) { 25 | if (offsetPosition == 0f) { 26 | float paddingLeft = mViewPager.getPaddingLeft(); 27 | float paddingRight = mViewPager.getPaddingRight(); 28 | float width = mViewPager.getMeasuredWidth(); 29 | offsetPosition = paddingLeft / (width - paddingLeft - paddingRight); 30 | } 31 | float currentPos = position - offsetPosition; 32 | if (itemWidth == 0) { 33 | itemWidth = view.getWidth(); 34 | //由于左右边的缩小而减小的x的大小的一半 35 | reduceX = (2.0f - mScaleMax - mScaleMin) * itemWidth / 2.0f; 36 | } 37 | if (currentPos <= -1.0f) { 38 | view.setTranslationX(reduceX + mCoverWidth); 39 | view.setScaleX(mScaleMin); 40 | view.setScaleY(mScaleMin); 41 | } else if (currentPos <= 1.0) { 42 | float scale = (mScaleMax - mScaleMin) * Math.abs(1.0f - Math.abs(currentPos)); 43 | float translationX = currentPos * -reduceX; 44 | if (currentPos <= -0.5) {//两个view中间的临界,这时两个view在同一层,左侧View需要往X轴正方向移动覆盖的值() 45 | view.setTranslationX(translationX + mCoverWidth * Math.abs(Math.abs(currentPos) - 0.5f) / 0.5f); 46 | } else if (currentPos <= 0.0f) { 47 | view.setTranslationX(translationX); 48 | } else if (currentPos >= 0.5) {//两个view中间的临界,这时两个view在同一层 49 | view.setTranslationX(translationX - mCoverWidth * Math.abs(Math.abs(currentPos) - 0.5f) / 0.5f); 50 | } else { 51 | view.setTranslationX(translationX); 52 | } 53 | view.setScaleX(scale + mScaleMin); 54 | view.setScaleY(scale + mScaleMin); 55 | } else { 56 | view.setScaleX(mScaleMin); 57 | view.setScaleY(mScaleMin); 58 | view.setTranslationX(-reduceX - mCoverWidth); 59 | } 60 | 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /mzbanner/src/main/java/com/zhouwei/mzbanner/transformer/ScaleYTransformer.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbanner.transformer; 2 | 3 | import android.support.v4.view.ViewPager; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by zhouwei on 17/5/26. 8 | */ 9 | 10 | public class ScaleYTransformer implements ViewPager.PageTransformer { 11 | private static final float MIN_SCALE = 0.9F; 12 | @Override 13 | public void transformPage(View page, float position) { 14 | 15 | if(position < -1){ 16 | page.setScaleY(MIN_SCALE); 17 | }else if(position<= 1){ 18 | // 19 | float scale = Math.max(MIN_SCALE,1 - Math.abs(position)); 20 | page.setScaleY(scale); 21 | /*page.setScaleX(scale); 22 | 23 | if(position<0){ 24 | page.setTranslationX(width * (1 - scale) /2); 25 | }else{ 26 | page.setTranslationX(-width * (1 - scale) /2); 27 | }*/ 28 | 29 | }else{ 30 | page.setScaleY(MIN_SCALE); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /mzbanner/src/main/res/drawable/indicator_normal.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /mzbanner/src/main/res/drawable/indicator_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /mzbanner/src/main/res/layout/mz_banner_effect_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 15 | 16 | 17 | 23 | 30 | 31 | -------------------------------------------------------------------------------- /mzbanner/src/main/res/layout/mz_banner_normal_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 11 | 12 | 18 | 25 | 26 | -------------------------------------------------------------------------------- /mzbanner/src/main/res/values/attr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /mzbanner/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /mzbanner/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MZBanner 3 | 4 | -------------------------------------------------------------------------------- /mzbanner/src/test/java/com/zhouwei/mzbanner/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zhouwei.mzbanner; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ### MZBannerView 2 | 3 | [![](https://img.shields.io/badge/release-v2.0.2-blue.svg)](https://github.com/pinguo-zhouwei/MZBannerView/releases) 4 | [![](https://img.shields.io/badge/MZBannerView-v2.0.2-brightgreen.svg)](https://github.com/pinguo-zhouwei/MZBannerView) 5 | [![](https://img.shields.io/badge/API-16%2B-brightgreen.svg)](https://github.com/pinguo-zhouwei/MZBannerView) 6 | [![](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/pinguo-zhouwei/MZBannerView) 7 | [![](https://img.shields.io/badge/License-Apache--2.0-brightgreen.svg)]() 8 | [![](https://img.shields.io/badge/%E7%AE%80%E4%B9%A6-%E4%BE%9D%E7%84%B6%E8%8C%83%E7%89%B9%E7%A8%80%E8%A5%BF-red.svg)](https://www.jianshu.com/u/35167a70aa39) 9 | [![](https://img.shields.io/badge/%E5%85%AC%E4%BC%97%E5%8F%B7-Android%E6%8A%80%E6%9C%AF%E6%9D%82%E8%B4%A7%E9%93%BA-blue.svg)](https://mp.weixin.qq.com/mp/homepage?__biz=MzIxMTg5NjQyMA==&hid=1&sn=6914e8d560a0d524f937af629488b6b5&scene=1&devicetype=iMac+MacBookPro12%2C1+OSX+OSX+10.11.5+build(15F34)&version=12020810&lang=zh_CN&nettype=WIFI&ascene=0&session_us=gh_d32aef65c1b3&fontScale=100&pass_ticket=Wty8DxZurpU2xxUkFPtXL5oqMrigpoVVh1agsDKXukmezsMUUJaWb%2FdIlcrhpQOq&wx_header=1&uin=OTU2MjA1MzIy&key=ebe51358ecae289391e767e9274e1a2bf8576a9e4fd5bc2b31956a627346413f84f752a9dd302e2a157b6fb84991a4142881a8143d21cdd25b805b8ba327e3ba78443337a68c9a1b32095d9adc30ec4b) 10 | 11 | 现在的APP Banner大多数千篇一律,前几天看到魅族手机上所有魅族自家APP上的Banner效果不错,于是就想着来仿着做一个类似的效果。因此就有了这个库。但是为了使用方便,这个库不仅仅只有仿魅族效果的BannerView 来使用,还可以当作普通的BannerView 来使用,还可以当作一个ViewPager 来使用。使用很方便,具体使用方法和API 请看后面的示例。 12 | 13 | 14 | ![meizuappbanner](image/meizuappbanner.gif) --- ![魅族bannerView](image/魅族Banner_fial.gif) 15 | 左图为魅族APP上的Banner效果,右图是高仿效果。 16 | 17 | 18 | 19 | **MZBannerView 有以下功能:** 20 | 21 | 1 . 仿魅族BannerView 效果。 22 | 23 | 2 . 当普通Banner 使用 24 | 25 | 3 . 当普通ViewPager 使用。 26 | 27 | 4 . 当普通ViewPager使用(有魅族Banner效果) 28 | 29 | 5 . 仿爱奇艺Banner效果。 30 | 31 | ### Demo APK 32 | 33 | gif图片有点模糊,可以扫描下方二维码下载APK体验 34 | 35 | ![demo二维码.png](image/demo二维码.png) 36 | 37 | ### 相关博客 38 | 39 | [ViewPager系列之 仿魅族应用的广告BannerView](http://www.jianshu.com/p/653680cfe877) 40 | 41 | ### 更新日志 42 | 43 | **v1.1.1 :** 增加按住Banner 停止轮播,松开开始自动轮播的功能 44 | 45 | **v1.1.0 :** fix 在从网上获取数据后,banner 显示 造成 ANR 的bug(如果在onCreate()中设置资源显示则没问题) 46 | 47 | **v1.1.2 :** fix 更改数据之后,调用setPages重新刷新数据会crush的bug 48 | 49 | **v2.0.0 :** 50 | 51 | 1,add: 添加仿魅族Banner效果,中间Page覆盖两边。 52 | 53 | 2,fix 部分bug: 添加OnPageChangeListener 回调 pisition 不对的bug. 54 | 55 | **v2.0.1** 56 | 57 | 1 , 部分代码优化 58 | 2,添加设置Indicator的api,代码中和xml中都可以设置: 59 | 代码中: 60 | ```java 61 | mMZBanner.setIndicatorAlign(MZBannerView.IndicatorAlign.LEFT); 62 | mMZBanner.setIndicatorPadding(10,0,0,150); 63 | 64 | ``` 65 | xml中: 66 | ```java 67 | app:indicatorAlign="center" 68 | app:indicatorPaddingLeft="10dp" 69 | app:indicatorPaddingBottom="50dp" 70 | app:indicatorPaddingRight="10dp" 71 | app:indicatorPaddingTop="50dp" 72 | ``` 73 | **v2.0.2** 74 | 75 | 1,修复部分bug 76 | 2,代码优化,增加在代码中可以设置是否自动轮播 77 | 78 | 79 | >重要: 代码中所有的配置项都应该在`setPages()` 之前调用,不然有可能会无效 80 | 81 | 82 | ### Dependency 83 | Add it in your root build.gradle at the end of repositories: 84 | 85 | ```java 86 | allprojects { 87 | repositories { 88 | ... 89 | maven { url 'https://jitpack.io' } 90 | } 91 | } 92 | ``` 93 | Step 2. Add the dependency 94 | ``` 95 | dependencies { 96 | compile 'com.github.pinguo-zhouwei:MZBannerView:v2.0.2' 97 | } 98 | ``` 99 | 100 | ### 自定义属性 101 | 102 | | 属性名 | 属性意义 | 取值 | 103 | | -------- | -----: | :----: | 104 | | open_mz_mode | 是否开启魅族模式 | true 为魅族Banner效果,false 则普通Banner效果 | 105 | | canLoop | 是否轮播 | true 轮播,false 则为普通ViewPager | 106 | | indicatorPaddingLeft | 设置指示器距离左侧的距离 | 单位为 dp 的值 | 107 | | indicatorPaddingRight | 设置指示器距离右侧的距离 | 单位为 dp 的值 | 108 | | indicatorAlign | 设置指示器的位置 | 有三个取值:left 左边,center 剧中显示,right 右侧显示 | 109 | | middle_page_cover | 设置中间Page是否覆盖(真正的魅族Banner效果) | true 覆盖,false 无覆盖效果 | 110 | 111 | 112 | ### 使用方法 113 | 114 | 1 . xml 布局文件 115 | ```java 116 | 126 | ``` 127 | 2 . activity中代码: 128 | ```java 129 | mMZBanner = (MZBannerView) view.findViewById(R.id.banner); 130 | 131 | // 设置数据 132 | mMZBanner.setPages(list, new MZHolderCreator() { 133 | @Override 134 | public BannerViewHolder createViewHolder() { 135 | return new BannerViewHolder(); 136 | } 137 | }); 138 | 139 | public static class BannerViewHolder implements MZViewHolder { 140 | private ImageView mImageView; 141 | @Override 142 | public View createView(Context context) { 143 | // 返回页面布局 144 | View view = LayoutInflater.from(context).inflate(R.layout.banner_item,null); 145 | mImageView = (ImageView) view.findViewById(R.id.banner_image); 146 | return view; 147 | } 148 | 149 | @Override 150 | public void onBind(Context context, int position, Integer data) { 151 | // 数据绑定 152 | mImageView.setImageResource(data); 153 | } 154 | } 155 | ``` 156 | 3 .如果是当Banner使用,注意在onResume 中调用start()方法,在onPause中调用 pause() 方法。如果当普通ViewPager使用,则不需要。 157 | ```java 158 | @Override 159 | public void onPause() { 160 | super.onPause(); 161 | mMZBanner.pause();//暂停轮播 162 | } 163 | 164 | @Override 165 | public void onResume() { 166 | super.onResume(); 167 | mMZBanner.start();//开始轮播 168 | } 169 | ``` 170 | 171 | **通过`open_mz_mode `、`middle_page_cover`和`canLoop `这3个属性来控制MZBannerView 是用作Banner还是普通ViewPager,能控制多种Banner展示效果:** 172 | 173 | 1 . 魅族Banner 效果,中间Page覆盖两边。 174 | 175 | ```java 176 | app:open_mz_mode="true" 177 | app:canLoop="true" 178 | app:middle_page_cover="true" 179 | ``` 180 | 181 | ![Page 覆盖效果](http://upload-images.jianshu.io/upload_images/3513995-39f495bf8a915ad0.gif?imageMogr2/auto-orient/strip) 182 | 183 | 2 普通banner 使用。 184 | 185 | ```java 186 | app:open_mz_mode="false" 187 | app:canLoop="true" 188 | ``` 189 | ![普通Banner效果](http://upload-images.jianshu.io/upload_images/3513995-39f495bf8a915ad0.gif?imageMogr2/auto-orient/strip) 190 | 191 | 上图中的底部BannerView 示例。 192 | 193 | 3 仿魅族Banner 效果,中间Page不覆盖。 194 | 195 | ```java 196 | app:open_mz_mode="true" 197 | app:canLoop="true" 198 | app:middle_page_cover="false" 199 | ``` 200 | 201 | ![Page不覆盖效果](http://upload-images.jianshu.io/upload_images/3513995-9aa19c594f932982.gif?imageMogr2/auto-orient/strip) 202 | 203 | 4 仿爱奇艺Banner效果,Page 之间有间隔。 204 | 205 | ```java 206 | 216 | ``` 217 | 218 | 除了上面的代码外,还需要在Page 的item 布局里面设置左右Margin: 219 | 220 | ```java 221 | 222 | 226 | 234 | 235 | ``` 236 | 效果如下: 237 | 238 | ![仿爱奇艺Banner效果](http://upload-images.jianshu.io/upload_images/3513995-f753f5449512c06c.gif?imageMogr2/auto-orient/strip) 239 | 240 | 5 有魅族Banner 效果的普通ViewPager 使用 241 | 242 | 243 | ```java 244 | app:open_mz_mode="true" 245 | app:canLoop="false" 246 | ``` 247 | 248 | ![魅族Banner效果的普通ViewPager](http://upload-images.jianshu.io/upload_images/3513995-29d27def0753dd86.gif?imageMogr2/auto-orient/strip) 249 | 250 | 6 普通ViewPager 使用 251 | 252 | ```java 253 | app:canLoop="false" 254 | app:open_mz_mode="false" 255 | ``` 256 | 257 | ![普通ViewPager](http://upload-images.jianshu.io/upload_images/3513995-6cb035771cda9870.gif?imageMogr2/auto-orient/strip) 258 | 259 | 上面都是用Banner 展示的本地数据,但是项目中我们一般都是从网络获取Banner 数据,具体参考:`RemoteTestFragment.java` 260 | 261 | ![从网络获取数据](image/network_data.gif) 262 | 263 | 264 | 265 | 266 | ### 其他对外API 267 | ```java 268 | /******************************************************************************************************/ 269 | /** 对外API **/ 270 | /******************************************************************************************************/ 271 | //开始轮播 272 | start() 273 | //停止轮播 274 | pause() 275 | 276 | //设置BannerView 的切换时间间隔 277 | setDelayedTime(int delayedTime) 278 | // 设置页面改变监听器 279 | addPageChangeLisnter(ViewPager.OnPageChangeListener onPageChangeListener) 280 | 281 | //添加Page点击事件 282 | setBannerPageClickListener(BannerPageClickListener bannerPageClickListener) 283 | //设置是否显示Indicator 284 | setIndicatorVisible(boolean visible) 285 | // 获取ViewPager 286 | ViewPager getViewPager() 287 | // 设置 Indicator资源 288 | setIndicatorRes(int unSelectRes,int selectRes) 289 | //设置页面数据 290 | setPages(List datas,MZHolderCreator mzHolderCreator) 291 | //设置指示器显示位置 292 | setIndicatorAlign(IndicatorAlign indicatorAlign) 293 | //设置ViewPager(Banner)切换速度 294 | setDuration(int duration) 295 | ``` 296 | 因为是对ViewPager的包装,所有要设置某些ViewPager的属性,可以通过getViewPager 获取到ViewPager再设置对应属性 297 | 298 | ### 效果图: 299 | 300 | 1, BannerView 轮播效果图: 301 | 302 | ![魅族bannerView](image/魅族Banner_fial.gif) 303 | 304 | 305 | ### Thanks 306 | 感谢[Android-ConvenientBanner](https://github.com/saiwu-bigkoo/Android-ConvenientBanner),Android-ConvenientBanner 是一个不错的Banner库,我也参考了其中的部分代码 307 | 有兴趣的可以去看一下这个库。 308 | 感谢[ScaleViewPager](https://github.com/liuyuejinqiu/ScaleViewPager) 提供中间Page覆盖效果的思路。 309 | 310 | ### 联系方式 311 | 简书:[http://www.jianshu.com/u/35167a70aa39](http://www.jianshu.com/u/35167a70aa39) 312 | 313 | 掘金:[https://juejin.im/user/56949a9960b2e058a42be0ba](https://juejin.im/user/56949a9960b2e058a42be0ba) 314 | 315 | 公众号:**Android技术杂货铺** 316 | 317 | 欢迎关注我的公众号,第一时间获取我的博客更新提醒,以及更多有价值的原创Android干货文章、职场经验、面试技巧等等。 318 | 长按下方二维码即可关注。 319 | 320 | ![gzh.jpg](image/gzh.jpg) 321 | 322 | 323 | ### License 324 | 325 | ``` 326 | Copyright (C) 2017 zhouwei 327 | 328 | Licensed under the Apache License, Version 2.0 (the "License"); 329 | you may not use this file except in compliance with the License. 330 | You may obtain a copy of the License at 331 | 332 | http://www.apache.org/licenses/LICENSE-2.0 333 | 334 | Unless required by applicable law or agreed to in writing, software 335 | distributed under the License is distributed on an "AS IS" BASIS, 336 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 337 | See the License for the specific language governing permissions and 338 | limitations under the License. 339 | ``` -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':mzbanner' 2 | --------------------------------------------------------------------------------