aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSammysHP <sven@sammyshp.de>2011-12-03 04:13:27 -0800
committerSammysHP <sven@sammyshp.de>2011-12-03 04:13:27 -0800
commit1bece437a2e2d0674f95a684469f59580c286e3e (patch)
treec4cbbab9d6bf75e418c85f9750efae509ef87565
parent313be6a1e9fb334e1745f0f2f9117561b4be92dc (diff)
parentfbb191bb1442f1e1ad983c251866404e7648228d (diff)
downloadcgeo-1bece437a2e2d0674f95a684469f59580c286e3e.zip
cgeo-1bece437a2e2d0674f95a684469f59580c286e3e.tar.gz
cgeo-1bece437a2e2d0674f95a684469f59580c286e3e.tar.bz2
Merge pull request #850 from SammysHP/newindicator2
New viewpager-indicator
-rw-r--r--main/res/drawable-hdpi/pagerindicator_background.9.pngbin959 -> 0 bytes
-rw-r--r--main/res/drawable-ldpi/pagerindicator_background.9.pngbin367 -> 0 bytes
-rw-r--r--main/res/drawable/pagerindicator_background.9.pngbin579 -> 0 bytes
-rw-r--r--main/res/layout/cacheview.xml25
-rw-r--r--main/res/values/attrs.xml1
-rw-r--r--main/res/values/colors.xml2
-rw-r--r--main/res/values/styles.xml34
-rw-r--r--main/res/values/themes.xml2
-rw-r--r--main/res/values/vpi__attrs.xml56
-rw-r--r--main/res/values/vpi__colors.xml26
-rw-r--r--main/res/values/vpi__defaults.xml31
-rw-r--r--main/res/values/vpi__styles.xml39
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java68
-rw-r--r--main/src/com/viewpagerindicator/PageIndicator.java63
-rw-r--r--main/src/com/viewpagerindicator/TitlePageIndicator.java772
-rw-r--r--main/src/com/viewpagerindicator/TitleProvider.java28
16 files changed, 1033 insertions, 114 deletions
diff --git a/main/res/drawable-hdpi/pagerindicator_background.9.png b/main/res/drawable-hdpi/pagerindicator_background.9.png
deleted file mode 100644
index 2474e5c..0000000
--- a/main/res/drawable-hdpi/pagerindicator_background.9.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable-ldpi/pagerindicator_background.9.png b/main/res/drawable-ldpi/pagerindicator_background.9.png
deleted file mode 100644
index d9f91d6..0000000
--- a/main/res/drawable-ldpi/pagerindicator_background.9.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable/pagerindicator_background.9.png b/main/res/drawable/pagerindicator_background.9.png
deleted file mode 100644
index 697675b..0000000
--- a/main/res/drawable/pagerindicator_background.9.png
+++ /dev/null
Binary files differ
diff --git a/main/res/layout/cacheview.xml b/main/res/layout/cacheview.xml
index 05df377..936871d 100644
--- a/main/res/layout/cacheview.xml
+++ b/main/res/layout/cacheview.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res/cgeo.geocaching"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
@@ -36,21 +37,13 @@
android:layout_height="wrap_content"
android:layout_weight="1" />
- <RelativeLayout style="@style/pager_indicator" >
-
- <TextView
- android:id="@+id/indicator_prev"
- style="@style/pager_indicator.side"
- android:layout_alignParentLeft="true" />
-
- <TextView
- android:id="@+id/indicator_current"
- style="@style/pager_indicator.title" />
-
- <TextView
- android:id="@+id/indicator_next"
- style="@style/pager_indicator.side"
- android:layout_alignParentRight="true" />
- </RelativeLayout>
+ <com.viewpagerindicator.TitlePageIndicator
+ android:id="@+id/pager_indicator"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ app:footerColor="#ff888888"
+ app:footerIndicatorHeight="3dp"
+ app:footerIndicatorStyle="underline"
+ app:textSize="16dp" />
</LinearLayout> \ No newline at end of file
diff --git a/main/res/values/attrs.xml b/main/res/values/attrs.xml
index e6d7bba..187d4cb 100644
--- a/main/res/values/attrs.xml
+++ b/main/res/values/attrs.xml
@@ -17,7 +17,6 @@
<attr name="background_color_notice" format="color" />
<attr name="background_color_transparent" format="color" />
<attr name="separator_color" format="color" />
- <attr name="text_color_pagerindicator" format="color" />
<!-- drawables -->
<attr name="button" format="integer" />
diff --git a/main/res/values/colors.xml b/main/res/values/colors.xml
index 91fb6a5..1d965e3 100644
--- a/main/res/values/colors.xml
+++ b/main/res/values/colors.xml
@@ -25,7 +25,5 @@
<color name="link">#FF00C0FF</color>
<color name="button_enabled">#FF000000</color>
<color name="button_disabled">#66000000</color>
- <color name="text_pagerindicator">#FFFFFFFF</color>
- <color name="text_pagerindicator_sides">#88FFFFFF</color>
</resources> \ No newline at end of file
diff --git a/main/res/values/styles.xml b/main/res/values/styles.xml
index 58b404f..ad3fc8d 100644
--- a/main/res/values/styles.xml
+++ b/main/res/values/styles.xml
@@ -303,38 +303,4 @@
<item name="android:textColor">@android:color/white</item>
</style>
- <!-- pager -->
- <style name="pager_indicator">
- <item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:background">@drawable/pagerindicator_background</item>
- </style>
-
- <style name="pager_indicator.title">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_margin">5dip</item>
- <item name="android:layout_centerInParent">true</item>
- <item name="android:lines">1</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">end</item>
- <item name="android:textStyle">bold</item>
- <item name="android:textSize">16dip</item>
- <item name="android:textColor">@color/text_pagerindicator</item>
- <item name="android:background">@null</item>
- </style>
-
- <style name="pager_indicator.side">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_margin">1dip</item>
- <item name="android:layout_centerVertical">true</item>
- <item name="android:lines">1</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">end</item>
- <item name="android:textSize">12dip</item>
- <item name="android:textColor">@color/text_pagerindicator_sides</item>
- <item name="android:background">@null</item>
- </style>
-
</resources> \ No newline at end of file
diff --git a/main/res/values/themes.xml b/main/res/values/themes.xml
index 8b8c914..ba07eb2 100644
--- a/main/res/values/themes.xml
+++ b/main/res/values/themes.xml
@@ -31,7 +31,6 @@
<item name="text_color_grey">@color/text_grey_dark</item>
<item name="text_color_hint">@color/text_hint_dark</item>
<item name="text_color_link">@color/link</item>
- <item name="text_color_pagerindicator">@color/text_pagerindicator</item>
<item name="button_color_enabled">@color/button_enabled</item>
<item name="button_color_disabled">@color/button_disabled</item>
<item name="background_color">@color/background_dark</item>
@@ -64,7 +63,6 @@
<item name="text_color_grey">@color/text_grey_light</item>
<item name="text_color_hint">@color/text_hint_light</item>
<item name="text_color_link">@color/link</item>
- <item name="text_color_pagerindicator">@color/text_pagerindicator</item>
<item name="button_color_enabled">@color/button_enabled</item>
<item name="button_color_disabled">@color/button_disabled</item>
<item name="background_color">@color/background_light</item>
diff --git a/main/res/values/vpi__attrs.xml b/main/res/values/vpi__attrs.xml
new file mode 100644
index 0000000..4eeb55b
--- /dev/null
+++ b/main/res/values/vpi__attrs.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 Patrik Ã…kerfeldt
+ Copyright (C) 2011 Jake Wharton
+
+ 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.
+-->
+
+<resources>
+ <declare-styleable name="ViewPagerIndicator">
+ <!-- Style of the title indicator. -->
+ <attr name="vpiTitlePageIndicatorStyle" format="reference"/>
+ </declare-styleable>
+
+ <declare-styleable name="TitlePageIndicator">
+ <!-- Screen edge padding. -->
+ <attr name="clipPadding" format="dimension" />
+ <!-- Color of the footer line and indicator. -->
+ <attr name="footerColor" format="color" />
+ <!-- Height of the footer line. -->
+ <attr name="footerLineHeight" format="dimension" />
+ <!-- Style of the indicator. Default is triangle. -->
+ <attr name="footerIndicatorStyle">
+ <enum name="none" value="0" />
+ <enum name="triangle" value="1" />
+ <enum name="underline" value="2" />
+ </attr>
+ <!-- Height of the indicator above the footer line. -->
+ <attr name="footerIndicatorHeight" format="dimension" />
+ <!-- Left and right padding of the underline indicator. -->
+ <attr name="footerIndicatorUnderlinePadding" format="dimension" />
+ <!-- Padding between the bottom of the title and the footer. -->
+ <attr name="footerPadding" format="dimension" />
+ <!-- Color of the selected title. -->
+ <attr name="selectedColor" format="color" />
+ <!-- Whether or not the selected item is displayed as bold. -->
+ <attr name="selectedBold" format="boolean" />
+ <!-- Color of regular titles. -->
+ <attr name="textColor" format="color" />
+ <!-- Size of title text. -->
+ <attr name="textSize" format="dimension" />
+ <!-- Padding between titles when bumping into each other. -->
+ <attr name="titlePadding" format="dimension" />
+ <!-- Padding between titles and the top of the View. -->
+ <attr name="topPadding" format="dimension" />
+ </declare-styleable>
+</resources>
diff --git a/main/res/values/vpi__colors.xml b/main/res/values/vpi__colors.xml
new file mode 100644
index 0000000..c0d958f
--- /dev/null
+++ b/main/res/values/vpi__colors.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <color name="vpi__background_holo_dark">#ff000000</color>
+ <color name="vpi__background_holo_light">#fff3f3f3</color>
+ <color name="vpi__bright_foreground_holo_dark">@color/vpi__background_holo_light</color>
+ <color name="vpi__bright_foreground_holo_light">@color/vpi__background_holo_dark</color>
+ <color name="vpi__bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
+ <color name="vpi__bright_foreground_disabled_holo_light">#ffb2b2b2</color>
+ <color name="vpi__bright_foreground_inverse_holo_dark">@color/vpi__bright_foreground_holo_light</color>
+ <color name="vpi__bright_foreground_inverse_holo_light">@color/vpi__bright_foreground_holo_dark</color>
+</resources>
diff --git a/main/res/values/vpi__defaults.xml b/main/res/values/vpi__defaults.xml
new file mode 100644
index 0000000..4e0bb8f
--- /dev/null
+++ b/main/res/values/vpi__defaults.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 Jake Wharton
+
+ 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.
+-->
+
+<resources>
+ <dimen name="default_title_indicator_clip_padding">4dp</dimen>
+ <color name="default_title_indicator_footer_color">#FF6899FF</color>
+ <dimen name="default_title_indicator_footer_line_height">1px</dimen>
+ <integer name="default_title_indicator_footer_indicator_style">1</integer>
+ <dimen name="default_title_indicator_footer_indicator_height">5dp</dimen>
+ <dimen name="default_title_indicator_footer_indicator_underline_padding">20dp</dimen>
+ <dimen name="default_title_indicator_footer_padding">8dp</dimen>
+ <color name="default_title_indicator_selected_color">#FFFFFFFF</color>
+ <bool name="default_title_indicator_selected_bold">true</bool>
+ <color name="default_title_indicator_text_color">#FFAAAAAA</color>
+ <dimen name="default_title_indicator_text_size">18dp</dimen>
+ <dimen name="default_title_indicator_title_padding">5dp</dimen>
+ <dimen name="default_title_indicator_top_padding">0dp</dimen>
+</resources> \ No newline at end of file
diff --git a/main/res/values/vpi__styles.xml b/main/res/values/vpi__styles.xml
new file mode 100644
index 0000000..0662c1c
--- /dev/null
+++ b/main/res/values/vpi__styles.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 Jake Wharton
+
+ 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.
+-->
+
+<resources>
+ <style name="Theme.PageIndicatorDefaults" parent="android:Theme">
+ <item name="vpiTitlePageIndicatorStyle">@style/Widget.TitlePageIndicator</item>
+ </style>
+
+ <style name="Widget"></style>
+
+ <style name="Widget.TitlePageIndicator" parent="Widget">
+ <item name="clipPadding">@dimen/default_title_indicator_clip_padding</item>
+ <item name="footerColor">@color/default_title_indicator_footer_color</item>
+ <item name="footerLineHeight">@dimen/default_title_indicator_footer_line_height</item>
+ <item name="footerIndicatorStyle">@integer/default_title_indicator_footer_indicator_style</item>
+ <item name="footerIndicatorHeight">@dimen/default_title_indicator_footer_indicator_height</item>
+ <item name="footerIndicatorUnderlinePadding">@dimen/default_title_indicator_footer_indicator_underline_padding</item>
+ <item name="footerPadding">@dimen/default_title_indicator_footer_padding</item>
+ <item name="selectedColor">@color/default_title_indicator_selected_color</item>
+ <item name="selectedBold">@bool/default_title_indicator_selected_bold</item>
+ <item name="textColor">@color/default_title_indicator_text_color</item>
+ <item name="textSize">@dimen/default_title_indicator_text_size</item>
+ <item name="titlePadding">@dimen/default_title_indicator_title_padding</item>
+ <item name="topPadding">@dimen/default_title_indicator_top_padding</item>
+ </style>
+</resources>
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java
index 3f81e3c..368d1f1 100644
--- a/main/src/cgeo/geocaching/CacheDetailActivity.java
+++ b/main/src/cgeo/geocaching/CacheDetailActivity.java
@@ -14,6 +14,9 @@ import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.CryptUtils;
import cgeo.geocaching.utils.UnknownTagsHandler;
+import com.viewpagerindicator.TitlePageIndicator;
+import com.viewpagerindicator.TitleProvider;
+
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringEscapeUtils;
@@ -106,12 +109,6 @@ public class CacheDetailActivity extends AbstractActivity {
private int contextMenuWPIndex = -1;
/**
- * The index of the current page. We need this hack because {@link onPageSelected()} is not called after
- * initialization.
- */
- private int currentPageIndex = 0;
-
- /**
* A {@link List} of all available pages.
*/
private final List<Page> pageOrder = new ArrayList<Page>();
@@ -127,11 +124,6 @@ public class CacheDetailActivity extends AbstractActivity {
private ViewPagerAdapter viewPagerAdapter;
/**
- * The {@link ViewPagerIndicator} for this activity.
- */
- private ViewPagerIndicator viewPagerIndicator;
-
- /**
* If another activity is called and can modify the data of this activity, we refresh it on resume.
*/
private boolean refreshOnResume = false;
@@ -246,11 +238,12 @@ public class CacheDetailActivity extends AbstractActivity {
// initialize ViewPager
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
- viewPagerIndicator = new ViewPagerIndicator();
- pager.setOnPageChangeListener(viewPagerIndicator);
viewPagerAdapter = new ViewPagerAdapter();
pager.setAdapter(viewPagerAdapter);
+ TitlePageIndicator titleIndicator = (TitlePageIndicator) findViewById(R.id.pager_indicator);
+ titleIndicator.setViewPager(pager);
+
// Initialization done. Let's load the data with the given information.
new LoadCacheThread(geocode, guid, loadCacheHandler).start();
}
@@ -594,9 +587,6 @@ public class CacheDetailActivity extends AbstractActivity {
// notify the adapter that the data has changed
viewPagerAdapter.notifyDataSetChanged();
- // notify the indicator about the change
- viewPagerIndicator.onPageSelected(currentPageIndex);
-
// rendering done! remove progress-popup if any there
progress.dismiss();
}
@@ -900,7 +890,7 @@ public class CacheDetailActivity extends AbstractActivity {
/**
* The ViewPagerAdapter for scrolling through pages of the CacheDetailActivity.
*/
- private class ViewPagerAdapter extends PagerAdapter {
+ private class ViewPagerAdapter extends PagerAdapter implements TitleProvider {
@Override
public void destroyItem(View container, int position, Object object) {
@@ -988,50 +978,10 @@ public class CacheDetailActivity extends AbstractActivity {
// The ViewPager will get it back in instantiateItem()
return POSITION_NONE;
}
- }
-
- private class ViewPagerIndicator implements ViewPager.OnPageChangeListener {
-
- // TODO: Clickable prev + next
- private TextView indicatorPrev;
- private TextView indicatorCurrent;
- private TextView indicatorNext;
-
- public ViewPagerIndicator() {
- super();
-
- indicatorPrev = (TextView) findViewById(R.id.indicator_prev);
- indicatorCurrent = (TextView) findViewById(R.id.indicator_current);
- indicatorNext = (TextView) findViewById(R.id.indicator_next);
- }
-
- @Override
- public void onPageScrollStateChanged(int state) {
- }
-
- @Override
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
- }
@Override
- public void onPageSelected(int position) {
- currentPageIndex = position;
-
- indicatorCurrent.setText(res.getString(pageOrder.get(position).titleStringId));
-
- if (position > 0) {
- indicatorPrev.setText(res.getString(pageOrder.get(position - 1).titleStringId));
- indicatorPrev.setVisibility(View.VISIBLE);
- } else {
- indicatorPrev.setVisibility(View.GONE);
- }
-
- if (position < (pageOrder.size() - 1)) {
- indicatorNext.setText(res.getString(pageOrder.get(position + 1).titleStringId));
- indicatorNext.setVisibility(View.VISIBLE);
- } else {
- indicatorNext.setVisibility(View.GONE);
- }
+ public String getTitle(int position) {
+ return res.getString(pageOrder.get(position).titleStringId);
}
}
diff --git a/main/src/com/viewpagerindicator/PageIndicator.java b/main/src/com/viewpagerindicator/PageIndicator.java
new file mode 100644
index 0000000..26414d8
--- /dev/null
+++ b/main/src/com/viewpagerindicator/PageIndicator.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ * Copyright (C) 2011 Jake Wharton
+ *
+ * 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 com.viewpagerindicator;
+
+import android.support.v4.view.ViewPager;
+
+/**
+ * A PageIndicator is responsible to show an visual indicator on the total views
+ * number and the current visible view.
+ */
+public interface PageIndicator extends ViewPager.OnPageChangeListener {
+ /**
+ * Bind the indicator to a ViewPager.
+ *
+ * @param view
+ */
+ public void setViewPager(ViewPager view);
+
+ /**
+ * Bind the indicator to a ViewPager.
+ *
+ * @param view
+ * @param initialPosition
+ */
+ public void setViewPager(ViewPager view, int initialPosition);
+
+ /**
+ * <p>Set the current page of both the ViewPager and indicator.</p>
+ *
+ * <p>This <strong>must</strong> be used if you need to set the page before
+ * the views are drawn on screen (e.g., default start page).</p>
+ *
+ * @param item
+ */
+ public void setCurrentItem(int item);
+
+ /**
+ * Set a page change listener which will receive forwarded events.
+ *
+ * @param listener
+ */
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
+
+ /**
+ * Notify the indicator that the fragment list has changed.
+ */
+ public void notifyDataSetChanged();
+}
diff --git a/main/src/com/viewpagerindicator/TitlePageIndicator.java b/main/src/com/viewpagerindicator/TitlePageIndicator.java
new file mode 100644
index 0000000..17ec2bd
--- /dev/null
+++ b/main/src/com/viewpagerindicator/TitlePageIndicator.java
@@ -0,0 +1,772 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ * Copyright (C) 2011 Francisco Figueiredo Jr.
+ * Copyright (C) 2011 Jake Wharton
+ *
+ * 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 com.viewpagerindicator;
+
+import cgeo.geocaching.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewConfigurationCompat;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+import java.util.ArrayList;
+
+/**
+ * A TitlePageIndicator is a PageIndicator 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 ViewPager then titles are
+ * also scrolled.
+ */
+public class TitlePageIndicator extends View implements PageIndicator {
+ /**
+ * Percentage indicating what percentage of the screen width away from
+ * center should the underline be fully faded. A value of 0.25 means that
+ * halfway between the center of the screen and an edge.
+ */
+ private static final float SELECTION_FADE_PERCENTAGE = 0.25f;
+
+ /**
+ * Percentage indicating what percentage of the screen width away from
+ * center should the selected text bold turn off. A value of 0.05 means
+ * that 10% between the center and an edge.
+ */
+ private static final float BOLD_FADE_PERCENTAGE = 0.05f;
+
+ public enum IndicatorStyle {
+ None(0), Triangle(1), Underline(2);
+
+ public final int value;
+
+ private IndicatorStyle(int value) {
+ this.value = value;
+ }
+
+ public static IndicatorStyle fromValue(int value) {
+ for (IndicatorStyle style : IndicatorStyle.values()) {
+ if (style.value == value) {
+ return style;
+ }
+ }
+ return null;
+ }
+ }
+
+ private ViewPager mViewPager;
+ private ViewPager.OnPageChangeListener mListener;
+ private TitleProvider mTitleProvider;
+ private int mCurrentPage;
+ private int mCurrentOffset;
+ private int mScrollState;
+ private final Paint mPaintText;
+ private boolean mBoldText;
+ private int mColorText;
+ private int mColorSelected;
+ private Path mPath;
+ private final Paint mPaintFooterLine;
+ private IndicatorStyle mFooterIndicatorStyle;
+ private final Paint mPaintFooterIndicator;
+ private float mFooterIndicatorHeight;
+ private float mFooterIndicatorUnderlinePadding;
+ private float mFooterPadding;
+ private float mTitlePadding;
+ private float mTopPadding;
+ /** Left and right side padding for not active view titles. */
+ private float mClipPadding;
+ private float mFooterLineHeight;
+
+ private static final int INVALID_POINTER = -1;
+
+ private int mTouchSlop;
+ private float mLastMotionX = -1;
+ private int mActivePointerId = INVALID_POINTER;
+ private boolean mIsDragging;
+
+
+ public TitlePageIndicator(Context context) {
+ this(context, null);
+ }
+
+ public TitlePageIndicator(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.vpiTitlePageIndicatorStyle);
+ }
+
+ public TitlePageIndicator(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ //Load defaults from resources
+ final Resources res = getResources();
+ final int defaultFooterColor = res.getColor(R.color.default_title_indicator_footer_color);
+ final float defaultFooterLineHeight = res.getDimension(R.dimen.default_title_indicator_footer_line_height);
+ final int defaultFooterIndicatorStyle = res.getInteger(R.integer.default_title_indicator_footer_indicator_style);
+ final float defaultFooterIndicatorHeight = res.getDimension(R.dimen.default_title_indicator_footer_indicator_height);
+ final float defaultFooterIndicatorUnderlinePadding = res.getDimension(R.dimen.default_title_indicator_footer_indicator_underline_padding);
+ final float defaultFooterPadding = res.getDimension(R.dimen.default_title_indicator_footer_padding);
+ final int defaultSelectedColor = res.getColor(R.color.default_title_indicator_selected_color);
+ final boolean defaultSelectedBold = res.getBoolean(R.bool.default_title_indicator_selected_bold);
+ final int defaultTextColor = res.getColor(R.color.default_title_indicator_text_color);
+ final float defaultTextSize = res.getDimension(R.dimen.default_title_indicator_text_size);
+ final float defaultTitlePadding = res.getDimension(R.dimen.default_title_indicator_title_padding);
+ final float defaultClipPadding = res.getDimension(R.dimen.default_title_indicator_clip_padding);
+ final float defaultTopPadding = res.getDimension(R.dimen.default_title_indicator_top_padding);
+
+ //Retrieve styles attributes
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitlePageIndicator, defStyle, R.style.Widget_TitlePageIndicator);
+
+ //Retrieve the colors to be used for this view and apply them.
+ mFooterLineHeight = a.getDimension(R.styleable.TitlePageIndicator_footerLineHeight, defaultFooterLineHeight);
+ mFooterIndicatorStyle = IndicatorStyle.fromValue(a.getInteger(R.styleable.TitlePageIndicator_footerIndicatorStyle, defaultFooterIndicatorStyle));
+ mFooterIndicatorHeight = a.getDimension(R.styleable.TitlePageIndicator_footerIndicatorHeight, defaultFooterIndicatorHeight);
+ mFooterIndicatorUnderlinePadding = a.getDimension(R.styleable.TitlePageIndicator_footerIndicatorUnderlinePadding, defaultFooterIndicatorUnderlinePadding);
+ mFooterPadding = a.getDimension(R.styleable.TitlePageIndicator_footerPadding, defaultFooterPadding);
+ mTopPadding = a.getDimension(R.styleable.TitlePageIndicator_topPadding, defaultTopPadding);
+ mTitlePadding = a.getDimension(R.styleable.TitlePageIndicator_titlePadding, defaultTitlePadding);
+ mClipPadding = a.getDimension(R.styleable.TitlePageIndicator_clipPadding, defaultClipPadding);
+ mColorSelected = a.getColor(R.styleable.TitlePageIndicator_selectedColor, defaultSelectedColor);
+ mColorText = a.getColor(R.styleable.TitlePageIndicator_textColor, defaultTextColor);
+ mBoldText = a.getBoolean(R.styleable.TitlePageIndicator_selectedBold, defaultSelectedBold);
+
+ final float textSize = a.getDimension(R.styleable.TitlePageIndicator_textSize, defaultTextSize);
+ final int footerColor = a.getColor(R.styleable.TitlePageIndicator_footerColor, defaultFooterColor);
+ mPaintText = new Paint();
+ mPaintText.setTextSize(textSize);
+ mPaintText.setAntiAlias(true);
+ mPaintFooterLine = new Paint();
+ mPaintFooterLine.setStyle(Paint.Style.FILL_AND_STROKE);
+ mPaintFooterLine.setStrokeWidth(mFooterLineHeight);
+ mPaintFooterLine.setColor(footerColor);
+ mPaintFooterIndicator = new Paint();
+ mPaintFooterIndicator.setStyle(Paint.Style.FILL_AND_STROKE);
+ mPaintFooterIndicator.setColor(footerColor);
+
+ a.recycle();
+
+ final ViewConfiguration configuration = ViewConfiguration.get(context);
+ mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
+ }
+
+
+ public int getFooterColor() {
+ return mPaintFooterLine.getColor();
+ }
+
+ public void setFooterColor(int footerColor) {
+ mPaintFooterLine.setColor(footerColor);
+ mPaintFooterIndicator.setColor(footerColor);
+ invalidate();
+ }
+
+ public float getFooterLineHeight() {
+ return mFooterLineHeight;
+ }
+
+ public void setFooterLineHeight(float footerLineHeight) {
+ mFooterLineHeight = footerLineHeight;
+ mPaintFooterLine.setStrokeWidth(mFooterLineHeight);
+ invalidate();
+ }
+
+ public float getFooterIndicatorHeight() {
+ return mFooterIndicatorHeight;
+ }
+
+ public void setFooterIndicatorHeight(float footerTriangleHeight) {
+ mFooterIndicatorHeight = footerTriangleHeight;
+ invalidate();
+ }
+
+ public float getFooterIndicatorPadding() {
+ return mFooterPadding;
+ }
+
+ public void setFooterIndicatorPadding(float footerIndicatorPadding) {
+ mFooterPadding = footerIndicatorPadding;
+ invalidate();
+ }
+
+ public IndicatorStyle getFooterIndicatorStyle() {
+ return mFooterIndicatorStyle;
+ }
+
+ public void setFooterIndicatorStyle(IndicatorStyle indicatorStyle) {
+ mFooterIndicatorStyle = indicatorStyle;
+ invalidate();
+ }
+
+ public int getSelectedColor() {
+ return mColorSelected;
+ }
+
+ public void setSelectedColor(int selectedColor) {
+ mColorSelected = selectedColor;
+ invalidate();
+ }
+
+ public boolean isSelectedBold() {
+ return mBoldText;
+ }
+
+ public void setSelectedBold(boolean selectedBold) {
+ mBoldText = selectedBold;
+ invalidate();
+ }
+
+ public int getTextColor() {
+ return mColorText;
+ }
+
+ public void setTextColor(int textColor) {
+ mPaintText.setColor(textColor);
+ mColorText = textColor;
+ invalidate();
+ }
+
+ public float getTextSize() {
+ return mPaintText.getTextSize();
+ }
+
+ public void setTextSize(float textSize) {
+ mPaintText.setTextSize(textSize);
+ invalidate();
+ }
+
+ public float getTitlePadding() {
+ return this.mTitlePadding;
+ }
+
+ public void setTitlePadding(float titlePadding) {
+ mTitlePadding = titlePadding;
+ invalidate();
+ }
+
+ public float getTopPadding() {
+ return this.mTopPadding;
+ }
+
+ public void setTopPadding(float topPadding) {
+ mTopPadding = topPadding;
+ invalidate();
+ }
+
+ public float getClipPadding() {
+ return this.mClipPadding;
+ }
+
+ public void setClipPadding(float clipPadding) {
+ mClipPadding = clipPadding;
+ invalidate();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View#onDraw(android.graphics.Canvas)
+ */
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mViewPager == null) {
+ return;
+ }
+ final int count = mViewPager.getAdapter().getCount();
+ if (count == 0) {
+ return;
+ }
+
+ //Calculate views bounds
+ ArrayList<RectF> bounds = calculateAllBounds(mPaintText);
+
+ //Make sure we're on a page that still exists
+ if (mCurrentPage >= bounds.size()) {
+ setCurrentItem(bounds.size()-1);
+ }
+
+ final int countMinusOne = count - 1;
+ final float halfWidth = getWidth() / 2f;
+ final int left = getLeft();
+ final float leftClip = left + mClipPadding;
+ final int width = getWidth();
+ final int height = getHeight();
+ final int right = left + width;
+ final float rightClip = right - mClipPadding;
+
+ int page = mCurrentPage;
+ float offsetPercent;
+ if (mCurrentOffset <= halfWidth) {
+ offsetPercent = 1.0f * mCurrentOffset / width;
+ } else {
+ page += 1;
+ offsetPercent = 1.0f * (width - mCurrentOffset) / width;
+ }
+ final boolean currentSelected = (offsetPercent <= SELECTION_FADE_PERCENTAGE);
+ final boolean currentBold = (offsetPercent <= BOLD_FADE_PERCENTAGE);
+ final float selectedPercent = (SELECTION_FADE_PERCENTAGE - offsetPercent) / SELECTION_FADE_PERCENTAGE;
+
+ //Verify if the current view must be clipped to the screen
+ RectF curPageBound = bounds.get(mCurrentPage);
+ float curPageWidth = curPageBound.right - curPageBound.left;
+ if (curPageBound.left < leftClip) {
+ //Try to clip to the screen (left side)
+ clipViewOnTheLeft(curPageBound, curPageWidth, left);
+ }
+ if (curPageBound.right > rightClip) {
+ //Try to clip to the screen (right side)
+ clipViewOnTheRight(curPageBound, curPageWidth, right);
+ }
+
+ //Left views starting from the current position
+ if (mCurrentPage > 0) {
+ for (int i = mCurrentPage - 1; i >= 0; i--) {
+ RectF bound = bounds.get(i);
+ //Is left side is outside the screen
+ if (bound.left < leftClip) {
+ float w = bound.right - bound.left;
+ //Try to clip to the screen (left side)
+ clipViewOnTheLeft(bound, w, left);
+ //Except if there's an intersection with the right view
+ RectF rightBound = bounds.get(i + 1);
+ //Intersection
+ if (bound.right + mTitlePadding > rightBound.left) {
+ bound.left = rightBound.left - w - mTitlePadding;
+ bound.right = bound.left + w;
+ }
+ }
+ }
+ }
+ //Right views starting from the current position
+ if (mCurrentPage < countMinusOne) {
+ for (int i = mCurrentPage + 1 ; i < count; i++) {
+ RectF bound = bounds.get(i);
+ //If right side is outside the screen
+ if (bound.right > rightClip) {
+ float w = bound.right - bound.left;
+ //Try to clip to the screen (right side)
+ clipViewOnTheRight(bound, w, right);
+ //Except if there's an intersection with the left view
+ RectF leftBound = bounds.get(i - 1);
+ //Intersection
+ if (bound.left - mTitlePadding < leftBound.right) {
+ bound.left = leftBound.right + mTitlePadding;
+ bound.right = bound.left + w;
+ }
+ }
+ }
+ }
+
+ //Now draw views
+ for (int i = 0; i < count; i++) {
+ //Get the title
+ RectF bound = bounds.get(i);
+ //Only if one side is visible
+ if ((bound.left > left && bound.left < right) || (bound.right > left && bound.right < right)) {
+ final boolean currentPage = (i == page);
+ //Only set bold if we are within bounds
+ mPaintText.setFakeBoldText(currentPage && currentBold && mBoldText);
+
+ //Draw text as unselected
+ mPaintText.setColor(mColorText);
+ canvas.drawText(mTitleProvider.getTitle(i), bound.left, bound.bottom + mTopPadding, mPaintText);
+
+ //If we are within the selected bounds draw the selected text
+ if (currentPage && currentSelected) {
+ mPaintText.setColor(mColorSelected);
+ mPaintText.setAlpha((int)((mColorSelected >>> 24) * selectedPercent));
+ canvas.drawText(mTitleProvider.getTitle(i), bound.left, bound.bottom + mTopPadding, mPaintText);
+ }
+ }
+ }
+
+ //Draw the footer line
+ mPath = new Path();
+ mPath.moveTo(0, height - mFooterLineHeight / 2f);
+ mPath.lineTo(width, height - mFooterLineHeight / 2f);
+ mPath.close();
+ canvas.drawPath(mPath, mPaintFooterLine);
+
+ switch (mFooterIndicatorStyle) {
+ case Triangle:
+ mPath = new Path();
+ mPath.moveTo(halfWidth, height - mFooterLineHeight - mFooterIndicatorHeight);
+ mPath.lineTo(halfWidth + mFooterIndicatorHeight, height - mFooterLineHeight);
+ mPath.lineTo(halfWidth - mFooterIndicatorHeight, height - mFooterLineHeight);
+ mPath.close();
+ canvas.drawPath(mPath, mPaintFooterIndicator);
+ break;
+
+ case Underline:
+ if (!currentSelected) {
+ break;
+ }
+
+ RectF underlineBounds = bounds.get(page);
+ mPath = new Path();
+ mPath.moveTo(underlineBounds.left - mFooterIndicatorUnderlinePadding, height - mFooterLineHeight);
+ mPath.lineTo(underlineBounds.right + mFooterIndicatorUnderlinePadding, height - mFooterLineHeight);
+ mPath.lineTo(underlineBounds.right + mFooterIndicatorUnderlinePadding, height - mFooterLineHeight - mFooterIndicatorHeight);
+ mPath.lineTo(underlineBounds.left - mFooterIndicatorUnderlinePadding, height - mFooterLineHeight - mFooterIndicatorHeight);
+ mPath.close();
+
+ mPaintFooterIndicator.setAlpha((int)(0xFF * selectedPercent));
+ canvas.drawPath(mPath, mPaintFooterIndicator);
+ mPaintFooterIndicator.setAlpha(0xFF);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(android.view.MotionEvent ev) {
+ if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
+ return false;
+ }
+
+ final int action = ev.getAction();
+
+ switch (action & MotionEventCompat.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
+ mLastMotionX = ev.getX();
+ break;
+
+ case MotionEvent.ACTION_MOVE: {
+ final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+ final float x = MotionEventCompat.getX(ev, activePointerIndex);
+ final float deltaX = x - mLastMotionX;
+
+ if (!mIsDragging) {
+ if (Math.abs(deltaX) > mTouchSlop) {
+ mIsDragging = true;
+ }
+ }
+
+ if (mIsDragging) {
+ if (!mViewPager.isFakeDragging()) {
+ mViewPager.beginFakeDrag();
+ }
+
+ mLastMotionX = x;
+
+ mViewPager.fakeDragBy(deltaX);
+ }
+
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ if (!mIsDragging) {
+ final int count = mViewPager.getAdapter().getCount();
+ final int width = getWidth();
+ final float halfWidth = width / 2f;
+ final float sixthWidth = width / 6f;
+
+ if ((mCurrentPage > 0) && (ev.getX() < halfWidth - sixthWidth)) {
+ mViewPager.setCurrentItem(mCurrentPage - 1);
+ return true;
+ } else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) {
+ mViewPager.setCurrentItem(mCurrentPage + 1);
+ return true;
+ }
+ }
+
+ mIsDragging = false;
+ mActivePointerId = INVALID_POINTER;
+ if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag();
+ break;
+
+ case MotionEventCompat.ACTION_POINTER_DOWN: {
+ final int index = MotionEventCompat.getActionIndex(ev);
+ final float x = MotionEventCompat.getX(ev, index);
+ mLastMotionX = x;
+ mActivePointerId = MotionEventCompat.getPointerId(ev, index);
+ break;
+ }
+
+ case MotionEventCompat.ACTION_POINTER_UP:
+ final int pointerIndex = MotionEventCompat.getActionIndex(ev);
+ final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
+ if (pointerId == mActivePointerId) {
+ final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+ mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
+ }
+ mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId));
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Set bounds for the right textView including clip padding.
+ *
+ * @param curViewBound
+ * current bounds.
+ * @param curViewWidth
+ * width of the view.
+ */
+ private void clipViewOnTheRight(RectF curViewBound, float curViewWidth, int right) {
+ curViewBound.right = right - mClipPadding;
+ 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(RectF curViewBound, float curViewWidth, int left) {
+ curViewBound.left = left + mClipPadding;
+ curViewBound.right = mClipPadding + curViewWidth;
+ }
+
+ /**
+ * Calculate views bounds and scroll them according to the current index
+ *
+ * @param paint
+ * @param currentIndex
+ * @return
+ */
+ private ArrayList<RectF> calculateAllBounds(Paint paint) {
+ ArrayList<RectF> list = new ArrayList<RectF>();
+ //For each views (If no values then add a fake one)
+ final int count = mViewPager.getAdapter().getCount();
+ final int width = getWidth();
+ final int halfWidth = width / 2;
+ for (int i = 0; i < count; i++) {
+ RectF bounds = calcBounds(i, paint);
+ float w = (bounds.right - bounds.left);
+ float h = (bounds.bottom - bounds.top);
+ bounds.left = (halfWidth) - (w / 2) - mCurrentOffset + ((i - mCurrentPage) * width);
+ 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 RectF calcBounds(int index, Paint paint) {
+ //Calculate the text bounds
+ RectF bounds = new RectF();
+ bounds.right = paint.measureText(mTitleProvider.getTitle(index));
+ bounds.bottom = paint.descent() - paint.ascent();
+ return bounds;
+ }
+
+ @Override
+ public void setViewPager(ViewPager view) {
+ final PagerAdapter adapter = view.getAdapter();
+ if (adapter == null) {
+ throw new IllegalStateException("ViewPager does not have adapter instance.");
+ }
+ if (!(adapter instanceof TitleProvider)) {
+ throw new IllegalStateException("ViewPager adapter must implement TitleProvider to be used with TitlePageIndicator.");
+ }
+ mViewPager = view;
+ mViewPager.setOnPageChangeListener(this);
+ mTitleProvider = (TitleProvider)adapter;
+ invalidate();
+ }
+
+ @Override
+ public void setViewPager(ViewPager view, int initialPosition) {
+ setViewPager(view);
+ setCurrentItem(initialPosition);
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ invalidate();
+ }
+
+ @Override
+ public void setCurrentItem(int item) {
+ if (mViewPager == null) {
+ throw new IllegalStateException("ViewPager has not been bound.");
+ }
+ mViewPager.setCurrentItem(item);
+ mCurrentPage = item;
+ invalidate();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ mScrollState = state;
+
+ if (mListener != null) {
+ mListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ mCurrentPage = position;
+ mCurrentOffset = positionOffsetPixels;
+ invalidate();
+
+ if (mListener != null) {
+ mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+ mCurrentPage = position;
+ invalidate();
+ }
+
+ if (mListener != null) {
+ mListener.onPageSelected(position);
+ }
+ }
+
+ @Override
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+ mListener = listener;
+ }
+
+ /*
+ * (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(getClass().getSimpleName() + " 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) {
+ float result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ //We were told how big to be
+ result = specSize;
+ } else {
+ //Calculate the text bounds
+ RectF bounds = new RectF();
+ bounds.bottom = mPaintText.descent()-mPaintText.ascent();
+ result = bounds.bottom - bounds.top + mFooterLineHeight + mFooterPadding + mTopPadding;
+ if (mFooterIndicatorStyle != IndicatorStyle.None) {
+ result += mFooterIndicatorHeight;
+ }
+ }
+ return (int)result;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ SavedState savedState = (SavedState)state;
+ super.onRestoreInstanceState(savedState.getSuperState());
+ mCurrentPage = savedState.currentPage;
+ requestLayout();
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ SavedState savedState = new SavedState(superState);
+ savedState.currentPage = mCurrentPage;
+ return savedState;
+ }
+
+ static class SavedState extends BaseSavedState {
+ int currentPage;
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ private SavedState(Parcel in) {
+ super(in);
+ currentPage = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(currentPage);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
+ @Override
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ @Override
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/main/src/com/viewpagerindicator/TitleProvider.java b/main/src/com/viewpagerindicator/TitleProvider.java
new file mode 100644
index 0000000..2a04b65
--- /dev/null
+++ b/main/src/com/viewpagerindicator/TitleProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ *
+ * 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 com.viewpagerindicator;
+
+/**
+ * A TitleProvider provides the title to display according to a view.
+ */
+public interface TitleProvider {
+ /**
+ * Returns the title of the view at position
+ * @param position
+ * @return
+ */
+ public String getTitle(int position);
+}