Android Open Source - iPhoroidUI Title Flow Indicator






From Project

Back to project page iPhoroidUI.

License

The source code is released under:

Apache License

If you think the Android project iPhoroidUI 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 Patrik kerfeldt/*from ww  w.jav  a 2s.co m*/
 * 
 * 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.klab.iphoroid.widget.flowview;

import java.util.ArrayList;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import org.klab.iphoroid.R;


/**
 * A TitleFlowIndicator is a FlowIndicator which displays the title of left view
 * (if exist), the title of the current select view (centered) and the title of
 * the right view (if exist). When the user scrolls the ViewFlow then titles are
 * also scrolled.
 * 
 */
public class TitleFlowIndicator extends TextView implements FlowIndicator {

    private static final int TITLE_PADDING = 10;
    private static final int SELECTED_COLOR = 0xFFFFC445;
    private static final int TEXT_COLOR = 0xFFAAAAAA;
    private static final int TEXT_SIZE = 15;
    private static final int FOOTER_LINE_HEIGHT = 4;
    private static final int FOOTER_COLOR = 0xFFFFC445;
    private static final int FOOTER_TRIANGLE_HEIGHT = 10;

    private FlowView viewFlow;

    private int currentScroll = 0;
    private TitleProvider titleProvider = null;
    private int currentPosition = 0;

    private Paint paintText;
    private Paint paintSelected;
    private Path path;
    private Paint paintFooterLine;
    private Paint paintFooterTriangle;

    private int footerTriangleHeight;
    private int titlePadding;
    private int footerLineHeight;

    /**
     * Default constructor
     */
    public TitleFlowIndicator(Context context) {
        super(context);
        initDraw(TEXT_COLOR, TEXT_SIZE, SELECTED_COLOR, FOOTER_LINE_HEIGHT, FOOTER_COLOR);
    }

