ViewSwitcher的功能与用法

ViewSwitcher表明了视图切换组件,它自己继承了FramLayout,所以能够将多个View层叠在一块儿,每次只显示一个组件。当程序控制从一个View切换到另外一个View时,ViewSwitcher支持指定动画效果。android

为了给ViewSwitcher添加多个组件,通常经过调用ViewSwitcher的setFactory(ViewSwitcher.ViewFactory)方法为之设置ViewFactory,并由该ViewFactory为之建立View便可。app

实例:仿Android系统的Launcher界面ide

Android早期版本的Launcher界面是上下滚动的,新版Android的Launcher界面已经实现了分屏、左右滚动,本例就是经过ViewSwitcher来实现Android的分屏、左右滚动效果。布局

为了实现该效果,程序主界面考虑使用ViewSwitcher来组合多个GridView,每一个GridView表明一个屏幕应用程序,GridView中每一个单元格显示一个应用程序的图标和程序名。学习

布局文件以下动画

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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=".MainActivity">
    <!--定义一个ViewSwitcher组件-->
    <ViewSwitcher android:id="@+id/viewSwitcher" android:layout_width="match_parent" android:layout_height="match_parent"/>
    <!--定义滚动到上一屏的按钮-->
    <Button android:id="@+id/button_prev" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginBottom="8dp" android:onClick="prev" android:text="&lt;" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"/>
    <!--定义滚动到下一屏的按钮-->
    <Button android:id="@+id/button_next" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginBottom="8dp" android:onClick="next" android:text="&gt;" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"/>
</android.support.constraint.ConstraintLayout>

上面的界面布局文件中定义了一个ViewSwitcher组件和两个按钮,这两个按钮分别用于控制该ViewSwitcher显示上一屏和下一屏的程序列表。this

该实例的重点在于为该ViewSwitcher设置ViewFactory对象,而且当用户单击“<”和“>”两个按钮时控制ViewSwitcher显示上一屏和下一屏的应用程序。spa

该程序会考虑使用扩展BaseAdapter的方式为GridView提供Adapter,而本实例的关键就是根据用户单击的按钮来动态计算该BaseAdapter应该显示哪些程序列表。该程序的Activity代码以下。code

public class MainActivity extends AppCompatActivity { //定义一个常量,用于显示没屏显示的应用程序数
    public static final int NUMBER_PER_SCREEN = 12; //保存系统全部应用程序的List集合
    private List<DataItem> items = new ArrayList<>(); //记录当前正在显示第几屏的程序
    private int screenNo = -1; //保存程序所占的总屏数
    private int screenCount = 0; private ViewSwitcher switcher; //建立LayoutInflater对象
    private LayoutInflater inflater; //该BaseAdapter负责为每屏显示的GridView提供列表项

