TRACKING APP: TrackingActivity: ViewPager-layout
No files matched your search
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2010 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_enabled="false" android:color="@color/vpi__bright_foreground_disabled_holo_dark"/>
|
||||||
|
<item android:state_window_focused="false" android:color="@color/vpi__bright_foreground_holo_dark"/>
|
||||||
|
<item android:state_pressed="true" android:color="@color/vpi__bright_foreground_holo_dark"/>
|
||||||
|
<item android:state_selected="true" android:color="@color/vpi__bright_foreground_holo_dark"/>
|
||||||
|
<!--item android:state_activated="true" android:color="@color/vpi__bright_foreground_holo_dark"/-->
|
||||||
|
<item android:color="@color/vpi__bright_foreground_holo_dark"/> <!-- not selected -->
|
||||||
|
</selector>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2010 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_enabled="false" android:color="@color/vpi__bright_foreground_disabled_holo_light"/>
|
||||||
|
<item android:state_window_focused="false" android:color="@color/vpi__bright_foreground_holo_light"/>
|
||||||
|
<item android:state_pressed="true" android:color="@color/vpi__bright_foreground_holo_light"/>
|
||||||
|
<item android:state_selected="true" android:color="@color/vpi__bright_foreground_holo_light"/>
|
||||||
|
<!--item android:state_activated="true" android:color="@color/vpi__bright_foreground_holo_light"/-->
|
||||||
|
<item android:color="@color/vpi__bright_foreground_holo_light"/> <!-- not selected -->
|
||||||
|
|
||||||
|
</selector>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 147 B |
|
After Width: | Height: | Size: 148 B |
|
After Width: | Height: | Size: 147 B |
|
After Width: | Height: | Size: 146 B |
|
After Width: | Height: | Size: 153 B |
|
After Width: | Height: | Size: 145 B |
|
After Width: | Height: | Size: 148 B |
|
After Width: | Height: | Size: 151 B |
|
After Width: | Height: | Size: 150 B |
|
After Width: | Height: | Size: 150 B |
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 155 B |
|
After Width: | Height: | Size: 147 B |
|
After Width: | Height: | Size: 153 B |
|
After Width: | Height: | Size: 147 B |
|
After Width: | Height: | Size: 148 B |
|
After Width: | Height: | Size: 166 B |
|
After Width: | Height: | Size: 149 B |
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2008 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- Non focused states -->
|
||||||
|
<item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/vpi__tab_unselected_holo" />
|
||||||
|
<item android:state_focused="false" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/vpi__tab_selected_holo" />
|
||||||
|
|
||||||
|
<!-- Focused states -->
|
||||||
|
<item android:state_focused="true" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/vpi__tab_unselected_focused_holo" />
|
||||||
|
<item android:state_focused="true" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/vpi__tab_selected_focused_holo" />
|
||||||
|
|
||||||
|
<!-- Pressed -->
|
||||||
|
<!-- Non focused states -->
|
||||||
|
<item android:state_focused="false" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/vpi__tab_unselected_pressed_holo" />
|
||||||
|
<item android:state_focused="false" android:state_selected="true" android:state_pressed="true" android:drawable="@drawable/vpi__tab_selected_pressed_holo" />
|
||||||
|
|
||||||
|
<!-- Focused states -->
|
||||||
|
<item android:state_focused="true" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/vpi__tab_unselected_pressed_holo" />
|
||||||
|
<item android:state_focused="true" android:state_selected="true" android:state_pressed="true" android:drawable="@drawable/vpi__tab_selected_pressed_holo" />
|
||||||
|
</selector>
|
||||||
@@ -180,7 +180,7 @@
|
|||||||
android:id="@+id/stop_tracking_box"
|
android:id="@+id/stop_tracking_box"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"
|
||||||
android:layout_above="@id/bottomLayout"
|
android:layout_alignParentBottom="true"
|
||||||
android:background="@color/gray" >
|
android:background="@color/gray" >
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@@ -203,23 +203,5 @@
|
|||||||
android:textAllCaps="true"
|
android:textAllCaps="true"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/bottomLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:background="@color/darker_gray" >
|
|
||||||
|
|
||||||
<com.sap.sailing.android.tracking.app.customviews.OpenSansTextView
|
|
||||||
android:id="@+id/bottom_announcement"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textColor="@color/white" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
@@ -36,8 +36,18 @@
|
|||||||
android:id="@+id/pager"
|
android:id="@+id/pager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_below="@id/toolbar" />
|
android:layout_below="@id/toolbar"
|
||||||
|
android:layout_above="@+id/title_page_indicator"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<com.viewpagerindicator.CirclePageIndicator
|
||||||
|
android:id="@+id/title_page_indicator"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="#00000000"
|
||||||
|
android:layout_alignParentBottom="true"/>
|
||||||
|
|
||||||
<!-- <FrameLayout
|
<!-- <FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -179,7 +179,7 @@
|
|||||||
android:id="@+id/stop_tracking_box"
|
android:id="@+id/stop_tracking_box"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="100dp"
|
android:layout_height="100dp"
|
||||||
android:layout_above="@id/bottomLayout"
|
android:layout_alignParentBottom="true"
|
||||||
android:background="@color/gray" >
|
android:background="@color/gray" >
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@@ -202,23 +202,4 @@
|
|||||||
android:textAllCaps="true"
|
android:textAllCaps="true"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/bottomLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:background="@color/darker_gray" >
|
|
||||||
|
|
||||||
<com.sap.sailing.android.tracking.app.customviews.OpenSansTextView
|
|
||||||
android:id="@+id/bottom_announcement"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textColor="@color/white" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2012 Jake Wharton
|
||||||
|
Copyright (C) 2011 Patrik Åkerfeldt
|
||||||
|
|
||||||
|
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 circle indicator. -->
|
||||||
|
<attr name="vpiCirclePageIndicatorStyle" format="reference"/>
|
||||||
|
<!-- Style of the icon indicator's views. -->
|
||||||
|
<attr name="vpiIconPageIndicatorStyle" format="reference"/>
|
||||||
|
<!-- Style of the line indicator. -->
|
||||||
|
<attr name="vpiLinePageIndicatorStyle" format="reference"/>
|
||||||
|
<!-- Style of the title indicator. -->
|
||||||
|
<attr name="vpiTitlePageIndicatorStyle" format="reference"/>
|
||||||
|
<!-- Style of the tab indicator's tabs. -->
|
||||||
|
<attr name="vpiTabPageIndicatorStyle" format="reference"/>
|
||||||
|
<!-- Style of the underline indicator. -->
|
||||||
|
<attr name="vpiUnderlinePageIndicatorStyle" format="reference"/>
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
|
<attr name="centered" format="boolean" />
|
||||||
|
<attr name="selectedColor" format="color" />
|
||||||
|
<attr name="strokeWidth" format="dimension" />
|
||||||
|
<attr name="unselectedColor" format="color" />
|
||||||
|
|
||||||
|
<declare-styleable name="CirclePageIndicator">
|
||||||
|
<!-- Whether or not the indicators should be centered. -->
|
||||||
|
<attr name="centered" />
|
||||||
|
<!-- Color of the filled circle that represents the current page. -->
|
||||||
|
<attr name="fillColor" format="color" />
|
||||||
|
<!-- Color of the filled circles that represents pages. -->
|
||||||
|
<attr name="pageColor" format="color" />
|
||||||
|
<!-- Orientation of the indicator. -->
|
||||||
|
<attr name="android:orientation"/>
|
||||||
|
<!-- Radius of the circles. This is also the spacing between circles. -->
|
||||||
|
<attr name="radius" format="dimension" />
|
||||||
|
<!-- Whether or not the selected indicator snaps to the circles. -->
|
||||||
|
<attr name="snap" format="boolean" />
|
||||||
|
<!-- Color of the open circles. -->
|
||||||
|
<attr name="strokeColor" format="color" />
|
||||||
|
<!-- Width of the stroke used to draw the circles. -->
|
||||||
|
<attr name="strokeWidth" />
|
||||||
|
<!-- View background -->
|
||||||
|
<attr name="android:background"/>
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
|
<declare-styleable name="LinePageIndicator">
|
||||||
|
<!-- Whether or not the indicators should be centered. -->
|
||||||
|
<attr name="centered" />
|
||||||
|
<!-- Color of the unselected lines that represent the pages. -->
|
||||||
|
<attr name="unselectedColor" />
|
||||||
|
<!-- Color of the selected line that represents the current page. -->
|
||||||
|
<attr name="selectedColor" />
|
||||||
|
<!-- Width of each indicator line. -->
|
||||||
|
<attr name="lineWidth" format="dimension" />
|
||||||
|
<!-- Width of each indicator line's stroke. -->
|
||||||
|
<attr name="strokeWidth" />
|
||||||
|
<!-- Width of the gap between each indicator line. -->
|
||||||
|
<attr name="gapWidth" format="dimension" />
|
||||||
|
<!-- View background -->
|
||||||
|
<attr name="android:background"/>
|
||||||
|
</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" />
|
||||||
|
<!-- Position of the line. -->
|
||||||
|
<attr name="linePosition">
|
||||||
|
<enum name="bottom" value="0"/>
|
||||||
|
<enum name="top" value="1"/>
|
||||||
|
</attr>
|
||||||
|
<!-- Color of the selected title. -->
|
||||||
|
<attr name="selectedColor" />
|
||||||
|
<!-- Whether or not the selected item is displayed as bold. -->
|
||||||
|
<attr name="selectedBold" format="boolean" />
|
||||||
|
<!-- Color of regular titles. -->
|
||||||
|
<attr name="android:textColor" />
|
||||||
|
<!-- Size of title text. -->
|
||||||
|
<attr name="android:textSize" />
|
||||||
|
<!-- 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" />
|
||||||
|
<!-- View background -->
|
||||||
|
<attr name="android:background"/>
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
|
<declare-styleable name="UnderlinePageIndicator">
|
||||||
|
<!-- Whether or not the selected indicator fades. -->
|
||||||
|
<attr name="fades" format="boolean" />
|
||||||
|
<!-- Length of the delay to fade the indicator. -->
|
||||||
|
<attr name="fadeDelay" format="integer" />
|
||||||
|
<!-- Length of the indicator fade to transparent. -->
|
||||||
|
<attr name="fadeLength" format="integer" />
|
||||||
|
<!-- Color of the selected line that represents the current page. -->
|
||||||
|
<attr name="selectedColor" />
|
||||||
|
<!-- View background -->
|
||||||
|
<attr name="android:background"/>
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2012 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>
|
||||||
|
<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>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2012 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>
|
||||||
|
<bool name="default_circle_indicator_centered">true</bool>
|
||||||
|
<color name="default_circle_indicator_fill_color">#FFFFFFFF</color>
|
||||||
|
<color name="default_circle_indicator_page_color">#00000000</color>
|
||||||
|
<integer name="default_circle_indicator_orientation">0</integer>
|
||||||
|
<dimen name="default_circle_indicator_radius">3dp</dimen>
|
||||||
|
<bool name="default_circle_indicator_snap">false</bool>
|
||||||
|
<color name="default_circle_indicator_stroke_color">#FFDDDDDD</color>
|
||||||
|
<dimen name="default_circle_indicator_stroke_width">1dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="default_line_indicator_line_width">12dp</dimen>
|
||||||
|
<dimen name="default_line_indicator_gap_width">4dp</dimen>
|
||||||
|
<dimen name="default_line_indicator_stroke_width">1dp</dimen>
|
||||||
|
<color name="default_line_indicator_selected_color">#FF33B5E5</color>
|
||||||
|
<color name="default_line_indicator_unselected_color">#FFBBBBBB</color>
|
||||||
|
<bool name="default_line_indicator_centered">true</bool>
|
||||||
|
|
||||||
|
<dimen name="default_title_indicator_clip_padding">4dp</dimen>
|
||||||
|
<color name="default_title_indicator_footer_color">#FF33B5E5</color>
|
||||||
|
<dimen name="default_title_indicator_footer_line_height">2dp</dimen>
|
||||||
|
<integer name="default_title_indicator_footer_indicator_style">2</integer>
|
||||||
|
<dimen name="default_title_indicator_footer_indicator_height">4dp</dimen>
|
||||||
|
<dimen name="default_title_indicator_footer_indicator_underline_padding">20dp</dimen>
|
||||||
|
<dimen name="default_title_indicator_footer_padding">7dp</dimen>
|
||||||
|
<integer name="default_title_indicator_line_position">0</integer>
|
||||||
|
<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">#BBFFFFFF</color>
|
||||||
|
<dimen name="default_title_indicator_text_size">15dp</dimen>
|
||||||
|
<dimen name="default_title_indicator_title_padding">5dp</dimen>
|
||||||
|
<dimen name="default_title_indicator_top_padding">7dp</dimen>
|
||||||
|
|
||||||
|
<bool name="default_underline_indicator_fades">true</bool>
|
||||||
|
<integer name="default_underline_indicator_fade_delay">300</integer>
|
||||||
|
<integer name="default_underline_indicator_fade_length">400</integer>
|
||||||
|
<color name="default_underline_indicator_selected_color">#FF33B5E5</color>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?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="vpiIconPageIndicatorStyle">@style/Widget.IconPageIndicator</item>
|
||||||
|
<item name="vpiTabPageIndicatorStyle">@style/Widget.TabPageIndicator</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget">
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.TabPageIndicator" parent="Widget">
|
||||||
|
<item name="android:gravity">center</item>
|
||||||
|
<item name="android:background">@drawable/vpi__tab_indicator</item>
|
||||||
|
<item name="android:paddingLeft">22dip</item>
|
||||||
|
<item name="android:paddingRight">22dip</item>
|
||||||
|
<item name="android:paddingTop">12dp</item>
|
||||||
|
<item name="android:paddingBottom">12dp</item>
|
||||||
|
<item name="android:textAppearance">@style/TextAppearance.TabPageIndicator</item>
|
||||||
|
<item name="android:textSize">12sp</item>
|
||||||
|
<item name="android:maxLines">1</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="TextAppearance.TabPageIndicator" parent="Widget">
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="android:textColor">@color/vpi__dark_theme</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.IconPageIndicator" parent="Widget">
|
||||||
|
<item name="android:layout_marginLeft">6dp</item>
|
||||||
|
<item name="android:layout_marginRight">6dp</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
@@ -9,11 +9,10 @@ import android.os.IBinder;
|
|||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||||
import android.support.v4.view.PagerAdapter;
|
|
||||||
import android.support.v4.view.ViewPager;
|
import android.support.v4.view.ViewPager;
|
||||||
|
import android.support.v4.view.ViewPager.OnPageChangeListener;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
|
|
||||||
import com.google.android.gms.internal.cm;
|
|
||||||
import com.sap.sailing.android.shared.logging.ExLog;
|
import com.sap.sailing.android.shared.logging.ExLog;
|
||||||
import com.sap.sailing.android.tracking.app.BuildConfig;
|
import com.sap.sailing.android.tracking.app.BuildConfig;
|
||||||
import com.sap.sailing.android.tracking.app.R;
|
import com.sap.sailing.android.tracking.app.R;
|
||||||
@@ -28,11 +27,11 @@ import com.sap.sailing.android.tracking.app.services.TransmittingService.APIConn
|
|||||||
import com.sap.sailing.android.tracking.app.services.TransmittingService.APIConnectivityListener;
|
import com.sap.sailing.android.tracking.app.services.TransmittingService.APIConnectivityListener;
|
||||||
import com.sap.sailing.android.tracking.app.services.TransmittingService.TransmittingBinder;
|
import com.sap.sailing.android.tracking.app.services.TransmittingService.TransmittingBinder;
|
||||||
import com.sap.sailing.android.tracking.app.ui.fragments.CompassFragment;
|
import com.sap.sailing.android.tracking.app.ui.fragments.CompassFragment;
|
||||||
import com.sap.sailing.android.tracking.app.ui.fragments.HudFragment;
|
|
||||||
import com.sap.sailing.android.tracking.app.ui.fragments.TrackingFragment;
|
import com.sap.sailing.android.tracking.app.ui.fragments.TrackingFragment;
|
||||||
import com.sap.sailing.android.tracking.app.utils.AppPreferences;
|
import com.sap.sailing.android.tracking.app.utils.AppPreferences;
|
||||||
import com.sap.sailing.android.tracking.app.utils.DatabaseHelper;
|
import com.sap.sailing.android.tracking.app.utils.DatabaseHelper;
|
||||||
import com.sap.sailing.android.tracking.app.valueobjects.EventInfo;
|
import com.sap.sailing.android.tracking.app.valueobjects.EventInfo;
|
||||||
|
import com.viewpagerindicator.CirclePageIndicator;
|
||||||
|
|
||||||
public class TrackingActivity extends BaseActivity implements GPSQualityListener, APIConnectivityListener, MagneticHeadingListener {
|
public class TrackingActivity extends BaseActivity implements GPSQualityListener, APIConnectivityListener, MagneticHeadingListener {
|
||||||
|
|
||||||
@@ -100,6 +99,24 @@ public class TrackingActivity extends BaseActivity implements GPSQualityListener
|
|||||||
compassFragment = new CompassFragment();
|
compassFragment = new CompassFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Bind the title indicator to the adapter
|
||||||
|
CirclePageIndicator titleIndicator = (CirclePageIndicator)findViewById(R.id.title_page_indicator);
|
||||||
|
titleIndicator.setViewPager(mPager);
|
||||||
|
titleIndicator.setOnPageChangeListener(new OnPageChangeListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int arg0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrolled(int arg0, float arg1, int arg2) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrollStateChanged(int arg0) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
startTrackingService(eventId);
|
startTrackingService(eventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,9 +128,12 @@ public class TrackingFragment extends BaseFragment implements OnClickListener {
|
|||||||
*/
|
*/
|
||||||
public void updateTimer()
|
public void updateTimer()
|
||||||
{
|
{
|
||||||
long diff = System.currentTimeMillis() - prefs.getTrackingTimerStarted();
|
if (isAdded())
|
||||||
AutoResizeTextView textView = (AutoResizeTextView) getActivity().findViewById(R.id.tracking_time_label);
|
{
|
||||||
textView.setText(getTimeFormatString(diff));
|
long diff = System.currentTimeMillis() - prefs.getTrackingTimerStarted();
|
||||||
|
AutoResizeTextView textView = (AutoResizeTextView) getActivity().findViewById(R.id.tracking_time_label);
|
||||||
|
textView.setText(getTimeFormatString(diff));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,556 @@
|
|||||||
|
/*
|
||||||
|
* 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 static android.graphics.Paint.ANTI_ALIAS_FLAG;
|
||||||
|
import static android.widget.LinearLayout.HORIZONTAL;
|
||||||
|
import static android.widget.LinearLayout.VERTICAL;
|
||||||
|
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.Paint.Style;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.support.v4.view.MotionEventCompat;
|
||||||
|
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 com.sap.sailing.android.tracking.app.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws circles (one for each view). The current view position is filled and
|
||||||
|
* others are only stroked.
|
||||||
|
*/
|
||||||
|
public class CirclePageIndicator extends View implements PageIndicator {
|
||||||
|
private static final int INVALID_POINTER = -1;
|
||||||
|
|
||||||
|
private float mRadius;
|
||||||
|
private final Paint mPaintPageFill = new Paint(ANTI_ALIAS_FLAG);
|
||||||
|
private final Paint mPaintStroke = new Paint(ANTI_ALIAS_FLAG);
|
||||||
|
private final Paint mPaintFill = new Paint(ANTI_ALIAS_FLAG);
|
||||||
|
private ViewPager mViewPager;
|
||||||
|
private ViewPager.OnPageChangeListener mListener;
|
||||||
|
private int mCurrentPage;
|
||||||
|
private int mSnapPage;
|
||||||
|
private float mPageOffset;
|
||||||
|
private int mScrollState;
|
||||||
|
private int mOrientation;
|
||||||
|
private boolean mCentered;
|
||||||
|
private boolean mSnap;
|
||||||
|
|
||||||
|
private int mTouchSlop;
|
||||||
|
private float mLastMotionX = -1;
|
||||||
|
private int mActivePointerId = INVALID_POINTER;
|
||||||
|
private boolean mIsDragging;
|
||||||
|
|
||||||
|
|
||||||
|
public CirclePageIndicator(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CirclePageIndicator(Context context, AttributeSet attrs) {
|
||||||
|
this(context, attrs, R.attr.vpiCirclePageIndicatorStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
if (isInEditMode()) return;
|
||||||
|
|
||||||
|
//Load defaults from resources
|
||||||
|
final Resources res = getResources();
|
||||||
|
final int defaultPageColor = res.getColor(R.color.default_circle_indicator_page_color);
|
||||||
|
final int defaultFillColor = res.getColor(R.color.default_circle_indicator_fill_color);
|
||||||
|
final int defaultOrientation = res.getInteger(R.integer.default_circle_indicator_orientation);
|
||||||
|
final int defaultStrokeColor = res.getColor(R.color.default_circle_indicator_stroke_color);
|
||||||
|
final float defaultStrokeWidth = res.getDimension(R.dimen.default_circle_indicator_stroke_width);
|
||||||
|
final float defaultRadius = res.getDimension(R.dimen.default_circle_indicator_radius);
|
||||||
|
final boolean defaultCentered = res.getBoolean(R.bool.default_circle_indicator_centered);
|
||||||
|
final boolean defaultSnap = res.getBoolean(R.bool.default_circle_indicator_snap);
|
||||||
|
|
||||||
|
//Retrieve styles attributes
|
||||||
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyle, 0);
|
||||||
|
|
||||||
|
mCentered = a.getBoolean(R.styleable.CirclePageIndicator_centered, defaultCentered);
|
||||||
|
mOrientation = a.getInt(R.styleable.CirclePageIndicator_android_orientation, defaultOrientation);
|
||||||
|
mPaintPageFill.setStyle(Style.FILL);
|
||||||
|
mPaintPageFill.setColor(a.getColor(R.styleable.CirclePageIndicator_pageColor, defaultPageColor));
|
||||||
|
mPaintStroke.setStyle(Style.STROKE);
|
||||||
|
mPaintStroke.setColor(a.getColor(R.styleable.CirclePageIndicator_strokeColor, defaultStrokeColor));
|
||||||
|
mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth));
|
||||||
|
mPaintFill.setStyle(Style.FILL);
|
||||||
|
mPaintFill.setColor(a.getColor(R.styleable.CirclePageIndicator_fillColor, defaultFillColor));
|
||||||
|
mRadius = a.getDimension(R.styleable.CirclePageIndicator_radius, defaultRadius);
|
||||||
|
mSnap = a.getBoolean(R.styleable.CirclePageIndicator_snap, defaultSnap);
|
||||||
|
|
||||||
|
Drawable background = a.getDrawable(R.styleable.CirclePageIndicator_android_background);
|
||||||
|
if (background != null) {
|
||||||
|
setBackgroundDrawable(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.recycle();
|
||||||
|
|
||||||
|
final ViewConfiguration configuration = ViewConfiguration.get(context);
|
||||||
|
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setCentered(boolean centered) {
|
||||||
|
mCentered = centered;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCentered() {
|
||||||
|
return mCentered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPageColor(int pageColor) {
|
||||||
|
mPaintPageFill.setColor(pageColor);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPageColor() {
|
||||||
|
return mPaintPageFill.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFillColor(int fillColor) {
|
||||||
|
mPaintFill.setColor(fillColor);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFillColor() {
|
||||||
|
return mPaintFill.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrientation(int orientation) {
|
||||||
|
switch (orientation) {
|
||||||
|
case HORIZONTAL:
|
||||||
|
case VERTICAL:
|
||||||
|
mOrientation = orientation;
|
||||||
|
requestLayout();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Orientation must be either HORIZONTAL or VERTICAL.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOrientation() {
|
||||||
|
return mOrientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStrokeColor(int strokeColor) {
|
||||||
|
mPaintStroke.setColor(strokeColor);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStrokeColor() {
|
||||||
|
return mPaintStroke.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStrokeWidth(float strokeWidth) {
|
||||||
|
mPaintStroke.setStrokeWidth(strokeWidth);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getStrokeWidth() {
|
||||||
|
return mPaintStroke.getStrokeWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRadius(float radius) {
|
||||||
|
mRadius = radius;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRadius() {
|
||||||
|
return mRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSnap(boolean snap) {
|
||||||
|
mSnap = snap;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSnap() {
|
||||||
|
return mSnap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
if (mViewPager == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int count = mViewPager.getAdapter().getCount();
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCurrentPage >= count) {
|
||||||
|
setCurrentItem(count - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int longSize;
|
||||||
|
int longPaddingBefore;
|
||||||
|
int longPaddingAfter;
|
||||||
|
int shortPaddingBefore;
|
||||||
|
if (mOrientation == HORIZONTAL) {
|
||||||
|
longSize = getWidth();
|
||||||
|
longPaddingBefore = getPaddingLeft();
|
||||||
|
longPaddingAfter = getPaddingRight();
|
||||||
|
shortPaddingBefore = getPaddingTop();
|
||||||
|
} else {
|
||||||
|
longSize = getHeight();
|
||||||
|
longPaddingBefore = getPaddingTop();
|
||||||
|
longPaddingAfter = getPaddingBottom();
|
||||||
|
shortPaddingBefore = getPaddingLeft();
|
||||||
|
}
|
||||||
|
|
||||||
|
final float threeRadius = mRadius * 3;
|
||||||
|
final float shortOffset = shortPaddingBefore + mRadius;
|
||||||
|
float longOffset = longPaddingBefore + mRadius;
|
||||||
|
if (mCentered) {
|
||||||
|
longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - ((count * threeRadius) / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dX;
|
||||||
|
float dY;
|
||||||
|
|
||||||
|
float pageFillRadius = mRadius;
|
||||||
|
if (mPaintStroke.getStrokeWidth() > 0) {
|
||||||
|
pageFillRadius -= mPaintStroke.getStrokeWidth() / 2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw stroked circles
|
||||||
|
for (int iLoop = 0; iLoop < count; iLoop++) {
|
||||||
|
float drawLong = longOffset + (iLoop * threeRadius);
|
||||||
|
if (mOrientation == HORIZONTAL) {
|
||||||
|
dX = drawLong;
|
||||||
|
dY = shortOffset;
|
||||||
|
} else {
|
||||||
|
dX = shortOffset;
|
||||||
|
dY = drawLong;
|
||||||
|
}
|
||||||
|
// Only paint fill if not completely transparent
|
||||||
|
if (mPaintPageFill.getAlpha() > 0) {
|
||||||
|
canvas.drawCircle(dX, dY, pageFillRadius, mPaintPageFill);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only paint stroke if a stroke width was non-zero
|
||||||
|
if (pageFillRadius != mRadius) {
|
||||||
|
canvas.drawCircle(dX, dY, mRadius, mPaintStroke);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw the filled circle according to the current scroll
|
||||||
|
float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius;
|
||||||
|
if (!mSnap) {
|
||||||
|
cx += mPageOffset * threeRadius;
|
||||||
|
}
|
||||||
|
if (mOrientation == HORIZONTAL) {
|
||||||
|
dX = longOffset + cx;
|
||||||
|
dY = shortOffset;
|
||||||
|
} else {
|
||||||
|
dX = shortOffset;
|
||||||
|
dY = longOffset + cx;
|
||||||
|
}
|
||||||
|
canvas.drawCircle(dX, dY, mRadius, mPaintFill);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(android.view.MotionEvent ev) {
|
||||||
|
if (super.onTouchEvent(ev)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
|
||||||
|
switch (action) {
|
||||||
|
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) {
|
||||||
|
mLastMotionX = x;
|
||||||
|
if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) {
|
||||||
|
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)) {
|
||||||
|
if (action != MotionEvent.ACTION_CANCEL) {
|
||||||
|
mViewPager.setCurrentItem(mCurrentPage - 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) {
|
||||||
|
if (action != MotionEvent.ACTION_CANCEL) {
|
||||||
|
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);
|
||||||
|
mLastMotionX = MotionEventCompat.getX(ev, index);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view) {
|
||||||
|
if (mViewPager == view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mViewPager != null) {
|
||||||
|
mViewPager.setOnPageChangeListener(null);
|
||||||
|
}
|
||||||
|
if (view.getAdapter() == null) {
|
||||||
|
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||||
|
}
|
||||||
|
mViewPager = view;
|
||||||
|
mViewPager.setOnPageChangeListener(this);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view, int initialPosition) {
|
||||||
|
setViewPager(view);
|
||||||
|
setCurrentItem(initialPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 notifyDataSetChanged() {
|
||||||
|
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;
|
||||||
|
mPageOffset = positionOffset;
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int position) {
|
||||||
|
if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) {
|
||||||
|
mCurrentPage = position;
|
||||||
|
mSnapPage = 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) {
|
||||||
|
if (mOrientation == HORIZONTAL) {
|
||||||
|
setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec));
|
||||||
|
} else {
|
||||||
|
setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(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 measureLong(int measureSpec) {
|
||||||
|
int result;
|
||||||
|
int specMode = MeasureSpec.getMode(measureSpec);
|
||||||
|
int specSize = MeasureSpec.getSize(measureSpec);
|
||||||
|
|
||||||
|
if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) {
|
||||||
|
//We were told how big to be
|
||||||
|
result = specSize;
|
||||||
|
} else {
|
||||||
|
//Calculate the width according the views count
|
||||||
|
final int count = mViewPager.getAdapter().getCount();
|
||||||
|
result = (int)(getPaddingLeft() + getPaddingRight()
|
||||||
|
+ (count * 2 * mRadius) + (count - 1) * mRadius + 1);
|
||||||
|
//Respect AT_MOST value if that was what is called for by measureSpec
|
||||||
|
if (specMode == MeasureSpec.AT_MOST) {
|
||||||
|
result = Math.min(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 measureShort(int measureSpec) {
|
||||||
|
int result;
|
||||||
|
int specMode = MeasureSpec.getMode(measureSpec);
|
||||||
|
int specSize = MeasureSpec.getSize(measureSpec);
|
||||||
|
|
||||||
|
if (specMode == MeasureSpec.EXACTLY) {
|
||||||
|
//We were told how big to be
|
||||||
|
result = specSize;
|
||||||
|
} else {
|
||||||
|
//Measure the height
|
||||||
|
result = (int)(2 * mRadius + getPaddingTop() + getPaddingBottom() + 1);
|
||||||
|
//Respect AT_MOST value if that was what is called for by measureSpec
|
||||||
|
if (specMode == MeasureSpec.AT_MOST) {
|
||||||
|
result = Math.min(result, specSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRestoreInstanceState(Parcelable state) {
|
||||||
|
SavedState savedState = (SavedState)state;
|
||||||
|
super.onRestoreInstanceState(savedState.getSuperState());
|
||||||
|
mCurrentPage = savedState.currentPage;
|
||||||
|
mSnapPage = 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
* Copyright (C) 2012 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 static android.view.ViewGroup.LayoutParams.FILL_PARENT;
|
||||||
|
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v4.view.PagerAdapter;
|
||||||
|
import android.support.v4.view.ViewPager;
|
||||||
|
import android.support.v4.view.ViewPager.OnPageChangeListener;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.HorizontalScrollView;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.sap.sailing.android.tracking.app.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This widget implements the dynamic action bar tab behavior that can change
|
||||||
|
* across different configurations or circumstances.
|
||||||
|
*/
|
||||||
|
public class IconPageIndicator extends HorizontalScrollView implements PageIndicator {
|
||||||
|
private final IcsLinearLayout mIconsLayout;
|
||||||
|
|
||||||
|
private ViewPager mViewPager;
|
||||||
|
private OnPageChangeListener mListener;
|
||||||
|
private Runnable mIconSelector;
|
||||||
|
private int mSelectedIndex;
|
||||||
|
|
||||||
|
public IconPageIndicator(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IconPageIndicator(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
setHorizontalScrollBarEnabled(false);
|
||||||
|
|
||||||
|
mIconsLayout = new IcsLinearLayout(context, R.attr.vpiIconPageIndicatorStyle);
|
||||||
|
addView(mIconsLayout, new LayoutParams(WRAP_CONTENT, FILL_PARENT, Gravity.CENTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void animateToIcon(final int position) {
|
||||||
|
final View iconView = mIconsLayout.getChildAt(position);
|
||||||
|
if (mIconSelector != null) {
|
||||||
|
removeCallbacks(mIconSelector);
|
||||||
|
}
|
||||||
|
mIconSelector = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
final int scrollPos = iconView.getLeft() - (getWidth() - iconView.getWidth()) / 2;
|
||||||
|
smoothScrollTo(scrollPos, 0);
|
||||||
|
mIconSelector = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
post(mIconSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow();
|
||||||
|
if (mIconSelector != null) {
|
||||||
|
// Re-post the selector we saved
|
||||||
|
post(mIconSelector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetachedFromWindow() {
|
||||||
|
super.onDetachedFromWindow();
|
||||||
|
if (mIconSelector != null) {
|
||||||
|
removeCallbacks(mIconSelector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrollStateChanged(int arg0) {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageScrollStateChanged(arg0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrolled(int arg0, float arg1, int arg2) {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageScrolled(arg0, arg1, arg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int arg0) {
|
||||||
|
setCurrentItem(arg0);
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageSelected(arg0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view) {
|
||||||
|
if (mViewPager == view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mViewPager != null) {
|
||||||
|
mViewPager.setOnPageChangeListener(null);
|
||||||
|
}
|
||||||
|
PagerAdapter adapter = view.getAdapter();
|
||||||
|
if (adapter == null) {
|
||||||
|
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||||
|
}
|
||||||
|
mViewPager = view;
|
||||||
|
view.setOnPageChangeListener(this);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyDataSetChanged() {
|
||||||
|
mIconsLayout.removeAllViews();
|
||||||
|
IconPagerAdapter iconAdapter = (IconPagerAdapter) mViewPager.getAdapter();
|
||||||
|
int count = iconAdapter.getCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
ImageView view = new ImageView(getContext(), null, R.attr.vpiIconPageIndicatorStyle);
|
||||||
|
view.setImageResource(iconAdapter.getIconResId(i));
|
||||||
|
mIconsLayout.addView(view);
|
||||||
|
}
|
||||||
|
if (mSelectedIndex > count) {
|
||||||
|
mSelectedIndex = count - 1;
|
||||||
|
}
|
||||||
|
setCurrentItem(mSelectedIndex);
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view, int initialPosition) {
|
||||||
|
setViewPager(view);
|
||||||
|
setCurrentItem(initialPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentItem(int item) {
|
||||||
|
if (mViewPager == null) {
|
||||||
|
throw new IllegalStateException("ViewPager has not been bound.");
|
||||||
|
}
|
||||||
|
mSelectedIndex = item;
|
||||||
|
mViewPager.setCurrentItem(item);
|
||||||
|
|
||||||
|
int tabCount = mIconsLayout.getChildCount();
|
||||||
|
for (int i = 0; i < tabCount; i++) {
|
||||||
|
View child = mIconsLayout.getChildAt(i);
|
||||||
|
boolean isSelected = (i == item);
|
||||||
|
child.setSelected(isSelected);
|
||||||
|
if (isSelected) {
|
||||||
|
animateToIcon(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOnPageChangeListener(OnPageChangeListener listener) {
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.viewpagerindicator;
|
||||||
|
|
||||||
|
public interface IconPagerAdapter {
|
||||||
|
/**
|
||||||
|
* Get icon representing the page at {@code index} in the adapter.
|
||||||
|
*/
|
||||||
|
int getIconResId(int index);
|
||||||
|
|
||||||
|
// From PagerAdapter
|
||||||
|
int getCount();
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
package com.viewpagerindicator;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple extension of a regular linear layout that supports the divider API
|
||||||
|
* of Android 4.0+. The dividers are added adjacent to the children by changing
|
||||||
|
* their layout params. If you need to rely on the margins which fall in the
|
||||||
|
* same orientation as the layout you should wrap the child in a simple
|
||||||
|
* {@link android.widget.FrameLayout} so it can receive the margin.
|
||||||
|
*/
|
||||||
|
class IcsLinearLayout extends LinearLayout {
|
||||||
|
private static final int[] LL = new int[] {
|
||||||
|
/* 0 */ android.R.attr.divider,
|
||||||
|
/* 1 */ android.R.attr.showDividers,
|
||||||
|
/* 2 */ android.R.attr.dividerPadding,
|
||||||
|
};
|
||||||
|
private static final int LL_DIVIDER = 0;
|
||||||
|
private static final int LL_SHOW_DIVIDER = 1;
|
||||||
|
private static final int LL_DIVIDER_PADDING = 2;
|
||||||
|
|
||||||
|
private Drawable mDivider;
|
||||||
|
private int mDividerWidth;
|
||||||
|
private int mDividerHeight;
|
||||||
|
private int mShowDividers;
|
||||||
|
private int mDividerPadding;
|
||||||
|
|
||||||
|
|
||||||
|
public IcsLinearLayout(Context context, int themeAttr) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
TypedArray a = context.obtainStyledAttributes(null, LL, themeAttr, 0);
|
||||||
|
setDividerDrawable(a.getDrawable(IcsLinearLayout.LL_DIVIDER));
|
||||||
|
mDividerPadding = a.getDimensionPixelSize(LL_DIVIDER_PADDING, 0);
|
||||||
|
mShowDividers = a.getInteger(LL_SHOW_DIVIDER, SHOW_DIVIDER_NONE);
|
||||||
|
a.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDividerDrawable(Drawable divider) {
|
||||||
|
if (divider == mDivider) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mDivider = divider;
|
||||||
|
if (divider != null) {
|
||||||
|
mDividerWidth = divider.getIntrinsicWidth();
|
||||||
|
mDividerHeight = divider.getIntrinsicHeight();
|
||||||
|
} else {
|
||||||
|
mDividerWidth = 0;
|
||||||
|
mDividerHeight = 0;
|
||||||
|
}
|
||||||
|
setWillNotDraw(divider == null);
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
|
||||||
|
final int index = indexOfChild(child);
|
||||||
|
final int orientation = getOrientation();
|
||||||
|
final LayoutParams params = (LayoutParams) child.getLayoutParams();
|
||||||
|
if (hasDividerBeforeChildAt(index)) {
|
||||||
|
if (orientation == VERTICAL) {
|
||||||
|
//Account for the divider by pushing everything up
|
||||||
|
params.topMargin = mDividerHeight;
|
||||||
|
} else {
|
||||||
|
//Account for the divider by pushing everything left
|
||||||
|
params.leftMargin = mDividerWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final int count = getChildCount();
|
||||||
|
if (index == count - 1) {
|
||||||
|
if (hasDividerBeforeChildAt(count)) {
|
||||||
|
if (orientation == VERTICAL) {
|
||||||
|
params.bottomMargin = mDividerHeight;
|
||||||
|
} else {
|
||||||
|
params.rightMargin = mDividerWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
if (mDivider != null) {
|
||||||
|
if (getOrientation() == VERTICAL) {
|
||||||
|
drawDividersVertical(canvas);
|
||||||
|
} else {
|
||||||
|
drawDividersHorizontal(canvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.onDraw(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawDividersVertical(Canvas canvas) {
|
||||||
|
final int count = getChildCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
final View child = getChildAt(i);
|
||||||
|
|
||||||
|
if (child != null && child.getVisibility() != GONE) {
|
||||||
|
if (hasDividerBeforeChildAt(i)) {
|
||||||
|
final android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) child.getLayoutParams();
|
||||||
|
final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
|
||||||
|
drawHorizontalDivider(canvas, top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasDividerBeforeChildAt(count)) {
|
||||||
|
final View child = getChildAt(count - 1);
|
||||||
|
int bottom = 0;
|
||||||
|
if (child == null) {
|
||||||
|
bottom = getHeight() - getPaddingBottom() - mDividerHeight;
|
||||||
|
} else {
|
||||||
|
//final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||||
|
bottom = child.getBottom()/* + lp.bottomMargin*/;
|
||||||
|
}
|
||||||
|
drawHorizontalDivider(canvas, bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawDividersHorizontal(Canvas canvas) {
|
||||||
|
final int count = getChildCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
final View child = getChildAt(i);
|
||||||
|
|
||||||
|
if (child != null && child.getVisibility() != GONE) {
|
||||||
|
if (hasDividerBeforeChildAt(i)) {
|
||||||
|
final android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) child.getLayoutParams();
|
||||||
|
final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
|
||||||
|
drawVerticalDivider(canvas, left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasDividerBeforeChildAt(count)) {
|
||||||
|
final View child = getChildAt(count - 1);
|
||||||
|
int right = 0;
|
||||||
|
if (child == null) {
|
||||||
|
right = getWidth() - getPaddingRight() - mDividerWidth;
|
||||||
|
} else {
|
||||||
|
//final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||||
|
right = child.getRight()/* + lp.rightMargin*/;
|
||||||
|
}
|
||||||
|
drawVerticalDivider(canvas, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawHorizontalDivider(Canvas canvas, int top) {
|
||||||
|
mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
|
||||||
|
getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
|
||||||
|
mDivider.draw(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawVerticalDivider(Canvas canvas, int left) {
|
||||||
|
mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
|
||||||
|
left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
|
||||||
|
mDivider.draw(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasDividerBeforeChildAt(int childIndex) {
|
||||||
|
if (childIndex == 0 || childIndex == getChildCount()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
|
||||||
|
boolean hasVisibleViewBefore = false;
|
||||||
|
for (int i = childIndex - 1; i >= 0; i--) {
|
||||||
|
if (getChildAt(i).getVisibility() != GONE) {
|
||||||
|
hasVisibleViewBefore = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasVisibleViewBefore;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,450 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.support.v4.view.MotionEventCompat;
|
||||||
|
import android.support.v4.view.ViewConfigurationCompat;
|
||||||
|
import android.support.v4.view.ViewPager;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.FloatMath;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
|
|
||||||
|
import com.sap.sailing.android.tracking.app.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a line for each page. The current page line is colored differently
|
||||||
|
* than the unselected page lines.
|
||||||
|
*/
|
||||||
|
public class LinePageIndicator extends View implements PageIndicator {
|
||||||
|
private static final int INVALID_POINTER = -1;
|
||||||
|
|
||||||
|
private final Paint mPaintUnselected = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private final Paint mPaintSelected = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private ViewPager mViewPager;
|
||||||
|
private ViewPager.OnPageChangeListener mListener;
|
||||||
|
private int mCurrentPage;
|
||||||
|
private boolean mCentered;
|
||||||
|
private float mLineWidth;
|
||||||
|
private float mGapWidth;
|
||||||
|
|
||||||
|
private int mTouchSlop;
|
||||||
|
private float mLastMotionX = -1;
|
||||||
|
private int mActivePointerId = INVALID_POINTER;
|
||||||
|
private boolean mIsDragging;
|
||||||
|
|
||||||
|
|
||||||
|
public LinePageIndicator(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinePageIndicator(Context context, AttributeSet attrs) {
|
||||||
|
this(context, attrs, R.attr.vpiLinePageIndicatorStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinePageIndicator(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
if (isInEditMode()) return;
|
||||||
|
|
||||||
|
final Resources res = getResources();
|
||||||
|
|
||||||
|
//Load defaults from resources
|
||||||
|
final int defaultSelectedColor = res.getColor(R.color.default_line_indicator_selected_color);
|
||||||
|
final int defaultUnselectedColor = res.getColor(R.color.default_line_indicator_unselected_color);
|
||||||
|
final float defaultLineWidth = res.getDimension(R.dimen.default_line_indicator_line_width);
|
||||||
|
final float defaultGapWidth = res.getDimension(R.dimen.default_line_indicator_gap_width);
|
||||||
|
final float defaultStrokeWidth = res.getDimension(R.dimen.default_line_indicator_stroke_width);
|
||||||
|
final boolean defaultCentered = res.getBoolean(R.bool.default_line_indicator_centered);
|
||||||
|
|
||||||
|
//Retrieve styles attributes
|
||||||
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LinePageIndicator, defStyle, 0);
|
||||||
|
|
||||||
|
mCentered = a.getBoolean(R.styleable.LinePageIndicator_centered, defaultCentered);
|
||||||
|
mLineWidth = a.getDimension(R.styleable.LinePageIndicator_lineWidth, defaultLineWidth);
|
||||||
|
mGapWidth = a.getDimension(R.styleable.LinePageIndicator_gapWidth, defaultGapWidth);
|
||||||
|
setStrokeWidth(a.getDimension(R.styleable.LinePageIndicator_strokeWidth, defaultStrokeWidth));
|
||||||
|
mPaintUnselected.setColor(a.getColor(R.styleable.LinePageIndicator_unselectedColor, defaultUnselectedColor));
|
||||||
|
mPaintSelected.setColor(a.getColor(R.styleable.LinePageIndicator_selectedColor, defaultSelectedColor));
|
||||||
|
|
||||||
|
Drawable background = a.getDrawable(R.styleable.LinePageIndicator_android_background);
|
||||||
|
if (background != null) {
|
||||||
|
setBackgroundDrawable(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.recycle();
|
||||||
|
|
||||||
|
final ViewConfiguration configuration = ViewConfiguration.get(context);
|
||||||
|
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setCentered(boolean centered) {
|
||||||
|
mCentered = centered;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCentered() {
|
||||||
|
return mCentered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnselectedColor(int unselectedColor) {
|
||||||
|
mPaintUnselected.setColor(unselectedColor);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUnselectedColor() {
|
||||||
|
return mPaintUnselected.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedColor(int selectedColor) {
|
||||||
|
mPaintSelected.setColor(selectedColor);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelectedColor() {
|
||||||
|
return mPaintSelected.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLineWidth(float lineWidth) {
|
||||||
|
mLineWidth = lineWidth;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getLineWidth() {
|
||||||
|
return mLineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStrokeWidth(float lineHeight) {
|
||||||
|
mPaintSelected.setStrokeWidth(lineHeight);
|
||||||
|
mPaintUnselected.setStrokeWidth(lineHeight);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getStrokeWidth() {
|
||||||
|
return mPaintSelected.getStrokeWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGapWidth(float gapWidth) {
|
||||||
|
mGapWidth = gapWidth;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getGapWidth() {
|
||||||
|
return mGapWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
if (mViewPager == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int count = mViewPager.getAdapter().getCount();
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCurrentPage >= count) {
|
||||||
|
setCurrentItem(count - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final float lineWidthAndGap = mLineWidth + mGapWidth;
|
||||||
|
final float indicatorWidth = (count * lineWidthAndGap) - mGapWidth;
|
||||||
|
final float paddingTop = getPaddingTop();
|
||||||
|
final float paddingLeft = getPaddingLeft();
|
||||||
|
final float paddingRight = getPaddingRight();
|
||||||
|
|
||||||
|
float verticalOffset = paddingTop + ((getHeight() - paddingTop - getPaddingBottom()) / 2.0f);
|
||||||
|
float horizontalOffset = paddingLeft;
|
||||||
|
if (mCentered) {
|
||||||
|
horizontalOffset += ((getWidth() - paddingLeft - paddingRight) / 2.0f) - (indicatorWidth / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw stroked circles
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
float dx1 = horizontalOffset + (i * lineWidthAndGap);
|
||||||
|
float dx2 = dx1 + mLineWidth;
|
||||||
|
canvas.drawLine(dx1, verticalOffset, dx2, verticalOffset, (i == mCurrentPage) ? mPaintSelected : mPaintUnselected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(android.view.MotionEvent ev) {
|
||||||
|
if (super.onTouchEvent(ev)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
|
||||||
|
switch (action) {
|
||||||
|
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) {
|
||||||
|
mLastMotionX = x;
|
||||||
|
if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) {
|
||||||
|
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)) {
|
||||||
|
if (action != MotionEvent.ACTION_CANCEL) {
|
||||||
|
mViewPager.setCurrentItem(mCurrentPage - 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) {
|
||||||
|
if (action != MotionEvent.ACTION_CANCEL) {
|
||||||
|
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);
|
||||||
|
mLastMotionX = MotionEventCompat.getX(ev, index);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager viewPager) {
|
||||||
|
if (mViewPager == viewPager) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mViewPager != null) {
|
||||||
|
//Clear us from the old pager.
|
||||||
|
mViewPager.setOnPageChangeListener(null);
|
||||||
|
}
|
||||||
|
if (viewPager.getAdapter() == null) {
|
||||||
|
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||||
|
}
|
||||||
|
mViewPager = viewPager;
|
||||||
|
mViewPager.setOnPageChangeListener(this);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view, int initialPosition) {
|
||||||
|
setViewPager(view);
|
||||||
|
setCurrentItem(initialPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 notifyDataSetChanged() {
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrollStateChanged(int state) {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageScrollStateChanged(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int position) {
|
||||||
|
mCurrentPage = position;
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageSelected(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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) {
|
||||||
|
float result;
|
||||||
|
int specMode = MeasureSpec.getMode(measureSpec);
|
||||||
|
int specSize = MeasureSpec.getSize(measureSpec);
|
||||||
|
|
||||||
|
if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) {
|
||||||
|
//We were told how big to be
|
||||||
|
result = specSize;
|
||||||
|
} else {
|
||||||
|
//Calculate the width according the views count
|
||||||
|
final int count = mViewPager.getAdapter().getCount();
|
||||||
|
result = getPaddingLeft() + getPaddingRight() + (count * mLineWidth) + ((count - 1) * mGapWidth);
|
||||||
|
//Respect AT_MOST value if that was what is called for by measureSpec
|
||||||
|
if (specMode == MeasureSpec.AT_MOST) {
|
||||||
|
result = Math.min(result, specSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (int)FloatMath.ceil(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;
|
||||||
|
int specMode = MeasureSpec.getMode(measureSpec);
|
||||||
|
int specSize = MeasureSpec.getSize(measureSpec);
|
||||||
|
|
||||||
|
if (specMode == MeasureSpec.EXACTLY) {
|
||||||
|
//We were told how big to be
|
||||||
|
result = specSize;
|
||||||
|
} else {
|
||||||
|
//Measure the height
|
||||||
|
result = mPaintSelected.getStrokeWidth() + getPaddingTop() + getPaddingBottom();
|
||||||
|
//Respect AT_MOST value if that was what is called for by measureSpec
|
||||||
|
if (specMode == MeasureSpec.AT_MOST) {
|
||||||
|
result = Math.min(result, specSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (int)FloatMath.ceil(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
*/
|
||||||
|
void setViewPager(ViewPager view);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind the indicator to a ViewPager.
|
||||||
|
*
|
||||||
|
* @param view
|
||||||
|
* @param initialPosition
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
void setCurrentItem(int item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a page change listener which will receive forwarded events.
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the indicator that the fragment list has changed.
|
||||||
|
*/
|
||||||
|
void notifyDataSetChanged();
|
||||||
|
}
|
||||||
@@ -0,0 +1,285 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
* 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 static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v4.view.PagerAdapter;
|
||||||
|
import android.support.v4.view.ViewPager;
|
||||||
|
import android.support.v4.view.ViewPager.OnPageChangeListener;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.HorizontalScrollView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.sap.sailing.android.tracking.app.R;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This widget implements the dynamic action bar tab behavior that can change
|
||||||
|
* across different configurations or circumstances.
|
||||||
|
*/
|
||||||
|
public class TabPageIndicator extends HorizontalScrollView implements PageIndicator {
|
||||||
|
/** Title text used when no title is provided by the adapter. */
|
||||||
|
private static final CharSequence EMPTY_TITLE = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a callback when the selected tab has been reselected.
|
||||||
|
*/
|
||||||
|
public interface OnTabReselectedListener {
|
||||||
|
/**
|
||||||
|
* Callback when the selected tab has been reselected.
|
||||||
|
*
|
||||||
|
* @param position Position of the current center item.
|
||||||
|
*/
|
||||||
|
void onTabReselected(int position);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Runnable mTabSelector;
|
||||||
|
|
||||||
|
private final OnClickListener mTabClickListener = new OnClickListener() {
|
||||||
|
public void onClick(View view) {
|
||||||
|
TabView tabView = (TabView)view;
|
||||||
|
final int oldSelected = mViewPager.getCurrentItem();
|
||||||
|
final int newSelected = tabView.getIndex();
|
||||||
|
mViewPager.setCurrentItem(newSelected);
|
||||||
|
if (oldSelected == newSelected && mTabReselectedListener != null) {
|
||||||
|
mTabReselectedListener.onTabReselected(newSelected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final IcsLinearLayout mTabLayout;
|
||||||
|
|
||||||
|
private ViewPager mViewPager;
|
||||||
|
private ViewPager.OnPageChangeListener mListener;
|
||||||
|
|
||||||
|
private int mMaxTabWidth;
|
||||||
|
private int mSelectedTabIndex;
|
||||||
|
|
||||||
|
private OnTabReselectedListener mTabReselectedListener;
|
||||||
|
|
||||||
|
public TabPageIndicator(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TabPageIndicator(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
setHorizontalScrollBarEnabled(false);
|
||||||
|
|
||||||
|
mTabLayout = new IcsLinearLayout(context, R.attr.vpiTabPageIndicatorStyle);
|
||||||
|
addView(mTabLayout, new ViewGroup.LayoutParams(WRAP_CONTENT, MATCH_PARENT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnTabReselectedListener(OnTabReselectedListener listener) {
|
||||||
|
mTabReselectedListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||||
|
final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY;
|
||||||
|
setFillViewport(lockedExpanded);
|
||||||
|
|
||||||
|
final int childCount = mTabLayout.getChildCount();
|
||||||
|
if (childCount > 1 && (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {
|
||||||
|
if (childCount > 2) {
|
||||||
|
mMaxTabWidth = (int)(MeasureSpec.getSize(widthMeasureSpec) * 0.4f);
|
||||||
|
} else {
|
||||||
|
mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mMaxTabWidth = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int oldWidth = getMeasuredWidth();
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
final int newWidth = getMeasuredWidth();
|
||||||
|
|
||||||
|
if (lockedExpanded && oldWidth != newWidth) {
|
||||||
|
// Recenter the tab display if we're at a new (scrollable) size.
|
||||||
|
setCurrentItem(mSelectedTabIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void animateToTab(final int position) {
|
||||||
|
final View tabView = mTabLayout.getChildAt(position);
|
||||||
|
if (mTabSelector != null) {
|
||||||
|
removeCallbacks(mTabSelector);
|
||||||
|
}
|
||||||
|
mTabSelector = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;
|
||||||
|
smoothScrollTo(scrollPos, 0);
|
||||||
|
mTabSelector = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
post(mTabSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow();
|
||||||
|
if (mTabSelector != null) {
|
||||||
|
// Re-post the selector we saved
|
||||||
|
post(mTabSelector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetachedFromWindow() {
|
||||||
|
super.onDetachedFromWindow();
|
||||||
|
if (mTabSelector != null) {
|
||||||
|
removeCallbacks(mTabSelector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTab(int index, CharSequence text, int iconResId) {
|
||||||
|
final TabView tabView = new TabView(getContext());
|
||||||
|
tabView.mIndex = index;
|
||||||
|
tabView.setFocusable(true);
|
||||||
|
tabView.setOnClickListener(mTabClickListener);
|
||||||
|
tabView.setText(text);
|
||||||
|
|
||||||
|
if (iconResId != 0) {
|
||||||
|
tabView.setCompoundDrawablesWithIntrinsicBounds(iconResId, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0, MATCH_PARENT, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrollStateChanged(int arg0) {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageScrollStateChanged(arg0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrolled(int arg0, float arg1, int arg2) {
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageScrolled(arg0, arg1, arg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int arg0) {
|
||||||
|
setCurrentItem(arg0);
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageSelected(arg0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view) {
|
||||||
|
if (mViewPager == view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mViewPager != null) {
|
||||||
|
mViewPager.setOnPageChangeListener(null);
|
||||||
|
}
|
||||||
|
final PagerAdapter adapter = view.getAdapter();
|
||||||
|
if (adapter == null) {
|
||||||
|
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||||
|
}
|
||||||
|
mViewPager = view;
|
||||||
|
view.setOnPageChangeListener(this);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyDataSetChanged() {
|
||||||
|
mTabLayout.removeAllViews();
|
||||||
|
PagerAdapter adapter = mViewPager.getAdapter();
|
||||||
|
IconPagerAdapter iconAdapter = null;
|
||||||
|
if (adapter instanceof IconPagerAdapter) {
|
||||||
|
iconAdapter = (IconPagerAdapter)adapter;
|
||||||
|
}
|
||||||
|
final int count = adapter.getCount();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
CharSequence title = adapter.getPageTitle(i);
|
||||||
|
if (title == null) {
|
||||||
|
title = EMPTY_TITLE;
|
||||||
|
}
|
||||||
|
int iconResId = 0;
|
||||||
|
if (iconAdapter != null) {
|
||||||
|
iconResId = iconAdapter.getIconResId(i);
|
||||||
|
}
|
||||||
|
addTab(i, title, iconResId);
|
||||||
|
}
|
||||||
|
if (mSelectedTabIndex > count) {
|
||||||
|
mSelectedTabIndex = count - 1;
|
||||||
|
}
|
||||||
|
setCurrentItem(mSelectedTabIndex);
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view, int initialPosition) {
|
||||||
|
setViewPager(view);
|
||||||
|
setCurrentItem(initialPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCurrentItem(int item) {
|
||||||
|
if (mViewPager == null) {
|
||||||
|
throw new IllegalStateException("ViewPager has not been bound.");
|
||||||
|
}
|
||||||
|
mSelectedTabIndex = item;
|
||||||
|
mViewPager.setCurrentItem(item);
|
||||||
|
|
||||||
|
final int tabCount = mTabLayout.getChildCount();
|
||||||
|
for (int i = 0; i < tabCount; i++) {
|
||||||
|
final View child = mTabLayout.getChildAt(i);
|
||||||
|
final boolean isSelected = (i == item);
|
||||||
|
child.setSelected(isSelected);
|
||||||
|
if (isSelected) {
|
||||||
|
animateToTab(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOnPageChangeListener(OnPageChangeListener listener) {
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TabView extends TextView {
|
||||||
|
private int mIndex;
|
||||||
|
|
||||||
|
public TabView(Context context) {
|
||||||
|
super(context, null, R.attr.vpiTabPageIndicatorStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
|
||||||
|
// Re-measure if we went beyond our maximum size.
|
||||||
|
if (mMaxTabWidth > 0 && getMeasuredWidth() > mMaxTabWidth) {
|
||||||
|
super.onMeasure(MeasureSpec.makeMeasureSpec(mMaxTabWidth, MeasureSpec.EXACTLY),
|
||||||
|
heightMeasureSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return mIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,872 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 Jake Wharton
|
||||||
|
* Copyright (C) 2011 Patrik Akerfeldt
|
||||||
|
* Copyright (C) 2011 Francisco Figueiredo Jr.
|
||||||
|
*
|
||||||
|
* 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 java.util.ArrayList;
|
||||||
|
|
||||||
|
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.Rect;
|
||||||
|
import android.graphics.Typeface;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.support.v4.view.MotionEventCompat;
|
||||||
|
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 com.sap.sailing.android.tracking.app.R;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title text used when no title is provided by the adapter.
|
||||||
|
*/
|
||||||
|
private static final String EMPTY_TITLE = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a callback when the center item has been clicked.
|
||||||
|
*/
|
||||||
|
public interface OnCenterItemClickListener {
|
||||||
|
/**
|
||||||
|
* Callback when the center item has been clicked.
|
||||||
|
*
|
||||||
|
* @param position Position of the current center item.
|
||||||
|
*/
|
||||||
|
void onCenterItemClick(int position);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LinePosition {
|
||||||
|
Bottom(0), Top(1);
|
||||||
|
|
||||||
|
public final int value;
|
||||||
|
|
||||||
|
private LinePosition(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinePosition fromValue(int value) {
|
||||||
|
for (LinePosition position : LinePosition.values()) {
|
||||||
|
if (position.value == value) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ViewPager mViewPager;
|
||||||
|
private ViewPager.OnPageChangeListener mListener;
|
||||||
|
private int mCurrentPage = -1;
|
||||||
|
private float mPageOffset;
|
||||||
|
private int mScrollState;
|
||||||
|
private final Paint mPaintText = new Paint();
|
||||||
|
private boolean mBoldText;
|
||||||
|
private int mColorText;
|
||||||
|
private int mColorSelected;
|
||||||
|
private Path mPath = new Path();
|
||||||
|
private final Rect mBounds = new Rect();
|
||||||
|
private final Paint mPaintFooterLine = new Paint();
|
||||||
|
private IndicatorStyle mFooterIndicatorStyle;
|
||||||
|
private LinePosition mLinePosition;
|
||||||
|
private final Paint mPaintFooterIndicator = new Paint();
|
||||||
|
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;
|
||||||
|
|
||||||
|
private OnCenterItemClickListener mCenterItemClickListener;
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (isInEditMode()) return;
|
||||||
|
|
||||||
|
//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 defaultLinePosition = res.getInteger(R.integer.default_title_indicator_line_position);
|
||||||
|
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, 0);
|
||||||
|
|
||||||
|
//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);
|
||||||
|
mLinePosition = LinePosition.fromValue(a.getInteger(R.styleable.TitlePageIndicator_linePosition, defaultLinePosition));
|
||||||
|
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_android_textColor, defaultTextColor);
|
||||||
|
mBoldText = a.getBoolean(R.styleable.TitlePageIndicator_selectedBold, defaultSelectedBold);
|
||||||
|
|
||||||
|
final float textSize = a.getDimension(R.styleable.TitlePageIndicator_android_textSize, defaultTextSize);
|
||||||
|
final int footerColor = a.getColor(R.styleable.TitlePageIndicator_footerColor, defaultFooterColor);
|
||||||
|
mPaintText.setTextSize(textSize);
|
||||||
|
mPaintText.setAntiAlias(true);
|
||||||
|
mPaintFooterLine.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||||
|
mPaintFooterLine.setStrokeWidth(mFooterLineHeight);
|
||||||
|
mPaintFooterLine.setColor(footerColor);
|
||||||
|
mPaintFooterIndicator.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||||
|
mPaintFooterIndicator.setColor(footerColor);
|
||||||
|
|
||||||
|
Drawable background = a.getDrawable(R.styleable.TitlePageIndicator_android_background);
|
||||||
|
if (background != null) {
|
||||||
|
setBackgroundDrawable(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 LinePosition getLinePosition() {
|
||||||
|
return mLinePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLinePosition(LinePosition linePosition) {
|
||||||
|
mLinePosition = linePosition;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeface(Typeface typeface) {
|
||||||
|
mPaintText.setTypeface(typeface);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Typeface getTypeface() {
|
||||||
|
return mPaintText.getTypeface();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mCurrentPage is -1 on first start and after orientation changed. If so, retrieve the correct index from viewpager.
|
||||||
|
if (mCurrentPage == -1 && mViewPager != null) {
|
||||||
|
mCurrentPage = mViewPager.getCurrentItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Calculate views bounds
|
||||||
|
ArrayList<Rect> bounds = calculateAllBounds(mPaintText);
|
||||||
|
final int boundsSize = bounds.size();
|
||||||
|
|
||||||
|
//Make sure we're on a page that still exists
|
||||||
|
if (mCurrentPage >= boundsSize) {
|
||||||
|
setCurrentItem(boundsSize - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int countMinusOne = count - 1;
|
||||||
|
final float halfWidth = getWidth() / 2f;
|
||||||
|
final int left = getLeft();
|
||||||
|
final float leftClip = left + mClipPadding;
|
||||||
|
final int width = getWidth();
|
||||||
|
int height = getHeight();
|
||||||
|
final int right = left + width;
|
||||||
|
final float rightClip = right - mClipPadding;
|
||||||
|
|
||||||
|
int page = mCurrentPage;
|
||||||
|
float offsetPercent;
|
||||||
|
if (mPageOffset <= 0.5) {
|
||||||
|
offsetPercent = mPageOffset;
|
||||||
|
} else {
|
||||||
|
page += 1;
|
||||||
|
offsetPercent = 1 - mPageOffset;
|
||||||
|
}
|
||||||
|
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
|
||||||
|
Rect 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--) {
|
||||||
|
Rect bound = bounds.get(i);
|
||||||
|
//Is left side is outside the screen
|
||||||
|
if (bound.left < leftClip) {
|
||||||
|
int 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
|
||||||
|
Rect rightBound = bounds.get(i + 1);
|
||||||
|
//Intersection
|
||||||
|
if (bound.right + mTitlePadding > rightBound.left) {
|
||||||
|
bound.left = (int) (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++) {
|
||||||
|
Rect bound = bounds.get(i);
|
||||||
|
//If right side is outside the screen
|
||||||
|
if (bound.right > rightClip) {
|
||||||
|
int 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
|
||||||
|
Rect leftBound = bounds.get(i - 1);
|
||||||
|
//Intersection
|
||||||
|
if (bound.left - mTitlePadding < leftBound.right) {
|
||||||
|
bound.left = (int) (leftBound.right + mTitlePadding);
|
||||||
|
bound.right = bound.left + w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Now draw views
|
||||||
|
int colorTextAlpha = mColorText >>> 24;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
//Get the title
|
||||||
|
Rect 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);
|
||||||
|
final CharSequence pageTitle = getTitle(i);
|
||||||
|
|
||||||
|
//Only set bold if we are within bounds
|
||||||
|
mPaintText.setFakeBoldText(currentPage && currentBold && mBoldText);
|
||||||
|
|
||||||
|
//Draw text as unselected
|
||||||
|
mPaintText.setColor(mColorText);
|
||||||
|
if(currentPage && currentSelected) {
|
||||||
|
//Fade out/in unselected text as the selected text fades in/out
|
||||||
|
mPaintText.setAlpha(colorTextAlpha - (int)(colorTextAlpha * selectedPercent));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Except if there's an intersection with the right view
|
||||||
|
if (i < boundsSize - 1) {
|
||||||
|
Rect rightBound = bounds.get(i + 1);
|
||||||
|
//Intersection
|
||||||
|
if (bound.right + mTitlePadding > rightBound.left) {
|
||||||
|
int w = bound.right - bound.left;
|
||||||
|
bound.left = (int) (rightBound.left - w - mTitlePadding);
|
||||||
|
bound.right = bound.left + w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canvas.drawText(pageTitle, 0, pageTitle.length(), 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(pageTitle, 0, pageTitle.length(), bound.left, bound.bottom + mTopPadding, mPaintText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If we want the line on the top change height to zero and invert the line height to trick the drawing code
|
||||||
|
float footerLineHeight = mFooterLineHeight;
|
||||||
|
float footerIndicatorLineHeight = mFooterIndicatorHeight;
|
||||||
|
if (mLinePosition == LinePosition.Top) {
|
||||||
|
height = 0;
|
||||||
|
footerLineHeight = -footerLineHeight;
|
||||||
|
footerIndicatorLineHeight = -footerIndicatorLineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw the footer line
|
||||||
|
mPath.reset();
|
||||||
|
mPath.moveTo(0, height - footerLineHeight / 2f);
|
||||||
|
mPath.lineTo(width, height - footerLineHeight / 2f);
|
||||||
|
mPath.close();
|
||||||
|
canvas.drawPath(mPath, mPaintFooterLine);
|
||||||
|
|
||||||
|
float heightMinusLine = height - footerLineHeight;
|
||||||
|
switch (mFooterIndicatorStyle) {
|
||||||
|
case Triangle:
|
||||||
|
mPath.reset();
|
||||||
|
mPath.moveTo(halfWidth, heightMinusLine - footerIndicatorLineHeight);
|
||||||
|
mPath.lineTo(halfWidth + footerIndicatorLineHeight, heightMinusLine);
|
||||||
|
mPath.lineTo(halfWidth - footerIndicatorLineHeight, heightMinusLine);
|
||||||
|
mPath.close();
|
||||||
|
canvas.drawPath(mPath, mPaintFooterIndicator);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Underline:
|
||||||
|
if (!currentSelected || page >= boundsSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect underlineBounds = bounds.get(page);
|
||||||
|
final float rightPlusPadding = underlineBounds.right + mFooterIndicatorUnderlinePadding;
|
||||||
|
final float leftMinusPadding = underlineBounds.left - mFooterIndicatorUnderlinePadding;
|
||||||
|
final float heightMinusLineMinusIndicator = heightMinusLine - footerIndicatorLineHeight;
|
||||||
|
|
||||||
|
mPath.reset();
|
||||||
|
mPath.moveTo(leftMinusPadding, heightMinusLine);
|
||||||
|
mPath.lineTo(rightPlusPadding, heightMinusLine);
|
||||||
|
mPath.lineTo(rightPlusPadding, heightMinusLineMinusIndicator);
|
||||||
|
mPath.lineTo(leftMinusPadding, heightMinusLineMinusIndicator);
|
||||||
|
mPath.close();
|
||||||
|
|
||||||
|
mPaintFooterIndicator.setAlpha((int)(0xFF * selectedPercent));
|
||||||
|
canvas.drawPath(mPath, mPaintFooterIndicator);
|
||||||
|
mPaintFooterIndicator.setAlpha(0xFF);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(android.view.MotionEvent ev) {
|
||||||
|
if (super.onTouchEvent(ev)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
|
||||||
|
switch (action) {
|
||||||
|
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) {
|
||||||
|
mLastMotionX = x;
|
||||||
|
if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) {
|
||||||
|
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;
|
||||||
|
final float leftThird = halfWidth - sixthWidth;
|
||||||
|
final float rightThird = halfWidth + sixthWidth;
|
||||||
|
final float eventX = ev.getX();
|
||||||
|
|
||||||
|
if (eventX < leftThird) {
|
||||||
|
if (mCurrentPage > 0) {
|
||||||
|
if (action != MotionEvent.ACTION_CANCEL) {
|
||||||
|
mViewPager.setCurrentItem(mCurrentPage - 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (eventX > rightThird) {
|
||||||
|
if (mCurrentPage < count - 1) {
|
||||||
|
if (action != MotionEvent.ACTION_CANCEL) {
|
||||||
|
mViewPager.setCurrentItem(mCurrentPage + 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Middle third
|
||||||
|
if (mCenterItemClickListener != null && action != MotionEvent.ACTION_CANCEL) {
|
||||||
|
mCenterItemClickListener.onCenterItemClick(mCurrentPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mIsDragging = false;
|
||||||
|
mActivePointerId = INVALID_POINTER;
|
||||||
|
if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MotionEventCompat.ACTION_POINTER_DOWN: {
|
||||||
|
final int index = MotionEventCompat.getActionIndex(ev);
|
||||||
|
mLastMotionX = MotionEventCompat.getX(ev, index);
|
||||||
|
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(Rect curViewBound, float curViewWidth, int right) {
|
||||||
|
curViewBound.right = (int) (right - mClipPadding);
|
||||||
|
curViewBound.left = (int) (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, float curViewWidth, int left) {
|
||||||
|
curViewBound.left = (int) (left + mClipPadding);
|
||||||
|
curViewBound.right = (int) (mClipPadding + curViewWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate views bounds and scroll them according to the current index
|
||||||
|
*
|
||||||
|
* @param paint
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ArrayList<Rect> calculateAllBounds(Paint paint) {
|
||||||
|
ArrayList<Rect> list = new ArrayList<Rect>();
|
||||||
|
//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++) {
|
||||||
|
Rect bounds = calcBounds(i, paint);
|
||||||
|
int w = bounds.right - bounds.left;
|
||||||
|
int h = bounds.bottom - bounds.top;
|
||||||
|
bounds.left = (int)(halfWidth - (w / 2f) + ((i - mCurrentPage - mPageOffset) * 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 Rect calcBounds(int index, Paint paint) {
|
||||||
|
//Calculate the text bounds
|
||||||
|
Rect bounds = new Rect();
|
||||||
|
CharSequence title = getTitle(index);
|
||||||
|
bounds.right = (int) paint.measureText(title, 0, title.length());
|
||||||
|
bounds.bottom = (int) (paint.descent() - paint.ascent());
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view) {
|
||||||
|
if (mViewPager == view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mViewPager != null) {
|
||||||
|
mViewPager.setOnPageChangeListener(null);
|
||||||
|
}
|
||||||
|
if (view.getAdapter() == null) {
|
||||||
|
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||||
|
}
|
||||||
|
mViewPager = view;
|
||||||
|
mViewPager.setOnPageChangeListener(this);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view, int initialPosition) {
|
||||||
|
setViewPager(view);
|
||||||
|
setCurrentItem(initialPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyDataSetChanged() {
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a callback listener for the center item click.
|
||||||
|
*
|
||||||
|
* @param listener Callback instance.
|
||||||
|
*/
|
||||||
|
public void setOnCenterItemClickListener(OnCenterItemClickListener listener) {
|
||||||
|
mCenterItemClickListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
mPageOffset = positionOffset;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
//Measure our width in whatever mode specified
|
||||||
|
final int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
|
||||||
|
//Determine our height
|
||||||
|
float height;
|
||||||
|
final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||||
|
if (heightSpecMode == MeasureSpec.EXACTLY) {
|
||||||
|
//We were told how big to be
|
||||||
|
height = MeasureSpec.getSize(heightMeasureSpec);
|
||||||
|
} else {
|
||||||
|
//Calculate the text bounds
|
||||||
|
mBounds.setEmpty();
|
||||||
|
mBounds.bottom = (int) (mPaintText.descent() - mPaintText.ascent());
|
||||||
|
height = mBounds.bottom - mBounds.top + mFooterLineHeight + mFooterPadding + mTopPadding;
|
||||||
|
if (mFooterIndicatorStyle != IndicatorStyle.None) {
|
||||||
|
height += mFooterIndicatorHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final int measuredHeight = (int)height;
|
||||||
|
|
||||||
|
setMeasuredDimension(measuredWidth, measuredHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private CharSequence getTitle(int i) {
|
||||||
|
CharSequence title = mViewPager.getAdapter().getPageTitle(i);
|
||||||
|
if (title == null) {
|
||||||
|
title = EMPTY_TITLE;
|
||||||
|
}
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,404 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.support.v4.view.MotionEventCompat;
|
||||||
|
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 com.sap.sailing.android.tracking.app.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a line for each page. The current page line is colored differently
|
||||||
|
* than the unselected page lines.
|
||||||
|
*/
|
||||||
|
public class UnderlinePageIndicator extends View implements PageIndicator {
|
||||||
|
private static final int INVALID_POINTER = -1;
|
||||||
|
private static final int FADE_FRAME_MS = 30;
|
||||||
|
|
||||||
|
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
|
||||||
|
private boolean mFades;
|
||||||
|
private int mFadeDelay;
|
||||||
|
private int mFadeLength;
|
||||||
|
private int mFadeBy;
|
||||||
|
|
||||||
|
private ViewPager mViewPager;
|
||||||
|
private ViewPager.OnPageChangeListener mListener;
|
||||||
|
private int mScrollState;
|
||||||
|
private int mCurrentPage;
|
||||||
|
private float mPositionOffset;
|
||||||
|
|
||||||
|
private int mTouchSlop;
|
||||||
|
private float mLastMotionX = -1;
|
||||||
|
private int mActivePointerId = INVALID_POINTER;
|
||||||
|
private boolean mIsDragging;
|
||||||
|
|
||||||
|
private final Runnable mFadeRunnable = new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
if (!mFades) return;
|
||||||
|
|
||||||
|
final int alpha = Math.max(mPaint.getAlpha() - mFadeBy, 0);
|
||||||
|
mPaint.setAlpha(alpha);
|
||||||
|
invalidate();
|
||||||
|
if (alpha > 0) {
|
||||||
|
postDelayed(this, FADE_FRAME_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public UnderlinePageIndicator(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnderlinePageIndicator(Context context, AttributeSet attrs) {
|
||||||
|
this(context, attrs, R.attr.vpiUnderlinePageIndicatorStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnderlinePageIndicator(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
if (isInEditMode()) return;
|
||||||
|
|
||||||
|
final Resources res = getResources();
|
||||||
|
|
||||||
|
//Load defaults from resources
|
||||||
|
final boolean defaultFades = res.getBoolean(R.bool.default_underline_indicator_fades);
|
||||||
|
final int defaultFadeDelay = res.getInteger(R.integer.default_underline_indicator_fade_delay);
|
||||||
|
final int defaultFadeLength = res.getInteger(R.integer.default_underline_indicator_fade_length);
|
||||||
|
final int defaultSelectedColor = res.getColor(R.color.default_underline_indicator_selected_color);
|
||||||
|
|
||||||
|
//Retrieve styles attributes
|
||||||
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UnderlinePageIndicator, defStyle, 0);
|
||||||
|
|
||||||
|
setFades(a.getBoolean(R.styleable.UnderlinePageIndicator_fades, defaultFades));
|
||||||
|
setSelectedColor(a.getColor(R.styleable.UnderlinePageIndicator_selectedColor, defaultSelectedColor));
|
||||||
|
setFadeDelay(a.getInteger(R.styleable.UnderlinePageIndicator_fadeDelay, defaultFadeDelay));
|
||||||
|
setFadeLength(a.getInteger(R.styleable.UnderlinePageIndicator_fadeLength, defaultFadeLength));
|
||||||
|
|
||||||
|
Drawable background = a.getDrawable(R.styleable.UnderlinePageIndicator_android_background);
|
||||||
|
if (background != null) {
|
||||||
|
setBackgroundDrawable(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.recycle();
|
||||||
|
|
||||||
|
final ViewConfiguration configuration = ViewConfiguration.get(context);
|
||||||
|
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getFades() {
|
||||||
|
return mFades;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFades(boolean fades) {
|
||||||
|
if (fades != mFades) {
|
||||||
|
mFades = fades;
|
||||||
|
if (fades) {
|
||||||
|
post(mFadeRunnable);
|
||||||
|
} else {
|
||||||
|
removeCallbacks(mFadeRunnable);
|
||||||
|
mPaint.setAlpha(0xFF);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFadeDelay() {
|
||||||
|
return mFadeDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFadeDelay(int fadeDelay) {
|
||||||
|
mFadeDelay = fadeDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFadeLength() {
|
||||||
|
return mFadeLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFadeLength(int fadeLength) {
|
||||||
|
mFadeLength = fadeLength;
|
||||||
|
mFadeBy = 0xFF / (mFadeLength / FADE_FRAME_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelectedColor() {
|
||||||
|
return mPaint.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedColor(int selectedColor) {
|
||||||
|
mPaint.setColor(selectedColor);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
if (mViewPager == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int count = mViewPager.getAdapter().getCount();
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCurrentPage >= count) {
|
||||||
|
setCurrentItem(count - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int paddingLeft = getPaddingLeft();
|
||||||
|
final float pageWidth = (getWidth() - paddingLeft - getPaddingRight()) / (1f * count);
|
||||||
|
final float left = paddingLeft + pageWidth * (mCurrentPage + mPositionOffset);
|
||||||
|
final float right = left + pageWidth;
|
||||||
|
final float top = getPaddingTop();
|
||||||
|
final float bottom = getHeight() - getPaddingBottom();
|
||||||
|
canvas.drawRect(left, top, right, bottom, mPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
|
if (super.onTouchEvent(ev)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
|
||||||
|
switch (action) {
|
||||||
|
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) {
|
||||||
|
mLastMotionX = x;
|
||||||
|
if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) {
|
||||||
|
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)) {
|
||||||
|
if (action != MotionEvent.ACTION_CANCEL) {
|
||||||
|
mViewPager.setCurrentItem(mCurrentPage - 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) {
|
||||||
|
if (action != MotionEvent.ACTION_CANCEL) {
|
||||||
|
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);
|
||||||
|
mLastMotionX = MotionEventCompat.getX(ev, index);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager viewPager) {
|
||||||
|
if (mViewPager == viewPager) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mViewPager != null) {
|
||||||
|
//Clear us from the old pager.
|
||||||
|
mViewPager.setOnPageChangeListener(null);
|
||||||
|
}
|
||||||
|
if (viewPager.getAdapter() == null) {
|
||||||
|
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||||
|
}
|
||||||
|
mViewPager = viewPager;
|
||||||
|
mViewPager.setOnPageChangeListener(this);
|
||||||
|
invalidate();
|
||||||
|
post(new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
if (mFades) {
|
||||||
|
post(mFadeRunnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setViewPager(ViewPager view, int initialPosition) {
|
||||||
|
setViewPager(view);
|
||||||
|
setCurrentItem(initialPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 notifyDataSetChanged() {
|
||||||
|
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;
|
||||||
|
mPositionOffset = positionOffset;
|
||||||
|
if (mFades) {
|
||||||
|
if (positionOffsetPixels > 0) {
|
||||||
|
removeCallbacks(mFadeRunnable);
|
||||||
|
mPaint.setAlpha(0xFF);
|
||||||
|
} else if (mScrollState != ViewPager.SCROLL_STATE_DRAGGING) {
|
||||||
|
postDelayed(mFadeRunnable, mFadeDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int position) {
|
||||||
|
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
|
||||||
|
mCurrentPage = position;
|
||||||
|
mPositionOffset = 0;
|
||||||
|
invalidate();
|
||||||
|
mFadeRunnable.run();
|
||||||
|
}
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onPageSelected(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
|
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
|
||||||
|
@Override
|
||||||
|
public SavedState createFromParcel(Parcel in) {
|
||||||
|
return new SavedState(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SavedState[] newArray(int size) {
|
||||||
|
return new SavedState[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||