android.support.v4.view.PagerTitleStrip Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of support-v4 Show documentation
Show all versions of support-v4 Show documentation
The Support Package includes static "support libraries" that you can add to your Android application in order to use APIs that are either not available for older platform versions or that offer "utility" APIs that aren't a part of the framework APIs.
The newest version!
/*
* Copyright (C) 2011 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 android.support.v4.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.TextView;
/**
* PagerTitleStrip is a non-interactive indicator of the current, next,
* and previous pages of a {@link ViewPager}. It is intended to be used as a
* child view of a ViewPager widget in your XML layout.
* Add it as a child of a ViewPager in your layout file and set its
* android:layout_gravity to TOP or BOTTOM to pin it to the top or bottom
* of the ViewPager. The title from each page is supplied by the method
* {@link PagerAdapter#getPageTitle(int)} in the adapter supplied to
* the ViewPager.
*/
public class PagerTitleStrip extends ViewGroup implements ViewPager.Decor {
private static final String TAG = "PagerTitleStrip";
ViewPager mPager;
private TextView mPrevText;
private TextView mCurrText;
private TextView mNextText;
private int mLastKnownCurrentPage = -1;
private float mLastKnownPositionOffset = -1;
private int mScaledTextSpacing;
private boolean mUpdatingText;
private boolean mUpdatingPositions;
private final PageListener mPageListener = new PageListener();
private static final int[] ATTRS = new int[] {
android.R.attr.textAppearance,
android.R.attr.textColor,
android.R.attr.textSize
};
private static final int SIDE_ALPHA = 0x99; // single-byte alpha, 0 = invisible, FF = opaque
private static final int TEXT_SPACING = 16; // dip
public PagerTitleStrip(Context context) {
this(context, null);
}
public PagerTitleStrip(Context context, AttributeSet attrs) {
super(context, attrs);
addView(mPrevText = new TextView(context));
addView(mCurrText = new TextView(context));
addView(mNextText = new TextView(context));
final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
final int textAppearance = a.getResourceId(0, 0);
if (textAppearance != 0) {
mPrevText.setTextAppearance(context, textAppearance);
mCurrText.setTextAppearance(context, textAppearance);
mNextText.setTextAppearance(context, textAppearance);
}
if (a.hasValue(1)) {
final int textColor = a.getColor(1, 0);
mPrevText.setTextColor(textColor);
mCurrText.setTextColor(textColor);
mNextText.setTextColor(textColor);
}
final int textSize = a.getDimensionPixelSize(2, 0);
if (textSize != 0) {
mPrevText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
mCurrText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
mNextText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
}
a.recycle();
final int defaultColor = mPrevText.getTextColors().getDefaultColor();
final int transparentColor = (SIDE_ALPHA << 24) | (defaultColor & 0xFFFFFF);
mPrevText.setTextColor(transparentColor);
mNextText.setTextColor(transparentColor);
mPrevText.setEllipsize(TruncateAt.END);
mCurrText.setEllipsize(TruncateAt.END);
mNextText.setEllipsize(TruncateAt.END);
mPrevText.setSingleLine();
mCurrText.setSingleLine();
mNextText.setSingleLine();
final float density = context.getResources().getDisplayMetrics().density;
mScaledTextSpacing = (int) (TEXT_SPACING * density);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
final ViewParent parent = getParent();
if (!(parent instanceof ViewPager)) {
throw new IllegalStateException(
"PagerTitleStrip must be a direct child of a ViewPager.");
}
final ViewPager pager = (ViewPager) parent;
final PagerAdapter adapter = pager.getAdapter();
pager.setInternalPageChangeListener(mPageListener);
pager.setOnAdapterChangeListener(mPageListener);
mPager = pager;
updateAdapter(null, adapter);
}
@Override
protected void onDetachedFromWindow() {
updateAdapter(mPager.getAdapter(), null);
mPager.setInternalPageChangeListener(null);
mPager.setOnAdapterChangeListener(null);
mPager = null;
}
void updateText(int currentItem, PagerAdapter adapter) {
final int itemCount = adapter != null ? adapter.getCount() : 0;
mUpdatingText = true;
CharSequence text = null;
if (currentItem >= 1 && adapter != null) {
text = adapter.getPageTitle(currentItem - 1);
}
mPrevText.setText(text);
mCurrText.setText(adapter != null ? adapter.getPageTitle(currentItem) : null);
text = null;
if (currentItem + 1 < itemCount && adapter != null) {
text = adapter.getPageTitle(currentItem + 1);
}
mNextText.setText(text);
// Measure everything
final int width = getWidth() - getPaddingLeft() - getPaddingRight();
final int childHeight = getHeight() - getPaddingTop() - getPaddingBottom();
final int childWidthSpec = MeasureSpec.makeMeasureSpec((int) (width * 0.8f),
MeasureSpec.AT_MOST);
final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY);
mPrevText.measure(childWidthSpec, childHeightSpec);
mCurrText.measure(childWidthSpec, childHeightSpec);
mNextText.measure(childWidthSpec, childHeightSpec);
mLastKnownCurrentPage = currentItem;
if (!mUpdatingPositions) {
updateTextPositions(currentItem, mLastKnownPositionOffset);
}
mUpdatingText = false;
}
@Override
public void requestLayout() {
if (!mUpdatingText) {
super.requestLayout();
}
}
void updateAdapter(PagerAdapter oldAdapter, PagerAdapter newAdapter) {
if (oldAdapter != null) {
oldAdapter.unregisterDataSetObserver(mPageListener);
}
if (newAdapter != null) {
newAdapter.registerDataSetObserver(mPageListener);
}
if (mPager != null) {
mLastKnownCurrentPage = -1;
mLastKnownPositionOffset = -1;
updateText(mPager.getCurrentItem(), newAdapter);
requestLayout();
}
}
void updateTextPositions(int position, float positionOffset) {
if (position != mLastKnownCurrentPage) {
updateText(position, mPager.getAdapter());
} else if (positionOffset == mLastKnownPositionOffset) {
return;
}
mUpdatingPositions = true;
final int prevWidth = mPrevText.getMeasuredWidth();
final int currWidth = mCurrText.getMeasuredWidth();
final int nextWidth = mNextText.getMeasuredWidth();
final int halfCurrWidth = currWidth / 2;
final int stripWidth = getWidth();
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int textPaddedLeft = paddingLeft + halfCurrWidth;
final int textPaddedRight = paddingRight + halfCurrWidth;
final int contentWidth = stripWidth - textPaddedLeft - textPaddedRight;
float currOffset = positionOffset + 0.5f;
if (currOffset > 1.f) {
currOffset -= 1.f;
}
final int currCenter = stripWidth - textPaddedRight - (int) (contentWidth * currOffset);
final int currLeft = currCenter - currWidth / 2;
final int currRight = currLeft + currWidth;
mCurrText.layout(currLeft, paddingTop, currRight,
paddingTop + mCurrText.getMeasuredHeight());
final int prevLeft = Math.min(paddingLeft, currLeft - mScaledTextSpacing - prevWidth);
mPrevText.layout(prevLeft, paddingTop, prevLeft + prevWidth,
paddingTop + mPrevText.getMeasuredHeight());
final int nextLeft = Math.max(stripWidth - paddingRight - nextWidth,
currRight + mScaledTextSpacing);
mNextText.layout(nextLeft, paddingTop, nextLeft + nextWidth,
paddingTop + mNextText.getMeasuredHeight());
mLastKnownPositionOffset = positionOffset;
mUpdatingPositions = false;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("Must measure with an exact width");
}
int childHeight = heightSize;
int minHeight = 0;
int padding = 0;
final Drawable bg = getBackground();
if (bg != null) {
minHeight = bg.getIntrinsicHeight();
}
padding = getPaddingTop() + getPaddingBottom();
childHeight -= padding;
final int childWidthSpec = MeasureSpec.makeMeasureSpec((int) (widthSize * 0.8f),
MeasureSpec.AT_MOST);
final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeight, heightMode);
mPrevText.measure(childWidthSpec, childHeightSpec);
mCurrText.measure(childWidthSpec, childHeightSpec);
mNextText.measure(childWidthSpec, childHeightSpec);
if (heightMode == MeasureSpec.EXACTLY) {
setMeasuredDimension(widthSize, heightSize);
} else {
int textHeight = mCurrText.getMeasuredHeight();
setMeasuredDimension(widthSize, Math.max(minHeight, textHeight + padding));
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (mPager != null) {
updateTextPositions(mPager.getCurrentItem(), 0.f);
}
}
private class PageListener extends DataSetObserver implements ViewPager.OnPageChangeListener,
ViewPager.OnAdapterChangeListener {
private int mScrollState;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (positionOffset > 0.5f) {
// Consider ourselves to be on the next page when we're 50% of the way there.
position++;
}
updateTextPositions(position, positionOffset);
}
@Override
public void onPageSelected(int position) {
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
// Only update the text here if we're not dragging or settling.
updateText(mPager.getCurrentItem(), mPager.getAdapter());
}
}
@Override
public void onPageScrollStateChanged(int state) {
mScrollState = state;
}
@Override
public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter) {
updateAdapter(oldAdapter, newAdapter);
}
@Override
public void onChanged() {
updateText(mPager.getCurrentItem(), mPager.getAdapter());
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy