├── README.md └── TuTu ├── .classpath ├── .project ├── AndroidManifest.xml ├── bin ├── AndroidManifest.xml ├── classes │ └── com │ │ └── example │ │ └── lunbotu │ │ ├── ADBean.class │ │ ├── BuildConfig.class │ │ ├── ImageUtil$1.class │ │ ├── ImageUtil$ImageCallback.class │ │ ├── ImageUtil$getImageRunnable.class │ │ ├── ImageUtil.class │ │ ├── MainActivityTwo.class │ │ ├── MyAdapter$1.class │ │ ├── MyAdapter$OnItemClickListener.class │ │ ├── MyAdapter.class │ │ ├── R$attr.class │ │ ├── R$dimen.class │ │ ├── R$drawable.class │ │ ├── R$id.class │ │ ├── R$layout.class │ │ ├── R$string.class │ │ ├── R.class │ │ ├── ThreadPoolManager.class │ │ ├── TuTu$1.class │ │ ├── TuTu$2.class │ │ ├── TuTu$3.class │ │ ├── TuTu$4.class │ │ ├── TuTu$FixedSpeedScroller.class │ │ └── TuTu.class └── jarlist.cache ├── gen └── com │ └── example │ └── lunbotu │ ├── BuildConfig.java │ └── R.java ├── ic_launcher-web.png ├── libs └── android-support-v4.jar ├── proguard-project.txt ├── project.properties ├── res ├── drawable-hdpi │ ├── five.jpg │ ├── fore.jpg │ ├── ic_launcher.png │ ├── one.jpg │ ├── three.jpg │ └── two.jpg ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── drawable-xxhdpi │ └── ic_launcher.png ├── drawable │ ├── point_normal.xml │ ├── point_seletor.xml │ └── ponit_focus.xml ├── layout │ ├── activity_main.xml │ └── image_item.xml └── values │ ├── attrs.xml │ ├── dimens.xml │ └── strings.xml └── src └── com └── example └── lunbotu ├── ADBean.java ├── ImageUtil.java ├── MainActivityTwo.java ├── MyAdapter.java ├── ThreadPoolManager.java ├── TuTu.java └── widget ├── CircleFlowIndicator.java ├── FlowIndicator.java ├── ImageAdapter.java ├── TuTu2.java └── ViewFlow.java /README.md: -------------------------------------------------------------------------------- 1 | # 轮播图 2 | 可以加载本地图片或者网络资源的无限循环的轮播图,一行代码调用,图片三级缓存,节省流量,间隔自己设置,使用方便。 3 | 4 | 5 | 6 | 1、你只要写好布局就行,布局写成啥样你自己决定,扩展性强,满足多样化需求 7 | 例如: 8 | 9 | 10 | 11 | 16 | 17 | 18 | 23 | 24 | 31 | 32 | 39 | 40 | 47 | 48 | 49 | 50 | 51 | 52 | 2、添加轮播图对象 53 | 54 | 这是轮播图对象 55 | private String id; 56 | private String adName;//广告词 57 | private String imgUrl;//网络图片资源 58 | private int imgPath=-1;//本地图片资源 59 | private ImageView mImageView; 60 | 61 | 62 | 63 | 64 | 初始化轮播图对象并添加到list里面 65 | 66 | List listADbeans; 67 | /** 68 | * 本地图片资源 69 | */ 70 | private int[] ids = { R.drawable.one, R.drawable.two, R.drawable.three, 71 | R.drawable.fore, R.drawable.five }; 72 | /** 73 | * 显示文字 74 | */ 75 | private String[] des = { "1111111", "22222222", "3333333", "4444444444","55555555555" }; 76 | /** 77 | * 网络资源 78 | */ 79 | private String[] urls = { "http://a.hiphotos.baidu.com/image/pic/item/0bd162d9f2d3572ce98282e18e13632762d0c3af.jpg", 80 | "http://d.hiphotos.baidu.com/image/pic/item/1b4c510fd9f9d72aebede7a1d62a2834359bbb85.jpg", 81 | "http://h.hiphotos.baidu.com/image/pic/item/91ef76c6a7efce1be2f4f15cad51f3deb58f654c.jpg", 82 | "http://h.hiphotos.baidu.com/image/w%3D230/sign=3e9ec55457fbb2fb342b5f117f4b2043/e850352ac65c1038343303cbb0119313b07e896e.jpg", 83 | "http://e.hiphotos.baidu.com/image/pic/item/d53f8794a4c27d1e3625e52d18d5ad6edcc438dc.jpg" }; 84 | 85 | listADbeans = new ArrayList(); 86 | for(int i =0;i<5;i++){ 87 | ADBean bean = new ADBean(); 88 | bean.setAdName(des[i]);//广告文字 89 | bean.setId(i+""); 90 | bean.setImgUrl(urls[i]);//添加网络图片资源,如果不需要可以不用添加 91 | bean.setImgPath(ids[i]);//添加本地图片资源,如果不需要可以不用添加,如果网络资源和本地资源同时添加,默认使用的是本地资源,所以建议本地资源和网络资源添加一个 92 | listADbeans.add(bean); 93 | } 94 | 95 | 96 | 97 | 3、然后你只要把布局和轮播图对象添加进去就好了,同时开启轮播图 98 | 99 | TuTu tu = new TuTu(ad_viewPage, tv_msg, ll_dian, mContext, listADbeans);//把布局添加进去 100 | tu.startViewPager(4000);//动态设置滑动间隔,并且开启轮播图 101 | 102 | 4、在activity销毁时也罢要把轮播图销毁 103 | 104 | /** 105 | * 销毁轮播图 106 | */ 107 | @Override 108 | protected void onDestroy() { 109 | if(tu!=null){ 110 | tu.destroyView(); 111 | } 112 | super.onDestroy(); 113 | } 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /TuTu/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /TuTu/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | TuTu 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /TuTu/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /TuTu/bin/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/ADBean.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/ADBean.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/BuildConfig.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/BuildConfig.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/ImageUtil$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/ImageUtil$1.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/ImageUtil$ImageCallback.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/ImageUtil$ImageCallback.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/ImageUtil$getImageRunnable.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/ImageUtil$getImageRunnable.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/ImageUtil.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/ImageUtil.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/MainActivityTwo.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/MainActivityTwo.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/MyAdapter$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/MyAdapter$1.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/MyAdapter$OnItemClickListener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/MyAdapter$OnItemClickListener.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/MyAdapter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/MyAdapter.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/R$attr.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/R$attr.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/R$dimen.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/R$dimen.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/R$drawable.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/R$drawable.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/R$id.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/R$id.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/R$layout.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/R$layout.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/R$string.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/R$string.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/R.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/R.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/ThreadPoolManager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/ThreadPoolManager.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/TuTu$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/TuTu$1.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/TuTu$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/TuTu$2.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/TuTu$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/TuTu$3.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/TuTu$4.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/TuTu$4.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/TuTu$FixedSpeedScroller.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/TuTu$FixedSpeedScroller.class -------------------------------------------------------------------------------- /TuTu/bin/classes/com/example/lunbotu/TuTu.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/bin/classes/com/example/lunbotu/TuTu.class -------------------------------------------------------------------------------- /TuTu/bin/jarlist.cache: -------------------------------------------------------------------------------- 1 | # cache for current jar dependency. DO NOT EDIT. 2 | # format is 3 | # Encoding is UTF-8 4 | -------------------------------------------------------------------------------- /TuTu/gen/com/example/lunbotu/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /** Automatically generated file. DO NOT MODIFY */ 2 | package com.example.lunbotu; 3 | 4 | public final class BuildConfig { 5 | public final static boolean DEBUG = true; 6 | } -------------------------------------------------------------------------------- /TuTu/gen/com/example/lunbotu/R.java: -------------------------------------------------------------------------------- 1 | /* AUTO-GENERATED FILE. DO NOT MODIFY. 2 | * 3 | * This class was automatically generated by the 4 | * aapt tool from the resource data it found. It 5 | * should not be modified by hand. 6 | */ 7 | 8 | package com.example.lunbotu; 9 | 10 | public final class R { 11 | public static final class attr { 12 | } 13 | public static final class dimen { 14 | /** Default screen margins, per the Android Design guidelines. 15 | */ 16 | public static final int activity_horizontal_margin=0x7f040000; 17 | public static final int activity_vertical_margin=0x7f040001; 18 | } 19 | public static final class drawable { 20 | public static final int five=0x7f020000; 21 | public static final int fore=0x7f020001; 22 | public static final int ic_launcher=0x7f020002; 23 | public static final int one=0x7f020003; 24 | public static final int point_normal=0x7f020004; 25 | public static final int point_seletor=0x7f020005; 26 | public static final int ponit_focus=0x7f020006; 27 | public static final int three=0x7f020007; 28 | public static final int two=0x7f020008; 29 | } 30 | public static final class id { 31 | public static final int ad_viewPage=0x7f060000; 32 | public static final int ll_dian=0x7f060002; 33 | public static final int tv_msg=0x7f060001; 34 | } 35 | public static final class layout { 36 | public static final int activity_main=0x7f030000; 37 | } 38 | public static final class string { 39 | public static final int action_settings=0x7f050002; 40 | public static final int app_name=0x7f050000; 41 | public static final int hello_world=0x7f050001; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /TuTu/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/ic_launcher-web.png -------------------------------------------------------------------------------- /TuTu/libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/libs/android-support-v4.jar -------------------------------------------------------------------------------- /TuTu/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /TuTu/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /TuTu/res/drawable-hdpi/five.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/res/drawable-hdpi/five.jpg -------------------------------------------------------------------------------- /TuTu/res/drawable-hdpi/fore.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/res/drawable-hdpi/fore.jpg -------------------------------------------------------------------------------- /TuTu/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /TuTu/res/drawable-hdpi/one.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/res/drawable-hdpi/one.jpg -------------------------------------------------------------------------------- /TuTu/res/drawable-hdpi/three.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/res/drawable-hdpi/three.jpg -------------------------------------------------------------------------------- /TuTu/res/drawable-hdpi/two.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/res/drawable-hdpi/two.jpg -------------------------------------------------------------------------------- /TuTu/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /TuTu/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /TuTu/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kongdongdong/TuTu/2c964ae0dc4f08ef530610653412dab6ed20ee9f/TuTu/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /TuTu/res/drawable/point_normal.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /TuTu/res/drawable/point_seletor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /TuTu/res/drawable/ponit_focus.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /TuTu/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 17 | 18 | 25 | 26 | 33 | 34 | 41 | 42 | 43 | 44 | 45 | 50 | 51 | 55 | 56 | 57 | 64 | 65 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /TuTu/res/layout/image_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /TuTu/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /TuTu/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /TuTu/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 轮播图 5 | Hello world! 6 | Settings 7 | 8 | 9 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/ADBean.java: -------------------------------------------------------------------------------- 1 | package com.example.lunbotu; 2 | 3 | import android.graphics.Bitmap; 4 | import android.widget.ImageView; 5 | 6 | public class ADBean { 7 | 8 | private String id; 9 | private String adName;//广告词 10 | private String imgUrl;//网络图片资源 11 | private int imgPath=-1;//本地图片资源 12 | private ImageView mImageView; 13 | private Bitmap bitmap; 14 | 15 | 16 | public ImageView getmImageView() { 17 | return mImageView; 18 | } 19 | public void setmImageView(ImageView mImageView) { 20 | this.mImageView = mImageView; 21 | } 22 | public String getId() { 23 | return id; 24 | } 25 | public void setId(String id) { 26 | this.id = id; 27 | } 28 | public String getAdName() { 29 | return adName; 30 | } 31 | public void setAdName(String adName) { 32 | this.adName = adName; 33 | } 34 | public String getImgUrl() { 35 | return imgUrl; 36 | } 37 | public void setImgUrl(String imgUrl) { 38 | this.imgUrl = imgUrl; 39 | } 40 | public int getImgPath() { 41 | return imgPath; 42 | } 43 | public void setImgPath(int imgPath) { 44 | this.imgPath = imgPath; 45 | } 46 | public Bitmap getBitmap() { 47 | return bitmap; 48 | } 49 | public void setBitmap(Bitmap bitmap) { 50 | this.bitmap = bitmap; 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/ImageUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.lunbotu; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.ByteArrayInputStream; 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.FileNotFoundException; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.lang.ref.SoftReference; 13 | import java.net.HttpURLConnection; 14 | import java.net.URLConnection; 15 | import java.net.URL; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | import android.content.Context; 20 | import android.graphics.Bitmap; 21 | import android.graphics.BitmapFactory; 22 | import android.graphics.drawable.Drawable; 23 | import android.os.Environment; 24 | import android.os.Handler; 25 | import android.os.Message; 26 | import android.util.Log; 27 | 28 | /** 29 | * 30 | * 图片缓存类,封装了网络获取图片,本地缓存,内存缓存 31 | * 32 | **/ 33 | 34 | public class ImageUtil { 35 | private static HashMap> imageCache = new HashMap>(); 36 | public static final String IMAGE_PATH = "/sdcard/images/"; 37 | private Context mContext; 38 | public ImageUtil(Context mContext) { 39 | this.mContext = mContext; 40 | } 41 | /** 42 | * 对图片进行质量压�? 43 | * @param image 44 | * @return 45 | */ 46 | public Bitmap compressImage(Bitmap image) { 47 | 48 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 49 | image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这�?00表示不压缩,把压缩后的数据存放到baos�? 50 | int options = 100; 51 | while ( baos.toByteArray().length / 1024 > 800) { //循环判断如果压缩后图片是否大�?00kb,大于继续压缩 52 | baos.reset();//重置baos即清空baos 53 | image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos�? 54 | options -= 10;//每次都减�?0 55 | } 56 | ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream�? 57 | Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片 58 | return bitmap; 59 | } 60 | /** 61 | * JPG图片缓存 62 | * 63 | * @param imagePath 64 | * @param bitmap 65 | * @throws IOException 66 | */ 67 | public static void saveImageJpeg(String imagePath, Bitmap bitmap) 68 | throws IOException { 69 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 70 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); 71 | byte[] b = bos.toByteArray(); 72 | saveImage(imagePath, b); 73 | bos.flush(); 74 | bos.close(); 75 | } 76 | 77 | /** 78 | * PNG图片缓存 79 | * 80 | * @param imagePath 81 | * @param buffer 82 | * @throws IOException 83 | */ 84 | 85 | public static void saveImagePng(String imagePath, Bitmap bitmap) 86 | throws IOException { 87 | 88 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 89 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos); 90 | byte[] b = bos.toByteArray(); 91 | saveImage(imagePath, b); 92 | bos.flush(); 93 | bos.close(); 94 | } 95 | 96 | /** 97 | * 缓存图片 98 | * 99 | * @param imagePath 100 | * @param buffer 101 | * @throws IOException 102 | */ 103 | public static void saveImage(String imagePath, byte[] buffer) 104 | throws IOException { 105 | File f = new File(imagePath); 106 | if (f.exists()) { 107 | return; 108 | } else { 109 | File parentFile = f.getParentFile(); 110 | if (!parentFile.exists()) { 111 | parentFile.mkdirs(); 112 | } 113 | f.createNewFile(); 114 | FileOutputStream fos = new FileOutputStream(imagePath); 115 | fos.write(buffer); 116 | fos.flush(); 117 | fos.close(); 118 | } 119 | } 120 | 121 | /** 122 | * 从本地获取图片 123 | * 124 | * @param imagePath 125 | * @return Bitmap 126 | */ 127 | public static Bitmap getImageFromLocal(String imagePath) { 128 | File file = new File(imagePath); 129 | if (file.exists()) { 130 | Bitmap bitmap = BitmapFactory.decodeFile(imagePath); 131 | file.setLastModified(System.currentTimeMillis()); 132 | return bitmap; 133 | } 134 | return null; 135 | } 136 | 137 | /** 138 | * 从网络获取图片并缓存 139 | * 140 | * @return Bitmap 141 | * @throws IOException 142 | */ 143 | Bitmap mbitmap = null; 144 | String url = null; 145 | public void loadImage(final String imageName, final String imgUrl, 146 | final boolean isbusy, final ImageCallback callback) { 147 | callback.onStart(imgUrl); 148 | Bitmap bitmap = null; 149 | if (imageCache.containsKey(imgUrl)) { 150 | SoftReference softReference = imageCache.get(imgUrl); 151 | bitmap = softReference.get(); 152 | if (bitmap != null) { 153 | Log.i(TuTu.TAG, "从内存获得图片成功。。"); 154 | callback.loadImage(bitmap, imgUrl); 155 | } 156 | } 157 | bitmap = getBitmapFromData(imageName, mContext); 158 | if (bitmap != null) { 159 | imageCache.put(imgUrl, new SoftReference(bitmap)); 160 | Log.i(TuTu.TAG, "从本地获得图片成功。。"); 161 | callback.loadImage(bitmap, imgUrl); 162 | } else {// 从网络获取图片 163 | final Handler handler = new Handler() { 164 | @Override 165 | public void handleMessage(Message msg) { 166 | if (msg.obj != null) { 167 | synchronized (imageCache) { 168 | Map bitmapMap = (Map) msg.obj; 169 | for(String str:bitmapMap.keySet()){ 170 | mbitmap = bitmapMap.get(str); 171 | url = str; 172 | imageCache.put(url,new SoftReference(mbitmap)); 173 | } 174 | 175 | if (android.os.Environment.getExternalStorageState() 176 | .equals(android.os.Environment.MEDIA_MOUNTED)) { 177 | try { 178 | String imageName = url.substring(url.lastIndexOf("/")+1, url.length()); 179 | if(!imageName.endsWith(".jpg") && !imageName.endsWith(".png")){ 180 | imageName += ".png"; 181 | } 182 | String mImagePath = ImageUtil.IMAGE_PATH+imageName; 183 | saveBitmapToData(imageName, mbitmap, mContext); 184 | 185 | } catch (Exception e) { 186 | e.printStackTrace(); 187 | } 188 | } 189 | 190 | callback.loadImage(mbitmap, url); 191 | } 192 | 193 | 194 | } 195 | } 196 | }; 197 | 198 | getImageRunnable run = new getImageRunnable(imgUrl,handler,callback); 199 | ThreadPoolManager.getInstance().addTask(run); 200 | } 201 | } 202 | 203 | class getImageRunnable implements Runnable{ 204 | 205 | private String url; 206 | private Handler mHandler; 207 | private ImageCallback mCallback; 208 | public getImageRunnable(String imgUrl, Handler handler,ImageCallback callback) { 209 | url = imgUrl; 210 | mHandler = handler; 211 | mCallback = callback; 212 | } 213 | 214 | @Override 215 | public void run() { 216 | try { 217 | synchronized (imageCache) { 218 | 219 | } 220 | 221 | Bitmap bitmap = null; 222 | if (url != null && !"".equals(url)) { 223 | byte[] b = getUrlBytes(url); 224 | bitmap = BitmapFactory.decodeByteArray(b, 0, 225 | b.length); 226 | //bitmap = compressImage(bitmap); 227 | } 228 | Message msg = mHandler.obtainMessage(); 229 | Map bitmapMap = new HashMap(); 230 | bitmapMap.put(url, bitmap); 231 | msg.obj = bitmapMap; 232 | mHandler.sendMessage(msg); 233 | } catch (Exception e) { 234 | e.printStackTrace(); 235 | synchronized (imageCache) { 236 | mCallback.onFailed(url); 237 | } 238 | 239 | } 240 | } 241 | 242 | } 243 | 244 | public static int computeSampleSize(BitmapFactory.Options options, 245 | int minSideLength, int maxNumOfPixels) { 246 | int initialSize = computeInitialSampleSize(options, minSideLength, 247 | maxNumOfPixels); 248 | 249 | int roundedSize; 250 | if (initialSize <= 8) { 251 | roundedSize = 1; 252 | while (roundedSize < initialSize) { 253 | roundedSize <<= 1; 254 | } 255 | } else { 256 | roundedSize = (initialSize + 7) / 8 * 8; 257 | } 258 | 259 | return roundedSize; 260 | } 261 | 262 | private static int computeInitialSampleSize(BitmapFactory.Options options, 263 | int minSideLength, int maxNumOfPixels) { 264 | double w = options.outWidth; 265 | double h = options.outHeight; 266 | 267 | int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math 268 | .sqrt(w * h / maxNumOfPixels)); 269 | int upperBound = (minSideLength == -1) ? 128 : (int) Math.min( 270 | Math.floor(w / minSideLength), Math.floor(h / minSideLength)); 271 | 272 | if (upperBound < lowerBound) { 273 | // return the larger one when there is no overlapping zone. 274 | return lowerBound; 275 | } 276 | 277 | if ((maxNumOfPixels == -1) && (minSideLength == -1)) { 278 | return 1; 279 | } else if (minSideLength == -1) { 280 | return lowerBound; 281 | } else { 282 | return upperBound; 283 | } 284 | } 285 | 286 | /** 287 | * 获取指定路径的Byte[]数据-通用 288 | * 289 | * @param urlpath 290 | * @return byte[] 291 | * @throws Exception 292 | */ 293 | public static byte[] getUrlBytes(String urlpath) throws Exception { 294 | InputStream in_s = getUrlInputStream(urlpath); 295 | return readStream(in_s); 296 | } 297 | 298 | /** 299 | * 获取指定路径的InputStream数据-通用 300 | * 301 | * @param urlpath 302 | * @return byte[] 303 | * @throws Exception 304 | */ 305 | public static InputStream getUrlInputStream(String urlpath) 306 | throws Exception { 307 | URL url = new URL(urlpath); 308 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 309 | // conn.setRequestMethod("GET"); 310 | conn.setRequestMethod("GET"); 311 | conn.setConnectTimeout(15*1000);// 10秒超时 312 | int responseCode = conn.getResponseCode(); 313 | Log.i("image", responseCode + ""); 314 | System.out.println(responseCode + ""); 315 | if (responseCode == HttpURLConnection.HTTP_OK) {// 返回码200等于返回成功 316 | InputStream inputStream = conn.getInputStream(); 317 | return inputStream; 318 | } 319 | return null; 320 | } 321 | 322 | /** 323 | * 从InputStream中读取数据-通用 324 | * 325 | * @param inStream 326 | * @return byte[] 327 | * @throws Exception 328 | */ 329 | public static byte[] readStream(InputStream inStream) throws Exception { 330 | ByteArrayOutputStream outstream = new ByteArrayOutputStream(); 331 | byte[] buffer = new byte[128]; 332 | int len = -1; 333 | while ((len = inStream.read(buffer)) != -1) { 334 | outstream.write(buffer, 0, len); 335 | } 336 | outstream.close(); 337 | inStream.close(); 338 | return outstream.toByteArray(); 339 | } 340 | 341 | /** 342 | * 获取缓存路径 343 | * 344 | * @return sd卡路径 345 | */ 346 | public static String getCacheImgPath() { 347 | return Environment.getExternalStorageDirectory().getPath() 348 | + "/ambow/cache/"; 349 | } 350 | /** 351 | * 将图片保存到data/data目录下 352 | * 353 | * @param name 354 | * @param bitmap 355 | * @param context 356 | */ 357 | public void saveBitmapToData(String name, Bitmap bitmap, Context context) { 358 | try { 359 | FileOutputStream localFileOutputStream1 = context.openFileOutput( 360 | name, 0); 361 | 362 | Bitmap.CompressFormat localCompressFormat = Bitmap.CompressFormat.PNG; 363 | bitmap.compress(localCompressFormat, 100, localFileOutputStream1); 364 | 365 | localFileOutputStream1.close(); 366 | } catch (Exception e) { 367 | e.printStackTrace(); 368 | } 369 | } 370 | 371 | /** 372 | * 获取data/data下的图片文件 373 | * @param name 374 | * @param context 375 | * @return 376 | */ 377 | public Bitmap getBitmapFromData(String name, Context context) { 378 | FileInputStream localStream; 379 | Bitmap bitmap = null; 380 | try { 381 | localStream = context.openFileInput(name); 382 | bitmap = BitmapFactory.decodeStream(localStream); 383 | } catch (FileNotFoundException e) { 384 | e.printStackTrace(); 385 | } 386 | 387 | return bitmap; 388 | } 389 | 390 | 391 | /** 392 | * 类功能描述:给网络上获取的图片设置的回调 393 | * 394 | * @version 1.0

