mirror of
https://github.com/MatomoCamp/matomocamp-companion-android.git
synced 2024-09-19 16:13:46 +02:00
Replaced PagerSlidingTabStrip with a slightly improved version of
Android's example SlidingTabLayout.
This commit is contained in:
parent
831539359d
commit
b6e6ecf027
13 changed files with 543 additions and 619 deletions
|
@ -27,7 +27,6 @@ gradle build
|
|||
## Used libraries
|
||||
|
||||
* [Android Support Library](http://developer.android.com/tools/support-library/) by The Android Open Source Project
|
||||
* [PagerSlidingTabStrip](https://github.com/astuetz/PagerSlidingTabStrip) by Andreas Stuetz
|
||||
* [ViewPagerIndicator](http://viewpagerindicator.com/) by Jake Wharton
|
||||
* [PhotoView](https://github.com/chrisbanes/PhotoView) by Chris Banes
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="@android:integer/config_shortAnimTime">
|
||||
|
||||
<item android:drawable="@color/tab_pressed_fosdem" android:state_pressed="true"/>
|
||||
<item android:drawable="@color/tab_pressed_fosdem" android:state_focused="true"/>
|
||||
<item android:drawable="@android:color/transparent"/>
|
||||
|
||||
</selector>
|
|
@ -5,11 +5,10 @@
|
|||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<com.astuetz.PagerSlidingTabStrip
|
||||
android:id="@+id/indicator"
|
||||
<com.example.android.common.view.SlidingTabLayout
|
||||
android:id="@+id/sliding_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
app:pstsIndicatorColor="@color/fosdem_purple" />
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/pager"
|
||||
|
|
|
@ -11,11 +11,10 @@
|
|||
android:orientation="vertical"
|
||||
android:visibility="visible" >
|
||||
|
||||
<com.astuetz.PagerSlidingTabStrip
|
||||
android:id="@+id/indicator"
|
||||
<com.example.android.common.view.SlidingTabLayout
|
||||
android:id="@+id/sliding_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
app:pstsIndicatorColor="@color/fosdem_purple" />
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/pager"
|
||||
|
|
|
@ -4,18 +4,4 @@
|
|||
<!-- Drawable used as a background for activated items. -->
|
||||
<attr name="activatedBackgroundIndicator" format="reference" />
|
||||
|
||||
<declare-styleable name="PagerSlidingTabStrip">
|
||||
<attr name="pstsIndicatorColor" format="color" />
|
||||
<attr name="pstsUnderlineColor" format="color" />
|
||||
<attr name="pstsDividerColor" format="color" />
|
||||
<attr name="pstsIndicatorHeight" format="dimension" />
|
||||
<attr name="pstsUnderlineHeight" format="dimension" />
|
||||
<attr name="pstsDividerPadding" format="dimension" />
|
||||
<attr name="pstsTabPaddingLeftRight" format="dimension" />
|
||||
<attr name="pstsScrollOffset" format="dimension" />
|
||||
<attr name="pstsTabBackground" format="reference" />
|
||||
<attr name="pstsShouldExpand" format="boolean" />
|
||||
<attr name="pstsTextAllCaps" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
|
@ -2,7 +2,6 @@
|
|||
<resources>
|
||||
|
||||
<color name="fosdem_purple">#a91991</color>
|
||||
<color name="tab_pressed_fosdem">#80a91991</color>
|
||||
<color name="main_menu_background">#f0fafafa</color>
|
||||
<color name="translucent_grey">#29000000</color>
|
||||
<color name="schedule_time_background">#29000000</color>
|
||||
|
|
|
@ -112,6 +112,6 @@
|
|||
\nThe name FOSDEM and the gear logo are registered trademarks of FOSDEM VZW. Used with permission.
|
||||
\n
|
||||
\n<small>This application makes use of the following libraries:
|
||||
\n- <a href="http://developer.android.com/tools/support-library/">Android Support Library</a><i> by The Android Open Source Project</i>\n- <a href="https://github.com/astuetz/PagerSlidingTabStrip">PagerSlidingTabStrip</a><i> by Andreas Stuetz</i>\n- <a href="http://viewpagerindicator.com/">ViewPagerIndicator</a><i> by Jake Wharton</i>\n- <a href="https://github.com/chrisbanes/PhotoView">PhotoView</a><i> by Chris Banes</i></small></string>
|
||||
\n- <a href="http://developer.android.com/tools/support-library/">Android Support Library</a><i> by The Android Open Source Project</i>\n- <a href="http://viewpagerindicator.com/">ViewPagerIndicator</a><i> by Jake Wharton</i>\n- <a href="https://github.com/chrisbanes/PhotoView">PhotoView</a><i> by Chris Banes</i></small></string>
|
||||
|
||||
</resources>
|
|
@ -11,6 +11,7 @@
|
|||
<item name="android:textViewStyle">@style/TextView.Fosdem</item>
|
||||
<item name="android:listViewStyle">@style/ListView.Fosdem</item>
|
||||
<item name="activatedBackgroundIndicator">@drawable/activated_background</item>
|
||||
<item name="android:selectableItemBackground">@drawable/selectable_background</item>
|
||||
</style>
|
||||
|
||||
<style name="DialogTheme" parent="@android:style/Theme.Dialog" />
|
||||
|
|
|
@ -11,7 +11,7 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import be.digitalia.fosdem.R;
|
||||
|
||||
import com.astuetz.PagerSlidingTabStrip;
|
||||
import com.example.android.common.view.SlidingTabLayout;
|
||||
|
||||
public class LiveFragment extends Fragment {
|
||||
|
||||
|
@ -29,8 +29,9 @@ public class LiveFragment extends Fragment {
|
|||
|
||||
ViewPager pager = (ViewPager) view.findViewById(R.id.pager);
|
||||
pager.setAdapter(livePagerAdapter);
|
||||
PagerSlidingTabStrip indicator = (PagerSlidingTabStrip) view.findViewById(R.id.indicator);
|
||||
indicator.setViewPager(pager);
|
||||
SlidingTabLayout slidingTabs = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
|
||||
slidingTabs.setSelectedIndicatorColors(getResources().getColor(R.color.fosdem_purple));
|
||||
slidingTabs.setViewPager(pager);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import be.digitalia.fosdem.db.DatabaseManager;
|
|||
import be.digitalia.fosdem.loaders.GlobalCacheLoader;
|
||||
import be.digitalia.fosdem.model.Day;
|
||||
|
||||
import com.astuetz.PagerSlidingTabStrip;
|
||||
import com.example.android.common.view.SlidingTabLayout;
|
||||
|
||||
public class TracksFragment extends Fragment implements LoaderCallbacks<List<Day>> {
|
||||
|
||||
|
@ -31,7 +31,7 @@ public class TracksFragment extends Fragment implements LoaderCallbacks<List<Day
|
|||
View contentView;
|
||||
View emptyView;
|
||||
ViewPager pager;
|
||||
PagerSlidingTabStrip indicator;
|
||||
SlidingTabLayout slidingTabs;
|
||||
}
|
||||
|
||||
private static final int DAYS_LOADER_ID = 1;
|
||||
|
@ -60,7 +60,8 @@ public class TracksFragment extends Fragment implements LoaderCallbacks<List<Day
|
|||
holder.contentView = view.findViewById(R.id.content);
|
||||
holder.emptyView = view.findViewById(android.R.id.empty);
|
||||
holder.pager = (ViewPager) view.findViewById(R.id.pager);
|
||||
holder.indicator = (PagerSlidingTabStrip) view.findViewById(R.id.indicator);
|
||||
holder.slidingTabs = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
|
||||
holder.slidingTabs.setSelectedIndicatorColors(getResources().getColor(R.color.fosdem_purple));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
@ -102,7 +103,8 @@ public class TracksFragment extends Fragment implements LoaderCallbacks<List<Day
|
|||
public DaysLoader(Context context) {
|
||||
super(context);
|
||||
// Reload days list when the schedule has been refreshed
|
||||
LocalBroadcastManager.getInstance(context).registerReceiver(scheduleRefreshedReceiver, new IntentFilter(DatabaseManager.ACTION_SCHEDULE_REFRESHED));
|
||||
LocalBroadcastManager.getInstance(context).registerReceiver(scheduleRefreshedReceiver,
|
||||
new IntentFilter(DatabaseManager.ACTION_SCHEDULE_REFRESHED));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -142,7 +144,7 @@ public class TracksFragment extends Fragment implements LoaderCallbacks<List<Day
|
|||
if (holder.pager.getAdapter() == null) {
|
||||
holder.pager.setAdapter(daysAdapter);
|
||||
}
|
||||
holder.indicator.setViewPager(holder.pager);
|
||||
holder.slidingTabs.setViewPager(holder.pager);
|
||||
if (savedCurrentPage != -1) {
|
||||
holder.pager.setCurrentItem(Math.min(savedCurrentPage, totalPages - 1), false);
|
||||
savedCurrentPage = -1;
|
||||
|
|
|
@ -1,578 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Andreas Stuetz <andreas.stuetz@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.astuetz;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v4.view.ViewPager.OnPageChangeListener;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import be.digitalia.fosdem.R;
|
||||
|
||||
public class PagerSlidingTabStrip extends HorizontalScrollView {
|
||||
|
||||
public interface IconTabProvider {
|
||||
public int getPageIconResId(int position);
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
private static final int[] ATTRS = new int[] {
|
||||
android.R.attr.textSize,
|
||||
android.R.attr.textColor
|
||||
};
|
||||
// @formatter:on
|
||||
|
||||
private LinearLayout.LayoutParams defaultTabLayoutParams;
|
||||
private LinearLayout.LayoutParams expandedTabLayoutParams;
|
||||
|
||||
private final PageListener pageListener = new PageListener();
|
||||
public OnPageChangeListener delegatePageListener;
|
||||
|
||||
private LinearLayout tabsContainer;
|
||||
private ViewPager pager;
|
||||
|
||||
private int tabCount;
|
||||
|
||||
private int currentPosition = 0;
|
||||
private float currentPositionOffset = 0f;
|
||||
|
||||
private Paint rectPaint;
|
||||
private Paint dividerPaint;
|
||||
|
||||
private int indicatorColor = 0xFF666666;
|
||||
private int underlineColor = 0x1A000000;
|
||||
private int dividerColor = 0x1A000000;
|
||||
|
||||
private boolean shouldExpand = false;
|
||||
private boolean textAllCaps = true;
|
||||
|
||||
private int scrollOffset = 52;
|
||||
private int indicatorHeight = 8;
|
||||
private int underlineHeight = 2;
|
||||
private int dividerPadding = 12;
|
||||
private int tabPadding = 24;
|
||||
private int dividerWidth = 1;
|
||||
|
||||
private int tabTextSize = 12;
|
||||
private int tabTextColor = 0xFF666666;
|
||||
private Typeface tabTypeface = null;
|
||||
private int tabTypefaceStyle = Typeface.BOLD;
|
||||
|
||||
private int lastScrollX = 0;
|
||||
|
||||
private int tabBackgroundResId = R.drawable.background_tab;
|
||||
|
||||
private Locale locale;
|
||||
|
||||
public PagerSlidingTabStrip(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public PagerSlidingTabStrip(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
setFillViewport(true);
|
||||
setWillNotDraw(false);
|
||||
|
||||
tabsContainer = new LinearLayout(context);
|
||||
tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
|
||||
tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
||||
addView(tabsContainer);
|
||||
|
||||
DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||
|
||||
scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm);
|
||||
indicatorHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, indicatorHeight, dm);
|
||||
underlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, underlineHeight, dm);
|
||||
dividerPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerPadding, dm);
|
||||
tabPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tabPadding, dm);
|
||||
dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerWidth, dm);
|
||||
tabTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm);
|
||||
|
||||
// get system attrs (android:textSize and android:textColor)
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
|
||||
|
||||
tabTextSize = a.getDimensionPixelSize(0, tabTextSize);
|
||||
tabTextColor = a.getColor(1, tabTextColor);
|
||||
|
||||
a.recycle();
|
||||
|
||||
// get custom attrs
|
||||
|
||||
a = context.obtainStyledAttributes(attrs, R.styleable.PagerSlidingTabStrip);
|
||||
|
||||
indicatorColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, indicatorColor);
|
||||
underlineColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsUnderlineColor, underlineColor);
|
||||
dividerColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsDividerColor, dividerColor);
|
||||
indicatorHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsIndicatorHeight, indicatorHeight);
|
||||
underlineHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsUnderlineHeight, underlineHeight);
|
||||
dividerPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsDividerPadding, dividerPadding);
|
||||
tabPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTabPaddingLeftRight, tabPadding);
|
||||
tabBackgroundResId = a.getResourceId(R.styleable.PagerSlidingTabStrip_pstsTabBackground, tabBackgroundResId);
|
||||
shouldExpand = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsShouldExpand, shouldExpand);
|
||||
scrollOffset = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsScrollOffset, scrollOffset);
|
||||
textAllCaps = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsTextAllCaps, textAllCaps);
|
||||
|
||||
a.recycle();
|
||||
|
||||
rectPaint = new Paint();
|
||||
rectPaint.setAntiAlias(true);
|
||||
rectPaint.setStyle(Style.FILL);
|
||||
|
||||
dividerPaint = new Paint();
|
||||
dividerPaint.setAntiAlias(true);
|
||||
dividerPaint.setStrokeWidth(dividerWidth);
|
||||
|
||||
defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
expandedTabLayoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f);
|
||||
|
||||
if (locale == null) {
|
||||
locale = getResources().getConfiguration().locale;
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewPager(ViewPager pager) {
|
||||
this.pager = pager;
|
||||
|
||||
if (pager.getAdapter() == null) {
|
||||
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||
}
|
||||
|
||||
pager.setOnPageChangeListener(pageListener);
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setOnPageChangeListener(OnPageChangeListener listener) {
|
||||
this.delegatePageListener = listener;
|
||||
}
|
||||
|
||||
public void notifyDataSetChanged() {
|
||||
|
||||
tabsContainer.removeAllViews();
|
||||
|
||||
tabCount = pager.getAdapter().getCount();
|
||||
|
||||
for (int i = 0; i < tabCount; i++) {
|
||||
|
||||
if (pager.getAdapter() instanceof IconTabProvider) {
|
||||
addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconResId(i));
|
||||
} else {
|
||||
addTextTab(i, pager.getAdapter().getPageTitle(i).toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
updateTabStyles();
|
||||
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||
getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
} else {
|
||||
getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
|
||||
currentPosition = pager.getCurrentItem();
|
||||
scrollToChild(currentPosition, 0);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void addTextTab(final int position, String title) {
|
||||
|
||||
TextView tab = new TextView(getContext());
|
||||
tab.setText(title);
|
||||
tab.setGravity(Gravity.CENTER);
|
||||
tab.setSingleLine();
|
||||
|
||||
addTab(position, tab);
|
||||
}
|
||||
|
||||
private void addIconTab(final int position, int resId) {
|
||||
|
||||
ImageButton tab = new ImageButton(getContext());
|
||||
tab.setImageResource(resId);
|
||||
|
||||
addTab(position, tab);
|
||||
|
||||
}
|
||||
|
||||
private void addTab(final int position, View tab) {
|
||||
tab.setFocusable(true);
|
||||
tab.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
pager.setCurrentItem(position);
|
||||
}
|
||||
});
|
||||
|
||||
tab.setPadding(tabPadding, 0, tabPadding, 0);
|
||||
tabsContainer.addView(tab, position, shouldExpand ? expandedTabLayoutParams : defaultTabLayoutParams);
|
||||
}
|
||||
|
||||
private void updateTabStyles() {
|
||||
|
||||
for (int i = 0; i < tabCount; i++) {
|
||||
|
||||
View v = tabsContainer.getChildAt(i);
|
||||
|
||||
v.setBackgroundResource(tabBackgroundResId);
|
||||
|
||||
if (v instanceof TextView) {
|
||||
|
||||
TextView tab = (TextView) v;
|
||||
tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSize);
|
||||
tab.setTypeface(tabTypeface, tabTypefaceStyle);
|
||||
tab.setTextColor(tabTextColor);
|
||||
|
||||
// setAllCaps() is only available from API 14, so the upper case is made manually if we are on a
|
||||
// pre-ICS-build
|
||||
if (textAllCaps) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
tab.setAllCaps(true);
|
||||
} else {
|
||||
tab.setText(tab.getText().toString().toUpperCase(locale));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void scrollToChild(int position, int offset) {
|
||||
|
||||
if (tabCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int newScrollX = tabsContainer.getChildAt(position).getLeft() + offset;
|
||||
|
||||
if (position > 0 || offset > 0) {
|
||||
newScrollX -= scrollOffset;
|
||||
}
|
||||
|
||||
if (newScrollX != lastScrollX) {
|
||||
lastScrollX = newScrollX;
|
||||
scrollTo(newScrollX, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (isInEditMode() || tabCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int height = getHeight();
|
||||
|
||||
// draw indicator line
|
||||
|
||||
rectPaint.setColor(indicatorColor);
|
||||
|
||||
// default: line below current tab
|
||||
View currentTab = tabsContainer.getChildAt(currentPosition);
|
||||
float lineLeft = currentTab.getLeft();
|
||||
float lineRight = currentTab.getRight();
|
||||
|
||||
// if there is an offset, start interpolating left and right coordinates between current and next tab
|
||||
if (currentPositionOffset > 0f && currentPosition < tabCount - 1) {
|
||||
|
||||
View nextTab = tabsContainer.getChildAt(currentPosition + 1);
|
||||
final float nextTabLeft = nextTab.getLeft();
|
||||
final float nextTabRight = nextTab.getRight();
|
||||
|
||||
lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft);
|
||||
lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight);
|
||||
}
|
||||
|
||||
canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint);
|
||||
|
||||
// draw underline
|
||||
|
||||
rectPaint.setColor(underlineColor);
|
||||
canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);
|
||||
|
||||
// draw divider
|
||||
|
||||
dividerPaint.setColor(dividerColor);
|
||||
for (int i = 0; i < tabCount - 1; i++) {
|
||||
View tab = tabsContainer.getChildAt(i);
|
||||
canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private class PageListener implements OnPageChangeListener {
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
|
||||
currentPosition = position;
|
||||
currentPositionOffset = positionOffset;
|
||||
|
||||
scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));
|
||||
|
||||
invalidate();
|
||||
|
||||
if (delegatePageListener != null) {
|
||||
delegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
if (state == ViewPager.SCROLL_STATE_IDLE) {
|
||||
scrollToChild(pager.getCurrentItem(), 0);
|
||||
}
|
||||
|
||||
if (delegatePageListener != null) {
|
||||
delegatePageListener.onPageScrollStateChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
if (delegatePageListener != null) {
|
||||
delegatePageListener.onPageSelected(position);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setIndicatorColor(int indicatorColor) {
|
||||
this.indicatorColor = indicatorColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorColorResource(int resId) {
|
||||
this.indicatorColor = getResources().getColor(resId);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getIndicatorColor() {
|
||||
return this.indicatorColor;
|
||||
}
|
||||
|
||||
public void setIndicatorHeight(int indicatorLineHeightPx) {
|
||||
this.indicatorHeight = indicatorLineHeightPx;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getIndicatorHeight() {
|
||||
return indicatorHeight;
|
||||
}
|
||||
|
||||
public void setUnderlineColor(int underlineColor) {
|
||||
this.underlineColor = underlineColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineColorResource(int resId) {
|
||||
this.underlineColor = getResources().getColor(resId);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getUnderlineColor() {
|
||||
return underlineColor;
|
||||
}
|
||||
|
||||
public void setDividerColor(int dividerColor) {
|
||||
this.dividerColor = dividerColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerColorResource(int resId) {
|
||||
this.dividerColor = getResources().getColor(resId);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getDividerColor() {
|
||||
return dividerColor;
|
||||
}
|
||||
|
||||
public void setUnderlineHeight(int underlineHeightPx) {
|
||||
this.underlineHeight = underlineHeightPx;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getUnderlineHeight() {
|
||||
return underlineHeight;
|
||||
}
|
||||
|
||||
public void setDividerPadding(int dividerPaddingPx) {
|
||||
this.dividerPadding = dividerPaddingPx;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getDividerPadding() {
|
||||
return dividerPadding;
|
||||
}
|
||||
|
||||
public void setScrollOffset(int scrollOffsetPx) {
|
||||
this.scrollOffset = scrollOffsetPx;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getScrollOffset() {
|
||||
return scrollOffset;
|
||||
}
|
||||
|
||||
public void setShouldExpand(boolean shouldExpand) {
|
||||
this.shouldExpand = shouldExpand;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public boolean getShouldExpand() {
|
||||
return shouldExpand;
|
||||
}
|
||||
|
||||
public boolean isTextAllCaps() {
|
||||
return textAllCaps;
|
||||
}
|
||||
|
||||
public void setAllCaps(boolean textAllCaps) {
|
||||
this.textAllCaps = textAllCaps;
|
||||
}
|
||||
|
||||
public void setTextSize(int textSizePx) {
|
||||
this.tabTextSize = textSizePx;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public int getTextSize() {
|
||||
return tabTextSize;
|
||||
}
|
||||
|
||||
public void setTextColor(int textColor) {
|
||||
this.tabTextColor = textColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextColorResource(int resId) {
|
||||
this.tabTextColor = getResources().getColor(resId);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public int getTextColor() {
|
||||
return tabTextColor;
|
||||
}
|
||||
|
||||
public void setTypeface(Typeface typeface, int style) {
|
||||
this.tabTypeface = typeface;
|
||||
this.tabTypefaceStyle = style;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabBackground(int resId) {
|
||||
this.tabBackgroundResId = resId;
|
||||
}
|
||||
|
||||
public int getTabBackground() {
|
||||
return tabBackgroundResId;
|
||||
}
|
||||
|
||||
public void setTabPaddingLeftRight(int paddingPx) {
|
||||
this.tabPadding = paddingPx;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public int getTabPaddingLeftRight() {
|
||||
return tabPadding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState savedState = (SavedState) state;
|
||||
super.onRestoreInstanceState(savedState.getSuperState());
|
||||
currentPosition = savedState.currentPosition;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
SavedState savedState = new SavedState(superState);
|
||||
savedState.currentPosition = currentPosition;
|
||||
return savedState;
|
||||
}
|
||||
|
||||
static class SavedState extends BaseSavedState {
|
||||
int currentPosition;
|
||||
|
||||
public SavedState(Parcelable superState) {
|
||||
super(superState);
|
||||
}
|
||||
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
currentPosition = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(currentPosition);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
|
||||
@Override
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
324
src/com/example/android/common/view/SlidingTabLayout.java
Normal file
324
src/com/example/android/common/view/SlidingTabLayout.java
Normal file
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.common.view;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* To be used with ViewPager to provide a tab indicator component which give constant feedback as to
|
||||
* the user's scroll progress.
|
||||
* <p>
|
||||
* To use the component, simply add it to your view hierarchy. Then in your
|
||||
* {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
|
||||
* {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
|
||||
* <p>
|
||||
* The colors can be customized in two ways. The first and simplest is to provide an array of colors
|
||||
* via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
|
||||
* alternative is via the {@link TabColorizer} interface which provides you complete control over
|
||||
* which color is used for any individual position.
|
||||
* <p>
|
||||
* The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
|
||||
* providing the layout ID of your custom layout.
|
||||
*/
|
||||
public class SlidingTabLayout extends HorizontalScrollView {
|
||||
|
||||
/**
|
||||
* Allows complete control over the colors drawn in the tab layout. Set with
|
||||
* {@link #setCustomTabColorizer(TabColorizer)}.
|
||||
*/
|
||||
public interface TabColorizer {
|
||||
|
||||
/**
|
||||
* @return return the color of the indicator used when {@code position} is selected.
|
||||
*/
|
||||
int getIndicatorColor(int position);
|
||||
|
||||
/**
|
||||
* @return return the color of the divider drawn to the right of {@code position}.
|
||||
*/
|
||||
int getDividerColor(int position);
|
||||
|
||||
}
|
||||
|
||||
private static final int TITLE_OFFSET_DIPS = 24;
|
||||
private static final int TAB_VIEW_HORIZONTAL_PADDING_DIPS = 24;
|
||||
private static final int TAB_VIEW_VERTICAL_PADDING_DIPS = 16;
|
||||
private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
|
||||
|
||||
private int mTitleOffset;
|
||||
|
||||
private int mTabViewLayoutId;
|
||||
private int mTabViewTextViewId;
|
||||
|
||||
private ViewPager mViewPager;
|
||||
private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
|
||||
|
||||
private final SlidingTabStrip mTabStrip;
|
||||
|
||||
public SlidingTabLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SlidingTabLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
// Disable the Scroll Bar
|
||||
setHorizontalScrollBarEnabled(false);
|
||||
// Make sure that the Tab Strips fills this View
|
||||
setFillViewport(true);
|
||||
|
||||
mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
|
||||
|
||||
mTabStrip = new SlidingTabStrip(context);
|
||||
addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the custom {@link TabColorizer} to be used.
|
||||
*
|
||||
* If you only require simple custmisation then you can use
|
||||
* {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
|
||||
* similar effects.
|
||||
*/
|
||||
public void setCustomTabColorizer(TabColorizer tabColorizer) {
|
||||
mTabStrip.setCustomTabColorizer(tabColorizer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the colors to be used for indicating the selected tab. These colors are treated as a
|
||||
* circular array. Providing one color will mean that all tabs are indicated with the same
|
||||
* color.
|
||||
*/
|
||||
public void setSelectedIndicatorColors(int... colors) {
|
||||
mTabStrip.setSelectedIndicatorColors(colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the colors to be used for tab dividers. These colors are treated as a circular array.
|
||||
* Providing one color will mean that all tabs are indicated with the same color.
|
||||
*/
|
||||
public void setDividerColors(int... colors) {
|
||||
mTabStrip.setDividerColors(colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
|
||||
* required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
|
||||
* that the layout can update it's scroll position correctly.
|
||||
*
|
||||
* @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
|
||||
*/
|
||||
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
|
||||
mViewPagerPageChangeListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the custom layout to be inflated for the tab views.
|
||||
*
|
||||
* @param layoutResId
|
||||
* Layout id to be inflated
|
||||
* @param textViewId
|
||||
* id of the {@link TextView} in the inflated view
|
||||
*/
|
||||
public void setCustomTabView(int layoutResId, int textViewId) {
|
||||
mTabViewLayoutId = layoutResId;
|
||||
mTabViewTextViewId = textViewId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the associated view pager. Note that the assumption here is that the pager content
|
||||
* (number of tabs and tab titles) does not change after this call has been made.
|
||||
*/
|
||||
public void setViewPager(ViewPager viewPager) {
|
||||
mTabStrip.removeAllViews();
|
||||
|
||||
mViewPager = viewPager;
|
||||
if (viewPager != null) {
|
||||
viewPager.setOnPageChangeListener(new InternalViewPagerListener());
|
||||
populateTabStrip();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a default view to be used for tabs. This is called if a custom tab view is not set via
|
||||
* {@link #setCustomTabView(int, int)}.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
protected TextView createDefaultTabView(Context context) {
|
||||
TextView textView = new TextView(context);
|
||||
textView.setGravity(Gravity.CENTER);
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
|
||||
textView.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
// If we're running on Honeycomb or newer, then we can use the Theme's
|
||||
// selectableItemBackground to ensure that the View has a pressed state
|
||||
TypedValue outValue = new TypedValue();
|
||||
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
|
||||
textView.setBackgroundResource(outValue.resourceId);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
// If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
|
||||
textView.setAllCaps(true);
|
||||
}
|
||||
|
||||
float density = getResources().getDisplayMetrics().density;
|
||||
int horizontalPadding = (int) (TAB_VIEW_HORIZONTAL_PADDING_DIPS * density);
|
||||
int verticalPadding = (int) (TAB_VIEW_VERTICAL_PADDING_DIPS * density);
|
||||
textView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
||||
|
||||
return textView;
|
||||
}
|
||||
|
||||
private void populateTabStrip() {
|
||||
final PagerAdapter adapter = mViewPager.getAdapter();
|
||||
final View.OnClickListener tabClickListener = new TabClickListener();
|
||||
|
||||
for (int i = 0; i < adapter.getCount(); i++) {
|
||||
View tabView = null;
|
||||
TextView tabTitleView = null;
|
||||
|
||||
if (mTabViewLayoutId != 0) {
|
||||
// If there is a custom tab view layout id set, try and inflate it
|
||||
tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip, false);
|
||||
tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
|
||||
}
|
||||
|
||||
if (tabView == null) {
|
||||
tabView = createDefaultTabView(getContext());
|
||||
}
|
||||
|
||||
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
|
||||
tabTitleView = (TextView) tabView;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
tabTitleView.setText(adapter.getPageTitle(i));
|
||||
} else {
|
||||
// Emulate allCaps
|
||||
tabTitleView.setText(adapter.getPageTitle(i).toString().toUpperCase(Locale.getDefault()));
|
||||
}
|
||||
tabView.setOnClickListener(tabClickListener);
|
||||
|
||||
mTabStrip.addView(tabView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
if (mViewPager != null) {
|
||||
scrollToTab(mViewPager.getCurrentItem(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void scrollToTab(int tabIndex, int positionOffset) {
|
||||
final int tabStripChildCount = mTabStrip.getChildCount();
|
||||
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
View selectedChild = mTabStrip.getChildAt(tabIndex);
|
||||
if (selectedChild != null) {
|
||||
int targetScrollX = selectedChild.getLeft() + positionOffset;
|
||||
|
||||
if (tabIndex > 0 || positionOffset > 0) {
|
||||
// If we're not at the first child and are mid-scroll, make sure we obey the offset
|
||||
targetScrollX -= mTitleOffset;
|
||||
}
|
||||
|
||||
scrollTo(targetScrollX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
|
||||
private int mScrollState;
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
int tabStripChildCount = mTabStrip.getChildCount();
|
||||
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTabStrip.onViewPagerPageChanged(position, positionOffset);
|
||||
|
||||
View selectedTitle = mTabStrip.getChildAt(position);
|
||||
int extraOffset = (selectedTitle != null) ? (int) (positionOffset * selectedTitle.getWidth()) : 0;
|
||||
scrollToTab(position, extraOffset);
|
||||
|
||||
if (mViewPagerPageChangeListener != null) {
|
||||
mViewPagerPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
mScrollState = state;
|
||||
|
||||
if (mViewPagerPageChangeListener != null) {
|
||||
mViewPagerPageChangeListener.onPageScrollStateChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
|
||||
mTabStrip.onViewPagerPageChanged(position, 0f);
|
||||
scrollToTab(position, 0);
|
||||
}
|
||||
|
||||
if (mViewPagerPageChangeListener != null) {
|
||||
mViewPagerPageChangeListener.onPageSelected(position);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class TabClickListener implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
|
||||
if (v == mTabStrip.getChildAt(i)) {
|
||||
mViewPager.setCurrentItem(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
200
src/com/example/android/common/view/SlidingTabStrip.java
Normal file
200
src/com/example/android/common/view/SlidingTabStrip.java
Normal file
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.common.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
class SlidingTabStrip extends LinearLayout {
|
||||
|
||||
private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
|
||||
private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
|
||||
private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
|
||||
private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
|
||||
|
||||
private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
|
||||
private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
|
||||
private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
|
||||
|
||||
private final int mBottomBorderThickness;
|
||||
private final Paint mBottomBorderPaint;
|
||||
|
||||
private final int mSelectedIndicatorThickness;
|
||||
private final Paint mSelectedIndicatorPaint;
|
||||
|
||||
private final int mDefaultBottomBorderColor;
|
||||
|
||||
private final Paint mDividerPaint;
|
||||
private final float mDividerHeight;
|
||||
|
||||
private int mSelectedPosition;
|
||||
private float mSelectionOffset;
|
||||
|
||||
private SlidingTabLayout.TabColorizer mCustomTabColorizer;
|
||||
private final SimpleTabColorizer mDefaultTabColorizer;
|
||||
|
||||
SlidingTabStrip(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
SlidingTabStrip(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setWillNotDraw(false);
|
||||
|
||||
final float density = getResources().getDisplayMetrics().density;
|
||||
|
||||
TypedValue outValue = new TypedValue();
|
||||
context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true);
|
||||
final int themeForegroundColor = outValue.data;
|
||||
|
||||
mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor, DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
|
||||
|
||||
mDefaultTabColorizer = new SimpleTabColorizer();
|
||||
mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
|
||||
mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor, DEFAULT_DIVIDER_COLOR_ALPHA));
|
||||
|
||||
mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
|
||||
mBottomBorderPaint = new Paint();
|
||||
mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
|
||||
|
||||
mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
|
||||
mSelectedIndicatorPaint = new Paint();
|
||||
|
||||
mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
|
||||
mDividerPaint = new Paint();
|
||||
mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
|
||||
}
|
||||
|
||||
void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
|
||||
mCustomTabColorizer = customTabColorizer;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void setSelectedIndicatorColors(int... colors) {
|
||||
// Make sure that the custom colorizer is removed
|
||||
mCustomTabColorizer = null;
|
||||
mDefaultTabColorizer.setIndicatorColors(colors);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void setDividerColors(int... colors) {
|
||||
// Make sure that the custom colorizer is removed
|
||||
mCustomTabColorizer = null;
|
||||
mDefaultTabColorizer.setDividerColors(colors);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void onViewPagerPageChanged(int position, float positionOffset) {
|
||||
mSelectedPosition = position;
|
||||
mSelectionOffset = positionOffset;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
final int height = getHeight();
|
||||
final int childCount = getChildCount();
|
||||
final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
|
||||
final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null ? mCustomTabColorizer : mDefaultTabColorizer;
|
||||
|
||||
// Thick colored underline below the current selection
|
||||
if (childCount > 0) {
|
||||
View selectedTitle = getChildAt(mSelectedPosition);
|
||||
int left = selectedTitle.getLeft();
|
||||
int right = selectedTitle.getRight();
|
||||
int color = tabColorizer.getIndicatorColor(mSelectedPosition);
|
||||
|
||||
if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
|
||||
int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
|
||||
if (color != nextColor) {
|
||||
color = blendColors(nextColor, color, mSelectionOffset);
|
||||
}
|
||||
|
||||
// Draw the selection partway between the tabs
|
||||
View nextTitle = getChildAt(mSelectedPosition + 1);
|
||||
left = (int) (mSelectionOffset * nextTitle.getLeft() + (1.0f - mSelectionOffset) * left);
|
||||
right = (int) (mSelectionOffset * nextTitle.getRight() + (1.0f - mSelectionOffset) * right);
|
||||
}
|
||||
|
||||
mSelectedIndicatorPaint.setColor(color);
|
||||
|
||||
canvas.drawRect(left, height - mSelectedIndicatorThickness, right, height, mSelectedIndicatorPaint);
|
||||
}
|
||||
|
||||
// Thin underline along the entire bottom edge
|
||||
canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
|
||||
|
||||
// Vertical separators between the titles
|
||||
int separatorTop = (height - dividerHeightPx) / 2;
|
||||
for (int i = 0; i < childCount - 1; i++) {
|
||||
View child = getChildAt(i);
|
||||
mDividerPaint.setColor(tabColorizer.getDividerColor(i));
|
||||
canvas.drawLine(child.getRight(), separatorTop, child.getRight(), separatorTop + dividerHeightPx, mDividerPaint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the alpha value of the {@code color} to be the given {@code alpha} value.
|
||||
*/
|
||||
private static int setColorAlpha(int color, byte alpha) {
|
||||
return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
|
||||
}
|
||||
|
||||
/**
|
||||
* Blend {@code color1} and {@code color2} using the given ratio.
|
||||
*
|
||||
* @param ratio
|
||||
* of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
|
||||
* 0.0 will return {@code color2}.
|
||||
*/
|
||||
private static int blendColors(int color1, int color2, float ratio) {
|
||||
final float inverseRation = 1f - ratio;
|
||||
float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
|
||||
float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
|
||||
float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
|
||||
return Color.rgb((int) r, (int) g, (int) b);
|
||||
}
|
||||
|
||||
private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
|
||||
private int[] mIndicatorColors;
|
||||
private int[] mDividerColors;
|
||||
|
||||
@Override
|
||||
public final int getIndicatorColor(int position) {
|
||||
return mIndicatorColors[position % mIndicatorColors.length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getDividerColor(int position) {
|
||||
return mDividerColors[position % mDividerColors.length];
|
||||
}
|
||||
|
||||
void setIndicatorColors(int... colors) {
|
||||
mIndicatorColors = colors;
|
||||
}
|
||||
|
||||
void setDividerColors(int... colors) {
|
||||
mDividerColors = colors;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue