Android Open Source - GreenDroid Page Indicator






From Project

Back to project page GreenDroid.

License

The source code is released under:

Apache License

If you think the Android project GreenDroid listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2011 Cyril Mottier (http://www.cyrilmottier.com)
 */* w ww . java  2  s .  c  om*/
 * 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 greendroid.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;

import com.cyrilmottier.android.greendroid.R;

/**
 * <p>
 * Visual indicator of a paged content. The PageIndicator usually displays a
 * line of dots. Each dot represents a page. The PageIndicator supports two
 * types of dots.
 * </p>
 * <ul>
 * <li>{@link DotType#SINGLE}: all dots are drawn but only one is in the
 * selected state at a time. The selected one represents the currently visible
 * page.</li>
 * <li>{@link DotType#MULTIPLE}: the selected page is actually represented by
 * the amount of dots currently being drawn. This behavior is similar to the one
 * visible on the Android Launcher application.</li>
 * </ul>
 * <p>
 * You can have a look at GDCatalog to get a sample code of how to use a
 * PageIndicator in addition to a {@link PagedView}.
 * </p>
 * 
 * @author Cyril Mottier
 */
public class PageIndicator extends View {

    /**
     * Constant that may be used to select none of the dots in the PageIndicator
     */
    public static final int NO_ACTIVE_DOT = -1;

    /**
     * Interface containing of dot types supported by the PageIndicator class.
     * 
     * @author Cyril Mottier
     */
    public interface DotType {

        /**
         * Represents the single dot type. Only one selected dot may be drawn at
         * a time.
         */

        int SINGLE = 0;

        /**
         * Represents the multiple dot type. Several selected dot may be drawn
         * at a time. The number of dots drawn represents the currently
         * remaining page count.
         */
        int MULTIPLE = 1;
    }

    private static final int MIN_DOT_COUNT = 1;

    private static Rect sInRect = new Rect();
    private static Rect sOutRect = new Rect();

    private int mGravity;
    private int mDotSpacing;
    private Drawable mDotDrawable;
    private int mDotCount;
    private int mDotType;

    private int mActiveDot;

    private int[] mExtraState;

    private boolean mInitializing;

    public PageIndicator(Context context) {
        this(context, null);
    }

    public PageIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.gdPageIndicatorStyle);
    }

    public PageIndicator(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initPageIndicator();

        mInitializing = true;

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PageIndicator, defStyle, 0);

        setDotCount(a.getInt(R.styleable.PageIndicator_dotCount, mDotCount));
        setActiveDot(a.getInt(R.styleable.PageIndicator_activeDot, mActiveDot));
        setDotDrawable(a.getDrawable(R.styleable.PageIndicator_dotDrawable));
        setDotSpacing(a.getDimensionPixelSize(R.styleable.PageIndicator_dotSpacing, mDotSpacing));
        setGravity(a.getInt(R.styleable.PageIndicator_gravity, mGravity));
        setDotType(a.getInt(R.styleable.PageIndicator_dotType, mDotType));

        a.recycle();

        mInitializing = false;
    }

    private void initPageIndicator() {
        mDotCount = MIN_DOT_COUNT;
        mGravity = Gravity.CENTER;
        mActiveDot = 0;
        mDotSpacing = 0;
        mDotType = DotType.SINGLE;

        mExtraState = onCreateDrawableState(1);
        mergeDrawableStates(mExtraState, SELECTED_STATE_SET);
    }

    /**
     * Get the maximum number of dots to be drawn.
     * 
     * @return The maximum number of dots.
     * @see #setDotCount(int)
     */
    public int getDotCount() {
        return mDotCount;
    }

    /**
     * Set the number of dots.
     * 
     * @param dotCount The number oF dots
     * @see #getDotCount()
     */
    public void setDotCount(int dotCount) {
        if (dotCount < MIN_DOT_COUNT) {
            dotCount = MIN_DOT_COUNT;
        }

        if (mDotCount != dotCount) {
            mDotCount = dotCount;
            requestLayout();
            invalidate();
        }
    }

    /**
     * Return the current active dot. Depending on the current dot type of this
     * PageIndicator the current active dot may be the number of displayed dots
     * or the index of the selected dot
     * 
     * @return The current active dot index or dots count
     * @see #setActiveDot(int)
     */
    public int getActiveDot() {
        return mActiveDot;
    }

    /**
     * Set the index of the active dot or the number of active dots. Depending
     * on the current dot type of this PageIndicator the current active dot may
     * be the number of displayed dots or the index of the selected dot
     * 
     * @param activeDot The number/index of (the) active dot(s)
     * @see #getActiveDot()
     */
    public void setActiveDot(int activeDot) {
        if (activeDot < 0) {
            activeDot = NO_ACTIVE_DOT;
        }

        switch (mDotType) {
            case DotType.SINGLE:
                if (activeDot > mDotCount - 1) {
                    activeDot = NO_ACTIVE_DOT;
                }
                break;

            case DotType.MULTIPLE:
                if (activeDot > mDotCount) {
                    activeDot = NO_ACTIVE_DOT;
                }
        }

        mActiveDot = activeDot;
        invalidate();
    }

    /**
     * Return the Drawable currently used for each dot.
     * 
     * @return The Drawable used to draw each dot.
     */
    public Drawable getDotDrawable() {
        return mDotDrawable;
    }

    /**
     * Set the Drawable used for each dot. The given Drawable may be a
     * StateListDrawable in order to take advantage of the selection system. If
     * your StateListDrawable contains a android.R.attr.state_selected state,
     * the Drawable will be used to represent a selected dot.
     * <em><strong>Note :</strong> this methods does not support Drawable
     * that has no intrinsic dimensions.</em>
     * 
     * @param dotDrawable The Drawable used to represents a dot
     */
    public void setDotDrawable(Drawable dotDrawable) {
        if (dotDrawable != mDotDrawable) {
            if (mDotDrawable != null) {
                mDotDrawable.setCallback(null);
            }

            mDotDrawable = dotDrawable;

            if (dotDrawable != null) {

                if (dotDrawable.getIntrinsicHeight() == -1 || dotDrawable.getIntrinsicWidth() == -1) {
                    // Do not accept Drawable with no intrinsic dimensions.
                    return;
                }

                dotDrawable.setBounds(0, 0, dotDrawable.getIntrinsicWidth(), dotDrawable.getIntrinsicHeight());
                dotDrawable.setCallback(this);
                if (dotDrawable.isStateful()) {
                    dotDrawable.setState(getDrawableState());
                }
            }

            requestLayout();
            invalidate();
        }
    }

    /**
     * The spacing between each dot
     * 
     * @return The spacing between each dot
     */
    public int getDotSpacing() {
        return mDotSpacing;
    }

    /**
     * Set the spacing between each dot
     * 
     * @param dotSpacing The spacing between each dot.
     */
    public void setDotSpacing(int dotSpacing) {
        if (dotSpacing != mDotSpacing) {
            mDotSpacing = dotSpacing;
            requestLayout();
            invalidate();
        }
    }

    /**
     * Return the gravity used to draw dots/
     * 
     * @return The current gravity
     */
    public int getGravity() {
        return mGravity;
    }

    /**
     * Specifies how to align the dots by the view's x- and/or y-axis when the
     * space taken by the dots is smaller than the view.
     * 
     * @param gravity The gravity
     */
    public void setGravity(int gravity) {
        if (mGravity != gravity) {
            mGravity = gravity;
            invalidate();
        }
    }

    /**
     * The current dot type
     * 
     * @return The dot type of this {@link PageIndicator}
     * @see DotType
     */
    public int getDotType() {
        return mDotType;
    }

    /**
     * Specifies the type of dot actually drawn by this {@link PageIndicator}
     * 
     * @param dotType The dot type to use
     * @see DotType
     */
    public void setDotType(int dotType) {
        if (dotType == DotType.SINGLE || dotType == DotType.MULTIPLE) {
            if (mDotType != dotType) {
                mDotType = dotType;
                invalidate();
            }
        }
    }

    @Override
    public void requestLayout() {
        if (!mInitializing) {
            super.requestLayout();
        }
    }

    @Override
    public void invalidate() {
        if (!mInitializing) {
            super.invalidate();
        }
    }

    @Override
    protected boolean verifyDrawable(Drawable who) {
        return super.verifyDrawable(who) || who == mDotDrawable;
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        mExtraState = onCreateDrawableState(1);
        mergeDrawableStates(mExtraState, SELECTED_STATE_SET);
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        Drawable d = mDotDrawable;

        int width = 0;
        int height = 0;
        if (d != null) {
            width = mDotCount * (d.getIntrinsicWidth() + mDotSpacing) - mDotSpacing;
            height = d.getIntrinsicHeight();
        }

        width += getPaddingRight() + getPaddingLeft();
        height += getPaddingBottom() + getPaddingTop();

        setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));
    }

    @Override
    protected void onDraw(Canvas canvas) {

        final Drawable d = mDotDrawable;
        if (d != null) {

            final int count = mDotType == DotType.SINGLE ? mDotCount : mActiveDot;

            if (count <= 0) {
                return;
            }

            final int h = d.getIntrinsicHeight();
            final int w = Math.max(0, count * (d.getIntrinsicWidth() + mDotSpacing) - mDotSpacing);

            final int pRight = getPaddingRight();
            final int pLeft = getPaddingLeft();
            final int pTop = getPaddingTop();
            final int pBottom = getPaddingBottom();

            sInRect.set(pLeft, pTop, getWidth() - pRight, getHeight() - pBottom);
            Gravity.apply(mGravity, w, h, sInRect, sOutRect);

            canvas.save();
            canvas.translate(sOutRect.left, sOutRect.top);
            for (int i = 0; i < count; i++) {
                if (d.isStateful()) {
                    int[] state = getDrawableState();
                    if (mDotType == DotType.MULTIPLE || i == mActiveDot) {
                        state = mExtraState;
                    }
                    // HACK Cyril: The following code prevent the setState call
                    // from invalidating the View again (which will result in
                    // calling onDraw over and over again).
                    d.setCallback(null);
                    d.setState(state);
                    d.setCallback(this);
                }
                d.draw(canvas);
                canvas.translate(mDotSpacing + d.getIntrinsicWidth(), 0);
            }
            canvas.restore();
        }
    }

    static class SavedState extends BaseSavedState {

        int activeDot;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            activeDot = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(activeDot);
        }

        public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);

        ss.activeDot = mActiveDot;

        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());

        mActiveDot = ss.activeDot;
    }
}




