廣告條效果實現----ViewPager載入大圖片(LruCache)以及定時重新整理,

來源:互聯網
上載者:User

廣告條效果實現----ViewPager載入大圖片(LruCache)以及定時重新整理,

先來看看效果:



1、廣告條效果應該是使用的比較廣泛的一個效果了,使用的基本構架就是一個ViewPager組件,在低版本的Android中,我們需要手動匯入v4 jar包才可以使用。


2、ViewPager的載入方式與listview的載入方式不太一樣,對於listview,其中總是會使用到子view的複用,但是對於viewpager,動態滑動的時候,它只保持三個頁面在記憶體中,也就是:當前顯示頁面,前一個頁面和後一個頁面;其他頁面都被銷毀釋放掉。


3、對於大圖片的載入,如果不做處理,可能一兩張圖片就會導致OOM,應用掛掉;在早期版本中,2.3以前,經常的做法是使用軟引用和弱引用集合來處理在記憶體中載入圖片,但是對於Android3.0的版本,Android系統偏向於直接回收掉軟引用的對象而不是軟引用的成員,這就導致了本做法不再適用。但是好在Android系統同時給出了一個比較好的工具讓我們來處理圖片的載入:LruCache。這個類非常適合用來緩衝圖片,它的主要演算法原理是把最近使用的對象用強引用儲存在 LinkedHashMap 中,並且把最近最少使用的對象在緩衝值達到預設定值之前從記憶體中移除。


4、大圖片載入的老生長提的問題就是在載入之前先使用bitmapfactory來調整圖片的大小,這裡涉及到BitmapFactory.Options.inJustDecodeBounds = true;通過options.outHeight;和options.outWidth;拿到圖片的寬高,然後再根據螢幕的寬高來縮放圖片,達到壓縮的效果。


5、另外一個關於ViewPager的小問題就是在於直接調用adapter.notifydatasetchanged()方法,無法重新整理viewpager的資料;這裡解決的版本有兩個:

a.   重寫pageadapter的getItemPosition方法,讓其直接返回POSITION_NONE,這時候再調用notifydatasetchanged則可以起作用

b.   在更新完資料之後,調用一個handler發送對應的message,來手動重新整理局部資料,這種方式比較推薦,實際上也可以用於listview的局部重新整理,比較通用。


6、這裡還實現了一個兩邊無線迴圈滑動的效果,實際上的圖片只有六張,但是我們可以無線往兩邊滑動,實際上兩邊的數量是integer.max_value/2,

核心思想在於getCount方法返回一個integer.max)value,然後對於postion的處理都使用position%6,這樣來實現,具體細節可以參看代碼


