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>
相關文章
相關標籤/搜索