    /**
     * The contructor used with an inflater
     * 
     * @param context
     * @param attrs
     */
    public TitleFlowIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        // Retrieve styles attributs
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.org_klab_iphoroid_widget_flowview_TitleFlowIndicator);
        // Retrieve the colors to be used for this view and apply them.
        int footerColor = a.getColor(R.styleable.org_klab_iphoroid_widget_flowview_TitleFlowIndicator_footerColor, FOOTER_COLOR);
        footerLineHeight = a.getInt(R.styleable.org_klab_iphoroid_widget_flowview_TitleFlowIndicator_footerLineHeight, FOOTER_LINE_HEIGHT);
        footerTriangleHeight = a.getInt(R.styleable.org_klab_iphoroid_widget_flowview_TitleFlowIndicator_footerTriangleHeight, FOOTER_TRIANGLE_HEIGHT);
        int selectedColor = a.getColor(R.styleable.org_klab_iphoroid_widget_flowview_TitleFlowIndicator_selectedColor, SELECTED_COLOR);
        int textColor = a.getColor(R.styleable.org_klab_iphoroid_widget_flowview_TitleFlowIndicator_textColor, TEXT_COLOR);
        float textSize = a.getFloat(R.styleable.org_klab_iphoroid_widget_flowview_TitleFlowIndicator_textSize, TEXT_SIZE);
        titlePadding = a.getInt(R.styleable.org_klab_iphoroid_widget_flowview_TitleFlowIndicator_titlePadding, TITLE_PADDING);
        initDraw(textColor, textSize, selectedColor, footerLineHeight, footerColor);
    }

    /**
     * Initialize draw objects
     */
    private void initDraw(int textColor, float textSize, int selectedColor, int footerLineHeight, int footerColor) {
        paintText = new Paint();
        paintText.setColor(textColor);
        paintText.setTextSize(textSize);
        paintText.setAntiAlias(true);
        paintSelected = new Paint();
        paintSelected.setColor(selectedColor);
        paintSelected.setTextSize(textSize);
        paintSelected.setAntiAlias(true);
        paintFooterLine = new Paint();
        paintFooterLine.setStyle(Paint.Style.FILL_AND_STROKE);
        paintFooterLine.setStrokeWidth(footerLineHeight);
        paintFooterLine.setColor(FOOTER_COLOR);
        paintFooterTriangle = new Paint();
        paintFooterTriangle.setStyle(Paint.Style.FILL_AND_STROKE);
        paintFooterTriangle.setColor(footerColor);
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.view.View#onDraw(android.graphics.Canvas)
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // Calculate views bounds
        ArrayList<Rect> bounds = calculateAllBounds(paintText);

        // If no value then add a fake one
        int count = (viewFlow != null && viewFlow.getAdapter() != null) ? viewFlow.getAdapter().getCount() : 1;

        // Verify if the current view must be clipped to the screen
        Rect curViewBound = bounds.get(currentPosition);
        int curViewWidth = curViewBound.right - curViewBound.left;
        if (curViewBound.left < 0) {
            // Try to clip to the screen (left side)
            curViewBound.left = 0;
            curViewBound.right = curViewWidth;
        }
        if (curViewBound.right > getLeft() + getWidth()) {
            // Try to clip to the screen (right side)
            curViewBound.right = getLeft() + getWidth();
            curViewBound.left = curViewBound.right - curViewWidth;
        }

        // Left views starting from the current position
        if (currentPosition > 0) {
            for (int iLoop = currentPosition - 1; iLoop >= 0; iLoop--) {
                Rect bound = bounds.get(iLoop);
                int w = bound.right - bound.left;
                // Si left side is outside the screen
                if (bound.left < 0) {
                    // Try to clip to the screen (left side)
                    bound.left = 0;
                    bound.right = w;
                    // Except if there's an intersection with the right view
                    if (iLoop < count - 1 && currentPosition != iLoop) {
                        Rect rightBound = bounds.get(iLoop + 1);
                        // Intersection
                        if (bound.right + TITLE_PADDING > rightBound.left) {
                            bound.left = rightBound.left - (w + titlePadding);
                        }
                    }
                }
            }
        }
        // Right views starting from the current position
        if (currentPosition < count - 1) {
            for (int iLoop = currentPosition + 1; iLoop < count; iLoop++) {
                Rect bound = bounds.get(iLoop);
                int w = bound.right - bound.left;
                // If right side is outside the screen
                if (bound.right > getLeft() + getWidth()) {
                    // Try to clip to the screen (right side)
                    bound.right = getLeft() + getWidth();
                    bound.left = bound.right - w;
                    // Except if there's an intersection with the left view
                    if (iLoop > 0 && currentPosition != iLoop) {
                        Rect leftBound = bounds.get(iLoop - 1);
                        // Intersection
                        if (bound.left - TITLE_PADDING < leftBound.right) {
                            bound.left = leftBound.right + titlePadding;
                        }
                    }
                }
            }
        }

        // Now draw views
        for (int iLoop = 0; iLoop < count; iLoop++) {
            // Get the title
            String title = getTitle(iLoop);
            Rect bound = bounds.get(iLoop);
            // Only if one side is visible
            if ((bound.left > getLeft() && bound.left < getLeft() + getWidth()) || (bound.right > getLeft() && bound.right < getLeft() + getWidth())) {
                Paint paint = paintText;
                // Change the color is the title is closed to the center
                int middle = (bound.left + bound.right) / 2;
                if (Math.abs(middle - (getWidth() / 2)) < 20) {
                    paint = paintSelected;
                }
                canvas.drawText(title, bound.left, bound.bottom, paint);
            }
        }

        // Draw the footer line
        path = new Path();
        path.moveTo(0, getHeight() - footerLineHeight);
        path.lineTo(getWidth(), getHeight() - footerLineHeight);
        path.close();
        canvas.drawPath(path, paintFooterLine);
        // Draw the footer triangle
        path = new Path();
        path.moveTo(getWidth() / 2, getHeight() - footerLineHeight - footerTriangleHeight);
        path.lineTo(getWidth() / 2 + footerTriangleHeight, getHeight() - footerLineHeight);
        path.lineTo(getWidth() / 2 - footerTriangleHeight, getHeight() - footerLineHeight);
        path.close();
        canvas.drawPath(path, paintFooterTriangle);
    }

    /**
     * Calculate views bounds and scroll them according to the current index
     * 
     * @param paint
     * @param currentIndex
     * @return
     */
    private ArrayList<Rect> calculateAllBounds(Paint paint) {
        ArrayList<Rect> list = new ArrayList<Rect>();
        // For each views (If no values then add a fake one)
        int count = (viewFlow != null && viewFlow.getAdapter() != null) ? viewFlow.getAdapter().getCount() : 1;
        for (int iLoop = 0; iLoop < count; iLoop++) {
            Rect bounds = calcBounds(iLoop, paint);
            int w = (bounds.right - bounds.left);
            int h = (bounds.bottom - bounds.top);
            bounds.left = (getWidth() / 2) - (w / 2) - currentScroll + (iLoop * getWidth());
            bounds.right = bounds.left + w;
            bounds.top = 0;
            bounds.bottom = h;
            list.add(bounds);
        }

        return list;
    }

    /**
     * Calculate the bounds for a view's title
     * 
     * @param index
     * @param paint
     * @return
     */
    private Rect calcBounds(int index, Paint paint) {
        // Get the title
        String title = getTitle(index);
        // Calculate the text bounds
        Rect bounds = new Rect();
        bounds.right = (int) paint.measureText(title);
        bounds.bottom = (int) (paint.descent() - paint.ascent());
        return bounds;
    }

    /**
     * Returns the title
     * 
     * @param pos
     * @return
     */
    private String getTitle(int pos) {
        // Set the default title
        String title = "title " + pos;
        // If the TitleProvider exist
        if (titleProvider != null) {
            title = titleProvider.getTitle(pos);
        }
        return title;
    }

    /*
     * @see org.taptwo.android.widget.FlowIndicator#onScrolled(int, int, int, int)
     */
    @Override
    public void onScrolled(int h, int v, int oldh, int oldv) {
        currentScroll = h;
        invalidate();
    }

    /*
     * @see
     * org.taptwo.android.widget.ViewFlow.ViewSwitchListener#onSwitched(android
     * .view.View, int)
     */
    @Override
    public void onSwitched(View view, int position) {
        currentPosition = position;
        invalidate();
    }

    /*
     * @see org.taptwo.android.widget.FlowIndicator#setViewFlow(org.taptwo.android.widget.ViewFlow)
     */
    @Override
    public void setViewFlow(FlowView view) {
        viewFlow = view;
        invalidate();
    }

    /**
     * Set the title provider
     * 
     * @param provider
     */
    public void setTitleProvider(TitleProvider provider) {
        titleProvider = provider;
    }

    /*
     * @see android.view.View#onMeasure(int, int)
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    /**
     * Determines the width of this view
     * 
     * @param measureSpec A measureSpec packed into an int
     * @return The width of the view, honoring constraints from measureSpec
     */
    private int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("ViewFlow can only be used in EXACTLY mode.");
        }
        result = specSize;
        return result;
    }

    /**
     * Determines the height of this view
     * 
     * @param measureSpec A measureSpec packed into an int
     * @return The height of the view, honoring constraints from measureSpec
     */
    private int measureHeight(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        // We were told how big to be
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        }
        // Measure the height
        else {
            // Calculate the text bounds
            Rect bounds = new Rect();
            bounds.bottom = (int) (paintText.descent() - paintText.ascent());
            result = bounds.bottom - bounds.top + footerTriangleHeight + footerLineHeight + 10;
            return result;
        }
        return result;
    }
}




