Android:ViewPager扩展详解——带有导航的ViewPagerIndicator(附带图片缓存,异步加载图片)

大家都用过viewpager了, github上有对viewpager进行扩展,导航风格更加丰富,这个开源项目是ViewPagerIndicator,很好用,但是例子比较简单,实际用起来要进行很多扩展,比如在fragment里进行图片缓存和图片异步加载。

下面是ViewPagerIndicator源码运行后的效果,大家也都看过了,我多此一举截几张图;

下载源码请点击这里

===========================================华丽的分割线========================================

下面是我改装过的,可异步加载图片,可图片缓存:

看到美女你心动了没有呢?

package com.example.viewpagerindicatortest;

import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import com.viewpagerindicator.TabPageIndicator;

/**
 * 基于Fragment的Tab样式的viewpager;
 *
 * @author andy
 *
 * 更多详情请访问博客:http://blog.csdn.net/lyc66666666666
 */
public class SampleTabsDefault extends FragmentActivity {

	//tab标题
    private static final String[] CONTENT = new String[] { "Recent", "Artists", "Albums", "Songs", "Playlists", "Genres" ,"test"};

	private List<SubFragment> list = new ArrayList<SubFragment>();

	String[] urls = new String[] {

			"http://a.hiphotos.baidu.com/image/pic/item/3bf33a87e950352ad6465dad5143fbf2b2118b6b.jpg",
			"http://a.hiphotos.baidu.com/image/pic/item/c8177f3e6709c93d002077529d3df8dcd0005440.jpg",
			"http://f.hiphotos.baidu.com/image/pic/item/7aec54e736d12f2ecc3d90f84dc2d56285356869.jpg",
			"http://e.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de308a87fc96eef01f3a297969.jpg",
			"http://d.hiphotos.baidu.com/image/pic/item/f31fbe096b63f624b88f7e8e8544ebf81b4ca369.jpg",
			"http://h.hiphotos.baidu.com/image/pic/item/11385343fbf2b2117c2dc3c3c88065380cd78e38.jpg",
			"http://c.hiphotos.baidu.com/image/pic/item/3801213fb80e7bec5ed8456c2d2eb9389b506b38.jpg"

	};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.simple_tabs);

        /*
         * 初始化:组装多个fragment
         * 第一次创建subfragment不会执行onCreateView方法
         */
        for (int i = 0; i < 7; i++) {

        	SubFragment fragment =new SubFragment(urls[i]);
			list.add(fragment);
		}

        ViewPager pager = (ViewPager)findViewById(R.id.pager);
        pager.setAdapter(new MyAdapter(getSupportFragmentManager(),list));//设置适配器

        TabPageIndicator indicator = (TabPageIndicator)findViewById(R.id.indicator);
        indicator.setViewPager(pager);//

    }

    /**
     * FragmentPagerAdapter用来适配Fragment
     */
    class MyAdapter extends FragmentPagerAdapter {

    	List<SubFragment> mList;

		public MyAdapter(FragmentManager fm,List<SubFragment> list) {
			super(fm);
			mList = list;
		}

		/**
		 * FragmentPagerAdapter初始化item的时候会调用一次getItem,
		 * 而第二次返回item则不调用getItem方法,而是执行SubFragment的onCreateView方法;
		 * 也就是说只有在与fragment关联的时候会调用一次getItem,以后则不调用;
		 */
		@Override
		public Fragment getItem(int position) {

			return mList.get(position);

		}

		/*
		 * 返回title
		 */
        @Override
        public CharSequence getPageTitle(int position) {
            return CONTENT[position % CONTENT.length].toUpperCase();
        }

        /*
         * 返回总页数
         */
        @Override
        public int getCount() {
          return mList.size();
        }

    }

}
package com.example.viewpagerindicatortest;

import java.io.IOException;
import java.lang.ref.SoftReference;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;

import android.annotation.SuppressLint;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

/**
 * 基于Fragment的Tab样式的viewpager;
 *
 * @author andy
 *
 * 更多详情请访问博客:http://blog.csdn.net/lyc66666666666
 */
@SuppressLint("ValidFragment")
public  class SubFragment extends Fragment {

    private static final String KEY_CONTENT = "TestFragment:Content";

    private String mContent = "???";

    private String url;

