使用ViewSwitcher仿制Android系统的Launcher界面

  ViewSwitcher代表了视图切换组件,它本身继承了FrameLayout,因此可以将多个View层叠在一起,每次只显示一个组件。当程序控制从一个View切换到另一个View时,ViewSwitcher支持指定动画效果。

​  为了给ViewSwitcher添加多个组件,一般通过调用ViewSwitcher的setFactory(ViewSwitcher.ViewFactory) 方法为之设置ViewFactory,并由该ViewFactory为之创建View即可。

最终实现的效果如下:
在这里插入图片描述

​  那就话不多说,上代码:

public class Activity137 extends Activity {

    // 定义每个屏幕显示的应用程序数
    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;
    private LayoutInflater inflater;

    // 该BaseAdapter负责为每屏幕显示的View提供列表项
    private BaseAdapter adapter = new BaseAdapter() {
        @Override
        public int getCount() {
            // 如果当前是最后一屏,且应用程序的数量不足铺满一个屏幕
            if (screenNo == screenCount - 1 && items.size() % NUMBER_PER_SCREEN != 0) {
                return items.size() % 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) {
                view = inflater.inflate(R.layout.labelicon, null);
                ImageView icon = view.findViewById(R.id.icon);
                TextView label = view.findViewById(R.id.label);
                viewHolder = new ViewHolder(icon, label);
                // 将viewHolder和view关联绑定,可以避免重复创建和查找视图
                view.setTag(viewHolder);
            } else {
                view = convertView;
                viewHolder = (ViewHolder) view.getTag();
            }
            viewHolder.imageView.setImageDrawable(getItem(position).drawable);
            viewHolder.textView.setText(getItem(position).dataName);
            return view;
        }
    };

    // 代表应用程序的内部类
    public static class DataItem {
        // 应用程序名称
        String dataName;
        // 应用程序图标
        Drawable drawable;

        public DataItem(String dataName, Drawable drawable) {
            this.dataName = dataName;
            this.drawable = drawable;
        }
    }

    public static class ViewHolder {
        ImageView imageView;
        TextView textView;

        public ViewHolder(ImageView imageView, TextView textView) {
            this.imageView = imageView;
            this.textView = textView;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout137);
        inflater = LayoutInflater.from(this);

        // 创建一个包含40个元素的List集合,用于模拟包含40个应用程序
        for (int i = 0; i < 40; i++) {
            String label = i + "";
            Drawable icon = getResources().getDrawable(R.mipmap.ic_launcher, null);
            items.add(new DataItem(label, icon));
        }
        // 计算应用程序所占的总屏幕数
        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(new ViewSwitcher.ViewFactory() {
            @Override
            public View makeView() {
                return inflater.inflate(R.layout.slidelistview, null);
            }
        });

        // 页面加载的时候显示第一屏
        next(null);
    }

    public void next(View view) {
        if (screenNo < screenCount - 1) {
            screenNo++;
            // 为ViewSwitcher组件显示过程设置动画
            switcher.setInAnimation(this, R.anim.slide_in_right);
            // 设置隐藏过程的动画
            switcher.setOutAnimation(this, R.anim.slide_out_left);
            // 控制下一屏将要显示的GridView对应的Adapter
            ((GridView) switcher.getNextView()).setAdapter(adapter);
            // 显示下一屏
            switcher.showNext();
        }
    }

    public void pre(View view) {
        if (screenNo > 0) {
            screenNo--;
            // 为ViewSwitcher组件显示过程设置动画
            switcher.setInAnimation(this, R.anim.slide_in_left);
            // 设置隐藏过程的动画
            switcher.setOutAnimation(this, R.anim.slide_out_right);
            // 控制上一屏将要显示的GridView对应的Adapter
            ((GridView) switcher.getNextView()).setAdapter(adapter);
            // 显示上一屏
            switcher.showPrevious();
        }
    }

}

主界面布局——layout137:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="500dp">

    <ViewSwitcher
        android:id="@+id/viewSwitcher"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:id="@+id/bt_pre"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="12dp"
        android:layout_marginBottom="8dp"
        android:onClick="pre"
        android:text="&lt;"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/bt_next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp"
        android:layout_marginBottom="8dp"
        android:onClick="next"
        android:text="&gt;"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

列表项组件布局——labelicon:

<?xml version="1.0" encoding="UTF-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:padding="10dp">

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

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

</LinearLayout>

每个屏显示应用程序的布局——slidelistview:

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:numColumns="4" />

动画资源:

slide_in_right:

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

slide_out_left:

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

slide_in_left:

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

slide_out_right:

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


因为刚开始做相关的工作,理解经常出现错误,欢迎指摘。
日拱一卒,共同进步!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值