Android滑动页面ViewPager的详细总结

一.ViewPager的基础知识

(一)ViewPager概述

        ViewPager是谷歌官方给我们提供的一个兼容低版本安卓设备的软件包,里面包囊了只有在安卓3.0以上可以使用的api。而viewpager就是其中之一利用它,我们可以做很多事情,从最简单的导航,到页面菜单等等。那如何使用它呢,与ListView类似,我们也需要一个适配器,他就是PagerAdapter。
        ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的View类。ViewPager类需要一个PagerAdapter适配器类给它提供数据。ViewPager经常和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和 FragmentStatePagerAdapter类供Fragment中的ViewPager使用。
        ViewPager的功能就是可以使视图滑动,就像Lanucher左右滑动那样。

(二)ViewPager的使用步骤三个步骤来使用:

1.在住布局文件里加入

2.加载要显示的页卡

3.在Activity里实例化ViewPager组件,并设置它的Adapter(就是PagerAdapter,方法与 ListView一样的),在这里一般需要重写PagerAdapter。

(三)实现一个PagerAdapter,至少覆盖以下方法:

1.instantiateItem(ViewGroup, int)返回视图对象

2.destroyItem(ViewGroup, int, Object)销毁视图对象

3.getCount() 视图个数

4.isViewFromObject(View, Object)一般传入arg0==arg1.用来判断两个视图是否是等价的

(四)ViewPager的XML配置

.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" > 
 .support.v4.view.ViewPager>

(五)ViewPager的监听事件

viewpager.setOnPageChangeListener(new OnPageChangeListener() {
         @Override
        public void onPageSelected(int arg0) {
                     //当页面选中时 
          } 
           @Override 
         public void onPageScrolled(int arg0, float arg1, int arg2) { 
        //arg0 当前页
                 //arg1 移动页百分比
         //arg2 移动像素点 
          }
          @Override 
        public void onPageScrollStateChanged(int arg0) { 
        //滑动状态改变 
         }
 });

二.PagerTitleStrip和PagerTabStrip

(一)PagerTitleStrip

        PagerTitleStrip是ViewPager的一个关于当前页面、上一个页面和下一个页面的一个非交互的指示器。它经常作为ViewPager控件的一个子控件被被添加在XML布局文件中。在你的布局文件中,将它作为子控件添加在ViewPager中。而且要将它的android:layout_gravity属性设置为TOP或BOTTOM来将它显示在ViewPager的顶部或底部。每个页面的标题是通过适配器的getPageTitle(int)函数提供给ViewPager的。

(二)PagerTabStrip

PagerTabStrip与PagerTitleStrip类似,只有两点不同
PagerTabStrip在当前页面下,会有一个下划线条来提示当前页面的Tab是哪个。 PagerTabStrip的Tab是可以点击的,当用户点击某一个Tab时,当前页面就会跳转到这个页面,而PagerTitleStrip则没这个功能。

(三)自定义Tab

例子:实现一个跟随页面移动的指示条
具体的实现的代码都是在ViewPager的监听方法中实现

三.ViewPager结合Fragment显示

        我们知道,实现ViewPager是要有适配器的,我们前面用的适配器是 PagerAdapter,而对于Fragment,它所使用的适配器是:FragmentPagerAdapter。 FragmentPagerAdapter派生自PagerAdapter,它是用来呈现Fragment页面的,这些 Fragment页面会一直保存在fragment manager中,以便用户可以随时取用。
在 使 用 ViewPager 时 , 必 须 使 用 v 4 包 下 的 Fragment, 并 且 使 用 FragmentActivity。
这个适配器最好用于有限个静态fragment页面的管理。尽管不可见的视图有时会被销毁,但用户所有 访问过的fragment都会被保存在内存中。因此fragment实例会保存大量的各种状态,这就造成了很 大的内存开销。所以如果要处理大量的页面切换,建议使用FragmentStatePagerAdapter.
        对于FragmentPagerAdapter的派生类,只需要重写getItem(int)和getCount()就可以了。

public class FragAdapter extends FragmentPagerAdapter { 
    private List mFragments; 
    public FragAdapter(FragmentManager fm,List fragments) {
        super(fm);
        mFragments=fragments;
     }
    @Override  
    public Fragment getItem(int arg0) { 
        //根据传来的参数arg0,来返回当前要显示的Fragment 
        return mFragments.get(arg0); 
    }
    @Override 
    public int getCount() { 
        //返回用于滑动的fragment总数
        return mFragments.size();  
      } 
 }

下面是ViewPager的使用示例

四.ViewPager显示可滑动的图片页面

这个应用在广告页面或启动页面都是蛮多的。效果图:
Android滑动页面ViewPager的详细总结_第1张图片

        这里设计的是页面可以左右滑动页面,实现图片的切换,并且下面有每一个图片对应的图标,当页面滑动到第八张图片弹出一个按钮,可以做相应的操作。
        这里设置了无限滑动的设置!代码控制的。
代码设计:

(一)布局文件activity_main.xml设计


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <android.support.v4.view.ViewPager
        android:id="@+id/main_vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


    <LinearLayout
        android:id="@+id/main_ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20dp"
        android:gravity="center"
        android:orientation="horizontal" />
    <Button
        android:id="@+id/main_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_margin="20dp"
        android:text="点击马上体验!"
        android:visibility="invisible" />

RelativeLayout>

(二)设置下面小圆点的选择器资源文件

在drawable文件夹下,创建start_selsect.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/star" android:state_selected="true">item>
    <item android:state_selected="false">
        <shape android:shape="oval">
            <solid android:color="@android:color/darker_gray" />
        shape>
    item>
selector>

上面要放一张小星星的图片到资源文件中。
下面还有放八张大图片到资源文件中,用于划屏时显示。

(三)主方法的类的java代码

package fuxi.viewpager1;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;

import java.util.ArrayList;
import java.util.List;


