初次使用viewpager,笔记,即左右滑动效果

原创
2015/03/14 21:16
阅读数 165

      初学android,想尝试做一个带左右滑动界面的功能的APP,方便我查看两张地铁线路图,因为平时得打开图册去慢慢找,相当麻烦,所以为了方便就有这个想法。

#开发过程中直接参考官方文档的例子 Creating Swipe Views
#Url:http://developer.android.com/design/patterns/swipe-views.html


(图片来自官方例子)
#连接中有示例动画,我这不再重复,还有不要跟我说打不开,请自备梯子(X墙)
特别提醒:如果想更深刻地去理解 Viewpager ->  FramentStatePagerAdapter -> Fragment 中的设计概念,可以去阅读设计模式中的《适配器模Adapter》


先首我们要知道四个重要类:

  • FragmentActivity

           这是supportV4里提供的Activity子类,主要是为了向下兼容,注意的是,要用getSupportFragmentManager(),而非getFragmentManager(),只是使用Support包里的类而原API的,都必须要用这个方法,具体看下文。

  • Viewpager
           它主要的作用就是实现左右滑动切换视图的功能,这个已由系统实现好,我们直接调用即可。

  • FragmentStatePagerAdapter

            作为ViewpagerFragment之间的一个对接适配器,实现使用不同的页切换处理逻辑之间的松藕合。        
    这个类同样是SupportV4里提供的FragmentStatePagerAdapter这里得说一下它的父类PagerAdapter,
    PagerAdapter有两个子类FragmentStatePagerAdapterFragmentPagerAdapter
    文档中提到这两个类的差别在于:
    FragmentPagerAdapter是当你的页数较少并相对固定,比如只有三个或两,可选用这个,因为
    它在页面切换后并不会销毁被隐藏的页面,想切换回来时响应速度更快更流畅,原内容还会保留。
      PS:我在打印LOG时发现,这个适配器会在会话初始化时就已经一次性把所有选项加载完。
    FragmentStatePagerAdapter是当你 的选项页是一个比较大的集合,并而数量是不固定时,可选用这个,因为
    它在页面切换后会承之销毁被隐藏的页面,每次切换回去时再重新创建 ,这样的目的是为了节省内存开销。
      PS:经试验,它会预先加载下一页,当你到第3页的时候,第1页会被销毁,当前页的一前一后还会被保留(2和4).
            由于我这例子只用了固定的两个选项页,所以我选择用FragmentPagerAdapter

  • Fragment

    名词解释:片断。我个人理解就是一个独立的activity,但它是可以被嵌入到另一个Activity的布局中,如果有WEB开发
    经验的朋友 应该知道HTML中的iframe, 其实这两者就是一个道理。

接下来是具体实现我会在贴出来的代码中用注释说明,不再在本文叙述。

—— CollectionActivity.java (主入口)


import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;

/**
 * 应用的主入口Activity,这里只负责创建viewpager控件及其所需的配置,不做其它事情<br/>
 * viewpager滑动过渡交由ViewPagerAdapter处理{@link  subwayimg.someday.cn.com.subwayimg.ViewPagerAdapter},<br/>
 * 显示具体内容交由ImgFragment{@link  subwayimg.someday.cn.com.subwayimg.ImgFragment}处理<br/>
 *
 * Created by jie on 15-3-12.
 */
public class CollectionActivity extends FragmentActivity 
{
    //负责处理左右滑动效果的动画适配器
    ViewPagerAdapter mViewPagerAdapter;
    //viewpager控件对象
    ViewPager mViewPager;

    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //适配器构造需要一个FragmentManager,因为是使support包,所以要用getSupportFragmentManager()
        mViewPagerAdapter =  new ViewPagerAdapter( getSupportFragmentManager());
        //获取主布局(activity_main)中的ViewPager控件对象
        mViewPager = (ViewPager) findViewById(R.id.activity_main_viewpager);
        //设置 负责左右滑动逻辑处理的适配器对象
        mViewPager.setAdapter(mViewPagerAdapter);
    }
}



—— CollectionActivity 对应的布局文件 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main_viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />



——ViewPagerAdapter 滑动适配器



import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;