Java Source Code List

org.klab.iphoroid.util.ActivityUtil.java
org.klab.iphoroid.util.Cache.java
org.klab.iphoroid.widget.adpterview.OnScrollListener.java
org.klab.iphoroid.widget.coverflow.CoverFlowGallery.java
org.klab.iphoroid.widget.coverflow.CoverFlowImageAdapterBase.java
org.klab.iphoroid.widget.flowview.CircleFlowIndicator.java
org.klab.iphoroid.widget.flowview.FlowIndicator.java
org.klab.iphoroid.widget.flowview.FlowView.java
org.klab.iphoroid.widget.flowview.TitleFlowIndicator.java
org.klab.iphoroid.widget.flowview.TitleProvider.java
org.klab.iphoroid.widget.gallery.ScrollDetectableGallery.java
org.klab.iphoroid.widget.listview.AdapterWrapper.java
org.klab.iphoroid.widget.listview.EndlessAdapter.java
org.klab.iphoroid.widget.listview.PullToRefreshEndlessListView.java
org.klab.iphoroid.widget.listview.PullToRefreshListView.java
org.klab.iphoroid.widget.listview.RefreshableArrayAdapter.java
org.klab.iphoroid.widget.support.DownloadTask.java
org.klab.iphoroid.widget.support.HasImage.java
org.klab.iphoroid.widget.support.ImageCache.java
org.klab.iphoroid.widget.support.ImageDownloadTask.java
org.klab.iphoroid.widget.support.SimpleImageDownloadTask.java