public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {

    //布局中的对象
    ViewPager vp;
    LinearLayout ll;
    Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn = (Button) findViewById(R.id.main_btn);

        initPoints();//初始化小圆点
        initView();//初始化数据
    }

    /**
     * 实现小圆点的添加,
     * 找到线性布局动态的向线性布局内添加小圆,并添加drawable选择的效果
     */
    private void initPoints() {
        //实例化线性布局
        ll = (LinearLayout) findViewById(R.id.main_ll);
        //绘制和图片对应的圆点的数量
        for (int i = 0; i < images.length; i++) {
            View view = new View(this);
            //设置圆点的大小
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(30, 30);
            //设置间距
            params.setMargins(10, 10, 10, 10);
            //设置图片的自定义效果
            view.setBackgroundResource(R.drawable.stars_select);
            //把设置好的视图属性设置到View中
            view.setLayoutParams(params);
            //把创建好的View添加到线性布局中
            ll.addView(view);
        }
        Log.e("TAG", ":" + ll.getChildCount());
        //设置选中线性布局中的第一个
        ll.getChildAt(0).setSelected(true);
    }

    /**
     * 初始化数据
     */
    private void initView() {
        //实例化ViewPager
        vp = (ViewPager) findViewById(R.id.main_vp);
        //创建适配器对象
        Myadapter adapter = new Myadapter();
        //给视图ViewPager添加适配器
        vp.setAdapter(adapter);
        //给ViewPager添加监听事件
        //这个监听事件设置不是点击的,也不是选中的,使用添加页面改变的监听
        vp.addOnPageChangeListener(this);
        //设置图片开始的位置,从中间开始,并且是从八张图片中的第一张开始
        vp.setCurrentItem(Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2 % 8));
    }

    /**
     * 下面三个方法是,实现ViewPager监听页面改变时要实现的方法
     */
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        //页面滑动时触发
    }


    int index = 0;//设置一个游标值记录当前的显示页面

    @Override
    //页面选中时的回调方法
    public void onPageSelected(int position) {
        //对小圆点的设置
        //取消前一个视图的选中
        ll.getChildAt(index).setSelected(false);
        //选中下一个显示的视图
        ll.getChildAt(position % 8).setSelected(true);
        //跟新游标的值
        index = position % 8;
        //当显示最后一个页面时,可以实现跳转
        if (index == 7) {
            ll.setVisibility(View.INVISIBLE);
            btn.setVisibility(View.VISIBLE);
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // Toast.makeText(MainActivity.this, "点击了按钮", Toast.LENGTHRT).show();
                    //页面跳转到具体页面
                    //startActivity(new Intent(MainActivity.this, MainActivity2.class));
                    //关闭原来界面
                    finish();
                }
            });
        } else {
            ll.setVisibility(View.VISIBLE);
            btn.setVisibility(View.INVISIBLE);
        }

    }

    //页面状态改变时的回调方法
    @Override
    public void onPageScrollStateChanged(int state) {
        //对ViewPager状态进行判断决定是否执行轮播页面
        if (state == ViewPager.SCROLL_STATE_IDLE) {
            if (!handler.hasMessages(1)) {
                startGuide();
            }
        } else {
            stopGuide();
        }
    }


    /**
     * 创建一个Handler对象,用于实现自动轮播画面
     */
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            vp.setCurrentItem(vp.getCurrentItem() + 1);
            sendEmptyMessageDelayed(1, 2000);//延长两秒后给自己发消息,没有被移除前都是会一直循环的
        }
    };


    /**
     * 开始轮播
     */
    private void startGuide() {
        handler.sendEmptyMessageDelayed(1, 2000);
    }

    /**
     * 停止轮播
     */
    private void stopGuide() {
        //把消息移除,轮播页面就会停止
        handler.removeMessages(1);
    }


    //数据源,8张图片
    int[] images = {R.mipmap.a1, R.mipmap.a2, R.mipmap.a3, R.mipmap.a4, R.mipmap.a5, R.mipmap.a6, R.mipmap.a7, R.mipmap.a8};

    //定义一个集合用来存放视图的View对象
    List listOfView = new ArrayList<>();

    /**
     * 在类内创建Adapter对象,
     * 这里ViewPager要对应的Adapter是PagerAdapter
     */
    class Myadapter extends PagerAdapter {

        //可滑动的页面的数量
        @Override
        public int getCount() {
            //return listOfView.size();//实现只能滑动一遍图片的效果
            return Integer.MAX_VALUE;//实现无限滑动的效果
        }

        //判断两页的地址是否相同
        @Override
        public boolean isViewFromObject(View view, Object object) {
            //这是google要求的写法
            return view == object;
        }


        //重写构造方法,当创建实例时,把数据添加到集合中
        public Myadapter() {
            for (int i = 0; i < images.length; i++) {
                //创建ImageView存放图片
                ImageView iv = new ImageView(getApplicationContext());
                iv.setScaleType(ImageView.ScaleType.FIT_XY);
                iv.setImageResource(images[i]);
                //把图片添加到集合zhong
                listOfView.add(iv);
            }
        }

        //下面的两个方法也是必须重写的

        //这里要返回的是View的视图对象
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            //添加一个item 显示
            //Toast.makeText(getBaseContext(), position + "页", Toast.LENGTH_SHORT).show();
            container.addView(listOfView.get(position % 8));
            return listOfView.get(position % 8);
        }

        //销毁一个View的对象
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(listOfView.get(position % 8));
        }
    }

}

程序运行后的界面上面已经展示了,滑动页面后显示:
Android滑动页面ViewPager的详细总结_第2张图片

当页面滑动到第八个时,显示的界面:
Android滑动页面ViewPager的详细总结_第3张图片

        这里就可以实现相关页面的跳转,但是本实例中只是关闭页面。
        上面程序使用了Handler对象操作实现自动轮播的页面,如果没有滑动页面两秒页面是会自动轮播的,而滑动时页面是不会轮播的。

五.ViewPager和Fragment的结合使用实现

页面实现效果:
Android滑动页面ViewPager的详细总结_第4张图片
页面往右滑动时出现的画面:
Android滑动页面ViewPager的详细总结_第5张图片

可以看到上面有一个指示器在跟着滑动。
代码设计:

(一)布局文件activity_main.xml的设计


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

    <RadioGroup
        android:id="@+id/home_rg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/home_rb_dujia"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/back"
            android:button="@null"
            android:gravity="center"
            android:padding="10dp"
            android:text="旅游度假" />

        <RadioButton
            android:id="@+id/home_rb_ticker"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/back"
            android:button="@null"
            android:gravity="center"
            android:padding="10dp"
            android:text="景点门票" />

    RadioGroup>
    
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="5dp">

        <View
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#4e6bd4" />

        <View
            android:id="@+id/home_fl_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#16308c" />
    FrameLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/home_vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

LinearLayout>

        这里使用的是ViewPager来装载碎片,既没有使用fragment标签,也没有使用FrameLayout标签。

(二)上面的按钮的背景是自定义的颜色选择器

在drawable文件夹下的back.xml文件


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/colorPrimary" android:state_selected="false" />
    <item android:drawable="@color/colorAccent" android:state_selected="true" />
selector>

上面的颜色资源也是系统提供的,也可以使用自己定义的。

(三)第一个碎片类

package fuxi.viewpager2;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * 这是个人旅游页面的碎片布局
 */

public class TourFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载系统里面的布局文件
        TextView view = (TextView) View.inflate(getActivity(), android.R.layout.simple_list_item_1, null);
        view.setText("这是个人旅游页面的碎片布局");
        view.setBackgroundColor(Color.YELLOW);
        return view;
    }

}

(四)第二个碎片类

package fuxi.viewpager2;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 *  这是景点售票页面的碎片布局
 */

public class TickerFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载系统里面的布局文件
        TextView view = (TextView) View.inflate(getActivity(), android.R.layout.simple_list_item_1, null);
        view.setText("这是景点售票页面的碎片布局");
        view.setBackgroundColor(Color.GREEN);
        return view;
    }

}

(五)主方法的类

