现在的移动应用, 很常见的一个交互效果就是在首页顶部添加图片轮播的控件, 焦点图可以放入广告, 也可以放入文章的内容图片, 它们不断自动切换, 点击焦点图即跳至对应的界面. 交互效果很棒. 做图片轮播的效果, 方法并不少. 本文使用了常见的viewpager 去实现. 支持显示网络图片下载在缓存显示, 如果有SD卡则默认将图片下载至SD卡中再显示本地的图片.
其实网上这类代码已经很多, 应该也有很多写得比我好. 今天有点时间, 就做了个来练手, 顺便写下自己第一篇原创文章. 敲代码之前也参考了一些网上的例子, 感谢那些大神!
好了,不多说别的, 直接上代码.(为了减少类的数量, 将一些方法直接写在主类中, 多多见谅哈~)
MainActivity:
/**
* 图片轮播器<br>支持显示网络图片以及将网络图片下载至本地显示
* @author Mr.ET
*
*/
public class MainActivity extends Activity{
private List<ImageView> mImageViewList = null;
private List<View> mViewList = null;
private TextView mArticleTitle = null;
private ViewPager mViewPager = null;
private Handler mHandler = null;
private LinearLayout mCustomSpace = null;
private MyPagerAdapter adapter = null;
private boolean loopPlayState = false;
private View view;
//private final String mySign = "url";
private List<String> tList,pList,nList;
private List<Bitmap> bList;
//private int p1 = -1,p2 = -1,p3 = -1,p4 = -1;
private String name;
//图片总数
private final int pAccount = 4;
//控制图片变量
private int pNum = 0;
private int readStyle = -1;
private final static int readInNet = 0;
private final static int readInSD = 1;
private final static int readInCache = 2;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == 0x111){
if(bList != null && bList.size() > 0 && readStyle != readInNet) bList.clear();
if(mImageViewList != null && mImageViewList.size() > 0) mImageViewList.clear();
//图片已备齐,可以设置pager图片
for(int i=0;i<pList.size();i++){
ImageView imageView = new ImageView(MainActivity.this);
imageView.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
imageView.setScaleType(ScaleType.FIT_XY);
imageView.setOnClickListener(new ClickListener(i));
mImageViewList.add(imageView);
view = new View(MainActivity.this);
LayoutParams layoutParams = new LayoutParams(14, 14);
layoutParams.setMargins(3, 0, 3, 0);
view.setLayoutParams(layoutParams);
view.setBackgroundResource(R.drawable.dot_normal);
mViewList.add(view);
mCustomSpace.addView(view);
if(readStyle != readInNet){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bm = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/demo/"+nList.get(i)+".jpg", options);
bList.add(bm);
}
}
adapter = new MyPagerAdapter();
mViewPager.setAdapter(adapter);
mViewPager.setOnPageChangeListener(new MyPageChangeListener());
if (!loopPlayState) {
mArticleTitle.setText(tList.get(0));
mViewPager.setCurrentItem(0);
mHandler.postDelayed(loopPlay, 3000);
loopPlayState = true;
}
}
super.handleMessage(msg);
}
};
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager)findViewById(R.id.viewpager);
mArticleTitle = (TextView)findViewById(R.id.article_title);
mCustomSpace = (LinearLayout)findViewById(R.id.custom_space);
mHandler = new Handler();
mImageViewList = new ArrayList<ImageView>();
mViewList = new ArrayList<View>();
tList = new ArrayList<String>();
pList = new ArrayList<String>();
nList = new ArrayList<String>();
bList = new ArrayList<Bitmap>();
for(int i=0;i<4;i++){ tList.add("这是标题"+i); }
pList.add("http://b.hiphotos.baidu.com/image/pic/item/203fb80e7bec54e767710215bb389b504fc26a1f.jpg");
pList.add("http://d.hiphotos.baidu.com/image/pic/item/32fa828ba61ea8d37e6f6c0f950a304e251f586f.jpg");
pList.add("http://g.hiphotos.baidu.com/image/pic/item/e1fe9925bc315c605aeb75e48fb1cb13495477ba.jpg");
pList.add("http://h.hiphotos.baidu.com/image/pic/item/d000baa1cd11728bd0359429cafcc3cec3fd2ca4.jpg");
readyToImage();
}
/**
* 下载图片前的准备 <br>主要根据有无SD卡来准备图片是下载在本地还是放在内存中
*/
public void readyToImage(){
if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){ //有SD卡
String folderPath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/demo";
File demoFile = new File(folderPath);
if(!demoFile.exists()){ //不存在这个文件夹,即不存在所需的图片. 就启动线程去下载图片
readStyle = readInSD;
for(int p=0;p<pList.size();p++){
DLPThread mythread = new DLPThread(pList.get(p));
mythread.start();
}
}else{
File[] files = demoFile.listFiles();
if(files.length >= 4 && isImage(getFileType(files[0].getName())) && isImage(getFileType(files[1].getName()))
&& isImage(getFileType(files[2].getName())) && isImage(getFileType(files[3].getName()))){
readStyle = readInCache;
for(int i=0;i<4;i++){ nList.add(files[i].getName()); }
mainSetImage();
}else{ //下载图片
readStyle = readInSD;
for(int p=0;p<pList.size();p++){
DLPThread mythread = new DLPThread(pList.get(p));
mythread.start();
}
}
}
}else{ //无SD卡
readStyle = readInNet;
for(int p=0;p<pList.size();p++){
DLPThread mythread = new DLPThread(pList.get(p));
mythread.start();
}
}
}
/**
* 线程下载图片至本地
* @author Mr.ET
*
*/
class DLPThread extends Thread{
private String url;
public DLPThread(String url){
this.url = url;
}
public void run(){
try {
Looper.prepare();
Bitmap bitmap = (Bitmap)utils.requestGet(this.url, Bitmap.class);
name = String.valueOf(System.currentTimeMillis());
nList.add(name); //存放文件名
if(readStyle != readInNet){
File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/demo");
if(!folder.exists()){
folder.mkdir();
}
String path = folder + "/"+name+".jpg";
File file = new File(path);
FileOutputStream fileOutputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
}else{ //无SD卡
bList.add(bitmap);
}
pNum ++;
setImage();
Looper.loop();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void setImage(){
if(pNum == pAccount){
handler.sendEmptyMessage(0x111);
}
}
private final class MyPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return mImageViewList.size();
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView(mImageViewList.get(position));
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView temp = mImageViewList.get(position);
temp.setImageBitmap(bList.get(position));
((ViewPager) container).addView(temp);
return temp;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
}
/**
* 当ViewPager中页面的状态发生改变时调用
*
* @author Mr.ET
*
*/
private class MyPageChangeListener implements OnPageChangeListener {
private int historyPosition = 0;
/**
* 当ViewPager中页面的状态发生改变时调用
*/
public void onPageSelected(int position) {
mArticleTitle.setText(tList.get(position));
mViewList.get(historyPosition).setBackgroundResource(
R.drawable.dot_normal);
mViewList.get(position).setBackgroundResource(
R.drawable.dot_focused);
historyPosition = position;
}
public void onPageScrollStateChanged(int arg0) {
}
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
}
/**
* 设置自动间隔3秒自动切换图片
*/
Runnable loopPlay = new Runnable() {
@Override
public void run() {
int position = mViewPager.getCurrentItem();
if(position == (pList.size()-1)){
position = 0;
mViewPager.setCurrentItem(position);
}
else{
Log.i("position++", "position++="+position++);
mViewPager.setCurrentItem(position++);
}
mHandler.postDelayed(loopPlay, 3000);
}
};
private class ClickListener implements OnClickListener{
private int location;
public ClickListener(int location){
this.location = location;
}
@Override
public void onClick(View v){
Toast.makeText(MainActivity.this, "你点击了第"+this.location+"张的图片", 1000).show();
}
}
/**
* 获取文件类型
* @param fileName
* @return
*/
public static String getFileType(String fileName) {
if (fileName != null) {
int typeIndex = fileName.lastIndexOf(".");
if (typeIndex != -1) {
String fileType = fileName.substring(typeIndex + 1)
.toLowerCase();
return fileType;
}
}
return "";
}
/**
* 判断是否图片
* @param type
* @return
*/
public static boolean isImage(String type) {
if (type != null
&& (type.equals("jpg") || type.equals("gif")
|| type.equals("png") || type.equals("jpeg")
|| type.equals("bmp") || type.equals("wbmp")
|| type.equals("ico") || type.equals("jpe"))) {
return true;
}
return false;
}
/**
* 直接从SD获取图片显示
*/
public void mainSetImage(){
if(bList != null && bList.size() > 0) bList.clear();
if(mImageViewList != null && mImageViewList.size() > 0) mImageViewList.clear();
//图片已备齐,可以设置pager图片
for(int i=0;i<4;i++){
ImageView imageView = new ImageView(MainActivity.this);
imageView.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
imageView.setScaleType(ScaleType.FIT_XY);
imageView.setOnClickListener(new ClickListener(i));
mImageViewList.add(imageView);
view = new View(MainActivity.this);
LayoutParams layoutParams = new LayoutParams(14, 14);
layoutParams.setMargins(3, 0, 3, 0);
view.setLayoutParams(layoutParams);
view.setBackgroundResource(R.drawable.dot_normal);
mViewList.add(view);
mCustomSpace.addView(view);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bm = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/demo/"+nList.get(i), options);
bList.add(bm);
}
adapter = new MyPagerAdapter();
mViewPager.setAdapter(adapter);
mViewPager.setOnPageChangeListener(new MyPageChangeListener());
if (!loopPlayState) {
mArticleTitle.setText(tList.get(0));
mViewPager.setCurrentItem(0);
mHandler.postDelayed(loopPlay, 3000);
loopPlayState = true;
}
}
}
utils, 里面也简单的封装一下httpclient.
public class utils {
private static DefaultHttpClient httpClient;
static{
if(null == httpClient){
HttpParams httpParams = new BasicHttpParams();
HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
HttpProtocolParams.setUseExpectContinue(httpParams, true);
ConnManagerParams.setMaxTotalConnections(httpParams, 10);
ConnManagerParams.setTimeout(httpParams, 60000);
ConnPerRouteBean connPerRoute = new ConnPerRouteBean(8);
ConnManagerParams.setMaxConnectionsPerRoute(httpParams,connPerRoute);
HttpConnectionParams.setConnectionTimeout(httpParams, 20000);
HttpConnectionParams.setSoTimeout(httpParams, 30000);
SchemeRegistry schreg = new SchemeRegistry();
schreg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schreg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager connManager = new ThreadSafeClientConnManager(httpParams, schreg);
httpClient = new DefaultHttpClient(connManager, httpParams);
}
}
public static HttpClient getHttpClient(){
return httpClient;
}
public static Object requestGet(String url,Class<?>c){
try {
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet);
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
byte[] b = readInputStream(response.getEntity().getContent());
if(c == String.class){
String resultStr = new String(b);
return resultStr;
}
if(c == Bitmap.class){
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
// BitmapFactory.Options options = new BitmapFactory.Options();
// options.inSampleSize = 10;
// Bitmap bitmap = BitmapFactory.decodeStream(response.getEntity().getContent(), null, options);
return bitmap;
}
}else{
//sorry, can not ask for the http server......
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static byte[] readInputStream(InputStream in) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int len = 0;
while ((len = in.read(b)) != -1) {
baos.write(b, 0, len);
}
in.close();
return baos.toByteArray();
}
}
下面是用到的资源文件
dot_focused.xml :
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#aaFFFFFF" />
<corners android:radius="50dip" />
</shape>
dot_normal.xml :
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#33000000" />
<corners android:radius="5dip" />
</shape>
主要思路:
先判断手机是否有SD卡: 1, 有SD卡. 将图片下载至SD卡中, 图片轮播将图片转为bitmap, 显示在imageview中. 2, 无SD卡. 将图片下载至缓存中, 直接转为bitmap并显示在imageview中.
第二种方法很不好, 因为每次打开应用都要发HTTP请求去下载图片,再来显示, 而HTTP请求是相当耗资源的操作, 严重影响交互. 所以请尽量减少无谓的HTTP请求. 当你的应用第一次安装, 这个时候就去下载这四个图片放在本地, 这是必须的, 因为这时候本地一张图片都没有嘛. 然后当用户继续操作应用, 比如继续看新闻看别的文章的时候, 可以在后台启动个线程 去 检查这四张图片的接口有无更新, 如果有更新, 再启动线程将图片悄悄的下载在本地中 , 并更新图片轮播的内容. 这样, 当用户下次再启动应用的时候, 图片轮播加载图片的速度就快了哦. 这是其中之一的思路. 具体还要看应用的需求, 在实现上有所变化.
代码中有注释, 也很简单. 应该很容易看懂吧.
例子写的不够简洁, 也还有不少可以优化的地方, 奈何时间有限, 请多包涵. 咱们互相学习, 一起进步吧. ^^