/**
 * 实现FragmentPagerAdapter接口,
 * 接口要求我们最少完成以下事情<br>
 * 1.实现一个带有FragmentManager参数的构造器,并调用父构造方法{@link #ViewPagerAdapter}<br>
 * 2.告诉viewpager控件我们共有多少个选项页{@link #getCount}<br>
 * 3.告诉viewpager控件当前页的标题{@link #getPageTitle}<br>
 * 4.这是最重要的一点,当左右滑动件事发生后,给控件返回一个当前要显示的View {@link #getItem}<br>
 * Created by jie on 15-3-11.
 */
public class ViewPagerAdapter extends FragmentPagerAdapter {
    public ViewPagerAdapter(FragmentManager fm) { super(fm); }

    /**
     * 获取当然要显示的视图View
     * @param i 当前页数 从0开始
     * @return 视图
     */
    @Override
    public Fragment getItem(int i) 
    {
        //创建要显示的ImgFramgent,并传送当前页参数,0为第一页,1为第二页
        Fragment fragment = new ImgFragment();
        Bundle args = new Bundle();
        args.putInt(ImgFragment.ARG_COUNT_NAME, i);
        fragment.setArguments(args);
        return fragment;
    }

    /**
     * 获取选项页而总数
     * @return 页数
     */
    @Override
    public int getCount() 
    {
        //豪无疑问,我只有两个图片想显示,所以只需两页,返回2
        return 2;
    }

    /**
     * 返回当前显示页的标题名称
     * 注意一点,这个方法只有在你使用了标题栏的时候才会调用,即ActionBar
     * @param position 当前页数 从0开始
     * @return 标题名称字符
     */
    @Override
    public CharSequence getPageTitle(int position) 
    {
        return "OBJECT " + (position + 1);
    }
}



——ImgFragment



import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;

/**
 * 用于显示图片的Fragment,一个片断式的view
 * 分别显示assets资源文件里的两张图片subway_1 和 subway_2
 *
 * Created by jie on 15-3-11.
 */
public class ImgFragment extends android.support.v4.app.Fragment {
    //传参字段,当前显示页数
    public static final String ARG_COUNT_NAME = "COUNT";


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        //保证最后两个参数不被参改,即必须这样传参,(这是官方注释的原话,不知道我理解是否正确)
        View rootView = inflater.inflate( R.layout.img_ragment, container, false);
        //获取传过来的当前显示页
        int args = getArguments().getInt(ARG_COUNT_NAME);

        //获取图像对象
        Bitmap subwayImg = getSubwayImgBitmap(args);

        //设置要显示的图像
        ((ImageView) rootView.findViewById(R.id.image_view)).setImageBitmap(subwayImg);

        return rootView;
    }

    /**
     * 获取图片的封装方法,从Assets文件夹里取出图片
     * @param args 要获取第几张
     * @return Bitmap 图像对象
     */
    private Bitmap getSubwayImgBitmap(int args) 
    {
        Bitmap subwayImg = null;
        InputStream imgInputStream = null;
        try {

            if(0 == args)
            {
                imgInputStream = getActivity().getApplicationContext().getAssets().open("subway_1.png");
            }
            else
            {
                imgInputStream = getActivity().getApplicationContext().getAssets().open("subway_2.png");
            }
            subwayImg = BitmapFactory.decodeStream(imgInputStream);

        } catch (IOException e) {
            e.printStackTrace();
        }
        finally 
        {
            if (null != imgInputStream)
            {
                try {
                    imgInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
        return subwayImg;
    }
}

——ImgFragment 对应的布局文件


<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" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity$PlaceholderFragment">

    <ImageView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/image_view"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
</RelativeLayout>



本章就到这里了,如果文中有什么地方说错了希望大家指正,最后完整代码我托管在osc@git中:
https://git.oschina.net/someday/SubwayImg.git

        最后,程序中只实现左右滑动查看图片,并且为了避免OOM,强制在显示前把原图缩小3倍,但真正需求是要实现对图片的手势放大缩大功能,这会在写下一篇博文中继续记录学习过程。


展开阅读全文
打赏
0
3 收藏
分享
加载中
更多评论
打赏
0 评论
3 收藏
0
分享
返回顶部
顶部