package fuxi.viewpager2;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RadioGroup;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener, ViewPager.OnPageChangeListener {

    //定义布局内的控件
    RadioGroup rg;
    View vi;//自定义的指示器
    ViewPager vp;

    //数据源的集合
    List list = new ArrayList<>();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //加载数据
        list.add(new TourFragment());
        list.add(new TickerFragment());
        setContentView(R.layout.activity_main);
        initView();

    }

    /**
     * 初始化布局
     */
    private void initView() {
        //实例化控件
        rg = (RadioGroup) findViewById(R.id.home_rg);
        vp = (ViewPager) findViewById(R.id.home_vp);
        vi = findViewById(R.id.home_fl_view);
        //创建适配器,设置的碎片管理器使用的是getChildFragmentManager()
        FragmentStatePagerAdapter adapter = new Myadapter(getSupportFragmentManager());
        //给ViewPager设置适配器
        vp.setAdapter(adapter);
        //给控件设置监听事件
        rg.setOnCheckedChangeListener(this);
        //给ViewPager设置监听器使用的是add而不是set了
        vp.addOnPageChangeListener(this);
        initVi();

    }


    //屏幕一半的宽度
    int width;

    //把下划线View设置初始值
    private void initVi() {
        width = getResources().getDisplayMetrics().widthPixels / 2;
        //设置下划线View的长度
        FrameLayout.LayoutParams par = new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.MATCH_PARENT);
        vi.setLayoutParams(par);

    }


    //单选按钮点击后触发的回调方法
    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        //点击后选择对应的ViewPager页面
        vp.setCurrentItem(checkedId == R.id.home_rb_dujia ? 0 : 1);
    }

    //屏幕滑动的回调方法,设置指示器
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        //"页面:" + position + "
        // offset偏移百分比" + positionOffset
        // pix像素" + positionOffsetPixels
        //设置下划线的属性
        //设置下划线View的长度
        FrameLayout.LayoutParams par = (FrameLayout.LayoutParams) vi.getLayoutParams();
        //设置下划线距离左边的位置长度
        int left = (int) ((positionOffset + position) * width);
        par.setMargins(left, 0, 0, 0);
        vi.setLayoutParams(par);
    }

    //屏幕被选择的回调方法
    @Override
    public void onPageSelected(int position) {
        //选择页面后设置单选按钮的选择
        rg.check(position == 0 ? R.id.home_rb_dujia : R.id.home_rb_ticker);
    }

    //滑动页面状态的改变,这个方法不用理会
    //如果要实现自动轮播可以重写
    @Override
    public void onPageScrollStateChanged(int state) {

    }

    //创建ViewPager适配器的类
    class Myadapter extends FragmentStatePagerAdapter {

        public Myadapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return list.get(position);
        }

        @Override
        public int getCount() {
            return list.size();
        }
    }

}

        可以看到这里没有使用事务,就可以实现页面的隐藏和显示,这些都是ViewPager在底层已经做好的事情了。
        本示例中也设计了指示器的效果,就是按钮下面那条横线,设计的方法也是有三种的,一个是使用PagerTitleStrip,一个是使用PagerTabStrip,另一个就是使用自定义的指示器。当然这三种只是简单的指示器的设计,如果想要特殊效果的指示器还是有很多方法的。指示器的使用另作总结。
        个人觉得使用自定义的指示器还是比较方便的,而且代码是固定的,如果不理解也没关系,复制使用就可以了。另外两种指示器是比较另类的,还有其他指示器的设计方法是比较麻烦的。

六.Fragment和ViewPager结合使用的例子

        程序设计外层的页面是五个Fragment页面,不能滑动,只能点击切换,但是其中一个Fragment页面有ViewPager页面,可以实现滑动页面。
程序运行效果:
Android滑动页面ViewPager的详细总结_第6张图片

点击下面的按钮可以实现Fragment界面的切换,这里设计中间一个Fragment是一个ViewPager页面,可以左右滑动选择页面。
Android滑动页面ViewPager的详细总结_第7张图片
这个页面和上面一个示例是相似的。但是这里是碎片中的碎片!
可以看到这里每一个按钮都做了选择器。并且中间碎片页面也是有个指示器的。

下面是代码设计:

(一)布局文件

1.activity_main.xml布局文件


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.exam.framework.MainActivity">

    <RadioGroup
        android:id="@+id/main_rg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/main_rb0"
            style="@style/MyRadioStyle"
            android:drawableTop="@drawable/favor"
            android:tag="0"
            android:text="收藏" />

        <RadioButton
            android:id="@+id/main_rb1"
            style="@style/MyRadioStyle"
            android:drawableTop="@drawable/order"
            android:tag="1"
            android:text="订单" />

        <RadioButton
            android:id="@+id/main_rb2"
            style="@style/MyRadioStyle"
            android:drawableTop="@drawable/home"
            android:tag="2"
            android:text="主页" />

        <RadioButton
            android:id="@+id/main_rb3"
            style="@style/MyRadioStyle"
            android:drawableTop="@drawable/uc"
            android:singleLine="true"
            android:tag="3"
            android:text="个人中心" />

        <RadioButton
            android:id="@+id/main_rb4"
            style="@style/MyRadioStyle"
            android:drawableTop="@drawable/setting"
            android:tag="4"
            android:text="设置" />

    RadioGroup>

    <FrameLayout
        android:id="@+id/main_fl"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/main_rg">FrameLayout>

RelativeLayout>

