Android开发 - ViewPager和ViewFlipper控件的使用 - 实现图片内容轮播(无限滚动、自动滚动和显示小白点)

文章目录

    • ViewPager
      • 简单demo - 手动滑动
      • 添加动画
      • 设置监听
      • 无限滚动
      • 自动滚动
      • 小白点
      • 手势或者触摸监听
        • 触摸监听事件
        • 手势监听事件
      • 点击事件
    • ViewFlipper
      • 简单demo
      • 动画
      • 事件监听

突发奇想,想到了APP上的图片轮播的功能,感觉很实用啊,就查了一下,然后学一学玩一玩。
不仅可以用于App首页的图片内容轮播,还可以用于启动页的滑动介绍等等。

ViewPager

ViewPager是Android扩展包v4包中的一个类,允许用户左右滑动切换显示不同的view。类似RecyclerView,需要一个PagerAdapter适配器提供显示的数据,通常可以和Fragment一起使用,即碎片,且专门提供了FragmentPagerAdapter和FragmentStatePagerAdapter类给Fragment使用。

简单demo - 手动滑动

通过一个简单demo看看具体是怎么使用的。
首先修改activity_main.xml,添加一个ViewPager控件。

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

创建布局文件viewpager_item.xml,由于只是一个简单demo,因此只需要一个TextView控件即可。


<TextView android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/ViewContent"
    android:layout_gravity="center"
    android:gravity="center"
    android:text="ss"
    xmlns:android="http://schemas.android.com/apk/res/android" />

创建适配器类MyViewPagerAdapter,这个适配器也比较简单,主要就是instantiateItem()方法,在这里面对View子项的内容进行设置,我这里是先加载布局,然后获取TextView控件,设置文字然后add到container中,返回view即可。

public class MyPagerAdapter extends PagerAdapter {
    private Context MyContext;
    private  List<String> MyTextList;
    public MyPagerAdapter(Context context,List<String> TextList){
        this.MyContext=context;
        this.MyTextList=TextList;
    }
    @Override
    public int getCount() {
        return MyTextList.size();
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View)object);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view=View.inflate(MyContext,R.layout.viewpager_item,null);
        TextView ViewContentTextView=view.findViewById(R.id.ViewContent);
        ViewContentTextView.setText(MyTextList.get(position));
        container.addView(view);
        return view;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }
}

最后修改MainActivity.java中的onCreate()方法,就是获取ViewPager实例,然后实例化适配器传入桉树,设置适配器即可。

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

        List<String> m= new ArrayList<>();
        for (int i=0;i<5;i++){
            m.add("第  "+i+"   个view");
        }
        ViewPager MyViewPager=findViewById(R.id.ShowView);
        MyViewPager.setAdapter(new MyPagerAdapter(this,m));
    }

之后运行程序,滑动屏幕可以发现内容改变了
Android开发 - ViewPager和ViewFlipper控件的使用 - 实现图片内容轮播(无限滚动、自动滚动和显示小白点)_第1张图片
Android开发 - ViewPager和ViewFlipper控件的使用 - 实现图片内容轮播(无限滚动、自动滚动和显示小白点)_第2张图片

添加动画

新建MyPagerTransformer继承PagerTransformer类

public class MyPagerTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;
    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();
        // [-Infinity,-1)
        if (position < -1) {
            // This page is way off-screen to the left.
            view.setAlpha(0);
        }
        // [-1,0]
        else if (position <= 0) {
            // Use the default slide transition when moving to the left page
            view.setAlpha(1);
            view.setTranslationX(0);
            view.setScaleX(1);
            view.setScaleY(1);
        }
        // (0,1]
        else if (position <= 1) {
            // Fade the page out.
            view.setAlpha(1 - position);
            // Counteract the default slide transition
            view.setTranslationX(pageWidth * -position);
            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
        }
        // (1,+Infinity]
        else {
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}

在MainActivity.java中设置一下,加一行就行了

MyViewPager.setPageTransformer(false,new MyPagerTransformer());

运行程序后可以看到动画效果了,淡入淡出的动画效果。
这个动画好像有些开源框架提供好多种动画效果。

设置监听

调用SetOnPageChangeListener()方法设置监听,但是我的as显示这个方法已经过时了,改成addOnPageChangeListener即可,可以监听滑动的整个过程、滑动的每个状态以及改变的是哪个Page。
新建一个自定义过滤器就可以更方便地看到日志输出。

MyViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                Log.d("ViewPagerListener", "滑动中   position:" + position + "   positionOffset:" + positionOffset + "   positionOffsetPixels:" + positionOffsetPixels);
            }

            @Override
            public void onPageSelected(int position) {
                Log.d("ViewPagerListener","改变了   "+position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                switch (state) {
                    case ViewPager.SCROLL_STATE_IDLE:
                        Log.d("ViewPagerListener", "静止中");
                        break;
                    case ViewPager.SCROLL_STATE_DRAGGING:
                        Log.d("ViewPagerListener", "滑动中");
                        break;
                    case ViewPager.SCROLL_STATE_SETTLING:
                        Log.d("ViewPagerListener", "结束");
                        break;
                }
            }
        });

