Android Open Source - Munin-for-Android Title Flow Indicator






From Project

Back to project page Munin-for-Android.

License

The source code is released under:

GNU General Public License

If you think the Android project Munin-for-Android 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   www  .j ava  2s .c  o 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.taptwo.android.widget;

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.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import com.chteuchteu.munin.R;

import java.util.ArrayList;

/**
 * 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 float TITLE_PADDING = 10.0f;
  private static final float CLIP_PADDING = 0.0f;
  private static final int SELECTED_COLOR = 0xFFFFC445;
  private static final boolean SELECTED_BOLD = false;
  private static final int TEXT_COLOR = 0xCCF0F0F0;
  private static final int TEXT_SIZE = 15;
  private static final float FOOTER_LINE_HEIGHT = 4.0f;
  private static final int FOOTER_COLOR = 0xFFFFC445;
  private static final float FOOTER_TRIANGLE_HEIGHT = 10;
  private ViewFlow 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 float footerTriangleHeight;
  private float titlePadding;
  /**
   * Left and right side padding for not active view titles.
   */
  private float clipPadding;
  private float footerLineHeight;

  /* These are hardcoded just like in TextView */
  private static final int SANS = 1;
  private static final int SERIF = 2;
  private static final int MONOSPACE = 3;

  private Typeface typeface;

  /**
   * Default constructor
   */
  public TitleFlowIndicator(Context context) {
    super(context);
    initDraw(TEXT_COLOR, TEXT_SIZE, SELECTED_COLOR, SELECTED_BOLD, TEXT_SIZE, 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

    int typefaceIndex = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "typeface", 0);
    int textStyleIndex = attrs.getAttributeIntValue("http://schemas.android.com/apk/res/android", "textStyle", 0);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitleFlowIndicator);

    String customTypeface = a.getString(R.styleable.TitleFlowIndicator_customTypeface);
    // Retrieve the colors to be used for this view and apply them.
    int footerColor = a.getColor(R.styleable.TitleFlowIndicator_footerColor, FOOTER_COLOR);
    footerLineHeight = a.getDimension(R.styleable.TitleFlowIndicator_footerLineHeight, FOOTER_LINE_HEIGHT);
    footerTriangleHeight = a.getDimension(R.styleable.TitleFlowIndicator_footerTriangleHeight, FOOTER_TRIANGLE_HEIGHT);
    int selectedColor = a.getColor(R.styleable.TitleFlowIndicator_selectedColor, SELECTED_COLOR);
    boolean selectedBold = a.getBoolean(R.styleable.TitleFlowIndicator_selectedBold, SELECTED_BOLD);
    int textColor = a.getColor(R.styleable.TitleFlowIndicator_textColor2, TEXT_COLOR);
    float textSize = a.getDimension(R.styleable.TitleFlowIndicator_textSize2, TEXT_SIZE);
    float selectedSize = a.getDimension(R.styleable.TitleFlowIndicator_selectedSize, textSize);
    titlePadding = a.getDimension(R.styleable.TitleFlowIndicator_titlePadding, TITLE_PADDING);
    clipPadding = a.getDimension(R.styleable.TitleFlowIndicator_clipPadding, CLIP_PADDING);
    initDraw(textColor, textSize, selectedColor, selectedBold, selectedSize, footerLineHeight, footerColor);

    if (customTypeface != null)
      typeface = Typeface.createFromAsset(context.getAssets(), customTypeface);
    else
      typeface = getTypefaceByIndex(typefaceIndex);
    typeface = Typeface.create(typeface, textStyleIndex);

  }

  /**
   * Initialize draw objects
   */
  private void initDraw(int textColor, float textSize, int selectedColor, boolean selectedBold, float selectedSize, float footerLineHeight, int footerColor) {
    paintText = new Paint();
    paintText.setColor(textColor);
    paintText.setTextSize(textSize);
    paintText.setAntiAlias(true);
    paintSelected = new Paint();
    paintSelected.setColor(selectedColor);
    paintSelected.setTextSize(selectedSize);
    paintSelected.setFakeBoldText(selectedBold);
    paintSelected.setAntiAlias(true);
    paintFooterLine = new Paint();
    paintFooterLine.setStyle(Paint.Style.FILL_AND_STROKE);
    paintFooterLine.setStrokeWidth(footerLineHeight);
    paintFooterLine.setColor(footerColor);
    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)
      clipViewOnTheLeft(curViewBound, curViewWidth);
    }
    if (curViewBound.right > getLeft() + getWidth()) {
      // Try to clip to the screen (right side)
      clipViewOnTheRight(curViewBound, 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)
          clipViewOnTheLeft(bound, 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 + (int) 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)
          clipViewOnTheRight(bound, 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 + (int) 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;
        }
        paint.setTypeface(typeface);
        canvas.drawText(title, bound.left, bound.bottom, paint);
      }
    }

    // Draw the footer line
    path = new Path();
    int coordY = getHeight() - 1;
    coordY -= (footerLineHeight % 2 == 1) ? footerLineHeight / 2 : footerLineHeight / 2 - 1;
    path.moveTo(0, coordY);
    path.lineTo(getWidth(), coordY);
    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);

  }

  /**
   * Set bounds for the right textView including clip padding.
   * 
   * @param curViewBound
   *            current bounds.
   * @param curViewWidth
   *            width of the view.
   */
  private void clipViewOnTheRight(Rect curViewBound, int curViewWidth) {
    curViewBound.right = getLeft() + getWidth() - (int) clipPadding;
    curViewBound.left = curViewBound.right - curViewWidth;
  }

  /**
   * Set bounds for the left textView including clip padding.
   * 
   * @param curViewBound
   *            current bounds.
   * @param curViewWidth
   *            width of the view.
   */
  private void clipViewOnTheLeft(Rect curViewBound, int curViewWidth) {
    curViewBound.left = 0 + (int) clipPadding;
    curViewBound.right = curViewWidth;
  }

  /**
   * 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;
  }

  /*
   * (non-Javadoc)
   * 
   * @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();
  }

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

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

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

  /*
   * (non-Javadoc)
   * 
   * @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 + (int) footerTriangleHeight + (int) footerLineHeight + 10;
      return result;
    }
    return result;
  }

  private Typeface getTypefaceByIndex(int typefaceIndex) {
    switch (typefaceIndex) {
    case SANS:
      return Typeface.SANS_SERIF;

    case SERIF:
      return Typeface.SERIF;

    case MONOSPACE:
      return Typeface.MONOSPACE;
    default:
      return Typeface.DEFAULT;
    }
  }
}




Java Source Code List

com.chteuchteu.munin.BootReceiver.java
com.chteuchteu.munin.CustomSSLFactory.java
com.chteuchteu.munin.MuninFoo.java
com.chteuchteu.munin.Service_Notifications.java
com.chteuchteu.munin.adptr.Adapter_ExpandableListView.java
com.chteuchteu.munin.adptr.Adapter_GraphView.java
com.chteuchteu.munin.adptr.Adapter_IconList.java
com.chteuchteu.munin.adptr.Adapter_SeparatedList.java
com.chteuchteu.munin.exc.ImportExportWebserviceException.java
com.chteuchteu.munin.exc.NullMuninFooException.java
com.chteuchteu.munin.exc.TrialExpirationDateReached.java
com.chteuchteu.munin.hlpr.BillingService.java
com.chteuchteu.munin.hlpr.DatabaseHelper.java
com.chteuchteu.munin.hlpr.DigestUtils.java
com.chteuchteu.munin.hlpr.DocumentationHelper.java
com.chteuchteu.munin.hlpr.DrawerHelper.java
com.chteuchteu.munin.hlpr.DynazoomHelper.java
com.chteuchteu.munin.hlpr.EncryptionHelper.java
com.chteuchteu.munin.hlpr.GridDownloadHelper.java
com.chteuchteu.munin.hlpr.I18nHelper.java
com.chteuchteu.munin.hlpr.ImportExportHelper.java
com.chteuchteu.munin.hlpr.JSONHelper.java
com.chteuchteu.munin.hlpr.MediaScannerUtil.java
com.chteuchteu.munin.hlpr.NetHelper.java
com.chteuchteu.munin.hlpr.SQLite.java
com.chteuchteu.munin.hlpr.Util.java
com.chteuchteu.munin.obj.AlertsWidget.java
com.chteuchteu.munin.obj.GraphWidget.java
com.chteuchteu.munin.obj.GridItem.java
com.chteuchteu.munin.obj.Grid.java
com.chteuchteu.munin.obj.HTTPResponse_Bitmap.java
com.chteuchteu.munin.obj.HTTPResponse.java
com.chteuchteu.munin.obj.Label.java
com.chteuchteu.munin.obj.MuninMaster.java
com.chteuchteu.munin.obj.MuninPlugin.java
com.chteuchteu.munin.obj.MuninServer.java
com.chteuchteu.munin.obj.SearchResult.java
com.chteuchteu.munin.ui.Activity_About.java
com.chteuchteu.munin.ui.Activity_AlertsPluginSelection.java
com.chteuchteu.munin.ui.Activity_Alerts.java
com.chteuchteu.munin.ui.Activity_GoPremium.java
com.chteuchteu.munin.ui.Activity_GraphView.java
com.chteuchteu.munin.ui.Activity_Grid.java
com.chteuchteu.munin.ui.Activity_Grids.java
com.chteuchteu.munin.ui.Activity_Label.java
com.chteuchteu.munin.ui.Activity_Labels.java
com.chteuchteu.munin.ui.Activity_Main.java
com.chteuchteu.munin.ui.Activity_Notifications.java
com.chteuchteu.munin.ui.Activity_Plugins.java
com.chteuchteu.munin.ui.Activity_Server.java
com.chteuchteu.munin.ui.Activity_ServersEdit.java
com.chteuchteu.munin.ui.Activity_Servers.java
com.chteuchteu.munin.ui.Activity_Settings.java
com.chteuchteu.munin.ui.HackyDrawerLayout.java
com.chteuchteu.munin.ui.MuninActivity.java
com.chteuchteu.munin.wdget.Widget_AlertsWidget_Configure.java
com.chteuchteu.munin.wdget.Widget_AlertsWidget_ViewsFactory.java
com.chteuchteu.munin.wdget.Widget_AlertsWidget_WidgetProvider.java
com.chteuchteu.munin.wdget.Widget_AlertsWidget_WidgetService.java
com.chteuchteu.munin.wdget.Widget_GraphWidget_Configure.java
com.chteuchteu.munin.wdget.Widget_GraphWidget_WidgetProvider.java
com.mobeta.android.dslv.DragSortController.java
com.mobeta.android.dslv.DragSortCursorAdapter.java
com.mobeta.android.dslv.DragSortItemViewCheckable.java
com.mobeta.android.dslv.DragSortItemView.java
com.mobeta.android.dslv.DragSortListView.java
com.mobeta.android.dslv.ResourceDragSortCursorAdapter.java
com.mobeta.android.dslv.SimpleDragSortCursorAdapter.java
com.mobeta.android.dslv.SimpleFloatViewManager.java
org.taptwo.android.widget.CircleFlowIndicator.java
org.taptwo.android.widget.FlowIndicator.java
org.taptwo.android.widget.TitleFlowIndicator.java
org.taptwo.android.widget.TitleProvider.java
org.taptwo.android.widget.ViewFlow.java
uk.co.senab.photoview.Compat.java
uk.co.senab.photoview.IPhotoView.java
uk.co.senab.photoview.PhotoViewAttacher.java
uk.co.senab.photoview.PhotoView.java
uk.co.senab.photoview.SDK16.java
uk.co.senab.photoview.ScrollerProxy.java
uk.co.senab.photoview.VersionedGestureDetector.java