国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

安卓自學(xué)——ViewPager與FragmentTabHost實(shí)現(xiàn)拖動(dòng)翻頁(yè)

2019-11-06 09:37:20
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

使用ViewPager 和 FragmentTabHost 實(shí)現(xiàn)滑動(dòng)標(biāo)簽頁(yè)翻動(dòng)

示例效果: 實(shí)現(xiàn)翻頁(yè)效果

主要思路分為兩個(gè)方面: 1. ViewPager 實(shí)現(xiàn)左右拖動(dòng)切換 Fragment,F(xiàn)ragmentTabHost 點(diǎn)擊底部按鈕切換 Fragment; 2. 將 ViewPager 的翻頁(yè)動(dòng)作與 FragmentTabHost 的頁(yè)面切換進(jìn)行關(guān)聯(lián),反過(guò)來(lái)又將 FragmentTabHost 的點(diǎn)擊切換與 ViewPager 的翻頁(yè)進(jìn)行關(guān)聯(lián),這樣就能實(shí)現(xiàn)點(diǎn)擊和拖拽翻頁(yè)的同步了;

后面會(huì)有詳細(xì)代碼,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 實(shí)現(xiàn)拖動(dòng)切換 Fragment 并與 FragmentTabHost 進(jìn)行關(guān)聯(lián)

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

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

MainActivity.class中創(chuàng)建 ViewPager 的代碼如下:

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

為了響應(yīng)拖動(dòng)切換事件,MainActivity需實(shí)現(xiàn) ViewPager.OnPageChangeListener接口,其下3個(gè)接口方法實(shí)現(xiàn)如下,注意到在onPageSelected()中, ViewPager 的切換引起 FragmentTabHost 同步切換也是在此實(shí)現(xiàn):

// 當(dāng)滾動(dòng)狀態(tài)發(fā)生改變時(shí)調(diào)用,特別適合在用戶開(kāi)始拖動(dòng)時(shí)觸發(fā) @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } // 當(dāng)前頁(yè)滾動(dòng)時(shí)會(huì)調(diào)用此方法 @Override public void onPageScrollStateChanged(int state) { } // 當(dāng)新頁(yè)面變?yōu)檫x中狀態(tài)時(shí)會(huì)調(diào)用此方法 @Override public void onPageSelected(int position) { TabWidget widget = fragmentTabHost.getTabWidget(); // 在查找取得焦點(diǎn)的view時(shí),descendant focusability定義了view group與其后代的聯(lián)系 int oldFocusability = widget.getDescendantFocusability(); widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); // 這里關(guān)聯(lián)到 fragmentTabHost 一起切換 fragmentTabHost.setCurrentTab(position); widget.setDescendantFocusability(oldFocusability); }

三、FragmentTabHost 點(diǎn)擊切換 Fragment 并與 ViewPager 關(guān)聯(lián)

“綁定”也許并不準(zhǔn)確,實(shí)際上是在一個(gè)接口方法onTabChanged() (接口為 FragmentTabHost.OnTabChangeListener)中令 ViewPager 的當(dāng)前頁(yè)與 FragmentTabHost 切換時(shí)同步改變,實(shí)現(xiàn)“綁定”作用。

在 MainActivity 中初始化 FragmentTabHost:

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

實(shí)現(xiàn) FragmentTabHost.OnTabChangeListener 接口的 onTabChanged() 方法如下:

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

一個(gè)Tab頁(yè)包含一個(gè) Tab 指示器,content,用于跟蹤它的 tag,TabSpec 就是用來(lái)選擇這些內(nèi)容。

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

Tab 內(nèi)容有3種: 1. View的id 2. 創(chuàng)建視圖內(nèi)容的 TabHost.TabContentFactory 3. 啟動(dòng) Activity 的 Intent

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

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

MainActivity.class實(shí)現(xiàn) onTabChanged()接口方法如下:

// 當(dāng)標(biāo)簽頁(yè)切換時(shí)會(huì)調(diào)用此方法 @Override public void onTabChanged(String s) { // viewpager 的 setCurrentItem 方法用于設(shè)置當(dāng)前選中頁(yè)面 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 進(jìn)行綁定 initView(); // 創(chuàng)建3個(gè)Fragment,通過(guò)Adapter添加到 ViewPager 中作為Tab頁(yè) 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() { // 這里的添加順序?qū)?tab 頁(yè)的先后順序有影響 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()); }}

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

<?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>

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

<?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>

至于切換的幾個(gè) Tab ,里面使用的 Fragment 可自行創(chuàng)建空白或關(guān)聯(lián)有xml 的 fragment 再根據(jù)需要進(jìn)行各種界面繪制,示例中只包含了一個(gè) <TextView> 用來(lái)顯示文字。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 玛纳斯县| 乐山市| 应用必备| 三门县| 北海市| 德昌县| 嫩江县| 曲麻莱县| 泽州县| 绥宁县| 崇礼县| 建瓯市| 庆城县| 财经| 盐山县| 土默特左旗| 临沧市| 永寿县| 浦县| 青龙| 来宾市| 同江市| 临洮县| 朔州市| 清徐县| 长泰县| 宁阳县| 岑巩县| 察隅县| 洛南县| 织金县| 图片| 琼中| 玉田县| 商洛市| 长汀县| 上高县| 雅江县| 镇宁| 贵港市| 三明市|