这里动态显示隐藏Fragment要先添加FrameLayout布局容器。

2.中间页面显示可滑动页面的布局文件activity_frag_home.xml


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

    <RadioGroup
        android:id="@+id/home_rg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/home_rb_dujia"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/back"
            android:button="@null"
            android:gravity="center"
            android:padding="10dp"
            android:text="旅游度假" />

        <RadioButton
            android:id="@+id/home_rb_ticker"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/back"
            android:button="@null"
            android:gravity="center"
            android:padding="10dp"
            android:text="景点门票" />

    RadioGroup>
    
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="5dp">

        <View
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#4e6bd4" />

        <View
            android:id="@+id/home_fl_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#16308c" />
    FrameLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/home_vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

LinearLayout>

这里也是动态加载Fragment但是使用的是ViewPager。并且这里有自定义的指示器。

(二)资源文件

上面有用到比较多的资源文件

1.第一个按钮的选择器

drawable–》favor.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/icon_favor_normal" android:state_checked="false" />
    <item android:drawable="@mipmap/icon_favor_press" android:state_checked="true" />
selector>

2.第一个按钮的选择器

drawable–》order.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/icon_order_normal" android:state_checked="false" />
    <item android:drawable="@mipmap/icon_order_press" android:state_checked="true" />
selector>

3.第一个按钮的选择器

drawable–》home.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/icon_home_normal" android:state_checked="false" />
    <item android:drawable="@mipmap/icon_home_press" android:state_checked="true" />
selector>

4.第一个按钮的选择器

drawable–》uc.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/icon_uc_normal" android:state_checked="false" />
    <item android:drawable="@mipmap/icon_uc_press" android:state_checked="true" />
selector>

5.第一个按钮的选择器

drawable–》setting.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/icon_setting_normal" android:state_checked="false" />
    <item android:drawable="@mipmap/icon_setting_press" android:state_checked="true" />
selector>

6.中间页面两个按钮的背景选择器

drawable–》back.xml


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/color_back" android:state_selected="false" />
    <item android:drawable="@color/color_backnor" android:state_selected="true" />
selector>

7.上面按钮背景还有两个颜色资源文件

Values——》colors.xml


<resources>
    <color name="colorPrimary">#3F51B5color>
    <color name="colorPrimaryDark">#303F9Fcolor>
    <color name="colorAccent">#FF4081color>
    <color name="color_back">#207579color>
    <color name="color_backnor">#7fdcd9color>
resources>

上面颜色资源中最下面俩个是自己添加的,上面的几个是系统有的。

(三)第一个碎片的java代码:

package com.exam.framework;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;



public class FavorFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载系统里面的布局文件
        TextView view = (TextView) View.inflate(getActivity(), android.R.layout.simple_list_item_1, null);
        view.setText("这是收藏页面");
        view.setBackgroundColor(Color.RED);
        return view;
    }
}

除了中间的Fragment的java代码是复杂一点的,其他的都是简单数据的显示。

(四)第二个Fragment页面的java代码:

package com.exam.framework;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;



public class OrderFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载系统里面的布局文件
        TextView view = (TextView) View.inflate(getActivity(), android.R.layout.simple_list_item_1, null);
        view.setText("这是订单页面的碎片布局");
        view.setBackgroundColor(Color.GREEN);
        return view;
    }

}

(五)第三个Fragment页面的java代码:

这个页面的代码和上面一个示例的代码几乎一样。

package com.exam.framework;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RadioGroup;

import java.util.ArrayList;
import java.util.List;



public class HomeFragment extends Fragment implements RadioGroup.OnCheckedChangeListener, ViewPager.OnPageChangeListener {

    //定义布局内的控件
    RadioGroup rg;
    View vi;
    ViewPager vp;