Java Source Code List

com.cyrilmottier.android.gdcatalog.AboutActivity.java
com.cyrilmottier.android.gdcatalog.ActionBarActivity.java
com.cyrilmottier.android.gdcatalog.AsyncImageViewListActivity.java
com.cyrilmottier.android.gdcatalog.BasicItemActivity.java
com.cyrilmottier.android.gdcatalog.CatalogActivity.java
com.cyrilmottier.android.gdcatalog.CatalogApplication.java
com.cyrilmottier.android.gdcatalog.InfoTabActivity.java
com.cyrilmottier.android.gdcatalog.MapPinMapActivity.java
com.cyrilmottier.android.gdcatalog.PagedViewActivity.java
com.cyrilmottier.android.gdcatalog.QuickActionActivity.java
com.cyrilmottier.android.gdcatalog.SegmentedActivity.java
com.cyrilmottier.android.gdcatalog.SimpleAsyncImageViewActivity.java
com.cyrilmottier.android.gdcatalog.TabbedActionBarActivity.java
com.cyrilmottier.android.gdcatalog.TweakedItemViewActivity.java
com.cyrilmottier.android.gdcatalog.WebContentActivity.java
com.cyrilmottier.android.gdcatalog.XmlItemActivity.java
com.cyrilmottier.android.gdcatalog.widget.HeadedTextItemView.java
com.cyrilmottier.android.gdcatalog.widget.HeadedTextItem.java
greendroid.app.ActionBarActivity.java
greendroid.app.GDActivity.java
greendroid.app.GDApplication.java
greendroid.app.GDExpandableListActivity.java
greendroid.app.GDListActivity.java
greendroid.app.GDMapActivity.java
greendroid.app.GDTabActivity.java
greendroid.graphics.drawable.ActionBarDrawable.java
greendroid.graphics.drawable.DrawableStateSet.java
greendroid.graphics.drawable.MapPinDrawable.java
greendroid.image.ChainImageProcessor.java
greendroid.image.ImageCache.java
greendroid.image.ImageLoader.java
greendroid.image.ImageProcessor.java
greendroid.image.ImageRequest.java
greendroid.image.MaskImageProcessor.java
greendroid.image.ScaleImageProcessor.java
greendroid.util.Config.java
greendroid.util.GDUtils.java
greendroid.util.Md5Util.java
greendroid.util.Time.java
greendroid.widget.ActionBarHost.java
greendroid.widget.ActionBarItem.java
greendroid.widget.ActionBar.java
greendroid.widget.AsyncImageView.java
greendroid.widget.ItemAdapter.java
greendroid.widget.LoaderActionBarItem.java
greendroid.widget.NormalActionBarItem.java
greendroid.widget.PageIndicator.java
greendroid.widget.PagedAdapter.java
greendroid.widget.PagedView.java
greendroid.widget.QuickActionBar.java
greendroid.widget.QuickActionGrid.java
greendroid.widget.QuickActionWidget.java
greendroid.widget.QuickAction.java
greendroid.widget.SegmentedAdapter.java
greendroid.widget.SegmentedBar.java
greendroid.widget.SegmentedHost.java
greendroid.widget.item.DescriptionItem.java
greendroid.widget.item.DrawableItem.java
greendroid.widget.item.Item.java
greendroid.widget.item.LongTextItem.java
greendroid.widget.item.ProgressItem.java
greendroid.widget.item.SeparatorItem.java
greendroid.widget.item.SubtextItem.java
greendroid.widget.item.SubtitleItem.java
greendroid.widget.item.TextItem.java
greendroid.widget.item.ThumbnailItem.java
greendroid.widget.itemview.DescriptionItemView.java
greendroid.widget.itemview.DrawableItemView.java
greendroid.widget.itemview.ItemView.java
greendroid.widget.itemview.LongTextItemView.java
greendroid.widget.itemview.ProgressItemView.java
greendroid.widget.itemview.SeparatorItemView.java
greendroid.widget.itemview.SubtextItemView.java
greendroid.widget.itemview.SubtitleItemView.java
greendroid.widget.itemview.TextItemView.java
greendroid.widget.itemview.ThumbnailItemView.java