亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

安卓自學——ViewPager與FragmentTabHost實現拖動翻頁

2019-11-06 09:37:20
字體:
來源:轉載
供稿:網友

使用ViewPager 和 FragmentTabHost 實現滑動標簽頁翻動

示例效果: 實現翻頁效果

主要思路分為兩個方面: 1. ViewPager 實現左右拖動切換 Fragment,FragmentTabHost 點擊底部按鈕切換 Fragment; 2. 將 ViewPager 的翻頁動作與 FragmentTabHost 的頁面切換進行關聯,反過來又將 FragmentTabHost 的點擊切換與 ViewPager 的翻頁進行關聯,這樣就能實現點擊和拖拽翻頁的同步了;

后面會有詳細代碼,demo鏈接:https://github.com/hry712/Android_ViewPager_FragmentTabHost_Demo.git

一、主界面layout

布局如下:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:orientation="vertical" tools:context="com.geekschoole.waimai.controllers.MainActivity"> <android.support.v4.view.ViewPager android:id="@+id/pager_fragments" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> </android.support.v4.view.ViewPager> <FrameLayout android:id="@+id/frame_tabContent" android:visibility="gone" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"></FrameLayout> <android.support.v4.app.FragmentTabHost android:id="@+id/tabhost_pages" android:layout_width="match_parent" android:layout_height="wrap_content"> </android.support.v4.app.FragmentTabHost> </LinearLayout>

二、用 ViewPager 實現拖動切換 Fragment 并與 FragmentTabHost 進行關聯

需要為 ViewPager 自定義 adapter ,用以裝填要切換的 Fragment ,并根據拖動事件的觸發返回相應的 Fragment,自定義 adapter 繼承自FragmentPagerAdapter(谷歌官方推薦使用提供的標準FragmentPagerAdapterFragmentStatePagerAdapter,后者適合于標簽頁較多的情況),代碼如下:

public class MyFragmentAdapter extends FragmentPagerAdapter { // 在 MainActivity 中會初始化各個 Fragment 構成列表一并傳入到 adapter 中處理 PRivate List<Fragment> fragments; public MyFragmentAdapter(FragmentManager fm, List<Fragment> fragments) { super(fm); this.fragments = fragments; } // 官方文檔中介紹只需重載 getItem 和 getCount 即可使用 // 該方法返回一個與特定位置相關的 Fragment @Override public Fragment getItem(int position) { return fragments.get(position); } // 返回可用視圖的總數 @Override public int getCount() { return fragments.size(); } }

MainActivity.class中創建 ViewPager 的代碼如下:

pager = (ViewPager) findViewById(R.id.pager_fragments); // fragmentList 是包括了已初始化并要進行切換的 Fragment 列表 pager.setAdapter(new MyFragmentAdapter(getSupportFragmentManager(), fragmentList));

為了響應拖動切換事件,MainActivity需實現 ViewPager.OnPageChangeListener接口,其下3個接口方法實現如下,注意到在onPageSelected()中, ViewPager 的切換引起 FragmentTabHost 同步切換也是在此實現:

// 當滾動狀態發生改變時調用,特別適合在用戶開始拖動時觸發 @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } // 當前頁滾動時會調用此方法 @Override public void onPageScrollStateChanged(int state) { } // 當新頁面變為選中狀態時會調用此方法 @Override public void onPageSelected(int position) { TabWidget widget = fragmentTabHost.getTabWidget(); // 在查找取得焦點的view時,descendant focusability定義了view group與其后代的聯系 int oldFocusability = widget.getDescendantFocusability(); widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); // 這里關聯到 fragmentTabHost 一起切換 fragmentTabHost.setCurrentTab(position); widget.setDescendantFocusability(oldFocusability); }

三、FragmentTabHost 點擊切換 Fragment 并與 ViewPager 關聯

“綁定”也許并不準確,實際上是在一個接口方法onTabChanged() (接口為 FragmentTabHost.OnTabChangeListener)中令 ViewPager 的當前頁與 FragmentTabHost 切換時同步改變,實現“綁定”作用。

在 MainActivity 中初始化 FragmentTabHost:

// 下面都是在準備 FragmentTabHost 的創建 fragmentTabHost = (FragmentTabHost); findViewById(R.id.tabhost_pages); // 要求 MainActivity 實現 FragmentTabHost.OnTabChangeListener 接口的 onTabChanged 方法 fragmentTabHost.setOnTabChangedListener(this); // 官方文檔中要求在從視圖層完成inflate后,必須調用setup方法繼續完成FragmentTabHost初始化 fragmentTabHost.setup(this, getSupportFragmentManager(), R.id.frame_tabContent); // 至此,FragmentTabHost 已經創建完成,下面要向其裝填底部欄的幾個按鈕 // fragmentArr[] 中保存了自定義的幾個 Fragment 類用作 Tab 頁 int count = fragmentsArr.length; for (int i = 0; i < count; i++) { // 使用了自定義的 getTabItemViewById() 方法 // 這里的 TabSpec 設置了 label 和 icon,icon的生成封裝在了 getTabItemViewById() 中 TabHost.TabSpec tabSpec = fragmentTabHost.newTabSpec(TabNameArr[i]).setIndicator(getTabItemViewById(i)); // 將底部按鈕與 fragment 關聯起來 fragmentTabHost.addTab(tabSpec, fragmentsArr[i], null); fragmentTabHost.getTabWidget().getChildAt(i).setBackgroundResource(R.drawable.bottom_switcher); }

實現 FragmentTabHost.OnTabChangeListener 接口的 onTabChanged() 方法如下:

@Override public void onTabChanged(String s) { // 通過這個方法令 fragmentTabHost 觸發 ViewPager 同步變化 pager.setCurrentItem(fragmentTabHost.getCurrentTab()); }

一個Tab頁包含一個 Tab 指示器,content,用于跟蹤它的 tag,TabSpec 就是用來選擇這些內容。

Tab指示器有兩種形式: 1. 設置一個 label 2. 設置一個 label 和 icon

Tab 內容有3種: 1. View的id 2. 創建視圖內容的 TabHost.TabContentFactory 3. 啟動 Activity 的 Intent

自定義的 getTabItemViewById()方法如下:

// 解析單個Tab頁按鈕的XML布局,將icon和label的具體內容依次裝填進去生成一個新的view供 TabSpec 使用 private View getTabItemViewById(int index) { // bottom_tab_switcher.xml 是每個標簽頁下對應的圖標和文字組合的小布局 View view = layoutInflater.inflate(R.layout.bottom_tab_switcher, null); ImageView imageViewTabIcon = (ImageView) view.findViewById(R.id.imgvw_bottom_tabIcon); // index 變量布局用于索引預制在數組變量中的tab命名字符串和圖片點擊動作響應xml文件 imageViewTabIcon.setImageResource(ImageViewArr[index]); TextView textViewTabName = (TextView) view.findViewById(R.id.tv_bottom_tabText); textViewTabName.setText(TabNameArr[index]); return view; }

MainActivity.class實現 onTabChanged()接口方法如下:

// 當標簽頁切換時會調用此方法 @Override public void onTabChanged(String s) { // viewpager 的 setCurrentItem 方法用于設置當前選中頁面 pager.setCurrentItem(fragmentTabHost.getCurrentTab()); }

四、主要代碼如下

MainActivity.class完整代碼如下:

package com.geekschoole.waimai.controllers;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentTabHost;import android.support.v4.view.ViewPager;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.TabHost;import android.widget.TabWidget;import android.widget.TextView;import com.geekschoole.waimai.views.IndexFragment;import com.geekschoole.waimai.views.OrderFragment;import com.geekschoole.waimai.R;import com.geekschoole.waimai.views.UserFragment;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener, FragmentTabHost.OnTabChangeListener{ private FragmentTabHost fragmentTabHost; private LayoutInflater layoutInflater; private Class fragmentsArr[] = {IndexFragment.class, OrderFragment.class, UserFragment.class}; private int ImageViewArr[] = {R.drawable.bottom_index_tab_selector, R.drawable.bottom_order_tab_selector, R.drawable.bottom_user_tab_selector}; private String TabNameArr[] = {"Index", "Order", "User"}; private List<Fragment> fragmentList = new ArrayList<>(); private ViewPager pager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 控件初始化,并將 ViewPager 與 FragmentTabHost 進行綁定 initView(); // 創建3個Fragment,通過Adapter添加到 ViewPager 中作為Tab頁 initTabs(); } private void initView() { layoutInflater = LayoutInflater.from(this); pager = (ViewPager) findViewById(R.id.pager_fragments); pager.addOnPageChangeListener(this); fragmentTabHost = (FragmentTabHost) findViewById(R.id.tabhost_pages); fragmentTabHost.setOnTabChangedListener(this); fragmentTabHost.setup(this, getSupportFragmentManager(), R.id.frame_tabContent); int count = fragmentsArr.length; for (int i = 0; i < count; i++) { TabHost.TabSpec tabSpec = fragmentTabHost.newTabSpec(TabNameArr[i]).setIndicator(getTabItemViewById(i)); fragmentTabHost.addTab(tabSpec, fragmentsArr[i], null); fragmentTabHost.getTabWidget().getChildAt(i).setBackgroundResource(R.drawable.bottom_switcher); } } private View getTabItemViewById(int index) { View view = layoutInflater.inflate(R.layout.bottom_tab_switcher, null); ImageView imageViewTabIcon = (ImageView) view.findViewById(R.id.imgvw_bottom_tabIcon); imageViewTabIcon.setImageResource(ImageViewArr[index]); TextView textViewTabName = (TextView) view.findViewById(R.id.tv_bottom_tabText); textViewTabName.setText(TabNameArr[index]); return view; } private void initTabs() { // 這里的添加順序對 tab 頁的先后順序有影響 fragmentList.add(new IndexFragment()); fragmentList.add(new OrderFragment()); fragmentList.add(new UserFragment()); pager.setAdapter(new MyFragmentAdapter(getSupportFragmentManager(), fragmentList)); fragmentTabHost.getTabWidget().setDividerDrawable(null); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageScrollStateChanged(int state) { } @Override public void onPageSelected(int position) { TabWidget widget = fragmentTabHost.getTabWidget(); int oldFocusability = widget.getDescendantFocusability(); widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); fragmentTabHost.setCurrentTab(position); widget.setDescendantFocusability(oldFocusability); } @Override public void onTabChanged(String s) { pager.setCurrentItem(fragmentTabHost.getCurrentTab()); }}

底部單個Tab圖標和label的組合布局 bottom_tab_switcher.xml如下(位于 res/layout/ 中),就是一個icon和一個label簡單的縱向排列:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center"> <ImageView android:id="@+id/imgvw_bottom_tabIcon" android:layout_width="30dp" android:layout_height="30dp" android:focusable="false" android:padding="3dp"/> <TextView android:id="@+id/tv_bottom_tabText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Index" android:textSize="10sp" /></LinearLayout>

底部每個 icon 點擊時的圖片切換配置bottom_index_tab_selector.xml 示例如下,需事先為每個圖標準備一套在選中和未選中時的 icon 圖片資源放置于 res/drawable/drawable-XXXdpi 下,在 getTabItemViewById() 方法的 imageViewTabIcon.setImageResource(ImageViewArr[index]); 中會為每個 icon 綁定此配置(配置文件中已經引用了圖片資源):

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <!--Non focused states--> <item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/index_unselected" /> <!--Focused states--> <item android:state_focused="true" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/index_selected" /> <!--Pressed--> <item android:state_selected="true" android:state_pressed="true" android:drawable="@drawable/index_selected" /> <item android:drawable="@drawable/index_selected" /></selector>

至于切換的幾個 Tab ,里面使用的 Fragment 可自行創建空白或關聯有xml 的 fragment 再根據需要進行各種界面繪制,示例中只包含了一個 <TextView> 用來顯示文字。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美激情精品久久久久久| 亚洲娇小xxxx欧美娇小| 国产精品美女在线观看| 久久伊人精品天天| 亚洲a中文字幕| 久久久女人电视剧免费播放下载| 亚洲一区二区三区视频播放| xxx成人少妇69| 久久99久国产精品黄毛片入口| 精品亚洲男同gayvideo网站| 日韩中文字幕在线精品| 97视频在线观看免费| 久久精品国产久精国产思思| 国产成人午夜视频网址| 精品视频久久久久久久| 欧美极品在线视频| 精品视频在线播放色网色视频| 欧美日韩福利电影| 久久国产色av| 欧美在线一区二区三区四| 欧美黑人极品猛少妇色xxxxx| 精品一区二区三区四区| 性亚洲最疯狂xxxx高清| 成人天堂噜噜噜| 久久精品视频播放| 色妞在线综合亚洲欧美| 精品呦交小u女在线| 欧美中文字幕在线观看| 国内成人精品视频| 影音先锋欧美在线资源| 日韩h在线观看| 奇米成人av国产一区二区三区| 国产一区二区在线播放| 国产精品69精品一区二区三区| 8x拔播拔播x8国产精品| 欧美国产第一页| 日韩高清电影好看的电视剧电影| 富二代精品短视频| 国产亚洲精品va在线观看| 日韩福利在线播放| 欧美激情视频网| 久久综合伊人77777蜜臀| 精品国产一区二区三区在线观看| 亚洲理论在线a中文字幕| 国产经典一区二区| 欧美国产日韩一区| 在线播放日韩专区| 国产伦精品免费视频| 国产精品久久久久av| 国产第一区电影| 日韩av最新在线观看| 欧美日韩人人澡狠狠躁视频| 久久天天躁狠狠躁夜夜躁| 在线播放日韩av| 亚洲欧洲激情在线| 亚洲天堂影视av| 欧美大秀在线观看| 久久久久久久久久久网站| 成人免费视频网址| 久久天天躁狠狠躁夜夜爽蜜月| 日韩精品有码在线观看| 午夜精品久久久久久久99黑人| 91色在线视频| 欧美日韩一区二区免费视频| 国产婷婷色综合av蜜臀av| 日韩av中文字幕在线免费观看| 久久99热精品这里久久精品| 色妞在线综合亚洲欧美| 亚洲成avwww人| 国产在线精品自拍| 国产欧美一区二区三区久久人妖| 中文字幕无线精品亚洲乱码一区| 亚州欧美日韩中文视频| 国产亚洲aⅴaaaaaa毛片| 欧美日韩国产精品一区二区不卡中文| 日韩精品有码在线观看| 久久视频免费观看| 日韩av中文字幕在线| 国产亚洲xxx| 亚洲一区二区精品| 色综合久久久888| 欧美老少做受xxxx高潮| 精品欧美激情精品一区| 欧美在线视频观看免费网站| 国产精品中文字幕在线观看| 久久深夜福利免费观看| 亚洲片在线观看| 国产成人在线视频| 91免费高清视频| 国产精品久久久亚洲| 日韩亚洲欧美中文在线| 欧美日韩成人网| 亚洲天堂开心观看| 欧美尺度大的性做爰视频| 91精品国产乱码久久久久久久久| 欧美尺度大的性做爰视频| 97视频免费观看| 精品视频在线观看日韩| 欧美黑人性视频| 国产欧美一区二区三区四区| 成人xxxx视频| 欧美国产日本高清在线| 日韩网站在线观看| 欧美日韩国产精品一区| 国产精品视频色| 欧洲日韩成人av| 九九热这里只有精品免费看| 久青草国产97香蕉在线视频| 亚洲人永久免费| 97国产精品免费视频| 亚洲国产私拍精品国模在线观看| 成人xxxxx| 亚洲精品欧美日韩专区| 国产精品日韩欧美综合| 亚洲图片欧美午夜| 成人久久精品视频| 欧美乱大交做爰xxxⅹ性3| 国产成人91久久精品| 国产精品av在线播放| 亚洲色在线视频| 日韩欧美aⅴ综合网站发布| 亚洲理论在线a中文字幕| 欧美成人黄色小视频| 亚洲三级免费看| 日本不卡免费高清视频| 美女扒开尿口让男人操亚洲视频网站| 久久综合伊人77777蜜臀| 在线观看视频亚洲| 热99精品里视频精品| 亚洲国产精品va在线观看黑人| 91成人天堂久久成人| 在线成人一区二区| 亚洲第一网中文字幕| 亚洲成人激情视频| 国产极品jizzhd欧美| 久久精品国产v日韩v亚洲| 久久久免费精品| 亚洲欧洲免费视频| 久久久999精品免费| 欧美日韩福利电影| 亚洲人成77777在线观看网| 日韩精品有码在线观看| 欧美三级欧美成人高清www| 精品福利一区二区| 国产精品白嫩初高中害羞小美女| 538国产精品一区二区在线| 91久久精品美女| 欧美色欧美亚洲高清在线视频| 欧美一区深夜视频| 黄网动漫久久久| 国产成人精品免费视频| 欧美老少做受xxxx高潮| 毛片精品免费在线观看| 亚洲精品免费网站| 久久综合色88| 国产精品一区二区久久国产| 国产精品露脸av在线| 永久免费精品影视网站| 亚洲精品女av网站| 亚洲综合日韩中文字幕v在线| 成人做爰www免费看视频网站| 九九精品在线播放| 色妞欧美日韩在线| 色哟哟入口国产精品|