diff options
12 files changed, 548 insertions, 294 deletions
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/HorizontalTabView.java b/WordPress/src/main/java/org/wordpress/android/ui/HorizontalTabView.java deleted file mode 100644 index 9791c28f3..000000000 --- a/WordPress/src/main/java/org/wordpress/android/ui/HorizontalTabView.java +++ /dev/null @@ -1,244 +0,0 @@ -package org.wordpress.android.ui; - -import java.util.ArrayList; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Paint; -import android.graphics.Typeface; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.HorizontalScrollView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import org.wordpress.android.R; -import org.wordpress.android.util.BlogUtils; -import org.wordpress.android.util.DisplayUtils; - -/** - * A view that mimics the action bar tabs. It can be placed anywhere and appears - * under the sliding menu, unlike the action bar tabs - */ - -public class HorizontalTabView extends HorizontalScrollView implements OnClickListener { - private static final String TAG_PREFIX = "tab:"; - private ArrayList<Tab> mTabs; - private ArrayList<TextView> mTextViews; - private LinearLayout mTabContainer; - private float mMaxTabWidth = 0f; - private TabListener mTabListener; - private boolean mEnableScroll = true; - private LinearLayout mSelectedLayout; - - public HorizontalTabView(Context context) { - super(context); - init(); - } - public HorizontalTabView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - public HorizontalTabView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - - private void init() { - mTabs = new ArrayList<Tab>(); - mTextViews = new ArrayList<TextView>(); - - setupBackground(); - setupTabContainer(); - } - - private void setupBackground() { - setBackgroundColor(getResources().getColor(R.color.tab_background)); - } - - private void setupTabContainer() { - mTabContainer = new LinearLayout(getContext()); - HorizontalScrollView.LayoutParams linearLayoutParams = - new HorizontalScrollView.LayoutParams(HorizontalScrollView.LayoutParams.WRAP_CONTENT, HorizontalScrollView.LayoutParams.WRAP_CONTENT); - mTabContainer.setLayoutParams(linearLayoutParams); - mTabContainer.setOrientation(LinearLayout.HORIZONTAL); - - addView(mTabContainer); - - } - public Tab newTab() { - return new Tab(); - } - - public void addTab(Tab tab) { - tab.setPosition(mTabs.size()); - mTabs.add(tab); - - Context context = getContext(); - - int divWidth = DisplayUtils.dpToPx(context, 1); - int divTopMargin = DisplayUtils.dpToPx(context, 12); - int divHeight = DisplayUtils.dpToPx(context, 24); - - int tabPad = DisplayUtils.dpToPx(context, 16); - - int fontSizeSp = 12; - - // add dividers in the middle - not using divider property as it is API 11 - if (mTextViews.size() > 0) { - View divider = new View(getContext()); - LinearLayout.LayoutParams separatorParams = new LinearLayout.LayoutParams(divWidth, divHeight); - separatorParams.topMargin = divTopMargin; - divider.setLayoutParams(separatorParams); - divider.setBackgroundColor(getResources().getColor(R.color.tab_divider)); - mTabContainer.addView(divider); - } - - TextView textView = new TextView(getContext()); - LinearLayout.LayoutParams textViewParams = - new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); - textView.setLayoutParams(textViewParams); - textView.setGravity(Gravity.CENTER); - textView.setText(tab.getText()); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSizeSp); - textView.setTextColor(getResources().getColor(R.color.tab_text)); - textView.setTypeface(null, Typeface.BOLD); - - mTextViews.add(textView); - - LinearLayout linearLayout = new LinearLayout(getContext()); - LinearLayout.LayoutParams linearLayoutParams = - new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1); - linearLayout.setLayoutParams(linearLayoutParams); - linearLayout.addView(textView); - linearLayout.setTag(TAG_PREFIX + (mTabs.size()-1)); - linearLayout.setOnClickListener(this); - linearLayout.setBackgroundResource(R.drawable.tab_indicator_ab_wordpress); - linearLayout.setPadding(tabPad, tabPad, tabPad, tabPad); - - mTabContainer.addView(linearLayout); - - recomputeTabWidths(); - } - - /** Make the tabs have the same widths, where this width is based on the longest tab title **/ - private void recomputeTabWidths() { - // Determine the max width - for(TextView textView : mTextViews) { - Paint paint = textView.getPaint(); - float width = paint.measureText(textView.getText().toString()); - if (mMaxTabWidth < width) - mMaxTabWidth = width; - } - - // Set the tabs to use the max width - for(TextView textView : mTextViews) { - LinearLayout.LayoutParams textViewParams = - new LinearLayout.LayoutParams((int) mMaxTabWidth, LinearLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER); - textView.setLayoutParams(textViewParams); - } - - } - - public class Tab { - private String mText; - private int mPosition; - - @SuppressLint("DefaultLocale") - public CharSequence getText() { - return mText.toUpperCase(); - } - - public Tab setText(CharSequence pageTitle) { - mText = pageTitle.toString(); - return this; - } - - public int getPosition() { - return mPosition; - } - - public void setPosition(int position) { - this.mPosition = position; - } - } - - public interface TabListener { - public void onTabSelected(Tab tab); - } - - public TabListener getTabListener() { - return mTabListener; - } - - public void setTabListener(TabListener tabListener) { - this.mTabListener = tabListener; - } - - @Override - public void onClick(View v) { - if (v instanceof LinearLayout) { - LinearLayout layout = (LinearLayout) v; - - String tag = (String) layout.getTag(); - int position = Integer.valueOf(tag.substring(TAG_PREFIX.length())); - - // It is necessary to disable scrolling upon click before informing the listener - // because I've found that if setSelectedTab() was called in the listener implementation, - // and that setSelectedTab() is called again after onTabSelected(), it does not smooth scroll. - - // The call to setSelectedTab() in this method is necessary because if there was no listener or if - // it did not call setSelectedTab(), then it would appear as if nothing happened. - - mEnableScroll = false; - - if (mTabListener != null) - mTabListener.onTabSelected(mTabs.get(position)); - - mEnableScroll = true; - - setSelectedTab(position); - } - } - - public void setSelectedTab(int position) { - if (position >= mTextViews.size()) - return; - - if (mEnableScroll) { - scrollToTab(position); - setSelectedLayout(getTabParent(position)); - } - } - - public void setTabText(int position, String text) { - mTabs.get(position).mText = text; - mTextViews.get(position).setText(text); - } - - private void scrollToTab(int position) { - int tabWidth = getTabParent(position).getWidth(); - int parentWidth = ((View) this.getParent()).getWidth(); - - int offset = parentWidth / 2 - tabWidth / 2; - - smoothScrollTo(tabWidth * position - offset, 0); - } - - private LinearLayout getTabParent(int position) { - View tab = mTextViews.get(position); - return (LinearLayout) tab.getParent(); - } - - private void setSelectedLayout(LinearLayout layout) { - if (mSelectedLayout != null) { - mSelectedLayout.setSelected(false); - } - - mSelectedLayout = (LinearLayout)layout; - mSelectedLayout.setSelected(true); - } -}
\ No newline at end of file diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderSubsActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderSubsActivity.java index eeaec61b8..61c840d26 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderSubsActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderSubsActivity.java @@ -103,8 +103,8 @@ public class ReaderSubsActivity extends ActionBarActivity getSupportActionBar().setDisplayHomeAsUpEnabled(true); PagerTabStrip tabStrip = (PagerTabStrip) findViewById(R.id.pager_tabs); - tabStrip.setTabIndicatorColorResource(R.color.blue_light); - tabStrip.setBackgroundColor(getResources().getColor(R.color.color_primary)); + tabStrip.setTabIndicatorColorResource(R.color.tab_indicator); + tabStrip.setTextColor(getResources().getColor(R.color.tab_text_selected)); mEditAdd = (EditText) findViewById(R.id.edit_add); mEditAdd.setOnEditorActionListener(new TextView.OnEditorActionListener() { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/themes/ThemeBrowserActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/themes/ThemeBrowserActivity.java index c33f99ecc..5e79945af 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/themes/ThemeBrowserActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/themes/ThemeBrowserActivity.java @@ -25,9 +25,8 @@ import org.json.JSONException; import org.json.JSONObject; import org.wordpress.android.R; import org.wordpress.android.WordPress; +import org.wordpress.android.analytics.AnalyticsTracker; import org.wordpress.android.models.Theme; -import org.wordpress.android.ui.HorizontalTabView; -import org.wordpress.android.ui.HorizontalTabView.TabListener; import org.wordpress.android.ui.WPDrawerActivity; import org.wordpress.android.ui.posts.PostsActivity; import org.wordpress.android.ui.themes.ThemeDetailsFragment.ThemeDetailsFragmentCallback; @@ -38,8 +37,8 @@ import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.DisplayUtils; import org.wordpress.android.util.NetworkUtils; +import org.wordpress.android.widgets.SlidingTabLayout; import org.wordpress.android.widgets.WPAlertDialogFragment; -import org.wordpress.android.analytics.AnalyticsTracker; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -48,11 +47,11 @@ import java.util.ArrayList; * The theme browser. Accessible via side menu drawer. */ public class ThemeBrowserActivity extends WPDrawerActivity implements - ThemeTabFragmentCallback, ThemeDetailsFragmentCallback, ThemePreviewFragmentCallback, - TabListener { - private HorizontalTabView mTabView; + ThemeTabFragmentCallback, ThemeDetailsFragmentCallback, ThemePreviewFragmentCallback { + private ThemePagerAdapter mThemePagerAdapter; private ViewPager mViewPager; + private SlidingTabLayout mTabLayout; private ThemeSearchFragment mSearchFragment; private ThemePreviewFragment mPreviewFragment; private ThemeDetailsFragment mDetailsFragment; @@ -91,23 +90,12 @@ public class ThemeBrowserActivity extends WPDrawerActivity implements mViewPager = (ViewPager) findViewById(R.id.theme_browser_pager); mViewPager.setAdapter(mThemePagerAdapter); - mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { - @Override - public void onPageSelected(int position) { - mTabView.setSelectedTab(position); - } - }); - - mTabView = (HorizontalTabView) findViewById(R.id.horizontalTabView1); - mTabView.setTabListener(this); - int count = ThemeSortType.values().length; - for (int i = 0; i < count; i++) { - String title = ThemeSortType.values()[i].getTitle(); - - mTabView.addTab(mTabView.newTab().setText(title)); - } - mTabView.setSelectedTab(0); + mTabLayout = (SlidingTabLayout) findViewById(R.id.sliding_tabs); + mTabLayout.setCustomTabView(R.layout.tab_text, R.id.text_tab); + mTabLayout.setSelectedIndicatorColors(getResources().getColor(R.color.tab_indicator)); + mTabLayout.setDistributeEvenly(true); + mTabLayout.setViewPager(mViewPager); FragmentManager fm = getFragmentManager(); fm.addOnBackStackChangedListener(mOnBackStackChangedListener); @@ -138,10 +126,10 @@ public class ThemeBrowserActivity extends WPDrawerActivity implements int backstackCount = getFragmentManager().getBackStackEntryCount(); if (backstackCount == 0) { mViewPager.setVisibility(View.VISIBLE); - mTabView.setVisibility(View.VISIBLE); + mTabLayout.setVisibility(View.VISIBLE); } else { mViewPager.setVisibility(View.GONE); - mTabView.setVisibility(View.GONE); + mTabLayout.setVisibility(View.GONE); } if (getDrawerToggle() != null) { @@ -164,11 +152,6 @@ public class ThemeBrowserActivity extends WPDrawerActivity implements } } - @Override - public void onTabSelected(HorizontalTabView.Tab tab) { - mViewPager.setCurrentItem(tab.getPosition()); - } - public class ThemePagerAdapter extends FragmentStatePagerAdapter { ThemeTabFragment[] mTabFragment = new ThemeTabFragment[ThemeSortType.values().length]; diff --git a/WordPress/src/main/java/org/wordpress/android/widgets/SlidingTabLayout.java b/WordPress/src/main/java/org/wordpress/android/widgets/SlidingTabLayout.java new file mode 100644 index 000000000..fa675dcd9 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/widgets/SlidingTabLayout.java @@ -0,0 +1,325 @@ +/* +<<<<<<< Updated upstream + * Copyright (C) 2013 The Android Open Source Project +======= + * Copyright 2014 Google Inc. All rights reserved. +>>>>>>> Stashed changes + * + * 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 org.wordpress.android.widgets; + +import android.content.Context; +import android.graphics.Typeface; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +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...)}. 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); + + } + + private static final int TITLE_OFFSET_DIPS = 24; + private static final int TAB_VIEW_PADDING_DIPS = 16; + private static final int TAB_VIEW_TEXT_SIZE_SP = 12; + + private int mTitleOffset; + + private int mTabViewLayoutId; + private int mTabViewTextViewId; + private boolean mDistributeEvenly; + + private ViewPager mViewPager; + private SparseArray<String> mContentDescriptions = new SparseArray<String>(); + 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...)} to achieve + * similar effects. + */ + public void setCustomTabColorizer(TabColorizer tabColorizer) { + mTabStrip.setCustomTabColorizer(tabColorizer); + } + + public void setDistributeEvenly(boolean distributeEvenly) { + mDistributeEvenly = distributeEvenly; + } + + /** + * 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); + } + + /** + * 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)}. + */ + 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); + textView.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + TypedValue outValue = new TypedValue(); + getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, + outValue, true); + textView.setBackgroundResource(outValue.resourceId); + textView.setAllCaps(true); + + int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density); + textView.setPadding(padding, padding, padding, padding); + + 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 (mDistributeEvenly) { + LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams(); + lp.width = 0; + lp.weight = 1; + } + + tabTitleView.setText(adapter.getPageTitle(i)); + tabView.setOnClickListener(tabClickListener); + String desc = mContentDescriptions.get(i, null); + if (desc != null) { + tabView.setContentDescription(desc); + } + + mTabStrip.addView(tabView); + if (i == mViewPager.getCurrentItem()) { + tabView.setSelected(true); + } + } + } + + public void setContentDescription(int i, String desc) { + mContentDescriptions.put(i, desc); + } + + @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); + } + for (int i = 0; i < mTabStrip.getChildCount(); i++) { + mTabStrip.getChildAt(i).setSelected(position == i); + } + 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; + } + } + } + } + +} diff --git a/WordPress/src/main/java/org/wordpress/android/widgets/SlidingTabStrip.java b/WordPress/src/main/java/org/wordpress/android/widgets/SlidingTabStrip.java new file mode 100644 index 000000000..a082065c2 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/widgets/SlidingTabStrip.java @@ -0,0 +1,171 @@ +/* +<<<<<<< Updated upstream + * Copyright (C) 2013 The Android Open Source Project +======= + * Copyright 2014 Google Inc. All rights reserved. +>>>>>>> Stashed changes + * + * 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 org.wordpress.android.widgets; +import android.R; +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 = 0; + private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; + private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 3; + private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5; + + private final int mBottomBorderThickness; + private final Paint mBottomBorderPaint; + + private final int mSelectedIndicatorThickness; + private final Paint mSelectedIndicatorPaint; + + private final int mDefaultBottomBorderColor; + + 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(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); + + mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density); + mBottomBorderPaint = new Paint(); + mBottomBorderPaint.setColor(mDefaultBottomBorderColor); + + mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density); + mSelectedIndicatorPaint = new Paint(); + } + + 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 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 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); + } + + /** + * 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; + + @Override + public final int getIndicatorColor(int position) { + return mIndicatorColors[position % mIndicatorColors.length]; + } + + void setIndicatorColors(int... colors) { + mIndicatorColors = colors; + } + } +} diff --git a/WordPress/src/main/res/color/tab_text_color.xml b/WordPress/src/main/res/color/tab_text_color.xml new file mode 100644 index 000000000..e265ce6d1 --- /dev/null +++ b/WordPress/src/main/res/color/tab_text_color.xml @@ -0,0 +1,5 @@ + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@color/tab_text_selected" android:state_selected="true" /> + <item android:color="@color/tab_text_normal" /> +</selector> diff --git a/WordPress/src/main/res/layout/reader_activity_subs.xml b/WordPress/src/main/res/layout/reader_activity_subs.xml index a0dc43805..127739f6a 100644 --- a/WordPress/src/main/res/layout/reader_activity_subs.xml +++ b/WordPress/src/main/res/layout/reader_activity_subs.xml @@ -21,9 +21,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top" + android:background="@color/tab_background" android:paddingBottom="@dimen/margin_large" android:paddingTop="@dimen/margin_large" - android:textAppearance="@style/ReaderPagerTabStripText" /> + android:textAppearance="@style/ReaderTabStripTextAppearance" /> </android.support.v4.view.ViewPager> diff --git a/WordPress/src/main/res/layout/tab_text.xml b/WordPress/src/main/res/layout/tab_text.xml new file mode 100644 index 000000000..c315e8aed --- /dev/null +++ b/WordPress/src/main/res/layout/tab_text.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<org.wordpress.android.widgets.WPTextView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/text_tab" + android:layout_width="wrap_content" + android:layout_height="@dimen/toolbar_height" + android:background="?android:selectableItemBackground" + android:gravity="center" + android:paddingLeft="@dimen/margin_large" + android:paddingRight="@dimen/margin_large" + android:textAllCaps="true" + android:textColor="@color/tab_text_color" + android:textSize="@dimen/text_sz_medium" + android:textStyle="bold" + tools:text="text_tab" />
\ No newline at end of file diff --git a/WordPress/src/main/res/layout/theme_browser_activity.xml b/WordPress/src/main/res/layout/theme_browser_activity.xml index a73bff1ff..ccf5040d0 100644 --- a/WordPress/src/main/res/layout/theme_browser_activity.xml +++ b/WordPress/src/main/res/layout/theme_browser_activity.xml @@ -1,23 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/theme_browser_container" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" > + android:orientation="vertical"> - <org.wordpress.android.ui.HorizontalTabView - android:id="@+id/horizontalTabView1" + <org.wordpress.android.widgets.SlidingTabLayout + android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentLeft="true" - android:layout_alignParentTop="true" - android:fillViewport="true" - android:scrollbars="none" /> + android:background="@color/tab_background" /> <android.support.v4.view.ViewPager android:id="@+id/theme_browser_pager" android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_below="@id/horizontalTabView1" /> + android:layout_height="match_parent" /> -</RelativeLayout>
\ No newline at end of file +</LinearLayout>
\ No newline at end of file diff --git a/WordPress/src/main/res/values/colors.xml b/WordPress/src/main/res/values/colors.xml index e6ea42d03..2eaa450a8 100644 --- a/WordPress/src/main/res/values/colors.xml +++ b/WordPress/src/main/res/values/colors.xml @@ -55,10 +55,11 @@ <color name="theme_details_premium">#B0710E</color> <color name="theme_feature_text">#555555</color> - <!-- Horizontal Tab View colors --> - <color name="tab_divider">#565656</color> - <color name="tab_background">#363636</color> - <color name="tab_text">@color/white</color> + <!-- Tab Strip colors --> + <color name="tab_background">@color/color_primary</color> + <color name="tab_text_normal">@color/blue_light</color> + <color name="tab_text_selected">@color/white</color> + <color name="tab_indicator">@color/blue_light</color> <!-- Stats bar graph colors --> <color name="stats_bar_graph_views">#7CABC1</color> diff --git a/WordPress/src/main/res/values/reader_styles.xml b/WordPress/src/main/res/values/reader_styles.xml index d16c4a4e9..af4872748 100644 --- a/WordPress/src/main/res/values/reader_styles.xml +++ b/WordPress/src/main/res/values/reader_styles.xml @@ -176,11 +176,11 @@ <!-- progress bars --> <style name="ReaderProgressBar" parent="@android:style/Widget.Holo.Light.ProgressBar" /> - <!-- tab strip text appearance --> - <style name="ReaderPagerTabStripText"> + <style name="ReaderTabStripTextAppearance"> <item name="android:textSize">@dimen/text_sz_medium</item> <item name="android:textStyle">bold</item> - <item name="android:textColor">@color/white</item> + <item name="android:textColor">@color/tab_text_color</item> <item name="android:textAllCaps">true</item> + <item name="android:gravity">center</item> </style> </resources>
\ No newline at end of file diff --git a/WordPress/src/main/res/values/styles.xml b/WordPress/src/main/res/values/styles.xml index ccab0415a..2a2a87671 100644 --- a/WordPress/src/main/res/values/styles.xml +++ b/WordPress/src/main/res/values/styles.xml @@ -338,4 +338,5 @@ <style name="WordPress.SwipeToRefresh"> <item name="refreshIndicatorColor">@color/blue_new_kid</item> </style> + </resources>
\ No newline at end of file |