    public SubFragment(String url) {

    	this.url = url;
    	System.out.println("url:"+url);

	}
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
            mContent = savedInstanceState.getString(KEY_CONTENT);
        }
    }

    View v ;

    /**
     * 每次翻页都会调用onCreateView创建一次组件
     */
	@Override
	public View onCreateView(LayoutInflater inflater,
			final ViewGroup container, Bundle savedInstanceState) {

		v = inflater.inflate(R.layout.test, null);

		new AsyncImageLoader().loadDrawable(url, new ImageCallback() {

			@SuppressLint("NewApi")
			public void imageLoaded(Drawable imageDrawable, String imageUrl) {
				System.out.println("图片获取完成");

				ImageView image = (ImageView) v.findViewById(R.id.img);
				image.setBackground(imageDrawable);

			}
		});

		return v;
	}

    /**
	 * 定义回调接口
	 */
	public interface ImageCallback {
		public void imageLoaded(Drawable imageDrawable, String imageUrl);
	}

    /**
	 * 异步加载图片
	 */
	static class AsyncImageLoader {

	    Global global;

		public AsyncImageLoader() {
			global = Global.getInstance();
		}

		/**
		 * 创建子线程加载图片
		 * 子线程加载完图片交给handler处理(子线程不能更新ui,而handler处在主线程,可以更新ui)
		 * handler又交给imageCallback,imageCallback须要自己来实现,在这里可以对回调参数进行处理
		 *
		 * @param imageUrl :须要加载的图片url
		 * @param imageCallback:
		 * @return
		 */
		public Drawable loadDrawable(final String imageUrl,
				final ImageCallback imageCallback) {

			//如果缓存中存在图片  ,则首先使用缓存
			if (global.getCache(imageUrl)!=null) {
				System.out.println("存在缓存~~~~~~~~~~~~~~~~~");
				SoftReference<Drawable> softReference = global.getCache(imageUrl);
				Drawable drawable = softReference.get();
				if (drawable != null) {
					imageCallback.imageLoaded(drawable, imageUrl);//执行回调
					return drawable;
				}
			}

			/**
			 * 在主线程里执行回调,更新视图
			 */
			final Handler handler = new Handler() {
				public void handleMessage(Message message) {
					imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
				}
			};

			/**
			 * 创建子线程访问网络并加载图片 ,把结果交给handler处理
			 */
			new Thread() {
				@Override
				public void run() {
					Drawable drawable = loadImageFromUrl(imageUrl);
					// 下载完的图片放到缓存里
					global.setCache(imageUrl, new SoftReference<Drawable>(drawable));
					Message message = handler.obtainMessage(0, drawable);
					handler.sendMessage(message);
				}
			}.start();

			return null;
		}

		/**
		 * 下载图片  (注意HttpClient 和httpUrlConnection的区别)
		 */
		public Drawable loadImageFromUrl(String url) {

			try {
				HttpClient client = new DefaultHttpClient();
				client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000*15);
				HttpGet get = new HttpGet(url);
				HttpResponse response;

				response = client.execute(get);
				if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
					HttpEntity entity = response.getEntity();

					Drawable d = Drawable.createFromStream(entity.getContent(),
							"src");

					return d;
				} else {
					return null;
				}
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

			return null;
		}

	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putString(KEY_CONTENT, mContent);
	}

}
package com.example.viewpagerindicatortest;

import java.lang.ref.SoftReference;
import java.util.HashMap;

import android.graphics.drawable.Drawable;

/**
 * 全局变量,以软引用方式存放图片缓存
 *
 * @author andy
 *
 * 更多详情请访问博客:http://blog.csdn.net/lyc66666666666
 */
public class Global {

	// 软引用,使用内存做临时缓存 (程序退出,或内存不够则清除软引用)
	private static HashMap<String, SoftReference<Drawable>> imageCache;

	private static Global global;

	public static Global getInstance() {

		if (global == null) {
			global = new Global();
		}

		if (imageCache == null) {
			imageCache = new HashMap<String, SoftReference<Drawable>>();
		}

		return global;

	}

	//存放缓存
	public void setCache(String url, SoftReference<Drawable> softReference) {

		imageCache.put(url, softReference);

	}

	//获取缓存
	public SoftReference<Drawable> getCache(String url) {

		return imageCache.get(url);

	}

	//清除缓存
	public void clearCache() {
		if (imageCache.size() > 0) {
			imageCache.clear();
		}
	}

}

simple_tabs.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 Jake Wharton

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <com.viewpagerindicator.TabPageIndicator
        android:id="@+id/indicator"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        />
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        />

</LinearLayout>

test.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/img"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

AndroidMainfest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.viewpagerindicatortest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

         <activity
            android:name=".SampleTabsDefault"
            android:label="@string/app_name"
            android:theme="@style/Theme.PageIndicatorDefaults">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

点击下载源码

Android:ViewPager扩展详解——带有导航的ViewPagerIndicator(附带图片缓存,异步加载图片),布布扣,bubuko.com