修改时间:
修改备注:
395 | */ 396 | public interface ImageCallback { 397 | public void onStart(String imageUrl); 398 | public void loadImage(Bitmap bitmap, String imageUrl); 399 | public void onFailed(String imageUrl); 400 | } 401 | 402 | } 403 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/MainActivityTwo.java: -------------------------------------------------------------------------------- 1 | package com.example.lunbotu; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import android.app.Activity; 7 | import android.content.Context; 8 | import android.os.Bundle; 9 | import android.support.v4.view.ViewPager; 10 | import android.widget.ImageView; 11 | import android.widget.LinearLayout; 12 | import android.widget.TextView; 13 | 14 | import com.example.lunbotu.widget.CircleFlowIndicator; 15 | import com.example.lunbotu.widget.ImageAdapter; 16 | import com.example.lunbotu.widget.TuTu2; 17 | import com.example.lunbotu.widget.ViewFlow; 18 | 19 | public class MainActivityTwo extends Activity{ 20 | 21 | private ViewPager ad_viewPage; 22 | /** 23 | * 显示的文字Textview 24 | */ 25 | private TextView tv_msg; 26 | /** 27 | * 添加小圆点的线性布局 28 | */ 29 | private LinearLayout ll_dian; 30 | /** 31 | * 轮播图对象列表 32 | */ 33 | List listADbeans; 34 | List listADbeans2; 35 | /** 36 | * 本地图片资源 37 | */ 38 | private int[] ids = { R.drawable.one, R.drawable.two, R.drawable.three, 39 | R.drawable.fore, R.drawable.five }; 40 | /** 41 | * 显示文字 42 | */ 43 | private String[] des = { "1111111", "22222222", "3333333", "4444444444","55555555555" }; 44 | /** 45 | * 网络资源 46 | */ 47 | private String[] urls = { "http://a.hiphotos.baidu.com/image/pic/item/0bd162d9f2d3572ce98282e18e13632762d0c3af.jpg", 48 | "http://d.hiphotos.baidu.com/image/pic/item/1b4c510fd9f9d72aebede7a1d62a2834359bbb85.jpg", 49 | "http://h.hiphotos.baidu.com/image/pic/item/91ef76c6a7efce1be2f4f15cad51f3deb58f654c.jpg", 50 | "http://h.hiphotos.baidu.com/image/w%3D230/sign=3e9ec55457fbb2fb342b5f117f4b2043/e850352ac65c1038343303cbb0119313b07e896e.jpg", 51 | "http://e.hiphotos.baidu.com/image/pic/item/d53f8794a4c27d1e3625e52d18d5ad6edcc438dc.jpg" }; 52 | 53 | private TuTu tu; 54 | private Context mContext; 55 | private ViewFlow viewFlow; 56 | private ImageAdapter imageAdapter; 57 | 58 | protected void onCreate(Bundle savedInstanceState) { 59 | super.onCreate(savedInstanceState); 60 | setContentView(R.layout.activity_main); 61 | mContext = this; 62 | initView(); 63 | //initAD(); 64 | initAD2(); 65 | } 66 | private void initAD2() { 67 | listADbeans2 = new ArrayList(); 68 | for(int i =0;i<5;i++){ 69 | ADBean bean = new ADBean(); 70 | bean.setmImageView(new ImageView(mContext)); 71 | bean.setAdName(des[i]); 72 | bean.setId(i+""); 73 | bean.setImgUrl(urls[i]);//网络图片 74 | //bean.setImgPath(ids[i]); 75 | listADbeans2.add(bean); 76 | } 77 | 78 | imageAdapter = new ImageAdapter(this,listADbeans2); 79 | viewFlow = (ViewFlow) findViewById(R.id.viewflow); 80 | viewFlow.setAdapter(imageAdapter); 81 | viewFlow.setmSideBuffer(listADbeans2.size()); // 实际图片张数, 我的ImageAdapter实际图片张数为3 82 | 83 | CircleFlowIndicator indic = (CircleFlowIndicator) findViewById(R.id.viewflowindic); 84 | TuTu2 tutu2 = new TuTu2(this,viewFlow,listADbeans2,imageAdapter); 85 | tutu2.setFlowIndicator(indic); 86 | tutu2.setTimeSpan(4000); 87 | tutu2.setSelection(3 * 1000); // 设置初始位置 88 | tutu2.startAutoFlowTimer(); // 启动自动播放 89 | tutu2.getNetImage(); 90 | /*viewFlow.setFlowIndicator(indic); 91 | viewFlow.setTimeSpan(4000); 92 | viewFlow.setSelection(3 * 1000); // 设置初始位置 93 | viewFlow.startAutoFlowTimer(); // 启动自动播放 94 | */ 95 | } 96 | /** 97 | * 初始化轮播图 98 | */ 99 | private void initAD() { 100 | listADbeans = new ArrayList(); 101 | for(int i =0;i<5;i++){ 102 | ADBean bean = new ADBean(); 103 | bean.setAdName(des[i]); 104 | bean.setId(i+""); 105 | bean.setImgUrl(urls[i]); 106 | //bean.setImgPath(ids[i]); 107 | listADbeans.add(bean); 108 | } 109 | tu = new TuTu(ad_viewPage, tv_msg, ll_dian, mContext, listADbeans); 110 | tu.startViewPager(4000);//动态设置滑动间隔,并且开启轮播图 111 | } 112 | 113 | /** 114 | * 初始化布局 115 | */ 116 | private void initView() { 117 | ad_viewPage = (ViewPager)findViewById(R.id.ad_viewPage); 118 | tv_msg = (TextView)findViewById(R.id.tv_msg); 119 | ll_dian = (LinearLayout)findViewById(R.id.ll_dian); 120 | 121 | } 122 | /** 123 | * 销毁轮播图 124 | */ 125 | @Override 126 | protected void onDestroy() { 127 | tu.destroyView(); 128 | super.onDestroy(); 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/MyAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.lunbotu; 2 | 3 | import java.util.List; 4 | 5 | import android.support.v4.view.PagerAdapter; 6 | import android.view.View; 7 | import android.view.View.OnClickListener; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | import android.widget.ImageView.ScaleType; 11 | import android.widget.RelativeLayout; 12 | import android.widget.LinearLayout.LayoutParams; 13 | 14 | public class MyAdapter extends PagerAdapter { 15 | List listADbeans=null; 16 | OnItemClickListener onItemClickListener; 17 | public MyAdapter(List listADbeans) { 18 | this.listADbeans = listADbeans; 19 | 20 | } 21 | public int getCount() { 22 | //把这个条数数值很大很大 23 | if(listADbeans != null && listADbeans.size()==1){ 24 | return 1; 25 | }else{ 26 | return Integer.MAX_VALUE; 27 | } 28 | 29 | } 30 | /**相当于getView:实例化每个页面的View和添加View 31 | * container:ViewPage 容器 32 | * position 位置 33 | */ 34 | public Object instantiateItem(ViewGroup container, final int position) { 35 | 36 | //根据位置取出某一个View 37 | ImageView view = null; 38 | if(listADbeans.size()==1){ 39 | view = listADbeans.get(0).getmImageView(); 40 | if(listADbeans.get(0).getImgPath() != -1){ 41 | view.setBackgroundResource(listADbeans.get(0).getImgPath()); 42 | } 43 | }else{ 44 | view = listADbeans.get(position%listADbeans.size()).getmImageView(); 45 | if(listADbeans.get(position%listADbeans.size()).getImgPath() != -1){ 46 | view.setBackgroundResource(listADbeans.get(position%listADbeans.size()).getImgPath()); 47 | } 48 | ViewGroup parent = (ViewGroup) view.getParent(); 49 | if (parent != null ) { 50 | //parent.removeView(view); 51 | container.removeView(view); 52 | } 53 | } 54 | 55 | 56 | 57 | view.setScaleType(ScaleType.FIT_XY); 58 | 59 | //添加到容器 60 | container.addView(view); 61 | /** 62 | * 添加点击事件 63 | */ 64 | view.setOnClickListener(new OnClickListener() { 65 | public void onClick(View v) { 66 | onItemClickListener.OnItemClick(v, position%listADbeans.size()); 67 | } 68 | }); 69 | 70 | return view;//返回实例化的View 71 | } 72 | /** 73 | * 判断view和instantiateItem返回的对象是否一样 74 | * Object : 时instantiateItem返回的对象 75 | */ 76 | public boolean isViewFromObject(View view, Object object) { 77 | if(view == object){ 78 | return true; 79 | }else{ 80 | return false; 81 | } 82 | } 83 | 84 | 85 | /**| 86 | * 实例化两张图片,最多只能装三张图片 87 | */ 88 | public void destroyItem(ViewGroup container, int position, Object object) { 89 | 90 | //释放资源, 91 | //container.removeView((View) object); 92 | 93 | } 94 | 95 | public synchronized void notifyImages(List listADbeans){ 96 | this.listADbeans = listADbeans; 97 | notifyDataSetChanged(); 98 | } 99 | 100 | public interface OnItemClickListener{ 101 | void OnItemClick(View view,int position); 102 | } 103 | 104 | public void setOnItemClickListener(OnItemClickListener onItemClickListener){ 105 | this.onItemClickListener = onItemClickListener; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/ThreadPoolManager.java: -------------------------------------------------------------------------------- 1 | package com.example.lunbotu; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | /** 7 | * 线程管理器 8 | **/ 9 | public class ThreadPoolManager { 10 | private ExecutorService service; 11 | 12 | private ThreadPoolManager(){ 13 | int num = Runtime.getRuntime().availableProcessors(); 14 | service = Executors.newFixedThreadPool(num); 15 | 16 | } 17 | 18 | private static final ThreadPoolManager manager= new ThreadPoolManager(); 19 | 20 | public static ThreadPoolManager getInstance(){ 21 | return manager; 22 | } 23 | 24 | public void addTask(Runnable runnable){ 25 | service.execute(runnable); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/TuTu.java: -------------------------------------------------------------------------------- 1 | package com.example.lunbotu; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Timer; 7 | import java.util.TimerTask; 8 | 9 | import com.example.lunbotu.ImageUtil.ImageCallback; 10 | import com.example.lunbotu.MyAdapter.OnItemClickListener; 11 | 12 | import android.annotation.SuppressLint; 13 | import android.content.Context; 14 | import android.graphics.Bitmap; 15 | import android.graphics.drawable.BitmapDrawable; 16 | import android.graphics.drawable.Drawable; 17 | import android.os.Handler; 18 | import android.support.v4.view.ViewPager; 19 | import android.support.v4.view.ViewPager.OnPageChangeListener; 20 | import android.text.TextUtils; 21 | import android.util.Log; 22 | import android.view.View; 23 | import android.view.View.OnClickListener; 24 | import android.view.animation.AccelerateInterpolator; 25 | import android.view.animation.Interpolator; 26 | import android.widget.ImageView; 27 | import android.widget.LinearLayout; 28 | import android.widget.Scroller; 29 | import android.widget.TextView; 30 | import android.widget.LinearLayout.LayoutParams; 31 | 32 | public class TuTu implements OnItemClickListener { 33 | public static final String TAG = "TuTu"; 34 | private ViewPager mViewPager; 35 | private TextView mTextView; 36 | private LinearLayout mLinearLayout; 37 | private MyAdapter myPagerAdapter; 38 | private int lastPoint = 0; 39 | private boolean isRunning = false; 40 | boolean stat = false; 41 | private Timer timer; 42 | private TimerTask timerTask; 43 | private List listADbeans; 44 | private Context mContext; 45 | private ImageUtil imageUtil; 46 | private int newPosition=0; 47 | private long delay=4000; 48 | Handler handler = new Handler() { 49 | public void handleMessage(android.os.Message msg) { 50 | int what = msg.what; 51 | if(what == 0){ 52 | if(listADbeans.size()>1){ 53 | mViewPager.setCurrentItem(mViewPager.getCurrentItem()+1, true); 54 | } 55 | 56 | 57 | } 58 | if(what ==1){ 59 | myPagerAdapter.notifyImages(listADbeans); 60 | } 61 | }; 62 | }; 63 | public TuTu(ViewPager mViewPager,TextView mTextView,LinearLayout mLinearLayout,Context mContext,List listADbeans) { 64 | this.mContext = mContext; 65 | this.listADbeans = listADbeans; 66 | this.mViewPager = mViewPager; 67 | this.mTextView = mTextView; 68 | this.mLinearLayout = mLinearLayout; 69 | imageUtil = new ImageUtil(mContext); 70 | //changeViewpagerSpace(); 71 | initADViewpager(); 72 | 73 | } 74 | 75 | /** 76 | * 改变viewpager切换速度 77 | */ 78 | private void changeViewpagerSpace() { 79 | try { 80 | Field field = ViewPager.class.getDeclaredField("mScroller"); 81 | field.setAccessible(true); 82 | FixedSpeedScroller scroller = new FixedSpeedScroller(mViewPager.getContext(), 83 | new AccelerateInterpolator()); 84 | field.set(mViewPager, scroller); 85 | //scroller.setmDuration(200); 86 | } catch (Exception e) { 87 | e.printStackTrace(); 88 | } 89 | 90 | } 91 | private void initADViewpager() { 92 | for(int i = 0; i < listADbeans.size(); i++){ 93 | 94 | ImageView view = new ImageView(mContext); 95 | //view.setBackgroundResource(listADbeans.get(i).getImgPath()); 96 | // 把图片添加到列表 97 | listADbeans.get(i).setmImageView(view); 98 | // 实例化指示点 99 | ImageView point = new ImageView(mContext); 100 | point.setImageResource(R.drawable.point_seletor); 101 | LayoutParams params = new LayoutParams(dip2px(mContext,6), dip2px(mContext,6)); 102 | params.leftMargin = dip2px(mContext,10); 103 | point.setLayoutParams(params); 104 | // 将指示点添加到线性布局里 105 | mLinearLayout.addView(point); 106 | 107 | // 设置第一个高亮显示 108 | if (i == 0) { 109 | point.setEnabled(true); 110 | } else { 111 | point.setEnabled(false); 112 | } 113 | 114 | 115 | } 116 | // 设置适配器 117 | myPagerAdapter = new MyAdapter(listADbeans); 118 | myPagerAdapter.setOnItemClickListener(this); 119 | mViewPager.setAdapter(myPagerAdapter); 120 | // 设置默认文字信息 121 | if(listADbeans!= null && listADbeans.size()>0 && mTextView!= null){ 122 | mTextView.setText(listADbeans.get(0).getAdName()); 123 | } 124 | int midPosition = Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 125 | % listADbeans.size(); 126 | if(listADbeans.size()==1){ 127 | midPosition = 0; 128 | } 129 | mViewPager.setCurrentItem(midPosition); 130 | // 设置页面改变监听 131 | mViewPager.setOnPageChangeListener(new OnPageChangeListener() { 132 | private float mPreviousOffset = -1; 133 | private float mPreviousPosition = -1; 134 | /** 135 | * 当某个页面被选中的时候回调 136 | */ 137 | @Override 138 | public void onPageSelected(int position) { 139 | newPosition = position % listADbeans.size(); 140 | 141 | 142 | // 取出广告文字 143 | String msg = listADbeans.get(position % listADbeans.size()).getAdName(); 144 | if(mTextView!=null){ 145 | mTextView.setText(msg); 146 | } 147 | 148 | // 设置对应的页面高亮 149 | mLinearLayout.getChildAt(newPosition).setEnabled(true); 150 | // 是上次的点不显示高亮 151 | mLinearLayout.getChildAt(lastPoint).setEnabled(false); 152 | 153 | lastPoint = newPosition; 154 | 155 | } 156 | 157 | /** 158 | * 当某个页面被滚动的时候回调 159 | */ 160 | @Override 161 | public void onPageScrolled(int position, float positionOffset, 162 | int positionOffsetPixels) { 163 | 164 | } 165 | 166 | /** 167 | * 当状态发生改变的时候回调, 静止-滚动-静止 168 | */ 169 | @Override 170 | public void onPageScrollStateChanged(int state) { 171 | 172 | if(state ==1){ 173 | timer.cancel(); 174 | //timerTask.cancel(); 175 | stat = true; 176 | } 177 | if(state ==0){ 178 | if(stat){ 179 | startViewPager(delay); 180 | } 181 | stat = false; 182 | } 183 | } 184 | }); 185 | 186 | isRunning = true; 187 | getNetImages(); 188 | 189 | } 190 | /** 191 | * 加载网络图片 192 | */ 193 | private void getNetImages() { 194 | for(ADBean ad:listADbeans){ 195 | String url = ad.getImgUrl(); 196 | if(url ==null || TextUtils.isEmpty(url)){ 197 | return; 198 | } 199 | String imageName = url.substring(url.lastIndexOf("/")+1, url.length()); 200 | if(!imageName.endsWith(".jpg") && !imageName.endsWith(".png")){ 201 | imageName += ".png"; 202 | } 203 | String imagePath = ImageUtil.IMAGE_PATH+imageName; 204 | if(url!= null && !TextUtils.isEmpty(url)){ 205 | imageUtil.loadImage(imageName, url, true, new ImageCallback() { 206 | 207 | @Override 208 | public void onStart(String imageUrl) { 209 | Log.i(TAG, "开始=="+imageUrl); 210 | 211 | } 212 | 213 | @Override 214 | public void onFailed(String imageUrl) { 215 | Log.i(TAG, "失败=="+imageUrl); 216 | 217 | } 218 | 219 | @Override 220 | public void loadImage(Bitmap bitmap, String imageUrl) { 221 | Log.i(TAG, imageUrl); 222 | for(ADBean bean :listADbeans){ 223 | if(imageUrl.equals(bean.getImgUrl())){ 224 | bean.getmImageView().setImageBitmap(bitmap); 225 | } 226 | } 227 | handler.sendEmptyMessage(1); 228 | 229 | } 230 | }); 231 | } 232 | } 233 | 234 | } 235 | /** 236 | * 开启轮播图 237 | * @param delay 238 | */ 239 | public void startViewPager(long delay) { 240 | this.delay = delay; 241 | timer = new Timer(); 242 | timerTask = new TimerTask() { 243 | public void run() { 244 | handler.sendEmptyMessage(0); 245 | } 246 | }; 247 | timer.schedule(timerTask, delay,delay); 248 | } 249 | 250 | public void destroyView() { 251 | if(timer != null){ 252 | timer.cancel(); 253 | } 254 | if(timerTask!= null){ 255 | timerTask.cancel(); 256 | } 257 | } 258 | 259 | public class FixedSpeedScroller extends Scroller { 260 | private int mDuration = 400; 261 | 262 | public FixedSpeedScroller(Context context) { 263 | super(context); 264 | } 265 | 266 | public FixedSpeedScroller(Context context, Interpolator interpolator) { 267 | super(context, interpolator); 268 | } 269 | 270 | @Override 271 | public void startScroll(int startX, int startY, int dx, int dy, int duration) { 272 | // Ignore received duration, use fixed one instead 273 | super.startScroll(startX, startY, dx, dy, mDuration); 274 | } 275 | 276 | @Override 277 | public void startScroll(int startX, int startY, int dx, int dy) { 278 | // Ignore received duration, use fixed one instead 279 | super.startScroll(startX, startY, dx, dy, mDuration); 280 | } 281 | 282 | public void setmDuration(int time) { 283 | mDuration = time; 284 | } 285 | 286 | public int getmDuration() { 287 | return mDuration; 288 | } 289 | } 290 | /** 291 | * 根据手机的分辨率从 dip 的单位 转成为 px(像素) 292 | */ 293 | public static int dip2px(Context context, float dpValue) { 294 | final float scale = context.getResources().getDisplayMetrics().density; 295 | return (int) (dpValue * scale + 0.5f); 296 | } 297 | 298 | /** 299 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp 300 | */ 301 | public static int px2dip(Context context, float pxValue) { 302 | final float scale = context.getResources().getDisplayMetrics().density; 303 | return (int) (pxValue / scale + 0.5f); 304 | } 305 | /** 306 | * viewpager的item点击事件 307 | */ 308 | @Override 309 | public void OnItemClick(View view, int position) { 310 | System.out.println(position+""); 311 | 312 | } 313 | 314 | } 315 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/widget/CircleFlowIndicator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Patrik �kerfeldt 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.lunbotu.widget; 17 | 18 | 19 | 20 | import android.content.Context; 21 | import android.content.res.TypedArray; 22 | import android.graphics.Canvas; 23 | import android.graphics.Paint; 24 | import android.graphics.Paint.Style; 25 | import android.os.AsyncTask; 26 | import android.util.AttributeSet; 27 | import android.view.View; 28 | import android.view.animation.Animation; 29 | import android.view.animation.Animation.AnimationListener; 30 | import android.view.animation.AnimationUtils; 31 | 32 | import com.example.lunbotu.R; 33 | 34 | /** 35 | * A FlowIndicator which draws circles (one for each view). 36 | *
37 | * Availables attributes are:
38 | *
    39 | * activeColor: Define the color used to draw the active circle (default to white) 40 | *
41 | *
    42 | * inactiveColor: Define the color used to draw the inactive circles (default to 0x44FFFFFF) 43 | *
44 | *
    45 | * inactiveType: Define how to draw the inactive circles, either stroke or fill (default to stroke) 46 | *
47 | *
    48 | * activeType: Define how to draw the active circle, either stroke or fill (default to fill) 49 | *
50 | *
    51 | * fadeOut: Define the time (in ms) until the indicator will fade out (default to 0 = never fade out) 52 | *
53 | *
    54 | * radius: Define the circle radius (default to 4.0) 55 | *
56 | */ 57 | public class CircleFlowIndicator extends View implements FlowIndicator, 58 | AnimationListener { 59 | private static final int STYLE_STROKE = 0; 60 | private static final int STYLE_FILL = 1; 61 | 62 | private float radius = 4; 63 | private float circleSeparation = 2*radius+radius; 64 | private float activeRadius = 0.5f; 65 | private int fadeOutTime = 0; 66 | private final Paint mPaintInactive = new Paint(Paint.ANTI_ALIAS_FLAG); 67 | private final Paint mPaintActive = new Paint(Paint.ANTI_ALIAS_FLAG); 68 | private ViewFlow viewFlow; 69 | private int currentScroll = 0; 70 | private int flowWidth = 0; 71 | private FadeTimer timer; 72 | public AnimationListener animationListener = this; 73 | private Animation animation; 74 | private boolean mCentered = false; 75 | 76 | /** 77 | * Default constructor 78 | * 79 | * @param context 80 | */ 81 | public CircleFlowIndicator(Context context) { 82 | super(context); 83 | initColors(0xFFFFFFFF, 0xFFFFFFFF, STYLE_FILL, STYLE_STROKE); 84 | } 85 | 86 | /** 87 | * The contructor used with an inflater 88 | * 89 | * @param context 90 | * @param attrs 91 | */ 92 | public CircleFlowIndicator(Context context, AttributeSet attrs) { 93 | super(context, attrs); 94 | // Retrieve styles attributs 95 | TypedArray a = context.obtainStyledAttributes(attrs, 96 | R.styleable.CircleFlowIndicator); 97 | 98 | // Gets the inactive circle type, defaulting to "fill" 99 | int activeType = a.getInt(R.styleable.CircleFlowIndicator_activeType, 100 | STYLE_FILL); 101 | 102 | int activeDefaultColor = 0xFFFFFFFF; 103 | 104 | // Get a custom inactive color if there is one 105 | int activeColor = a 106 | .getColor(R.styleable.CircleFlowIndicator_activeColor, 107 | activeDefaultColor); 108 | 109 | // Gets the inactive circle type, defaulting to "stroke" 110 | int inactiveType = a.getInt( 111 | R.styleable.CircleFlowIndicator_inactiveType, STYLE_STROKE); 112 | 113 | int inactiveDefaultColor = 0x44FFFFFF; 114 | // Get a custom inactive color if there is one 115 | int inactiveColor = a.getColor( 116 | R.styleable.CircleFlowIndicator_inactiveColor, 117 | inactiveDefaultColor); 118 | 119 | // Retrieve the radius 120 | radius = a.getDimension(R.styleable.CircleFlowIndicator_radius, 4.0f); 121 | 122 | circleSeparation = a.getDimension(R.styleable.CircleFlowIndicator_circleSeparation, 2*radius+radius); 123 | activeRadius = a.getDimension(R.styleable.CircleFlowIndicator_activeRadius, 0.5f); 124 | // Retrieve the fade out time 125 | fadeOutTime = a.getInt(R.styleable.CircleFlowIndicator_fadeOut, 0); 126 | 127 | mCentered = a.getBoolean(R.styleable.CircleFlowIndicator_centered, false); 128 | 129 | initColors(activeColor, inactiveColor, activeType, inactiveType); 130 | } 131 | 132 | private void initColors(int activeColor, int inactiveColor, int activeType, 133 | int inactiveType) { 134 | // Select the paint type given the type attr 135 | switch (inactiveType) { 136 | case STYLE_FILL: 137 | mPaintInactive.setStyle(Style.FILL); 138 | break; 139 | default: 140 | mPaintInactive.setStyle(Style.STROKE); 141 | } 142 | mPaintInactive.setColor(inactiveColor); 143 | 144 | // Select the paint type given the type attr 145 | switch (activeType) { 146 | case STYLE_STROKE: 147 | mPaintActive.setStyle(Style.STROKE); 148 | break; 149 | default: 150 | mPaintActive.setStyle(Style.FILL); 151 | } 152 | mPaintActive.setColor(activeColor); 153 | } 154 | 155 | /* 156 | * (non-Javadoc) 157 | * 158 | * @see android.view.View#onDraw(android.graphics.Canvas) 159 | */ 160 | @Override 161 | protected void onDraw(Canvas canvas) { 162 | super.onDraw(canvas); 163 | int count = 3; 164 | if (viewFlow != null) { 165 | count = viewFlow.getViewsCount(); 166 | } 167 | 168 | //this is the amount the first circle should be offset to make the entire thing centered 169 | float centeringOffset = 0; 170 | 171 | int leftPadding = getPaddingLeft(); 172 | 173 | // Draw stroked circles 174 | for (int iLoop = 0; iLoop < count; iLoop++) { 175 | canvas.drawCircle(leftPadding + radius 176 | + (iLoop * circleSeparation) + centeringOffset, 177 | getPaddingTop() + radius, radius, mPaintInactive); 178 | } 179 | float cx = 0; 180 | if (flowWidth != 0) { 181 | // Draw the filled circle according to the current scroll 182 | cx = (currentScroll * circleSeparation) / flowWidth; 183 | } 184 | // The flow width has been upadated yet. Draw the default position 185 | canvas.drawCircle(leftPadding + radius + cx+centeringOffset, getPaddingTop() 186 | + radius, radius + activeRadius, mPaintActive); 187 | } 188 | 189 | /* 190 | * (non-Javadoc) 191 | * 192 | * @see 193 | * org.taptwo.android.widget.ViewFlow.ViewSwitchListener#onSwitched(android 194 | * .view.View, int) 195 | */ 196 | @Override 197 | public void onSwitched(View view, int position) { 198 | } 199 | 200 | /* 201 | * (non-Javadoc) 202 | * 203 | * @see 204 | * org.taptwo.android.widget.FlowIndicator#setViewFlow(org.taptwo.android 205 | * .widget.ViewFlow) 206 | */ 207 | @Override 208 | public void setViewFlow(ViewFlow view) { 209 | resetTimer(); 210 | viewFlow = view; 211 | flowWidth = viewFlow.getWidth(); 212 | invalidate(); 213 | } 214 | 215 | /* 216 | * (non-Javadoc) 217 | * 218 | * @see org.taptwo.android.widget.FlowIndicator#onScrolled(int, int, int, 219 | * int) 220 | */ 221 | @Override 222 | public void onScrolled(int h, int v, int oldh, int oldv) { 223 | setVisibility(View.VISIBLE); 224 | resetTimer(); 225 | flowWidth = viewFlow.getWidth(); 226 | if(viewFlow.getViewsCount()*flowWidth!=0){ 227 | currentScroll = h%(viewFlow.getViewsCount()*flowWidth); 228 | }else { 229 | currentScroll = h; 230 | } 231 | invalidate(); 232 | } 233 | 234 | /* 235 | * (non-Javadoc) 236 | * 237 | * @see android.view.View#onMeasure(int, int) 238 | */ 239 | @Override 240 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 241 | setMeasuredDimension(measureWidth(widthMeasureSpec), 242 | measureHeight(heightMeasureSpec)); 243 | } 244 | 245 | /** 246 | * Determines the width of this view 247 | * 248 | * @param measureSpec 249 | * A measureSpec packed into an int 250 | * @return The width of the view, honoring constraints from measureSpec 251 | */ 252 | private int measureWidth(int measureSpec) { 253 | int result = 0; 254 | int specMode = MeasureSpec.getMode(measureSpec); 255 | int specSize = MeasureSpec.getSize(measureSpec); 256 | 257 | // We were told how big to be 258 | if (specMode == MeasureSpec.EXACTLY) { 259 | result = specSize; 260 | } 261 | // Calculate the width according the views count 262 | else { 263 | int count = 3; 264 | if (viewFlow != null) { 265 | count = viewFlow.getViewsCount(); 266 | } 267 | float temp = circleSeparation - 2*radius; 268 | result = (int) (getPaddingLeft() + getPaddingRight() 269 | + (count * 2 * radius) + (count - 1) * temp + 1); 270 | // Respect AT_MOST value if that was what is called for by 271 | // measureSpec 272 | if (specMode == MeasureSpec.AT_MOST) { 273 | result = Math.min(result, specSize); 274 | } 275 | } 276 | return result; 277 | } 278 | 279 | /** 280 | * Determines the height of this view 281 | * 282 | * @param measureSpec 283 | * A measureSpec packed into an int 284 | * @return The height of the view, honoring constraints from measureSpec 285 | */ 286 | private int measureHeight(int measureSpec) { 287 | int result = 0; 288 | int specMode = MeasureSpec.getMode(measureSpec); 289 | int specSize = MeasureSpec.getSize(measureSpec); 290 | 291 | // We were told how big to be 292 | if (specMode == MeasureSpec.EXACTLY) { 293 | result = specSize; 294 | } 295 | // Measure the height 296 | else { 297 | result = (int) (2 * radius + getPaddingTop() + getPaddingBottom() + 1); 298 | // Respect AT_MOST value if that was what is called for by 299 | // measureSpec 300 | if (specMode == MeasureSpec.AT_MOST) { 301 | result = Math.min(result, specSize); 302 | } 303 | } 304 | return result; 305 | } 306 | 307 | /** 308 | * Sets the fill color 309 | * 310 | * @param color 311 | * ARGB value for the text 312 | */ 313 | public void setFillColor(int color) { 314 | mPaintActive.setColor(color); 315 | invalidate(); 316 | } 317 | 318 | /** 319 | * Sets the stroke color 320 | * 321 | * @param color 322 | * ARGB value for the text 323 | */ 324 | public void setStrokeColor(int color) { 325 | mPaintInactive.setColor(color); 326 | invalidate(); 327 | } 328 | 329 | /** 330 | * Resets the fade out timer to 0. Creating a new one if needed 331 | */ 332 | private void resetTimer() { 333 | // Only set the timer if we have a timeout of at least 1 millisecond 334 | if (fadeOutTime > 0) { 335 | // Check if we need to create a new timer 336 | if (timer == null || timer._run == false) { 337 | // Create and start a new timer 338 | timer = new FadeTimer(); 339 | timer.execute(); 340 | } else { 341 | // Reset the current tiemr to 0 342 | timer.resetTimer(); 343 | } 344 | } 345 | } 346 | 347 | /** 348 | * Counts from 0 to the fade out time and animates the view away when 349 | * reached 350 | */ 351 | private class FadeTimer extends AsyncTask { 352 | // The current count 353 | private int timer = 0; 354 | // If we are inside the timing loop 355 | private boolean _run = true; 356 | 357 | public void resetTimer() { 358 | timer = 0; 359 | } 360 | 361 | @Override 362 | protected Void doInBackground(Void... arg0) { 363 | while (_run) { 364 | try { 365 | // Wait for a millisecond 366 | Thread.sleep(1); 367 | // Increment the timer 368 | timer++; 369 | 370 | // Check if we've reached the fade out time 371 | if (timer == fadeOutTime) { 372 | // Stop running 373 | _run = false; 374 | } 375 | } catch (InterruptedException e) { 376 | // TODO Auto-generated catch block 377 | e.printStackTrace(); 378 | } 379 | } 380 | return null; 381 | } 382 | 383 | @Override 384 | protected void onPostExecute(Void result) { 385 | animation = AnimationUtils.loadAnimation(getContext(), 386 | android.R.anim.fade_out); 387 | animation.setAnimationListener(animationListener); 388 | startAnimation(animation); 389 | } 390 | } 391 | 392 | @Override 393 | public void onAnimationEnd(Animation animation) { 394 | setVisibility(View.GONE); 395 | } 396 | 397 | @Override 398 | public void onAnimationRepeat(Animation animation) { 399 | } 400 | 401 | @Override 402 | public void onAnimationStart(Animation animation) { 403 | } 404 | } -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/widget/FlowIndicator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Patrik �kerfeldt 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.lunbotu.widget; 17 | 18 | import com.example.lunbotu.widget.ViewFlow.ViewSwitchListener; 19 | 20 | /** 21 | * An interface which defines the contract between a ViewFlow and a 22 | * FlowIndicator.
23 | * A FlowIndicator is responsible to show an visual indicator on the total views 24 | * number and the current visible view.
25 | * 26 | */ 27 | public interface FlowIndicator extends ViewSwitchListener { 28 | 29 | /** 30 | * Set the current ViewFlow. This method is called by the ViewFlow when the 31 | * FlowIndicator is attached to it. 32 | * 33 | * @param view 34 | */ 35 | public void setViewFlow(ViewFlow view); 36 | 37 | /** 38 | * The scroll position has been changed. A FlowIndicator may implement this 39 | * method to reflect the current position 40 | * 41 | * @param h 42 | * @param v 43 | * @param oldh 44 | * @param oldv 45 | */ 46 | public void onScrolled(int h, int v, int oldh, int oldv); 47 | } 48 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/widget/ImageAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Patrik �kerfeldt 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.lunbotu.widget; 17 | 18 | import java.util.List; 19 | 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.graphics.Bitmap; 23 | import android.os.Bundle; 24 | import android.view.LayoutInflater; 25 | import android.view.View; 26 | import android.view.View.OnClickListener; 27 | import android.view.ViewGroup; 28 | import android.widget.BaseAdapter; 29 | import android.widget.ImageView; 30 | 31 | import com.example.lunbotu.ADBean; 32 | import com.example.lunbotu.R; 33 | 34 | public class ImageAdapter extends BaseAdapter { 35 | List listADbeans=null; 36 | private Context mContext; 37 | private LayoutInflater mInflater; 38 | private int[] ids = {R.drawable.fore, R.drawable.two,R.drawable.five}; 39 | 40 | public ImageAdapter(Context context,List listADbeans) { 41 | mContext = context; 42 | mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 43 | this.listADbeans = listADbeans; 44 | } 45 | 46 | @Override 47 | public int getCount() { 48 | return Integer.MAX_VALUE; //返回很大的值使得getView中的position不断增大来实现循环 49 | } 50 | 51 | @Override 52 | public Object getItem(int position) { 53 | return position; 54 | } 55 | 56 | @Override 57 | public long getItemId(int position) { 58 | return position; 59 | } 60 | 61 | @Override 62 | public View getView(final int position, View convertView, ViewGroup parent) { 63 | if (convertView == null) { 64 | convertView = mInflater.inflate(R.layout.image_item, null); 65 | } 66 | //ImageView imageView = ((ImageView) convertView.findViewById(R.id.imgView)); 67 | ImageView imageView = listADbeans.get(position%listADbeans.size()).getmImageView(); 68 | if(listADbeans.get(position%listADbeans.size()).getImgPath() != -1){ 69 | imageView.setImageResource(listADbeans.get(position%listADbeans.size()).getImgPath()); 70 | }else{ 71 | if(listADbeans.get(position%listADbeans.size()).getBitmap() != null){ 72 | System.out.println("不为空。。。"); 73 | imageView.setImageBitmap(listADbeans.get(position%listADbeans.size()).getBitmap()); 74 | } 75 | } 76 | //imageView.setImageResource(ids[position%ids.length]); 77 | convertView.setOnClickListener(new OnClickListener() { 78 | @Override 79 | public void onClick(View v) { 80 | 81 | } 82 | }); 83 | return imageView; 84 | } 85 | /** 86 | * 判断view和instantiateItem返回的对象是否一样 87 | * Object : 时instantiateItem返回的对象 88 | */ 89 | public boolean isViewFromObject(View view, Object object) { 90 | if(view == object){ 91 | return true; 92 | }else{ 93 | return false; 94 | } 95 | } 96 | 97 | 98 | /** 99 | * 实例化两张图片,最多只能装三张图片 100 | */ 101 | public void destroyItem(ViewGroup container, int position, Object object) { 102 | 103 | //释放资源, 104 | container.removeView((View) object); 105 | } 106 | 107 | public void notifyImages(String imageUrl,Bitmap bitmap){ 108 | for(ADBean ad:listADbeans){ 109 | if(imageUrl.equals(ad.getImgUrl())){ 110 | System.out.println(imageUrl); 111 | ad.setBitmap(bitmap); 112 | } 113 | } 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/widget/TuTu2.java: -------------------------------------------------------------------------------- 1 | package com.example.lunbotu.widget; 2 | 3 | import java.util.List; 4 | 5 | import android.content.Context; 6 | import android.graphics.Bitmap; 7 | import android.os.Handler; 8 | import android.text.TextUtils; 9 | import android.util.Log; 10 | import android.widget.ImageView; 11 | 12 | import com.example.lunbotu.ADBean; 13 | import com.example.lunbotu.ImageUtil; 14 | import com.example.lunbotu.ImageUtil.ImageCallback; 15 | 16 | public class TuTu2 { 17 | private static String TAG = "tutu2"; 18 | private List listADbeans2; 19 | private ViewFlow viewFlow; 20 | private ImageUtil imageUtil; 21 | private Context mContext; 22 | private ImageAdapter imageAdapter; 23 | 24 | Handler handler = new Handler() { 25 | public void handleMessage(android.os.Message msg) { 26 | int what = msg.what; 27 | if(what ==1){ 28 | //imageAdapter.notifyImages(listADbeans2); 29 | } 30 | }; 31 | }; 32 | 33 | public TuTu2(Context mContext,ViewFlow viewFlow, List listADbeans2, ImageAdapter imageAdapter) { 34 | this.mContext = mContext; 35 | this.viewFlow = viewFlow; 36 | this.imageAdapter = imageAdapter; 37 | this.listADbeans2 = listADbeans2; 38 | imageUtil = new ImageUtil(mContext); 39 | //getNetImage(); 40 | } 41 | public void getNetImage() { 42 | for(ADBean ad:listADbeans2){ 43 | String url = ad.getImgUrl(); 44 | if(url ==null || TextUtils.isEmpty(url)){ 45 | return; 46 | } 47 | String imageName = url.substring(url.lastIndexOf("/")+1, url.length()); 48 | if(!imageName.endsWith(".jpg") && !imageName.endsWith(".png")){ 49 | imageName += ".png"; 50 | } 51 | String imagePath = ImageUtil.IMAGE_PATH+imageName; 52 | if(url!= null && !TextUtils.isEmpty(url)){ 53 | imageUtil.loadImage(imageName, url, true, new ImageCallback() { 54 | 55 | @Override 56 | public void onStart(String imageUrl) { 57 | // TODO Auto-generated method stub 58 | 59 | } 60 | 61 | @Override 62 | public void onFailed(String imageUrl) { 63 | // TODO Auto-generated method stub 64 | 65 | } 66 | 67 | @Override 68 | public void loadImage(Bitmap bitmap, String imageUrl) { 69 | /*for(ADBean ad:listADbeans2){ 70 | if(imageUrl.equals(ad.getImgUrl())){ 71 | ad.getmImageView().setImageBitmap(bitmap); 72 | } 73 | } 74 | handler.sendEmptyMessage(1);*/ 75 | imageAdapter.notifyImages(imageUrl, bitmap); 76 | 77 | }; 78 | }); 79 | } 80 | } 81 | 82 | } 83 | /** 84 | * 设置指示器 85 | * @param indic 86 | */ 87 | public void setFlowIndicator(CircleFlowIndicator indic){ 88 | viewFlow.setFlowIndicator(indic); 89 | } 90 | /** 91 | * 设置间隔时间 92 | * @param time 93 | */ 94 | public void setTimeSpan(long time){ 95 | viewFlow.setTimeSpan(time); 96 | } 97 | /** 98 | * 设置初始位置 99 | * @param position 100 | */ 101 | public void setSelection(int position){ 102 | viewFlow.setSelection(position); 103 | } 104 | /** 105 | * 开始 106 | */ 107 | public void startAutoFlowTimer(){ 108 | viewFlow.startAutoFlowTimer(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /TuTu/src/com/example/lunbotu/widget/ViewFlow.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Patrik Åkerfeldt 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.lunbotu.widget; 17 | 18 | import java.util.ArrayList; 19 | import java.util.LinkedList; 20 | 21 | import android.content.Context; 22 | import android.content.res.Configuration; 23 | import android.content.res.TypedArray; 24 | import android.database.DataSetObserver; 25 | import android.os.Handler; 26 | import android.os.Message; 27 | import android.util.AttributeSet; 28 | import android.view.MotionEvent; 29 | import android.view.VelocityTracker; 30 | import android.view.View; 31 | import android.view.ViewConfiguration; 32 | import android.view.ViewGroup; 33 | import android.view.ViewTreeObserver.OnGlobalLayoutListener; 34 | import android.widget.AbsListView; 35 | import android.widget.Adapter; 36 | import android.widget.AdapterView; 37 | import android.widget.Scroller; 38 | 39 | import com.example.lunbotu.R; 40 | 41 | /** 42 | * A horizontally scrollable {@link ViewGroup} with items populated from an 43 | * {@link Adapter}. The ViewFlow uses a buffer to store loaded {@link View}s in. 44 | * The default size of the buffer is 3 elements on both sides of the currently 45 | * visible {@link View}, making up a total buffer size of 3 * 2 + 1 = 7. The 46 | * buffer size can be changed using the {@code sidebuffer} xml attribute. 47 | * 48 | */ 49 | public class ViewFlow extends AdapterView { 50 | 51 | private static final int SNAP_VELOCITY = 1000; 52 | private static final int INVALID_SCREEN = -1; 53 | private final static int TOUCH_STATE_REST = 0; 54 | private final static int TOUCH_STATE_SCROLLING = 1; 55 | 56 | private LinkedList mLoadedViews; 57 | private int mCurrentBufferIndex; 58 | private int mCurrentAdapterIndex; 59 | private int mSideBuffer = 2; 60 | private Scroller mScroller; 61 | private VelocityTracker mVelocityTracker; 62 | private int mTouchState = TOUCH_STATE_REST; 63 | private float mLastMotionX; 64 | private int mTouchSlop; 65 | private int mMaximumVelocity; 66 | private int mCurrentScreen; 67 | private int mNextScreen = INVALID_SCREEN; 68 | private boolean mFirstLayout = true; 69 | private ViewSwitchListener mViewSwitchListener; 70 | private Adapter mAdapter; 71 | private int mLastScrollDirection; 72 | private AdapterDataSetObserver mDataSetObserver; 73 | private FlowIndicator mIndicator; 74 | private int mLastOrientation = -1; 75 | private long timeSpan = 3000; 76 | private Handler handler; 77 | private OnGlobalLayoutListener orientationChangeListener = new OnGlobalLayoutListener() { 78 | 79 | @Override 80 | public void onGlobalLayout() { 81 | getViewTreeObserver().removeGlobalOnLayoutListener( 82 | orientationChangeListener); 83 | setSelection(mCurrentAdapterIndex); 84 | } 85 | }; 86 | 87 | /** 88 | * Receives call backs when a new {@link View} has been scrolled to. 89 | */ 90 | public static interface ViewSwitchListener { 91 | 92 | /** 93 | * This method is called when a new View has been scrolled to. 94 | * 95 | * @param view 96 | * the {@link View} currently in focus. 97 | * @param position 98 | * The position in the adapter of the {@link View} currently in focus. 99 | */ 100 | void onSwitched(View view, int position); 101 | 102 | } 103 | 104 | public ViewFlow(Context context) { 105 | super(context); 106 | mSideBuffer = 3; 107 | init(); 108 | } 109 | 110 | public ViewFlow(Context context, int sideBuffer) { 111 | super(context); 112 | mSideBuffer = sideBuffer; 113 | init(); 114 | } 115 | 116 | public ViewFlow(Context context, AttributeSet attrs) { 117 | super(context, attrs); 118 | TypedArray styledAttrs = context.obtainStyledAttributes(attrs, 119 | R.styleable.ViewFlow); 120 | mSideBuffer = styledAttrs.getInt(R.styleable.ViewFlow_sidebuffer, 3); 121 | init(); 122 | } 123 | 124 | private void init() { 125 | mLoadedViews = new LinkedList(); 126 | mScroller = new Scroller(getContext()); 127 | final ViewConfiguration configuration = ViewConfiguration 128 | .get(getContext()); 129 | mTouchSlop = configuration.getScaledTouchSlop(); 130 | mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); 131 | } 132 | 133 | public void startAutoFlowTimer(){ 134 | handler = new Handler(){ 135 | @Override 136 | public void handleMessage(Message msg) { 137 | 138 | snapToScreen((mCurrentScreen+1)%getChildCount()); 139 | Message message = handler.obtainMessage(0); 140 | sendMessageDelayed(message, timeSpan); 141 | } 142 | }; 143 | 144 | Message message = handler.obtainMessage(0); 145 | handler.sendMessageDelayed(message, timeSpan); 146 | } 147 | public void stopAutoFlowTimer(){ 148 | if(handler!=null) 149 | handler.removeMessages(0); 150 | handler = null; 151 | } 152 | 153 | public void onConfigurationChanged(Configuration newConfig) { 154 | if (newConfig.orientation != mLastOrientation) { 155 | mLastOrientation = newConfig.orientation; 156 | getViewTreeObserver().addOnGlobalLayoutListener(orientationChangeListener); 157 | } 158 | } 159 | 160 | public int getViewsCount() { 161 | return mSideBuffer; 162 | } 163 | 164 | @Override 165 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 166 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 167 | 168 | final int width = MeasureSpec.getSize(widthMeasureSpec); 169 | final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 170 | if (widthMode != MeasureSpec.EXACTLY && !isInEditMode()) { 171 | throw new IllegalStateException( 172 | "ViewFlow can only be used in EXACTLY mode."); 173 | } 174 | 175 | final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 176 | if (heightMode != MeasureSpec.EXACTLY && !isInEditMode()) { 177 | throw new IllegalStateException( 178 | "ViewFlow can only be used in EXACTLY mode."); 179 | } 180 | 181 | // The children are given the same width and height as the workspace 182 | final int count = getChildCount(); 183 | for (int i = 0; i < count; i++) { 184 | getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); 185 | } 186 | 187 | if (mFirstLayout) { 188 | mScroller.startScroll(0, 0, mCurrentScreen * width, 0, 0); 189 | mFirstLayout = false; 190 | } 191 | } 192 | 193 | @Override 194 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 195 | int childLeft = 0; 196 | 197 | final int count = getChildCount(); 198 | for (int i = 0; i < count; i++) { 199 | final View child = getChildAt(i); 200 | if (child.getVisibility() != View.GONE) { 201 | final int childWidth = child.getMeasuredWidth(); 202 | child.layout(childLeft, 0, childLeft + childWidth, 203 | child.getMeasuredHeight()); 204 | childLeft += childWidth; 205 | } 206 | } 207 | } 208 | 209 | @Override 210 | public boolean onInterceptTouchEvent(MotionEvent ev) { 211 | if (getChildCount() == 0) 212 | return false; 213 | 214 | if (mVelocityTracker == null) { 215 | mVelocityTracker = VelocityTracker.obtain(); 216 | } 217 | mVelocityTracker.addMovement(ev); 218 | 219 | final int action = ev.getAction(); 220 | final float x = ev.getX(); 221 | 222 | switch (action) { 223 | case MotionEvent.ACTION_DOWN: 224 | /* 225 | * If being flinged and user touches, stop the fling. isFinished 226 | * will be false if being flinged. 227 | */ 228 | if (!mScroller.isFinished()) { 229 | mScroller.abortAnimation(); 230 | } 231 | 232 | // Remember where the motion event started 233 | mLastMotionX = x; 234 | 235 | mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST 236 | : TOUCH_STATE_SCROLLING; 237 | if(handler!=null) 238 | handler.removeMessages(0); 239 | break; 240 | 241 | case MotionEvent.ACTION_MOVE: 242 | final int xDiff = (int) Math.abs(x - mLastMotionX); 243 | 244 | boolean xMoved = xDiff > mTouchSlop; 245 | 246 | if (xMoved) { 247 | // Scroll if the user moved far enough along the X axis 248 | mTouchState = TOUCH_STATE_SCROLLING; 249 | } 250 | 251 | if (mTouchState == TOUCH_STATE_SCROLLING) { 252 | // Scroll to follow the motion event 253 | final int deltaX = (int) (mLastMotionX - x); 254 | mLastMotionX = x; 255 | 256 | final int scrollX = getScrollX(); 257 | if (deltaX < 0) { 258 | if (scrollX > 0) { 259 | scrollBy(Math.max(-scrollX, deltaX), 0); 260 | } 261 | } else if (deltaX > 0) { 262 | final int availableToScroll = getChildAt( 263 | getChildCount() - 1).getRight() 264 | - scrollX - getWidth(); 265 | if (availableToScroll > 0) { 266 | scrollBy(Math.min(availableToScroll, deltaX), 0); 267 | } 268 | } 269 | return true; 270 | } 271 | break; 272 | 273 | case MotionEvent.ACTION_UP: 274 | if (mTouchState == TOUCH_STATE_SCROLLING) { 275 | final VelocityTracker velocityTracker = mVelocityTracker; 276 | velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 277 | int velocityX = (int) velocityTracker.getXVelocity(); 278 | 279 | if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) { 280 | // Fling hard enough to move left 281 | snapToScreen(mCurrentScreen - 1); 282 | } else if (velocityX < -SNAP_VELOCITY 283 | && mCurrentScreen < getChildCount() - 1) { 284 | // Fling hard enough to move right 285 | snapToScreen(mCurrentScreen + 1); 286 | } else { 287 | snapToDestination(); 288 | } 289 | 290 | if (mVelocityTracker != null) { 291 | mVelocityTracker.recycle(); 292 | mVelocityTracker = null; 293 | } 294 | } 295 | 296 | mTouchState = TOUCH_STATE_REST; 297 | if(handler!=null){ 298 | Message message = handler.obtainMessage(0); 299 | handler.sendMessageDelayed(message, timeSpan); 300 | } 301 | break; 302 | case MotionEvent.ACTION_CANCEL: 303 | mTouchState = TOUCH_STATE_REST; 304 | } 305 | return false; 306 | } 307 | 308 | @Override 309 | public boolean onTouchEvent(MotionEvent ev) { 310 | if (getChildCount() == 0) 311 | return false; 312 | 313 | if (mVelocityTracker == null) { 314 | mVelocityTracker = VelocityTracker.obtain(); 315 | } 316 | mVelocityTracker.addMovement(ev); 317 | 318 | final int action = ev.getAction(); 319 | final float x = ev.getX(); 320 | 321 | switch (action) { 322 | case MotionEvent.ACTION_DOWN: 323 | /* 324 | * If being flinged and user touches, stop the fling. isFinished 325 | * will be false if being flinged. 326 | */ 327 | if (!mScroller.isFinished()) { 328 | mScroller.abortAnimation(); 329 | } 330 | 331 | // Remember where the motion event started 332 | mLastMotionX = x; 333 | 334 | mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST 335 | : TOUCH_STATE_SCROLLING; 336 | if(handler!=null) 337 | handler.removeMessages(0); 338 | break; 339 | 340 | case MotionEvent.ACTION_MOVE: 341 | final int xDiff = (int) Math.abs(x - mLastMotionX); 342 | 343 | boolean xMoved = xDiff > mTouchSlop; 344 | 345 | if (xMoved) { 346 | // Scroll if the user moved far enough along the X axis 347 | mTouchState = TOUCH_STATE_SCROLLING; 348 | } 349 | 350 | if (mTouchState == TOUCH_STATE_SCROLLING) { 351 | // Scroll to follow the motion event 352 | final int deltaX = (int) (mLastMotionX - x); 353 | mLastMotionX = x; 354 | 355 | final int scrollX = getScrollX(); 356 | if (deltaX < 0) { 357 | if (scrollX > 0) { 358 | scrollBy(Math.max(-scrollX, deltaX), 0); 359 | } 360 | } else if (deltaX > 0) { 361 | final int availableToScroll = getChildAt( 362 | getChildCount() - 1).getRight() 363 | - scrollX - getWidth(); 364 | if (availableToScroll > 0) { 365 | scrollBy(Math.min(availableToScroll, deltaX), 0); 366 | } 367 | } 368 | return true; 369 | } 370 | break; 371 | 372 | case MotionEvent.ACTION_UP: 373 | if (mTouchState == TOUCH_STATE_SCROLLING) { 374 | final VelocityTracker velocityTracker = mVelocityTracker; 375 | velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 376 | int velocityX = (int) velocityTracker.getXVelocity(); 377 | 378 | if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) { 379 | // Fling hard enough to move left 380 | snapToScreen(mCurrentScreen - 1); 381 | } else if (velocityX < -SNAP_VELOCITY 382 | && mCurrentScreen < getChildCount() - 1) { 383 | // Fling hard enough to move right 384 | snapToScreen(mCurrentScreen + 1); 385 | } 386 | // else if (velocityX < -SNAP_VELOCITY 387 | // && mCurrentScreen == getChildCount() - 1) { 388 | // snapToScreen(0); 389 | // } 390 | // else if (velocityX > SNAP_VELOCITY 391 | // && mCurrentScreen == 0) { 392 | // snapToScreen(getChildCount() - 1); 393 | // } 394 | else { 395 | snapToDestination(); 396 | } 397 | 398 | if (mVelocityTracker != null) { 399 | mVelocityTracker.recycle(); 400 | mVelocityTracker = null; 401 | } 402 | } 403 | 404 | mTouchState = TOUCH_STATE_REST; 405 | 406 | if(handler!=null){ 407 | Message message = handler.obtainMessage(0); 408 | handler.sendMessageDelayed(message, timeSpan); 409 | } 410 | break; 411 | case MotionEvent.ACTION_CANCEL: 412 | snapToDestination(); 413 | mTouchState = TOUCH_STATE_REST; 414 | } 415 | return true; 416 | } 417 | 418 | @Override 419 | protected void onScrollChanged(int h, int v, int oldh, int oldv) { 420 | super.onScrollChanged(h, v, oldh, oldv); 421 | if (mIndicator != null) { 422 | /* 423 | * The actual horizontal scroll origin does typically not match the 424 | * perceived one. Therefore, we need to calculate the perceived 425 | * horizontal scroll origin here, since we use a view buffer. 426 | */ 427 | int hPerceived = h + (mCurrentAdapterIndex - mCurrentBufferIndex) 428 | * getWidth(); 429 | mIndicator.onScrolled(hPerceived, v, oldh, oldv); 430 | } 431 | } 432 | 433 | private void snapToDestination() { 434 | final int screenWidth = getWidth(); 435 | final int whichScreen = (getScrollX() + (screenWidth / 2)) 436 | / screenWidth; 437 | 438 | snapToScreen(whichScreen); 439 | } 440 | 441 | private void snapToScreen(int whichScreen) { 442 | mLastScrollDirection = whichScreen - mCurrentScreen; 443 | if (!mScroller.isFinished()) 444 | return; 445 | 446 | whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); 447 | 448 | mNextScreen = whichScreen; 449 | 450 | final int newX = whichScreen * getWidth(); 451 | final int delta = newX - getScrollX(); 452 | mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2); 453 | invalidate(); 454 | } 455 | 456 | @Override 457 | public void computeScroll() { 458 | if (mScroller.computeScrollOffset()) { 459 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 460 | postInvalidate(); 461 | } else if (mNextScreen != INVALID_SCREEN) { 462 | mCurrentScreen = Math.max(0, 463 | Math.min(mNextScreen, getChildCount() - 1)); 464 | mNextScreen = INVALID_SCREEN; 465 | postViewSwitched(mLastScrollDirection); 466 | } 467 | } 468 | 469 | /** 470 | * Scroll to the {@link View} in the view buffer specified by the index. 471 | * 472 | * @param indexInBuffer 473 | * Index of the view in the view buffer. 474 | */ 475 | private void setVisibleView(int indexInBuffer, boolean uiThread) { 476 | mCurrentScreen = Math.max(0, 477 | Math.min(indexInBuffer, getChildCount() - 1)); 478 | int dx = (mCurrentScreen * getWidth()) - mScroller.getCurrX(); 479 | mScroller.startScroll(mScroller.getCurrX(), mScroller.getCurrY(), dx, 480 | 0, 0); 481 | if(dx == 0) 482 | onScrollChanged(mScroller.getCurrX() + dx, mScroller.getCurrY(), mScroller.getCurrX() + dx, mScroller.getCurrY()); 483 | if (uiThread) 484 | invalidate(); 485 | else 486 | postInvalidate(); 487 | } 488 | 489 | /** 490 | * Set the listener that will receive notifications every time the {code 491 | * ViewFlow} scrolls. 492 | * 493 | * @param l 494 | * the scroll listener 495 | */ 496 | public void setOnViewSwitchListener(ViewSwitchListener l) { 497 | mViewSwitchListener = l; 498 | } 499 | 500 | @Override 501 | public Adapter getAdapter() { 502 | return mAdapter; 503 | } 504 | 505 | @Override 506 | public void setAdapter(Adapter adapter) { 507 | setAdapter(adapter, 0); 508 | } 509 | 510 | public void setAdapter(Adapter adapter, int initialPosition) { 511 | if (mAdapter != null) { 512 | mAdapter.unregisterDataSetObserver(mDataSetObserver); 513 | } 514 | 515 | mAdapter = adapter; 516 | 517 | if (mAdapter != null) { 518 | mDataSetObserver = new AdapterDataSetObserver(); 519 | mAdapter.registerDataSetObserver(mDataSetObserver); 520 | 521 | } 522 | if (mAdapter == null || mAdapter.getCount() == 0) 523 | return; 524 | 525 | setSelection(initialPosition); 526 | } 527 | 528 | @Override 529 | public View getSelectedView() { 530 | return (mCurrentBufferIndex < mLoadedViews.size() ? mLoadedViews 531 | .get(mCurrentBufferIndex) : null); 532 | } 533 | 534 | @Override 535 | public int getSelectedItemPosition() { 536 | return mCurrentAdapterIndex; 537 | } 538 | 539 | /** 540 | * Set the FlowIndicator 541 | * 542 | * @param flowIndicator 543 | */ 544 | public void setFlowIndicator(FlowIndicator flowIndicator) { 545 | mIndicator = flowIndicator; 546 | mIndicator.setViewFlow(this); 547 | } 548 | 549 | @Override 550 | public void setSelection(int position) { 551 | mNextScreen = INVALID_SCREEN; 552 | mScroller.forceFinished(true); 553 | if (mAdapter == null) 554 | return; 555 | 556 | position = Math.max(position, 0); 557 | position = Math.min(position, mAdapter.getCount()-1); 558 | 559 | ArrayList recycleViews = new ArrayList(); 560 | View recycleView; 561 | while (!mLoadedViews.isEmpty()) { 562 | recycleViews.add(recycleView = mLoadedViews.remove()); 563 | detachViewFromParent(recycleView); 564 | } 565 | 566 | View currentView = makeAndAddView(position, true, 567 | (recycleViews.isEmpty() ? null : recycleViews.remove(0))); 568 | mLoadedViews.addLast(currentView); 569 | 570 | for(int offset = 1; mSideBuffer - offset >= 0; offset++) { 571 | int leftIndex = position - offset; 572 | int rightIndex = position + offset; 573 | if(leftIndex >= 0) 574 | mLoadedViews.addFirst(makeAndAddView(leftIndex, false, 575 | (recycleViews.isEmpty() ? null : recycleViews.remove(0)))); 576 | if(rightIndex < mAdapter.getCount()) 577 | mLoadedViews.addLast(makeAndAddView(rightIndex, true, 578 | (recycleViews.isEmpty() ? null : recycleViews.remove(0)))); 579 | } 580 | 581 | mCurrentBufferIndex = mLoadedViews.indexOf(currentView); 582 | mCurrentAdapterIndex = position; 583 | 584 | for (View view : recycleViews) { 585 | removeDetachedView(view, false); 586 | } 587 | requestLayout(); 588 | setVisibleView(mCurrentBufferIndex, false); 589 | if (mIndicator != null) { 590 | mIndicator.onSwitched(mLoadedViews.get(mCurrentBufferIndex), 591 | mCurrentAdapterIndex); 592 | } 593 | if (mViewSwitchListener != null) { 594 | mViewSwitchListener 595 | .onSwitched(mLoadedViews.get(mCurrentBufferIndex), 596 | mCurrentAdapterIndex); 597 | } 598 | } 599 | 600 | private void resetFocus() { 601 | mLoadedViews.clear(); 602 | removeAllViewsInLayout(); 603 | 604 | for (int i = Math.max(0, mCurrentAdapterIndex - mSideBuffer); i < Math 605 | .min(mAdapter.getCount(), mCurrentAdapterIndex + mSideBuffer 606 | + 1); i++) { 607 | mLoadedViews.addLast(makeAndAddView(i, true, null)); 608 | if (i == mCurrentAdapterIndex) 609 | mCurrentBufferIndex = mLoadedViews.size() - 1; 610 | } 611 | requestLayout(); 612 | } 613 | 614 | private void postViewSwitched(int direction) { 615 | if (direction == 0) 616 | return; 617 | 618 | if (direction > 0) { // to the right 619 | mCurrentAdapterIndex++; 620 | mCurrentBufferIndex++; 621 | 622 | // if(direction > 1) { 623 | // mCurrentAdapterIndex += mAdapter.getCount() - 2; 624 | // mCurrentBufferIndex += mAdapter.getCount() - 2; 625 | // } 626 | 627 | View recycleView = null; 628 | 629 | // Remove view outside buffer range 630 | if (mCurrentAdapterIndex > mSideBuffer) { 631 | recycleView = mLoadedViews.removeFirst(); 632 | detachViewFromParent(recycleView); 633 | // removeView(recycleView); 634 | mCurrentBufferIndex--; 635 | } 636 | 637 | // Add new view to buffer 638 | int newBufferIndex = mCurrentAdapterIndex + mSideBuffer; 639 | if (newBufferIndex < mAdapter.getCount()) 640 | mLoadedViews.addLast(makeAndAddView(newBufferIndex, true, 641 | recycleView)); 642 | 643 | } else { // to the left 644 | mCurrentAdapterIndex--; 645 | mCurrentBufferIndex--; 646 | 647 | // if(direction < -1) { 648 | // mCurrentAdapterIndex -= mAdapter.getCount() - 2; 649 | // mCurrentBufferIndex -= mAdapter.getCount() - 2; 650 | // } 651 | 652 | View recycleView = null; 653 | 654 | // Remove view outside buffer range 655 | if (mAdapter.getCount() - 1 - mCurrentAdapterIndex > mSideBuffer) { 656 | recycleView = mLoadedViews.removeLast(); 657 | detachViewFromParent(recycleView); 658 | } 659 | 660 | // Add new view to buffer 661 | int newBufferIndex = mCurrentAdapterIndex - mSideBuffer; 662 | if (newBufferIndex > -1) { 663 | mLoadedViews.addFirst(makeAndAddView(newBufferIndex, false, 664 | recycleView)); 665 | mCurrentBufferIndex++; 666 | } 667 | 668 | } 669 | 670 | requestLayout(); 671 | setVisibleView(mCurrentBufferIndex, true); 672 | if (mIndicator != null) { 673 | mIndicator.onSwitched(mLoadedViews.get(mCurrentBufferIndex), 674 | mCurrentAdapterIndex); 675 | } 676 | if (mViewSwitchListener != null) { 677 | mViewSwitchListener 678 | .onSwitched(mLoadedViews.get(mCurrentBufferIndex), 679 | mCurrentAdapterIndex); 680 | } 681 | } 682 | 683 | private View setupChild(View child, boolean addToEnd, boolean recycle) { 684 | ViewGroup.LayoutParams p = (ViewGroup.LayoutParams) child 685 | .getLayoutParams(); 686 | if (p == null) { 687 | p = new AbsListView.LayoutParams( 688 | ViewGroup.LayoutParams.FILL_PARENT, 689 | ViewGroup.LayoutParams.WRAP_CONTENT, 0); 690 | } 691 | if (recycle) 692 | attachViewToParent(child, (addToEnd ? -1 : 0), p); 693 | else 694 | addViewInLayout(child, (addToEnd ? -1 : 0), p, true); 695 | return child; 696 | } 697 | 698 | private View makeAndAddView(int position, boolean addToEnd, View convertView) { 699 | View view = mAdapter.getView(position, convertView, this); 700 | return setupChild(view, addToEnd, convertView != null); 701 | } 702 | 703 | class AdapterDataSetObserver extends DataSetObserver { 704 | 705 | @Override 706 | public void onChanged() { 707 | View v = getChildAt(mCurrentBufferIndex); 708 | if (v != null) { 709 | for (int index = 0; index < mAdapter.getCount(); index++) { 710 | if (v.equals(mAdapter.getItem(index))) { 711 | mCurrentAdapterIndex = index; 712 | break; 713 | } 714 | } 715 | } 716 | resetFocus(); 717 | } 718 | 719 | @Override 720 | public void onInvalidated() { 721 | // Not yet implemented! 722 | } 723 | 724 | } 725 | 726 | public void setTimeSpan(long timeSpan) { 727 | this.timeSpan = timeSpan; 728 | } 729 | 730 | public void setmSideBuffer(int mSideBuffer) { 731 | this.mSideBuffer = mSideBuffer; 732 | } 733 | } 734 | --------------------------------------------------------------------------------