好,廢話說完,上代碼:

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 };private List<ImageView> imageViews = new ArrayList<ImageView>();private 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;/** * 設定一個標誌位來判斷是否繼續自動滑動 */private boolean isRunning = false;private int lastPointPosition;private boolean operationFlag;/** * 線程池對象 */private ScheduledExecutorService pool;private Object[] objs;private String[] descriptions = { "圖片描述一", "圖片描述二", "圖片描述三", "圖片描述四","圖片描述五", "圖片描述六" };private LinearLayout ll_points;private TextView tv_des;private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case 0:// adapter.notifyDataSetChanged();// 不用adapter.notifyDataSetChanged(),而使用局部重新整理的方法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);// 往後移動一頁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);// 初始化imageviews集合initImageViews();// 初始化布局檔案中的viewinitViews();// 初始化視窗參數initWindowParams();// 初始化lrucacheinitLruCache();// 三個線程的線程池pool = Executors.newScheduledThreadPool(3);// 初始化一個bitmapfactory選項對象options = new Options();// 初始化小點initPointGroup();notifyAdapter();// 設定初始的時候在Integer一半附近的第一張圖的位置上viewPager.setCurrentItem(Integer.MAX_VALUE / 2+ (Integer.MAX_VALUE / 2) % ids.length);// 自動滑動標誌位置為trueisRunning = true;// 給viewpager添加滑動監聽器setViewPagerOnageChangeListener();// msg.what=1,延遲2秒handler.sendEmptyMessageDelayed(1, 2000);}private void setViewPagerOnageChangeListener() {viewPager.setOnPageChangeListener(new OnPageChangeListener() {/** * 當頁面被選中的時候回調的方法 */@Overridepublic void onPageSelected(int position) {ll_points.getChildAt(lastPointPosition % 6).setEnabled(false);ll_points.getChildAt(position % 6).setEnabled(true);lastPointPosition = position;// 設定對應的標題文字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(15, 2, 15, 5);for (int i = 0; i < ids.length; i++) {ImageView point = new ImageView(this);point.setBackgroundResource(R.drawable.point_bg);// 設定位置參數point.setLayoutParams(layoutParams);if (i == 0) {point.setEnabled(true);} else {point.setEnabled(false);}ll_points.addView(point);}}private void initLruCache() {// lrucache通過建構函式傳入緩衝值,以kb為單位,因為這裡除以了1204int maxMem = (int) (Runtime.getRuntime().maxMemory() / 1024);// 本來是1024,這裡除以1024應該是為了防止int類型溢出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);// 重寫此方法來衡量每張圖片的大小,預設返回圖片數量。return bitmap.getWidth() * bitmap.getHeight() / 1024;// 下面這一句要求API 12// return bitmap.getByteCount() / 1024;// 這裡和上面都除以1024,達到一致即可}};}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 自適應螢幕的viewpager大小的參數}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();}/** * 將對應key的bitmap加入到cache中 *  * @param key * @param bitmap */public void addBitmapToMemoryCache(String key, Bitmap bitmap) {if (getBitmapFromMemCache(key) == null) {mMemoryCache.put(key, bitmap);}}/** * 從cache中取出對應key的bitmap對象 *  * @param key * @return */public Bitmap getBitmapFromMemCache(String key) {return mMemoryCache.get(key);}/** * 設定apdater的方法 */private void notifyAdapter() {if (adapter == null) {adapter = new MyAdapter();viewPager.setAdapter(adapter);} else {/* * 發現下面這一句並不能起到重新整理資料的作用, 除非將 getItemPosition方法的傳回值設為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);// 預設// 這裡是使用AsyncTask的方法BitmapWorkerTask task = new BitmapWorkerTask();task.execute(resId);// 下面是使用線程池的方式,兩種方式都可用,線程池可能對於網路載入會好一點// 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> {// 在後台載入圖片。@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(msg);return bitmap;}}public static Bitmap decodeSampledBitmapFromResource(Resources res,int resId, int reqWidth, int reqHeight) {// 第一次解析將inJustDecodeBounds設定為true,來擷取圖片大小final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeResource(res, resId, options);// 調用上面定義的方法計算inSampleSize值options.inSampleSize = calculateInSampleSize(options, reqWidth,reqHeight);System.out.println("inSampleSize=" + options.inSampleSize);// 使用擷取到的inSampleSize值再次解析圖片options.inJustDecodeBounds = false;return BitmapFactory.decodeResource(res, resId, options);}public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {// 源圖片的高度和寬度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) {// 計算出實際寬高和目標寬高的比率final int heightRatio = Math.round((float) height/ (float) reqHeight);final int widthRatio = Math.round((float) width / (float) reqWidth);// 選擇寬和高中最小的比率作為inSampleSize的值,這樣可以保證最終圖片的寬和高// 一定都會大於等於目標的寬和高。// inSampleSize = heightRatio < widthRatio ? heightRatio :// widthRatio;// 這裡我們選擇寬度對其的方式,所以縮放比選則寬度的比值inSampleSize = widthRatio;}return inSampleSize;}private class MyAdapter extends PagerAdapter {@Overridepublic int getCount() {// return ids.length;return Integer.MAX_VALUE;}@Overridepublic boolean isViewFromObject(View view, Object object) {// TODO Auto-generated method stubreturn view == object;}@Overridepublic Object instantiateItem(ViewGroup container, int position) {ImageView imageView = imageViews.get(position % 6);container.addView(imageView);loadBitmap(ids[position % 6], imageView);// 把id與imageview通過setTag方法掛鈎起來imageView.setTag(ids[position % 6]);return imageView;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {container.removeView((View) object);object = null;}// /**// * 這樣返回一個position_none之後,實現了viewpager的動態重新整理,但是也帶來了一些問題// */// @Override// public int getItemPosition(Object object) {// // TODO Auto-generated method stub// // return super.getItemPosition(object);// return POSITION_NONE;// }}}



布局檔案:

<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:layout_alignBottom="@id/viewPager"        android:background="#66ffffff"        android:gravity="bottom"        android:orientation="vertical" >        <TextView            android:id="@+id/tv_des"            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:gravity="center_horizontal"            android:textSize="15sp" />        <LinearLayout            android:id="@+id/ll_points"            android:layout_width="fill_parent"            android:layout_height="wrap_content"            android:gravity="center_horizontal"            android:orientation="horizontal" >        </LinearLayout>    </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>





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.