    //数据源的集合
    List list = new ArrayList<>();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //加载数据
        list.add(new TourFragment());
        list.add(new TickerFragment());
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载自己编写的布局文件
        return View.inflate(getActivity(), R.layout.activity_frag_home, null);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        //实例化控件
        rg = (RadioGroup) view.findViewById(R.id.home_rg);
        vp = (ViewPager) view.findViewById(R.id.home_vp);
        vi = view.findViewById(R.id.home_fl_view);
        //创建适配器,设置的碎片管理器使用的是getChildFragmentManager()
        FragmentStatePagerAdapter adapter = new Myadapter(getChildFragmentManager());
        //给ViewPager设置适配器
        vp.setAdapter(adapter);
        //给控件设置监听事件
        rg.setOnCheckedChangeListener(this);
        //给ViewPager设置监听器使用的是add而不是set了
        vp.addOnPageChangeListener(this);
        initVi();
    }

    //屏幕一般的宽度
    int width;

    //把下划线View设置初始值
    private void initVi() {
        width = getResources().getDisplayMetrics().widthPixels / 2;
        //设置下划线View的长度
        FrameLayout.LayoutParams par = new FrameLayout.LayoutParams(width, ViewGroup.LayoutParams.MATCH_PARENT);
        vi.setLayoutParams(par);

    }


    //单选按钮点击后触发的回调方法
    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        //点击后选择对应的ViewPager页面
        vp.setCurrentItem(checkedId == R.id.home_rb_dujia ? 0 : 1);
    }

    //屏幕滑动的回调方法
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        //"页面:" + position + "
        // offset偏移百分比" + positionOffset
        // pix像素" + positionOffsetPixels
        //设置下划线的属性
        //设置下划线View的长度
        FrameLayout.LayoutParams par = (FrameLayout.LayoutParams) vi.getLayoutParams();
        //设置下划线距离左边的位置长度
        int left = (int) ((positionOffset + position) * width);
        par.setMargins(left, 0, 0, 0);
        vi.setLayoutParams(par);
    }

    //屏幕被选择的回调方法
    @Override
    public void onPageSelected(int position) {
        //选择页面后设置单选按钮的选择
        rg.check(position == 0 ? R.id.home_rb_dujia : R.id.home_rb_ticker);
    }

    //这个方法不用理会
    @Override
    public void onPageScrollStateChanged(int state) {

    }

    //创建ViewPager适配器的类
    class Myadapter extends FragmentStatePagerAdapter {

        public Myadapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return list.get(position);
        }

        @Override
        public int getCount() {
            return list.size();
        }
    }


}

(六)第三个碎片页面的第一个碎片页面的java代码:

package com.exam.framework;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;



public class TourFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载系统里面的布局文件
        TextView view = (TextView) View.inflate(getActivity(), android.R.layout.simple_list_item_1, null);
        view.setText("这是个人旅游页面的碎片布局");
        view.setBackgroundColor(Color.YELLOW);
        return view;
    }

}

(七)第三个碎片页面的第二个碎片页面的java代码:

package com.exam.framework;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;



public class TickerFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载系统里面的布局文件
        TextView view = (TextView) View.inflate(getActivity(), android.R.layout.simple_list_item_1, null);
        view.setText("这是景点售票页面的碎片布局");
        view.setBackgroundColor(Color.BLUE);
        return view;
    }

}

(八)第四个Fragment页面的java代码:

package com.exam.framework;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;



public class UCFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载系统里面的布局文件
        TextView view = (TextView) View.inflate(getActivity(), android.R.layout.simple_list_item_1, null);
        view.setText("这是个人中心页面的碎片布局");
        view.setBackgroundColor(Color.YELLOW);
        return view;
    }

}

(九)第五个Fragment页面的java代码:

package com.exam.framework;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;



public class SettingFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载系统里面的布局文件
        TextView view = (TextView) View.inflate(getActivity(), android.R.layout.simple_list_item_1, null);
        view.setText("这是设置页面的碎片布局");
        view.setTextColor(Color.argb(1,6,0,0));
        view.setBackgroundColor(Color.BLACK);
        return view;
    }

}

