Android 中TabLayout自定義選擇背景滑塊的實例代碼
TabLayout是Android 的Material Design包中的一個控件,可以和V4包中的ViewPager搭配產生一個聯(lián)動的效果。這里我自定義了一個滑塊能夠跟隨TabLayout進行滑動選擇的SliderLayout。效果見下圖(白色方框):
下面是SliderLayout的源碼:
import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.support.design.widget.TabLayout; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import java.lang.ref.WeakReference; /** * Created by yyw on 2016/4/28. * 一個用來顯示當前的index的滑塊 */ public class SliderLayout extends LinearLayout { private int totalNum = 0; private ImageView mSlider; private Drawable mSliderImage; private WeakReference<TabLayout> mTabLayoutRef; public SliderLayout(Context context) { this(context, null); } public SliderLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SliderLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SliderLayout); mSliderImage = array.getDrawable(R.styleable.SliderLayout_slider_pic); if (mSliderImage == null) { mSliderImage = context.getResources().getDrawable(R.drawable.slider); } array.recycle(); init(context); } private void init(Context context) { mSlider = new ImageView(context); mSlider.setImageDrawable(mSliderImage); addView(mSlider, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); resetSlider(); } /** * 重新設置滑塊 */ private void resetSlider() { if (getOrientation() == HORIZONTAL) { resetHorizontalSlider(); } } /** * 重置水平方向的滑塊大小 */ private void resetHorizontalSlider() { if (mTabLayoutRef == null) return; TabLayout tabLayout = mTabLayoutRef.get(); if (tabLayout == null) return; LinearLayout mTabStrip = (LinearLayout) tabLayout.getChildAt(0); totalNum = mTabStrip.getChildCount(); if (totalNum > 0) { View firstView = mTabStrip.getChildAt(0); int width = firstView.getMeasuredWidth(); resetSlider(width); } } //重新設置滑塊的大小 private void resetSlider(int width) { LayoutParams params = (LayoutParams) mSlider.getLayoutParams(); params.width = width;//重新設置滑塊的大小 params.height = getHeight() / 2; params.gravity = Gravity.CENTER_VERTICAL; mSlider.setPadding(width / 10, 0, width / 10, 0);//設置View的左右向內收縮 mSlider.setLayoutParams(params); } public void setupWithTabLayout(TabLayout tabLayout) { mTabLayoutRef = new WeakReference<>(tabLayout); resetHorizontalSlider(); } public static final String TAG = SliderLayout.class.getName(); public static class SliderOnPageChangeListener extends TabLayout.TabLayoutOnPageChangeListener { private final WeakReference<SliderLayout> mSliderLayoutRef; public SliderOnPageChangeListener(TabLayout tabLayout, SliderLayout layout) { super(tabLayout); mSliderLayoutRef = new WeakReference<SliderLayout>(layout); layout.setupWithTabLayout(tabLayout); } @Override public void onPageScrollStateChanged(int state) { super.onPageScrollStateChanged(state); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { super.onPageScrolled(position, positionOffset, positionOffsetPixels); final SliderLayout layout = mSliderLayoutRef.get(); if (layout != null) { layout.setScrollPosition(position, positionOffset); } } } /** * 把滑塊滑動到指定的位置 * * @param position 當前位置 * @param positionOffset 滑動到下一個或上一個位置比例 */ private void setScrollPosition(int position, float positionOffset) { final int roundedPosition = Math.round(position + positionOffset); if (roundedPosition < 0 || roundedPosition >= totalNum) { return; } float scrollX = calculateScrollXForTab(position, positionOffset); scrollTo((int) scrollX, 0); } /** * 計算滑塊需要滑動的距離 * * @param position 當前選擇的位置 * @param positionOffset 滑動位置的百分百 * @return 滑動的距離 */ private int calculateScrollXForTab(int position, float positionOffset) { TabLayout tabLayout = mTabLayoutRef.get(); if (tabLayout == null) return 0; LinearLayout mTabStrip = (LinearLayout) tabLayout.getChildAt(0); if (mTabStrip == null) return 0; //當前選擇的View final View selectedChild = mTabStrip.getChildAt(position); //下一個View final View nextChild = position + 1 < mTabStrip.getChildCount() ? mTabStrip.getChildAt(position + 1) : null; //當前選擇的View的寬度 final int selectedWidth = selectedChild != null ? selectedChild.getWidth() : 0; //下一個View的寬度 final int nextWidth = nextChild != null ? nextChild.getWidth() : 0; //當前選擇的View的左邊位置,view的方位 final int left = selectedChild != null ? selectedChild.getLeft() : 0; //計算滑塊需要滑動的距離,左 + ,右 - ; int scrollX = -(left + ((int) ((selectedWidth + nextWidth) * positionOffset * 0.5f))); if (tabLayout.getTabMode() == TabLayout.MODE_SCROLLABLE) {//當為滑動模式的時候TabLayout會有水平方向的滑動 scrollX += tabLayout.getScrollX();//計算在TabLayout有滑動的時候,滑塊相對的滑動距離 } return scrollX; } }
其中比較關鍵的一個類是SliderOnPageChangeListener 這個類繼承的TabLayout.TabLayoutOnPageChangeListener類這個類我們看源碼(下面)這個是監(jiān)聽ViewPager滑動選擇的一個接口。我們要做的就是在這個類基礎上進行擴展讓SliderLayout也能監(jiān)聽到ViewPager的滑動。
public static class TabLayoutOnPageChangeListener implements ViewPager.OnPageChangeListener { private final WeakReference<TabLayout> mTabLayoutRef; private int mPreviousScrollState; private int mScrollState; public TabLayoutOnPageChangeListener(TabLayout tabLayout) { mTabLayoutRef = new WeakReference<>(tabLayout); } @Override public void onPageScrollStateChanged(int state) { mPreviousScrollState = mScrollState; mScrollState = state; } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { //省略 } } @Override public void onPageSelected(int position) { //省略 } private void reset() { mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE; } }
計算每次SliderLayout需要滑動的距離的方法是calculateScrollXForTab(int position, float positionOffset)(詳細看源碼)根據監(jiān)聽到的ViewPager滑動進行相關的計算并滑動SliderLayout
應用的時候一定要注意viewPager.setOnPageChangeListener(new SliderLayout.SliderOnPageChangeListener(mTabLayout,layout));要在mTabLayout.setupWithViewPager(viewPager);之后調用:
public class MainActivity extends AppCompatActivity { public static final String TAG = MainActivity.class.getName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final TabLayout mTabLayout = (TabLayout) findViewById(R.id.tab_layout); ViewPager viewPager = (ViewPager) findViewById(R.id.vp); SliderLayout layout = (SliderLayout) findViewById(R.id.slider_layout); viewPager.setAdapter(new MViewPagerAdapter(getSupportFragmentManager())); mTabLayout.setupWithViewPager(viewPager); //方法一定要在mTabLayout.setupWithViewPager(viewPager)之后不然沒有效果 viewPager.setOnPageChangeListener(new SliderLayout.SliderOnPageChangeListener(mTabLayout,layout)); } class MViewPagerAdapter extends FragmentPagerAdapter { public final String[] names = new String[]{"音樂","電影","電視","綜藝","直播","音樂","電影","電視","綜藝","直播"}; public MViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return BlankFragment.newInstance("param1", "param2"); } @Override public int getCount() { return 10; } @Override public CharSequence getPageTitle(int position) { return names[position]; } } }
布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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="match_parent" android:orientation="vertical"> <FrameLayout android:layout_width="match_parent" android:background="@color/cardview_dark_background" android:layout_height="50dp"> <com.example.yyw.waterripple.SliderLayout android:id="@+id/slider_layout" android:layout_width="match_parent" android:layout_height="50dp" app:slider_pic="@drawable/slider" android:orientation="horizontal" /> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="50dp" app:tabGravity="center" app:tabMode="scrollable" app:tabSelectedTextColor="#ff0000" app:tabTextColor="#ffffff" /> </FrameLayout> <android.support.v4.view.ViewPager android:id="@+id/vp" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> <declare-styleable name="SliderLayout"> <attr name="slider_pic" format="reference" /> </declare-styleable> <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:topLeftRadius="10dp" android:topRightRadius="10dp" android:bottomLeftRadius="10dp" android:bottomRightRadius="10dp" /> <solid android:color="#ffffff" /> </shape>
以上所述是小編給大家介紹的Android 中TabLayout自定義選擇背景滑塊的實例代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
相關文章
Android開發(fā)控制ScrollView滑動速度的方法
這篇文章主要介紹了Android開發(fā)控制ScrollView滑動速度的方法,結合實例形式分析了Android編程中ScrollView滑動事件相關操作技巧,需要的朋友可以參考下2017-02-02Android實現(xiàn)ListView異步加載的方法(改進版)
這篇文章主要介紹了Android實現(xiàn)ListView異步加載的方法,針對前面介紹的方法進行了線程操作的改進,具有一定參考借鑒價值,需要的朋友可以參考下2016-08-08android 電話狀態(tài)監(jiān)聽(來電和去電)實現(xiàn)代碼
從事android開發(fā)的朋友們可能電話狀態(tài)監(jiān)聽不是很擅長,接下來將詳細介紹電話狀態(tài)監(jiān)聽功能的實現(xiàn)步驟,需要了解的朋友可以參考下2012-12-12Kotlin使用TransitionDrawable實現(xiàn)顏色漸變效果流程講解
這篇文章主要介紹了Kotlin使用TransitionDrawable實現(xiàn)顏色漸變效果,這里,我們通過TransitionDrawable顯示顏色漸變效果,包括背景顏色的變化,以及圖片與圖片的漸變效果2023-02-02Android 6.0區(qū)別U盤和SD卡設備的方法詳解
今天小編就為大家分享一篇Android 6.0區(qū)別U盤和SD卡設備的方法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08