Android开发 - ViewPager和ViewFlipper控件的使用 - 实现图片内容轮播(无限滚动、自动滚动和显示小白点)_第3张图片

无限滚动

假设当前有3个View,无限滚动即在两边各添加一个View,比如原有123,在左右添加一个View,当滑到最左边的时候,切换到3,滑到最右边的时候,切换到position=0的view,就实现无限滚动了。
因为是切换view成功后才会切换到第一个或最后一个view,因此最好在左侧添加最后一个view,右侧添加第一个view,这样可以在视觉上有更好的效果。
即view3 - view1 - view2 - view3 - view1

...
if (position==4)
                    MyViewPager.setCurrentItem(1,false);
...
if (position==0)
                    MyViewPager.setCurrentItem(3,false);
...

自动滚动

自动滚动的逻辑大概是如下两条

  • 手动滑动开始的时候,自动滚动暂停
  • 手动滑动暂停的时候,自动滚动开始

这里我使用的是Handler处理定时任务,在MainActivity.java中编写内部类ViewPagerTimer类,继承自Runnable类,其逻辑主要就是获取当前view编号,延迟一定时间,然后切换到下一个view。
调用Handler的postDelayed()方法进行延迟,时间单位是毫秒。
要记得在MainActivity.java中的onDestroy()方法中设置ViewPagerTimerHandler=null

Handler ViewPagerTimerHandler;
int DelayTime=2000;
ViewPagerTimerHandler=new Handler();
ViewPagerTimerHandler.postDelayed(new ViewPagerTimer(),DelayTime);
//滚动定时器
class ViewPagerTimer implements Runnable{
	public ViewPagerTimer(){
    }
    @Override
    public void run() {
        int CurrentViewPager=MyViewPager.getCurrentItem();
        MyViewPager.setCurrentItem(CurrentViewPager+1);
        if (ViewPagerTimerHandler!=null){
            ViewPagerTimerHandler.postDelayed(this,DelayTime);
		}
	}
}

没解决的问题
这里我还没想到怎么监听手动滚动的时候暂停自动滚动,而且动画滚动时间有点快,似乎也是可以设置的。

小白点

小白点的话,主要就是在ViewPager控件下面放置一个LinearLayout,在这个布局中添加小圆点,用View创建小圆点,形状和颜色通过background背景设置。
在activity_main.xml中添加一个LinearLayout用于放置小白点,如果真用了可以把这两个控件放在一个LinearLayout中,就方便使用了。


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.k.androidpractie.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/ShowView"
        android:layout_width="match_parent"
        android:background="@color/burlywood"
        android:layout_height="60dp">android.support.v4.view.ViewPager>
    <LinearLayout
        android:id="@+id/WhitePoints"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignBottom="@+id/ShowView">
    LinearLayout>

RelativeLayout>

编写Background文件,这里用到了三个文件,一个是selector文件,其余两个是item,均位于drawable文件夹中。
selector是存放在drawable文件夹中 用来设置控件背景和字体颜色的。通过android:background属性设置selector,可以对控件的一些属性进行设置。我觉得其实有点类似WPF的触发器,满足相应条件就会应用相应属性
android:state_enabled属性值为true或者false,若控件设置view.setEnabled(true),则会使用@drawable/white的属性,设置view.setEnabled(false),则会使用@drawable/gray的属性。

filename:whitepoint_background.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/white" android:state_enabled="true" />
    <item android:drawable="@drawable/gray" android:state_enabled="false" />
selector>

filename:white.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    
    <solid android:color="#FF3030" />
    
    <corners android:radius="10dp" />
shape>

filename:gray.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    
    <solid android:color="@android:color/darker_gray" />
    
    <corners android:radius="10dp" />
shape>

在MainActivity.java中编写getWhitePoint()方法,在onCreate()方法中初始化的时候调用就好了。
在getWhitePoint()中,由于我有五个view,因此需要五个白点,这里的白点直接使用View,然后设置background背景,先给所有的View设为false,通过LinearLayout.LayoutParams设置控件的参数属性,如果不是第一个点,则设左边距为30,然后调用addView()方法添加到我的小白点布局WhitePointLinearLayout中。

LinearLayout WhitePontLinearLayout;
protected void onCreate(Bundle savedInstanceState) {
...
	WhitePontLinearLayout=findViewById(R.id.WhitePoints);
	getWhitePoint();
...
}
private void getWhitePoint(){
        View view;
        for (int i=0;i<5;i++){
            view=new View(this);
            view.setBackgroundResource(R.drawable.whitepoint_background);
            view.setEnabled(false);
            LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(30,30);
            if (i!=0)
                params.leftMargin=30;
            WhitePontLinearLayout.addView(view,params);
        }
        WhitePontLinearLayout.getChildAt(0).setEnabled(true);
    }