    private BaseAdapter adapter = new BaseAdapter() { @Override public int getCount() { //若是已经到了最后一屏,且因应用程序的数量不能整除NUMBER_PER_SCREEN
            if (screenNo == screenCount - 1 && items.size() % NUMBER_PER_SCREEN != 0) { //最后一屏显示的程序数为应用程序的数量对NUMBER_PER_SCREEN求余
                return items.size() % NUMBER_PER_SCREEN; //不然每屏显示的程序数为NUMBER_PER_SCREEN
            } else { return NUMBER_PER_SCREEN; } } @Override public DataItem getItem(int position) { //根据screenNo计算第position个列表项的数据
            return items.get(screenNo * NUMBER_PER_SCREEN + position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; ViewHolder viewHolder; if (convertView == null) { //加载R.layout.labelicon布局组件
                view = inflater.inflate(R.layout.labelicon, null); ImageView imageView = view.findViewById(R.id.imageview); TextView textView = view.findViewById(R.id.textview); viewHolder = new ViewHolder(imageView, textView); view.setTag(viewHolder); } else { view = convertView; viewHolder = (ViewHolder)view.getTag(); } //获取R.layout.labelicon布局文件中的ImageView组件,并为之设置图标
 viewHolder.imageView.setImageDrawable(getItem(position).drawable); //获取R.layout.labelicon布局文件中的TextView组件,并为之设置文本
 viewHolder.textView.setText(getItem(position).dataName); return view; } }; //表明应用程序的内部类
    public static class DataItem { //应用程序名称
 String dataName; //应用程序图标
 Drawable drawable; DataItem(String dataName, Drawable drawable) { this.dataName = dataName; this.drawable = drawable; } } //表明应用程序的内部类
    public static class ViewHolder { ImageView imageView; TextView textView; ViewHolder(ImageView imageView, TextView textView) { this.imageView = imageView; this.textView = textView; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); inflater = LayoutInflater.from(this); //建立一个包含40个元素的List集合,用于模拟包含40个应用程序
        for (int i = 0; i < 40; i++) { String label = "" + i; Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher, null); DataItem item = new DataItem(label, drawable); items.add(item); } //计算应用程序所占的总屏数 //若是应用程序的数量能整除NUMBER_PER_SCREEN,除法的结果就是总屏数 //若是不能整除,总屏数应该是除法的结果再加1
        screenCount = items.size() % NUMBER_PER_SCREEN == 0 ? items.size() / NUMBER_PER_SCREEN : items.size() / NUMBER_PER_SCREEN + 1; switcher = findViewById(R.id.viewSwitcher); switcher.setFactory(() -> { //加载R.layout.slidelistview组件,实际上就是一个GridView组件
            return inflater.inflate(R.layout.slidelistview, null); }); //页面加载时先显示第一屏
        next(null); } public void next (View v) { if (screenNo < screenCount - 1) { screenNo++; //为ViewSwitcher的组件显示过程设置动画
            switcher.setInAnimation(this, R.anim.slide_in_right); //为ViewSwitcher的组件隐藏过程设置动画
            switcher.setOutAnimation(this, R.anim.slide_out_left); //控制下一屏将要显示的GridView对应的Adapter
 ((GridView) switcher.getNextView()).setAdapter(adapter); //点击右边按钮,显示下一屏 //学习手势检测后,也可经过手势检查实现显示下一屏
 switcher.showNext(); } } public void prev(View v) { if (screenNo > 0) { screenNo--; //为ViewSwitcher的组件显示过程设置动画
            switcher.setInAnimation(this, R.anim.slide_in_right); //为ViewSwitcher的组件隐藏过程设置动画
            switcher.setOutAnimation(this, R.anim.slide_out_left); //控制下一屏将要显示的GridView对应的Adapter
 ((GridView) switcher.getNextView()).setAdapter(adapter); //点击右边按钮,显示下一屏 //学习手势检测后,也可经过手势检查实现显示下一屏
 switcher.showPrevious(); } } }

上面的程序使用screenNo保存当前正在显示第几屏的程序列表。该程序的关键在于粗体字代码部分,该粗体字代码建立了一个BaseAdpater对象,这个BaseAdpater会根据screenNo动态计算该Adapter总共包含多少个列表项(如getCount()方法所示),会根据screenNo计算每一个列表项的数据(如getItem(int position)方法所示)。xml

BaseAdpater的getView()只是简单加载了R.layout.labelicon布局文件,并使用当前列表项的图片数据填充R.layout.labelico布局文件中的ImageView,使用当前列表项的文本数据填充R.layout.labelicon布局文件中的TextView。下面是R.layout.labelicon的代码。

<?xml version="1.0" encoding="utf-8"?>
<!-- 定义一个垂直的LinearLayout,该容器中放置一个ImageView和一个TextView -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:gravity="center" android:orientation="vertical">

    <ImageView android:id="@+id/imageview" android:layout_width="wrap_content" android:layout_height="wrap_content" />

    <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" />
</LinearLayout>

当用户点击“>”按钮时,程序的事件处理方法将会控制viewSwitcher调用showNext()方法显示下一屏的程序列表,并且此时screenNo被加1,于是Adapter将会动态计算下一屏的程序列表,再将该Adapter传给ViewSwitcher接下来要显示的GridView。

为了实现ViewSwitcher切换View时的动画效果,程序的事件处理方法中调用了ViewSwitcher的setInAnimation()、setOutAnimation()方法来设置动画效果。本程序不只利用了Android系统提供的两个动画资源,还自行提供了动画资源。

R.anim.slide_in_right动画资源代码以下

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 设置从右边拖进来的动画 android:duration指定动画持续时间 -->
    <translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="@android:integer/config_mediumAnimTime" />
</set>

R.anim.slide_in_left动画资源代码以下

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 设置从左边拖出去的动画 android:duration指定动画持续时间 -->
    <translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="@android:integer/config_mediumAnimTime" />
</set>
相关文章
相关标签/搜索