First look at the effect:
1, the advertising bar effect should be a more extensive use of an effect, the use of the basic framework is a viewpager component, in the low version of Android, we need to manually import V4 jar package to use.
2, Viewpager loading mode and the ListView loading mode is not the same, for the ListView, which will always use to the sub-view of the reuse, but for viewpager, dynamic sliding, it only keeps three pages in memory, that is: the current display page, The previous page and the next page, and the other pages are destroyed and released.
3, for large pictures of the load, if not to do processing, may be one or two pictures will cause oom, the application hangs; In earlier versions, 2.3, it is common practice to use soft and weak reference collections to handle loading pictures in memory. However, for the Android3.0 version, the Android system tends to reclaim soft-referenced objects directly rather than soft-referenced members, which results in this practice no longer applicable. But fortunately, the Android system also gives a better tool for us to handle the loading of images: LruCache. This class is ideal for caching images, and its main algorithm is to store recently used objects in linkedhashmap with strong references, and to remove the least recently used objects from memory before the cached value reaches a predetermined value.
4, large picture loading of the old growth problem is to use bitmapfactory before loading to adjust the size of the picture, here involves BitmapFactory.Options.inJustDecodeBounds = true; Through Options.outheight, and options.outwidth; get the width of the picture, and then according to the width of the screen height to zoom the picture, to achieve the effect of compression.
5, another small problem about Viewpager is to call the Adapter.notifydatasetchanged () method directly, unable to refresh the Viewpager data; There are two versions resolved here:
A. Rewrite the GetItemPosition method of the PageAdapter to return it directly to Position_none, which can be useful if you call notifydatasetchanged again.
B. After updating the data, call a handler to send the corresponding message, to manually refresh the local data, this way is recommended, in fact, can also be used for The local refresh of the ListView, more general.
6, here also achieve a two-way wireless loop sliding effect, in fact, there are only six pictures, but we can wireless to both sides of the slide, in fact, the number of both sides is INTEGER.MAX_VALUE/2,
The core idea is that the GetCount method returns a Integer.max) value, and then uses position%6 for postion processing, which can be done in detail in the code
Okay, nonsense, on the code:
Mainactivity:
Package Com.example.advertisebardemo;import Java.util.arraylist;import Java.util.list;import Java.util.concurrent.executors;import Java.util.concurrent.scheduledexecutorservice;import android.app.Activity; Import Android.content.res.resources;import Android.graphics.bitmap;import Android.graphics.bitmapfactory;import Android.graphics.bitmapfactory.options;import Android.os.asynctask;import Android.os.bundle;import Android.os.handler;import Android.os.message;import Android.support.v4.util.lrucache;import Android.support.v4.view.pageradapter;import Android.support.v4.view.viewpager;import Android.support.v4.view.viewpager.onpagechangelistener;import Android.text.format.formatter;import Android.view.motionevent;import Android.view.view;import Android.view.view.ontouchlistener;import Android.view.viewgroup;import Android.view.windowmanager;import Android.widget.imageview;import Android.widget.linearlayout;import Android.widget.textview;public class Mainactivity extends Activity {private ViEwpager viewpager;private int[] ids = {r.drawable.a, r.drawable.b, R.DRAWABLE.C,R.DRAWABLE.D, R.DRAWABLE.E, R.DRAWABLE.F};p rivate list<imageview> imageviews = new arraylist<imageview> ();p rivate MyAdapter adapter; Private Options options;private int screenwidth;private int screenheight;private lrucache<string, bitmap> mmemorycache;private windowmanager wm;private int wwidth;private int wheight;/** * Set a flag bit to determine whether to continue to automatically slide */private boolean i srunning = False;private int lastpointposition;private boolean operationflag;/** * thread Pool object */private Scheduledexecutorservice pool;private object[] objs;private string[] descriptions = {"Picture description one", "Picture Description two", "Picture description three", "Picture Description four", "Picture Description Five", "Picture Description Six"};p rivate linearlayout ll_points;private TextView tv_des;private Handler Handler = new Handler () {@Overri depublic void Handlemessage (Message msg) {super.handlemessage (msg); switch (msg.what) {case 0:// Adapter.notifydatasetchanged ();//Not adapter.notifydatasetchanged (), while using local Refresh method int tag = Integer.parseint(String.valueof (((object[) msg.obj) [0]); ImageView IV = (ImageView) viewpager.findviewwithtag (tag); Iv.setimagebitmap ((Bitmap) ((object[]) msg.obj) [1]); Break;case 1:viewpager.setcurrentitem ( Viewpager.getcurrentitem () + 1);//Move Backward one page if (isrunning) {handler.sendemptymessagedelayed (1, 2000);} Break;case 2:break;default:break;}}; @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview ( R.layout.activity_main);//Initialize Imageviews collection initimageviews ();//Initialize the Viewinitviews () in the layout file;//Initialize window parameters Initwindowparams ();//Initialize Lrucacheinitlrucache ();//thread pool of three threads pool = Executors.newscheduledthreadpool (3);// Initializes a bitmapfactory option object options = new options ();//Initialize Small dots initpointgroup (); Notifyadapter ();// Set initial time in the position of the first image near half of the Integer Viewpager.setcurrentitem (integer.max_value/2+ (INTEGER.MAX_VALUE/2)% ids.length);// The auto-slide flag position is trueisrunning = true;//adds a slide listener to Viewpager setviewpageronagechangelistener ();//Msg.what=1, Delay 2 seconds handler.sendemptymessagedelayed (1, 2000);} Private VOID Setviewpageronagechangelistener () {Viewpager.setonpagechangelistener (new Onpagechangelistener () {/** * The method of callback when the page is selected */@Overridepublic void onpageselected (int position) {Ll_points.getchildat (lastpointposition% 6). SetEnabled (false); Ll_points.getchildat (position% 6). SetEnabled (true); lastpointposition = position;//Sets the corresponding descriptive text tv_ Des.settext (descriptions[position% 6]);} @Overridepublic void onpagescrolled (int position, float positionoffset,int positionoffsetpixels) {//TODO auto-generated method stub} @Overridepublic void onpagescrollstatechanged (int state) {//TODO auto-generated method stub} });} private void Initpointgroup () {linearlayout.layoutparams layoutparams = new Linearlayout.layoutparams (15, 15); Layoutparams.setmargins (2, 5); for (int i = 0; i < ids.length; i++) {ImageView point = new ImageView (this);p oint . Setbackgroundresource (R.DRAWABLE.POINT_BG);//Set position parameter Point.setlayoutparams (layoutparams); if (i = = 0) { Point.setenabled (TRUE);} else {point.setenabled (false);} Ll_poinTs.addview (point);}} private void Initlrucache () {///LRUCache passes through the constructor to the cache value, in kilobytes, because this is divided by 1204int maxMem = (int) (Runtime.getruntime (). MaxMemory ()/1024);//originally 1024, here divided by 1024 should be to prevent int type overflow int cacheSize = MAXMEM/4; System.out.println (Formatter.formatfilesize (this, cacheSize)); Mmemorycache = new lrucache<string, bitmap> ( cacheSize) {@Overrideprotected int sizeOf (String key, Bitmap Bitmap) {//Return super.sizeof (key, value);//Override this method to measure each picture's Size, the number of pictures is returned by default. return Bitmap.getwidth () * Bitmap.getheight ()/1024;//The following sentence requires API 12//return Bitmap.getbytecount ()/1024;//here and above are divided by 102 4, to achieve the same can}};} private void Initwindowparams () {wm = (WindowManager) getsystemservice (window_service); wwidth = Wm.getdefaultdisplay () . getwidth (); wheight = Wm.getdefaultdisplay (). GetHeight (); private void Initviews () {ll_points = (linearlayout) Findviewbyid (r.id.ll_points); tv_des = (TextView) Findviewbyid ( R.id.tv_des); Tv_des.settext (Descriptions[0]); Viewpager = (Viewpager) Findviewbyid (R.id.viewpager);//TODO Self-adapting screen ViewpagER size parameters}private void Initimageviews () {for (int i = 0; i < ids.length; i++) {Imageviews.add (new ImageView (This))}} @Overrideprotected void OnDestroy () {//TODO auto-generated method Stubsuper.ondestroy (); isrunning = false;//Android.os . Debug.stopmethodtracing ();} /** * Add the bitmap of the corresponding key to the cache * * @param key * @param bitmap */public void Addbitmaptomemorycache (String key, bitmap Bitma P) {if (Getbitmapfrommemcache (key) = = null) {Mmemorycache.put (key, bitmap);}} /** * Remove the Bitmap object of the corresponding key from the cache * * @param key * @return */public Bitmap getbitmapfrommemcache (String key) {return MMEMORYC Ache.get (key);} /** * Set Apdater method */private void Notifyadapter () {if (adapter = = NULL) {adapter = new Myadapter (); Viewpager.setadapter (AD Apter);} else {/* * The following sentence cannot be used to refresh the data unless the return value of the GetItemPosition method is set to Position_none *///adapter.notifydatasetchanged ();}} public void LoadBitmap (int resId, ImageView ImageView) {final String ImageKey = string.valueof (resId); final Bitmap Bitmap = Getbitmapfrommemcache (ImageKey);if (bitmap! = null) {Imageview.setimagebitmap (bitmap);} else {//Imageview.setimageresource (R.drawable.ic_launcher); /default//Here is the method of using Asynctask bitmapworkertask task = new Bitmapworkertask (); Task.execute (resId);//The following is how the thread pool is used, both of which are available, The thread pool may be a bit better for network loading//Pool.submit (new Myrunnable (ResId));}} Class Myrunnable implements Runnable {private int id;public myrunnable () {super ();} public myrunnable (int id) {super (); this.id = ID;} @Overridepublic void Run () {final Bitmap Bitmap = Decodesampledbitmapfromresource (Getresources (), ID, wwidth, wheight); System.out.println ("wwidth=" + wwidth); System.out.println ("wheight=" + wheight); Addbitmaptomemorycache (string.valueof (ID), bitmap); Message msg = Message.obtain (); msg.what = 0;OBJS = new object[] {id, bitmap};msg.obj = Objs;handler.sendmessage (msg);}} Class Bitmapworkertask extends Asynctask<integer, Void, bitmap> {//loading pictures in the background. @Overrideprotected Bitmap doinbackground (Integer ... params) {final Bitmap Bitmap = Decodesampledbitmapfromresource ( Getresources (), Params[0], wwidth, wheight); System.out.println ("wwidth=" + wwidth); System.out.println ("wheight=" + wheight); Addbitmaptomemorycache (String.valueof (params[0)), bitmap); Message msg = Message.obtain (); msg.what = 0;OBJS = new object[] {params[0], bitmap};msg.obj = Objs;handler.sendmessage (M (SG); return bitmap;}} public static Bitmap Decodesampledbitmapfromresource (Resources res,int resId, int reqwidth, int reqheight) {//first resolution will Inju Stdecodebounds set to True to get the picture size final bitmapfactory.options Options = new Bitmapfactory.options (); O Ptions.injustdecodebounds = true; Bitmapfactory.decoderesource (res, resId, options);//Call the method defined above to calculate the Insamplesize value options.insamplesize = Calculateinsamplesize (options, reqwidth,reqheight); System.out.println ("insamplesize=" + options.insamplesize);//Use the obtained Insamplesize value to parse the picture again Options.injustdecodebounds = False;return Bitmapfactory.decoderesource (res, resId, options);} public static int calculateinsamplesize (bitmapfactory.options options,int reqwidth, int reqheight) {//height of source pictureand width final int height = options.outheight;final int width = options.outwidth; System.out.println ("height=" + height); System.out.println ("width=" + width), int insamplesize = 1;if (height > Reqheight | | width > reqwidth) {//Calculate actual width and target The ratio of the width to the final int heightratio = Math.Round ((float) height/(float) reqheight); final int widthRatio = Math.Round ((float) width /(float) reqwidth);//select wide and high school minimum ratio as the value of insamplesize, so that the final picture width and height//must be greater than or equal to the target width and height. Insamplesize = HeightRatio < WidthRatio? HeightRatio://widthratio;//Here we select the width to its way, so the ratio of scaling to the width of the selection insamplesize = WidthRatio;} return insamplesize;} Private class Myadapter extends Pageradapter {@Overridepublic int getcount () {//return Ids.length;return Integer.max_val UE;} @Overridepublic Boolean isviewfromobject (View view, Object object) {//TODO auto-generated method Stubreturn view = = Objec t;} @Overridepublic Object Instantiateitem (viewgroup container, int position) {ImageView ImageView = Imageviews.get ( Position% 6); Container.addview (ImageView); lOadbitmap (ids[position% 6], imageView);//link the ID with the ImageView by Settag method Imageview.settag (ids[position% 6]); return ImageView;} @Overridepublic void Destroyitem (ViewGroup container, int position, object object) {Container.removeview (View) object) ; object = null;} /**//* This returns a Position_none, which implements the Viewpager dynamic refresh, but also brings some problems//*///@Override/public int getitemposition (Object Object) {////TODO auto-generated method stub////Return Super.getitemposition (object);//Return position_none;//}}}
Layout file:
<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http// Schemas.android.com/tools "android:layout_width=" match_parent "android:layout_height=" Match_parent "Tools:context = "${relativepackage}.${activityclass}" > <android.support.v4.view.viewpager android:id= "@+id/viewPager" Android:layout_width= "Fill_parent" android:layout_height= "202.5DP" android:layout_gravity= "Top"/> <linearlayout android:layout_width= "fill_parent" android:layout_height= "Wrap_content" Android:la yout_alignbottom= "@id/viewpager" android:background= "#66ffffff" android:gravity= "Bottom" Android:orie ntation= "vertical" > <textview android:id= "@+id/tv_des" android:layout_width= "Fill_pare NT "android:layout_height=" Wrap_content "android:gravity=" Center_horizontal "Android:text Size= "15sp"/> <linearlayout Android:id= "@+id/ll_points" android:layout_width= "fill_parent" android:layout_height= "Wrap_c Ontent "android:gravity=" center_horizontal "android:orientation=" Horizontal "> </linear Layout> </LinearLayout></RelativeLayout>
Point_bg.xml:
<?xml version= "1.0" encoding= "Utf-8"? ><selector xmlns:android= "http://schemas.android.com/apk/res/ Android "> <item android:drawable=" @drawable/point_normal "android:state_enabled=" false "></item > <item android:drawable= "@drawable/point_focused" android:state_enabled= "true" ></item></ Selector>
Point_normal.xml:
<?xml version= "1.0" encoding= "Utf-8"? ><shape xmlns:android= "Http://schemas.android.com/apk/res/android" android:shape= "Oval" > <size android:height= "5DP" android:width= "5DP"/> <solid Android:color= "#55eeeeee"/></shape>
Point_focused.xml:
<?xml version= "1.0" encoding= "Utf-8"? ><shape xmlns:android= "Http://schemas.android.com/apk/res/android" android:shape= "Oval" > <size android:height= "5DP" android:width= "5DP"/> <solid Android:color= "#ffffffff"/></shape>
Banner Effect Implementation----Viewpager load large picture (LruCache) and timed refresh