(十)第主页面的java代码:

这个代码也是要重点理解的。
package com.exam.framework;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.RadioGroup;

public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {

    //定义布局内的RadioGroup控件
    RadioGroup rg;
    //定义Fragment数组存放Fragment对象
    Fragment[] fragments = new Fragment[5];
    //之前选中的页面游标值
    int beforeIndex = -1;

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


    }

    //初始化数据
    private void initView() {
        //实例化RadioGroup
        rg = (RadioGroup) findViewById(R.id.main_rg);
        //为控件设置监听事件
        rg.setOnCheckedChangeListener(this);
        //默认显示主页面的碎片
        rg.check(R.id.main_rb2);
        // showFragment(2);
    }

    //点击对应的按钮后触发的事件
    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        //checkedId是布局文件里面的ID,比如:R.id.main_rb2
        View view = rg.findViewById(checkedId);
        String tag = view.getTag().toString();//获得对应视图的Tag字符串
        //显示对应的碎片
        showFragment(Integer.parseInt(tag));
        // Toast.makeText(this, "选择:" + tag, Toast.LENGTH_SHORT).show();
    }

    //显示碎片的方法
    private void showFragment(int index) {
        Log.e("TAG", "index=" + index);
        //如果点击的是前显示的页面,直接返回去
        if (beforeIndex == index) {
            return;
        }

        //对碎片继续各种操作,这里需要用到事务来完成
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        //隐藏上一次显示的碎片
        if (beforeIndex != -1) {
            ft.hide(fragments[beforeIndex]);
        }
        //如果要出现的碎片页面没有创建过,就要创建;否则显示出来就可以了
        if (fragments[index] == null) {
            //创建碎片(实例化)
            fragments[index] = FragmentUtil.CreateFragment(index);
            //把创建的布局添加到事务里面
            //第一个参数是存放碎片的位置
            //第二个参数是碎片的对象
            ft.add(R.id.main_fl, fragments[index]);
        } else {
            //如不是空的对象就直接显示出来就可以了
            ft.show(fragments[index]);
        }
        //提交事务
        ft.commit();
        //把当前的选择保存
        beforeIndex = index;


    }
}

程序运行的界面上面已经有了,这里就不演示了。

      由于文中用到的资源文件比较多,图片也是比较多,有些人可能不熟悉,这里提供项目源码文件的下载:
地址:http://download.csdn.net/detail/wenzhi20102321/9708875
      在程序开发中,碎片中有碎片,并且外面不能滑动,里面能滑动,或者外面的能滑动,而里面不能滑动都是有这样的需求的。

七.最后对Fragment和ViewPager做一个总结:

(一)Fragment

       Fragment是碎片的意思,其中可以显示碎片的方法有三种,一种是静态显示碎片使用标签fragment,另一个是使用动态显示碎片,要使用FrameLayout布局容器,还有一种是使用ViewPager来显示Fragment。
      但是无论使用哪一种,都是要写自定义的类来继承Fragment。
      并且要注意的是一般使用Fragment都是使用v4包下的,Activity对应的也是要v4包下,否则会报错。在AndroidStudio中是自动加载的,而Eclipse中要自己手动加载。

(二)ViewPager

      ViewPager的使用也是比较频繁的,比如引导页面,某些局部的广告页面,轮播的实现,都是我们要去掌握的知识。
      ViewPager的显示都是要使用Adapter的,如果是显示简单的图片的适配器使用的是:PagerAdapter,如果显示的是Fragment页面,使用的适配器是:FragmentStatePagerAdapter。

      ViewPager和Fragment结合使用在很多App程序中是非常常见和使用的。也是要我们去熟练掌握的一个UI设计形式。
      关于Fragment详细总结的知识我之前有一篇文章:
http://blog.csdn.net/wenzhi20102321/article/details/53572610

你可能感兴趣的:(android,Fragment,UI)