时间: 2024-10-22 18:54:00

Android:ViewPager扩展详解——带有导航的ViewPagerIndicator(附带图片缓存,异步加载图片)的相关文章

Android ListView异步加载图片乱序问题,原因分析及解决方案

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/45586553 在Android所有系统自带的控件当中,ListView这个控件算是用法比较复杂的了,关键是用法复杂也就算了,它还经常会出现一些稀奇古怪的问题,让人非常头疼.比如说在ListView中加载图片,如果是同步加载图片倒还好,但是一旦使用异步加载图片那么问题就来了,这个问题我相信很多Android开发者都曾经遇到过,就是异步加载图片会出现错位乱序的情况.遇到这个问题时,不

Android图片管理组件(双缓存+异步加载)

转自:http://www.oschina.net/code/snippet_219356_18887?p=3#comments ImageManager2这个类具有异步从网络下载图片,从sd读取本地图片,内存缓存,硬盘缓存,图片使用动画渐现等功能,已经将其应用在包含大量图片的应用中一年多,没有出现oom Android程序常常会内存溢出,网上也有很多解决方案,如软引用,手动调用recycle等等.但经过我们实践发现这些方案,都没能起到很好的效果,我们的应用依然会出现很多oom,尤其我们的应用包

imageloader+scaleimageview+viewpager组合异步加载图片的图片浏览功能

在qq空间或者微信朋友圈里  看到图片总会点击图片进行查看,图片放大缩小功能包括通过手势放大缩小旋转以及双击放大缩小,并且可以左右滑动看到前一张图片或者后一张图片,需要该功能的话,这篇文章或许可以给你帮助. 众所周知,imageloader异步加载图片,不仅可以快速加载图片,而且还可以将图片保存到sdk缓存中,因此下载图片用imageloader即可,如有不懂的,可简单看下我的这篇文章http://blog.csdn.net/u012303938/article/details/46330123

Android之ListView异步加载图片且仅显示可见子项中的图片

折腾了好多天,遇到 N 多让人崩溃无语的问题,不过今天终于有些收获了,这是实验的第一版,有些混乱,下一步进行改造细分,先把代码记录在这儿吧. 网上查了很多资料,发现都千篇一律,抄来抄去,很多细节和完整实例都没看到,只有自己一点点研究了,总体感觉 android 下面要显示个图片真不容易啊. 项目主要实现的功能: 异步加载图片图片内存缓存.异步磁盘文件缓存解决使用 viewHolder 后出现的图片错位问题优化列表滚动性能,仅显示可见子项中的图片无需固定图片显示高度,对高度进行缓存使列表滚动时不会

Android批量图片加载经典系列——使用LruCache、AsyncTask缓存并异步加载图片

一.问题描述 使用LruCache.AsyncTask实现批量图片的加载并达到下列技术要求 1.从缓存中读取图片,若不在缓存中,则开启异步线程(AsyncTask)加载图片,并放入缓存中 2.及时移除无效的异步线程;保证异步加载图片时不会乱序 3.只对当前屏幕可见部分进行缓存.异步加载图片 4.优化性能杜绝OOM 二.案例介绍 案例实现照片墙效果 三.主要技术 LruCache 内存缓存技术,在Android中 专门用来做图片缓存处理的组件,主要使用步骤 (1) 设置缓存图片的内存大小,如设置为

android开发干货:实现listview异步加载图片

针对listview异步加载图片这个问题,麦子学院android开发老师讲了一种非常实用的方法,麦子学院android开发老师说凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,下面就说实现方法,先贴上主方法的代码: package cn.wangmeng.test; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.

android listview 异步加载图片并防止错位

网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertView 但没有异步操作也不会有问题. 我简单分析一下: 当重用 convertView 时,最初一屏显示 7 条记录, getView 被调用 7 次,创建了 7 个 convertView. 当 Item1 划出屏幕, Item8 进入屏幕时,这时没有为 Item8 创建新的 view 实例, Ite

android listview 异步加载图片并防止错位+双缓存

网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertView 但没有异步操作也不会有问题. 我简单分析一下: 当重用 convertView 时,最初一屏显示 7 条记录, getView 被调用 7 次,创建了 7 个 convertView. 当 Item1 划出屏幕, Item8 进入屏幕时,这时没有为 Item8 创建新的 view 实例, Ite

【Android】纯代码创建页面布局(含异步加载图片)

开发环境:macOS 10.12 + Android Studio 2.2,MinSDK Android 5.1 先看看总体效果 本示例是基于Fragment进行的,直接上代码: [界面结构] 在 Fragment 中,采用 ScrollView + LinearLayout 实现. 1 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http:/