然后运行程序,就可以看到底下的小白点的,点的大小和颜色都可以在background的item那几个xml中自己设置。
Android开发 - ViewPager和ViewFlipper控件的使用 - 实现图片内容轮播(无限滚动、自动滚动和显示小白点)_第4张图片

手势或者触摸监听

触摸监听事件

通过继承OnTouchListener接口,实现onTouch()方法,这个方法中可以获取到手指滑动的坐标,处理开始和停止时的坐标,通过对坐标的处理,可以判断出是往什么方向滑动,响应相应的操作,比如左滑或者右滑。

手势监听事件

可以通过OnGestureListener实现,但是需要实现很多的方法。
另一个方法,继承GestureDetector.SimpleOnGestureListener类,实现onFling()方法,获取手指按下和松开的坐标,判断滑动状态,进行相应操作。

点击事件

这里的点击事件就是点击轮播的时候响应的事件,比如跳转之类的,比较简单,主要就是给View设置点击监听,我是在适配器中给View设置的监听。
由于我们使用了无限滚动,因此左右会各多出一个view,要搞清楚每个view和对应的position。

filename:MyPagerAdapter.java
...
public Object instantiateItem(ViewGroup container, final int position) {
        View view=View.inflate(MyContext,R.layout.viewpager_item,null);
        TextView ViewContentTextView=view.findViewById(R.id.ViewContent);
        final String Content=MyTextList.get(position);
        ViewContentTextView.setText(Content);
        container.addView(view);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MyContext,"this is view :"+MyTextList.get(position-1>0?position-1:0),Toast.LENGTH_SHORT).show();
            }
        });
        return view;
    }
...

运行程序后,点击轮播内容,会弹出Toast,显示当前轮播TextView的文字。
如果是轮播的图片的话,可以直接对ImageView设置监听事件。

ViewFlipper

这个控件可以很好的实现类似垂直滚动广告条的功能。

简单demo

在activity_main.xml中编写一个布局,就只有一个控件


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.k.androidpractie.MainActivity">
    <ViewFlipper
        android:id="@+id/ViewShow"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">ViewFlipper>
RelativeLayout>

编写子项布局viewflipper_item.xml,水平布局,左边一个ImageView,右边一个TextView,垂直滚动。


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/ViewShowImage"/>
    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:id="@+id/ViewShowText"
        android:layout_weight="1"
        android:gravity="center"
        android:textSize="25dp"/>
LinearLayout>

在MainActivity.java中设置显示的内容。调用setFlipInterval()设置滚动的时间间隔,调用startFlipping()方法启动。

public class MainActivity extends AppCompatActivity {
    ViewFlipper MyViewFlipper;
    ImageView TempImageView;
    TextView TempTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyViewFlipper=findViewById(R.id.ViewShow);
        for (int i=0;i<3;i++){
            View view= LayoutInflater.from(this).inflate(R.layout.viewflipper_item,null);
            TempImageView=view.findViewById(R.id.ViewShowImage);
            TempTextView=view.findViewById(R.id.ViewShowText);
            TempImageView.setImageResource(R.drawable.diamond);
            TempTextView.setText("abcdefgh  "+i);
            MyViewFlipper.addView(view);
        }
        MyViewFlipper.setFlipInterval(1000);
        MyViewFlipper.startFlipping();
    }
}

运行程序,可以看到
Android开发 - ViewPager和ViewFlipper控件的使用 - 实现图片内容轮播(无限滚动、自动滚动和显示小白点)_第5张图片
此时的效果和ViewPager控件的无动画效果差不多。

动画

在res文件夹中new一个安卓资源文件夹
右键res -> New -> Android resource directory -> anim
动画效果通过set标签设置,这个xml文件只能放在anim这种文件夹,不能放到drawable之类的文件夹。

  • in.xml:入动画Y轴位置从下100%移动到位置0,持续1s
  • out.xml:出动画从位置0移动到-100%位置,持续1s

此时需要将setFlipInterval(1000);参数改为setFlipInterval(2000);,如果是1000的话太快了重叠了,有兴趣可以自己试试。

filename:in.xml

<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000">
    
    <translate android:fromYDelta="100%p"  android:toYDelta="0"/>
set>

filename:out.xml

<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000">
    <translate android:fromYDelta="0" android:toYDelta="-100%p" />

set>

最后修改一下ViewFlipper控件,将这两个出入动画写到属性里面

<ViewFlipper
        android:id="@+id/ViewShow"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inAnimation="@anim/in"
        android:outAnimation="@anim/out">ViewFlipper>

我不会截gif,找一个间隙接涂,可以看到垂直滚动很顺滑。修改动画xml,Y改成X应该能实现水平动画。
Android开发 - ViewPager和ViewFlipper控件的使用 - 实现图片内容轮播(无限滚动、自动滚动和显示小白点)_第6张图片

事件监听

添加点击事件的话,只需要在MainActivity.java中对view设置OnClockListener鼠标点击监听即可。

你可能感兴趣的:(Android)