Walkthrough tutorial upon app launch
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 278 KiB |
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- xmlns:app="http://schemas.android.com/apk/res/com.viewpagerindicator.sample" -->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<com.viewpagerindicator.CirclePageIndicator
|
||||
android:id="@+id/indicator"
|
||||
android:padding="15dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_alignBottom="@id/pager"
|
||||
android:background="#00000000"
|
||||
style="@style/CustomCirclePageIndicator"
|
||||
/>
|
||||
<!--
|
||||
app:radius="10dp"
|
||||
app:fillColor="#FF888888"
|
||||
app:strokeColor="#FF000000"
|
||||
app:strokeWidth="2dp" -->
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:paddingLeft="4dip"
|
||||
android:paddingRight="4dip"
|
||||
android:background="@drawable/welcome_walkthrough_fabric"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/logo"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="110dip"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingBottom="10dip"
|
||||
android:layout_marginTop="30dip"
|
||||
android:text="Connect now\nto get started!"
|
||||
android:textColor="#444444"
|
||||
android:textSize="40dip"
|
||||
android:textStyle="bold"
|
||||
android:shadowRadius="2"
|
||||
android:shadowDy="1"
|
||||
android:shadowColor="@android:color/white" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textColor="#ff0000"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="253dp"
|
||||
android:paddingTop="5dip" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_later"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="45dip"
|
||||
android:gravity="center"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingRight="20dip"
|
||||
android:paddingBottom="5dip"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#ffffff" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/pw_login"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="45dip"
|
||||
android:layout_above="@id/login_later"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingRight="20dip"
|
||||
android:layout_marginLeft="15dip"
|
||||
android:layout_marginRight="15dip"
|
||||
android:textSize="16sp"
|
||||
android:text="@string/welcome_login_pw"/>
|
||||
|
||||
<com.facebook.android.LoginButton
|
||||
android:id="@+id/fb_login"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="45dip"
|
||||
android:layout_above="@id/pw_login"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingRight="20dip"
|
||||
android:layout_marginLeft="15dip"
|
||||
android:layout_marginRight="15dip"
|
||||
android:textSize="16sp"
|
||||
android:drawableLeft="@drawable/facebook"
|
||||
android:text="@string/actfm_ALA_fb_login" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/gg_login"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="45dip"
|
||||
android:layout_above="@id/fb_login"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingRight="20dip"
|
||||
android:layout_marginLeft="15dip"
|
||||
android:layout_marginRight="15dip"
|
||||
android:textSize="16sp"
|
||||
android:drawableLeft="@drawable/google"
|
||||
android:text="@string/actfm_ALA_gg_login" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tos"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="35dip"
|
||||
android:layout_above="@id/gg_login"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingRight="20dip"
|
||||
android:textSize="12.5sp"
|
||||
android:textColor="#ffffff" />
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/welcome_walkthrough_fabric"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/welcome_walkthrough_fabric" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/welcome_walkthrough_title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="27dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="Hello"
|
||||
android:textColor="#444444"
|
||||
android:textSize="40dip"
|
||||
android:textStyle="bold"
|
||||
android:shadowRadius="2"
|
||||
android:shadowDy="1"
|
||||
android:shadowColor="@android:color/white" />
|
||||
<ImageView
|
||||
android:id="@+id/welcome_walkthrough_image"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/welcome_walkthrough_1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/welcome_walkthrough_body"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginBottom="75dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="Hello"
|
||||
android:textColor="#444444"
|
||||
android:textSize="20dip"
|
||||
android:textStyle="bold"
|
||||
android:shadowRadius="2"
|
||||
android:shadowDy="1"
|
||||
android:shadowColor="@android:color/white" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,125 @@
|
||||
package com.todoroo.astrid.welcome.tutorial;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
|
||||
public class ViewPagerAdapter extends PagerAdapter
|
||||
{
|
||||
private static int[] images = new int[]
|
||||
{
|
||||
R.drawable.welcome_walkthrough_1,
|
||||
R.drawable.welcome_walkthrough_2,
|
||||
R.drawable.welcome_walkthrough_3,
|
||||
R.drawable.welcome_walkthrough_4,
|
||||
R.drawable.welcome_walkthrough_5,
|
||||
R.drawable.welcome_walkthrough_6,
|
||||
R.drawable.welcome_screen
|
||||
};
|
||||
private static String[] title = new String[]
|
||||
{
|
||||
"Welcome to Astrid!",
|
||||
"Make lists",
|
||||
"Share lists",
|
||||
"Divvy up tasks",
|
||||
"Provide details",
|
||||
"Discover",
|
||||
"Login"
|
||||
};
|
||||
private static String[] body = new String[]
|
||||
{
|
||||
"The perfect personal\nto-do list that works great\nwith friends",
|
||||
"Perfect for any list:\nto read, to watch, to buy,\nto visit, to do!",
|
||||
"Share lists\nwith friends, housemates,\nor your sweetheart!",
|
||||
"Never wonder who's\nbringing dessert!",
|
||||
"Tap to add notes,\nset reminders,\nand much more!",
|
||||
"Additional features,\nproductivity tips, and\nsuggestions from friends",
|
||||
"Login"
|
||||
};
|
||||
private static int[] layouts = new int[]
|
||||
{
|
||||
R.layout.welcome_walkthrough_page,
|
||||
R.layout.welcome_walkthrough_page,
|
||||
R.layout.welcome_walkthrough_page,
|
||||
R.layout.welcome_walkthrough_page,
|
||||
R.layout.welcome_walkthrough_page,
|
||||
R.layout.welcome_walkthrough_page,
|
||||
R.layout.welcome_walkthrough_login_page,
|
||||
|
||||
};
|
||||
private final Context context;
|
||||
public WelcomeWalkthrough parent;
|
||||
|
||||
public ViewPagerAdapter( Context context )
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
return layouts.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem( View pager, int position )
|
||||
{
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
|
||||
View pageView = inflater.inflate(layouts[position], null, true);
|
||||
pageView.setLayoutParams( new ViewGroup.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT));
|
||||
|
||||
if (position != getCount()-1){
|
||||
ImageView imageView = (ImageView) pageView.findViewById(R.id.welcome_walkthrough_image);
|
||||
imageView.setImageResource(images[position]);
|
||||
ImageView fabricImage = (ImageView) pageView.findViewById(R.id.welcome_walkthrough_fabric);
|
||||
fabricImage.setScaleType(ImageView.ScaleType.FIT_XY);
|
||||
|
||||
TextView titleView = (TextView) pageView.findViewById(R.id.welcome_walkthrough_title);
|
||||
titleView.setText(title[position]);
|
||||
TextView bodyView = (TextView) pageView.findViewById(R.id.welcome_walkthrough_body);
|
||||
bodyView.setText(body[position]);
|
||||
}
|
||||
|
||||
((ViewPager)pager).addView( pageView, 0 );
|
||||
parent.pageScrolled(position, pageView);
|
||||
return pageView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem( View pager, int position, Object view )
|
||||
{
|
||||
((ViewPager)pager).removeView( (View)view );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject( View view, Object object )
|
||||
{
|
||||
return view.equals( object );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishUpdate( View view ) {}
|
||||
|
||||
@Override
|
||||
public void restoreState( Parcelable p, ClassLoader c ) {}
|
||||
|
||||
@Override
|
||||
public Parcelable saveState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startUpdate( View view ) {}
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
|
||||
package com.todoroo.astrid.welcome.tutorial;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.Window;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.utility.DialogUtilities;
|
||||
import com.todoroo.astrid.actfm.ActFmLoginActivity;
|
||||
import com.todoroo.astrid.activity.Eula;
|
||||
import com.todoroo.astrid.welcome.WelcomeLogin;
|
||||
import com.viewpagerindicator.CirclePageIndicator;
|
||||
import com.viewpagerindicator.PageIndicator;
|
||||
|
||||
public class WelcomeWalkthrough extends ActFmLoginActivity {
|
||||
ViewPager mPager;
|
||||
ViewPagerAdapter mAdapter;
|
||||
PageIndicator mIndicator;
|
||||
View currentView;
|
||||
int currentPage;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
super.onCreate(savedInstanceState);
|
||||
//setContentView(R.layout.welcome_walkthrough);
|
||||
|
||||
mAdapter = new ViewPagerAdapter(this);
|
||||
mAdapter.parent = this;
|
||||
|
||||
mPager = (ViewPager)findViewById(R.id.pager);
|
||||
mPager.setAdapter(mAdapter);
|
||||
|
||||
mIndicator = (CirclePageIndicator)findViewById(R.id.indicator);
|
||||
mIndicator.setViewPager(mPager);
|
||||
}
|
||||
@Override
|
||||
protected int getContentViewResource() {
|
||||
return R.layout.welcome_walkthrough;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getTitleResource() {
|
||||
return 0;
|
||||
}
|
||||
public void pageScrolled(int position, View view){
|
||||
Log.d(null, "Updated ui");
|
||||
currentView = view;
|
||||
currentPage = position;
|
||||
if (position == mAdapter.getCount()-1) {
|
||||
initializeUI();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void initializeUI() {
|
||||
if(mAdapter == null)
|
||||
return;
|
||||
if(currentPage == mAdapter.getCount()-1){
|
||||
super.initializeUI();
|
||||
setupTermsOfService();
|
||||
setupLoginLater();
|
||||
}
|
||||
}
|
||||
|
||||
protected SpannableString getLinkStringWithCustomInterval(String base, String linkComponent,
|
||||
int start, int endOffset, final OnClickListener listener) {
|
||||
SpannableString link = new SpannableString (String.format("%s %s", //$NON-NLS-1$
|
||||
base, linkComponent));
|
||||
ClickableSpan linkSpan = new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(View widget) {
|
||||
listener.onClick(widget);
|
||||
}
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
ds.setUnderlineText(true);
|
||||
ds.setColor(Color.rgb(255, 255, 255));
|
||||
}
|
||||
};
|
||||
link.setSpan(linkSpan, start, link.length() + endOffset, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
return link;
|
||||
}
|
||||
protected void setupTermsOfService() {
|
||||
TextView tos = (TextView)currentView.findViewById(R.id.tos);
|
||||
tos.setOnClickListener(showTosListener);
|
||||
|
||||
String tosBase = getString(R.string.welcome_login_tos_base);
|
||||
String tosLink = getString(R.string.welcome_login_tos_link);
|
||||
SpannableString link = getLinkStringWithCustomInterval(tosBase, tosLink, tosBase.length() + 2, -1, showTosListener);
|
||||
tos.setText(link);
|
||||
}
|
||||
protected void setupPWLogin() {
|
||||
Button pwLogin = (Button) findViewById(R.id.pw_login);
|
||||
pwLogin.setOnClickListener(signUpListener);
|
||||
}
|
||||
/*
|
||||
protected void setupWalkthroughLogin() {
|
||||
Button loginButton = (Button)currentView.findViewById(R.id.walkthrough_login);
|
||||
loginButton.setOnClickListener(showWalkthroughLoginListener);
|
||||
}*/
|
||||
|
||||
|
||||
protected void setupLoginLater() {
|
||||
TextView loginLater = (TextView)currentView.findViewById(R.id.login_later);
|
||||
loginLater.setOnClickListener(loginLaterListener);
|
||||
String loginLaterBase = getString(R.string.welcome_login_later);
|
||||
SpannableString loginLaterLink = new SpannableString(String.format("%s", loginLaterBase)); //$NON-NLS-1$
|
||||
ClickableSpan laterSpan = new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(View widget) {
|
||||
loginLaterListener.onClick(widget);
|
||||
}
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
ds.setUnderlineText(true);
|
||||
ds.setColor(Color.rgb(255, 255, 255));
|
||||
}
|
||||
};
|
||||
loginLaterLink.setSpan(laterSpan, 0, loginLaterBase.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
loginLater.setText(loginLaterLink);
|
||||
}
|
||||
|
||||
protected final OnClickListener showTosListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Eula.showEulaBasic(WelcomeWalkthrough.this);
|
||||
}
|
||||
};
|
||||
private void showWelcomeLoginActivty() {
|
||||
Intent showWelcomeLogin = new Intent(this, WelcomeLogin.class);
|
||||
showWelcomeLogin.putExtra(ActFmLoginActivity.SHOW_TOAST, false);
|
||||
startActivity(showWelcomeLogin);
|
||||
}
|
||||
protected final OnClickListener showWalkthroughLoginListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showWelcomeLoginActivty();
|
||||
}
|
||||
};
|
||||
|
||||
protected final OnClickListener loginLaterListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
String title = getString(R.string.welcome_login_confirm_later_title);
|
||||
String confirmLater = getString(R.string.welcome_login_confirm_later_dialog);
|
||||
DialogUtilities.okCancelCustomDialog(WelcomeWalkthrough.this, title, confirmLater,
|
||||
R.string.welcome_login_confirm_later_ok,
|
||||
R.string.welcome_login_confirm_later_cancel,
|
||||
android.R.drawable.ic_dialog_alert,
|
||||
null, confirmLaterListener);
|
||||
}
|
||||
|
||||
private final DialogInterface.OnClickListener confirmLaterListener = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
#Android generated
|
||||
bin
|
||||
gen
|
||||
|
||||
#Eclipse
|
||||
.project
|
||||
.classpath
|
||||
.settings
|
||||
|
||||
#IntelliJ IDEA
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
#Maven
|
||||
target
|
||||
release.properties
|
||||
pom.xml.*
|
||||
@ -0,0 +1,88 @@
|
||||
Change Log
|
||||
==========
|
||||
|
||||
Version 2.2.2 *(2011-12-31)*
|
||||
----------------------------
|
||||
|
||||
* Fix incorrect `R.java` imports in all of the sample activities.
|
||||
|
||||
|
||||
Version 2.2.1 *(2011-12-31)*
|
||||
----------------------------
|
||||
|
||||
* New `setTypeface(Typeface)` and `getTypeface()` methods for title indicator.
|
||||
(Thanks Dimitri Fedorov)
|
||||
* Added styled tab indicator sample.
|
||||
* Support for widths other than those that could be measured exactly.
|
||||
|
||||
|
||||
Version 2.2.0 *(2011-12-13)*
|
||||
----------------------------
|
||||
|
||||
* Default title indicator style is now 'underline'.
|
||||
* Title indicator now allows specifying an `OnCenterItemClickListener` which
|
||||
will give you callbacks when the current item title has been clicked.
|
||||
(Thanks Chris Banes)
|
||||
|
||||
|
||||
Version 2.1.0 *(2011-11-30)*
|
||||
----------------------------
|
||||
|
||||
* Indicators now have a `notifyDataSetChanged` method which should be called
|
||||
when changes are made to the adapter.
|
||||
* Fix: Avoid `NullPointerException`s when the `ViewPager` is not immediately
|
||||
bound to the indicator.
|
||||
|
||||
|
||||
Version 2.0.0 *(2011-11-20)*
|
||||
----------------------------
|
||||
|
||||
* New `TabPageIndicator`! Uses the Ice Cream Sandwich-style action bar tabs
|
||||
which fill the width of the view when there are only a few tabs or provide
|
||||
horizontal animated scrolling when there are many.
|
||||
* Update to link against ACLv4r4. This will now be required in all implementing
|
||||
applications.
|
||||
* Allow dragging the title and circle indicators to drag the pager.
|
||||
* Remove orientation example as the DirectionalViewPager library has not been
|
||||
updated to ACLv4r4.
|
||||
|
||||
|
||||
Version 1.2.1 *(2011-10-20)*
|
||||
----------------------------
|
||||
|
||||
Maven 3 is now required when building from the command line.
|
||||
|
||||
* Update to support ADT 14.
|
||||
|
||||
|
||||
Version 1.2.0 *(2011-10-04)*
|
||||
----------------------------
|
||||
|
||||
* Move to `com.viewpagerindicator` package.
|
||||
* Move maven group and artifact to `com.viewpagerindicator:library`.
|
||||
|
||||
|
||||
Version 1.1.0 *(2011-10-02)*
|
||||
----------------------------
|
||||
|
||||
* Package changed from `com.jakewharton.android.viewpagerindicator` to
|
||||
`com.jakewharton.android.view`.
|
||||
* Add vertical orientation support to the circle indicator.
|
||||
* Fix: Corrected drawing bug where a single frame would be drawn as if the
|
||||
pager had completed its scroll when in fact it was still scrolling.
|
||||
(Thanks SimonVT!)
|
||||
|
||||
|
||||
Version 1.0.1 *(2011-09-15)*
|
||||
----------------------------
|
||||
|
||||
* Fade selected title color to normal text color during the swipe to and from
|
||||
the center position.
|
||||
* Fix: Ensure both the indicator and footer line are updated when changing the
|
||||
footer color via the `setFooterColor` method.
|
||||
|
||||
|
||||
Version 1.0.0 *(2011-08-07)*
|
||||
----------------------------
|
||||
|
||||
Initial release.
|
||||
@ -0,0 +1,152 @@
|
||||
Android ViewPagerIndicator
|
||||
==========================
|
||||
|
||||
Port of [Patrik Åkerfeldt][1]'s paging indicators that are compatible with the
|
||||
ViewPager from the [Android Compatibility Library][2] and
|
||||
[ActionBarSherlock][3].
|
||||
|
||||
Try out the sample application [on the Android Market][10].
|
||||
|
||||
![ViewPagerIndicator Sample Screenshots][9]
|
||||
|
||||
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
*For a working implementation of this project see the `sample/` folder.*
|
||||
|
||||
1. Include one of the widgets in your view. This should usually be placed
|
||||
adjacent to the `ViewPager` it represents.
|
||||
|
||||
<com.viewpagerindicator.TitlePageIndicator
|
||||
android:id="@+id/titles"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent" />
|
||||
|
||||
2. In your `onCreate` method (or `onCreateView` for a fragment), bind the
|
||||
indicator to the `ViewPager`.
|
||||
|
||||
//Set the pager with an adapter
|
||||
ViewPager pager = (ViewPager)findViewById(R.id.pager);
|
||||
pager.setAdapter(new TestAdapter(getSupportFragmentManager()));
|
||||
|
||||
//Bind the title indicator to the adapter
|
||||
TitlePageIndicator titleIndicator = (TitlePageIndicator)findViewById(R.id.titles);
|
||||
titleIndicator.setViewPager(pager);
|
||||
|
||||
*Note*: If you are using `TitlePageIndicator` your adapter must implement
|
||||
`TitleProvider`.
|
||||
|
||||
3. *(Optional)* If you use an `OnPageChangeListener` with your view pager
|
||||
you should set it in the indicator rather than on the pager directly.
|
||||
|
||||
//continued from above
|
||||
titleIndicator.setOnPageChangeListener(mPageChangeListener);
|
||||
|
||||
|
||||
Theming
|
||||
-------
|
||||
|
||||
There are three ways to style the look of the indicators.
|
||||
|
||||
1. **Theme XML**. An attribute for each type of indicator is provided in which
|
||||
you can specify a custom style.
|
||||
2. **Layout XML**. Through the use of a custom namespace you can include any
|
||||
desired styles.
|
||||
3. **Object methods**. Both styles have getters and setters for each style
|
||||
attribute which can be changed at any point.
|
||||
|
||||
Each indicator has a demo which creates the same look using each of these
|
||||
methods.
|
||||
|
||||
|
||||
Including In Your Project
|
||||
-------------------------
|
||||
|
||||
Android-ViewPagerIndicator is presented as an [Android library project][7]. A
|
||||
standalone JAR is not possible due to the theming capabilities offered by the
|
||||
indicator widgets.
|
||||
|
||||
You can include this project by [referencing it as a library project][8] in
|
||||
Eclipse or ant.
|
||||
|
||||
If you are a Maven user you can easily include the library by specifying it as
|
||||
a dependency:
|
||||
|
||||
<dependency>
|
||||
<groupId>com.viewpagerindicator</groupId>
|
||||
<artifactId>library</artifactId>
|
||||
<version>2.2.2</version>
|
||||
<type>apklib</type>
|
||||
</dependency>
|
||||
|
||||
You must also include the following repository:
|
||||
|
||||
<repository>
|
||||
<id>com.jakewharton</id>
|
||||
<url>http://r.jakewharton.com/maven/release</url>
|
||||
</repository>
|
||||
|
||||
|
||||
|
||||
This project depends on the `ViewPager` class which is available in the
|
||||
[Android Compatibility Library][2] or [ActionBarSherlock][3]. Details for
|
||||
including one of those libraries is available on their respecitve web sites.
|
||||
|
||||
|
||||
|
||||
|
||||
Developed By
|
||||
============
|
||||
|
||||
* Jake Wharton - <jakewharton@gmail.com>
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
* [Patrik Åkerfeldt][1] - Author of [ViewFlow][4], a precursor to the ViewPager,
|
||||
which supports paged views and is the original source of both the title
|
||||
and circle indicators.
|
||||
* [Francisco Figueiredo Jr.][5] - Idea and [first implementation][6] for
|
||||
fragment support via ViewPager.
|
||||
|
||||
|
||||
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Copyright 2011 Patrik Åkerfeldt
|
||||
Copyright 2011 Francisco Figueiredo Jr.
|
||||
Copyright 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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[1]: https://github.com/pakerfeldt
|
||||
[2]: http://developer.android.com/sdk/compatibility-library.html
|
||||
[3]: http://actionbarsherlock.com
|
||||
[4]: https://github.com/pakerfeldt/android-viewflow
|
||||
[5]: https://github.com/franciscojunior
|
||||
[6]: https://gist.github.com/1122947
|
||||
[7]: http://developer.android.com/guide/developing/projects/projects-eclipse.html
|
||||
[8]: http://developer.android.com/guide/developing/projects/projects-eclipse.html#ReferencingLibraryProject
|
||||
[9]: https://raw.github.com/JakeWharton/Android-ViewPagerIndicator/master/sample/screens.png
|
||||
[10]: https://market.android.com/details?id=com.viewpagerindicator.sample
|
||||
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.viewpagerindicator"
|
||||
android:versionCode="26"
|
||||
android:versionName="2.2.2">
|
||||
|
||||
<uses-sdk android:minSdkVersion="4" />
|
||||
</manifest>
|
||||
@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="library" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
|
||||
<!-- extension targets. Uncomment the ones where you want to do custom work
|
||||
in between standard targets -->
|
||||
<!--
|
||||
<target name="-pre-build">
|
||||
</target>
|
||||
<target name="-pre-compile">
|
||||
</target>
|
||||
|
||||
/* This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir} */
|
||||
<target name="-post-compile">
|
||||
</target>
|
||||
-->
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,115 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.2//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
|
||||
|
||||
<module name="Checker">
|
||||
<!--module name="NewlineAtEndOfFile"/-->
|
||||
<module name="FileLength"/>
|
||||
<module name="FileTabCharacter"/>
|
||||
|
||||
<!-- Trailing spaces -->
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="message" value="Line has trailing spaces."/>
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<property name="cacheFile" value="${checkstyle.cache.file}"/>
|
||||
|
||||
<!-- Checks for Javadoc comments. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||
<!--module name="JavadocMethod"/-->
|
||||
<!--module name="JavadocType"/-->
|
||||
<!--module name="JavadocVariable"/-->
|
||||
<!--module name="JavadocStyle"/-->
|
||||
|
||||
|
||||
<!-- Checks for Naming Conventions. -->
|
||||
<!-- See http://checkstyle.sf.net/config_naming.html -->
|
||||
<module name="ConstantName"/>
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName"/>
|
||||
<module name="MemberName"/>
|
||||
<module name="MethodName"/>
|
||||
<module name="PackageName"/>
|
||||
<module name="ParameterName"/>
|
||||
<module name="StaticVariableName"/>
|
||||
<module name="TypeName"/>
|
||||
|
||||
|
||||
<!-- Checks for imports -->
|
||||
<!-- See http://checkstyle.sf.net/config_import.html -->
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
|
||||
<module name="RedundantImport"/>
|
||||
<module name="UnusedImports"/>
|
||||
|
||||
|
||||
<!-- Checks for Size Violations. -->
|
||||
<!-- See http://checkstyle.sf.net/config_sizes.html -->
|
||||
<!--module name="LineLength"/-->
|
||||
<!--module name="MethodLength"/-->
|
||||
<!--module name="ParameterNumber"/-->
|
||||
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
<!--module name="EmptyForIteratorPad"/-->
|
||||
<!--module name="MethodParamPad"/-->
|
||||
<!--module name="NoWhitespaceAfter"/-->
|
||||
<!--module name="NoWhitespaceBefore"/-->
|
||||
<!--module name="OperatorWrap"/-->
|
||||
<!--module name="ParenPad"/-->
|
||||
<!--module name="TypecastParenPad"/-->
|
||||
<!--module name="WhitespaceAfter"/-->
|
||||
<!--module name="WhitespaceAround"/-->
|
||||
|
||||
|
||||
<!-- Modifier Checks -->
|
||||
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
|
||||
<!--module name="ModifierOrder"/-->
|
||||
<!--module name="RedundantModifier"/-->
|
||||
|
||||
|
||||
<!-- Checks for blocks. You know, those {}'s -->
|
||||
<!-- See http://checkstyle.sf.net/config_blocks.html -->
|
||||
<!--module name="AvoidNestedBlocks"/-->
|
||||
<!--module name="EmptyBlock"/-->
|
||||
<!--module name="LeftCurly"/-->
|
||||
<!--module name="NeedBraces"/-->
|
||||
<!--module name="RightCurly"/-->
|
||||
|
||||
|
||||
<!-- Checks for common coding problems -->
|
||||
<!-- See http://checkstyle.sf.net/config_coding.html -->
|
||||
<!--module name="AvoidInlineConditionals"/-->
|
||||
<!--module name="DoubleCheckedLocking"/--> <!-- MY FAVOURITE -->
|
||||
<!--module name="EmptyStatement"/-->
|
||||
<!--module name="EqualsHashCode"/-->
|
||||
<!--module name="HiddenField"/-->
|
||||
<!--module name="IllegalInstantiation"/-->
|
||||
<!--module name="InnerAssignment"/-->
|
||||
<!--module name="MagicNumber"/-->
|
||||
<!--module name="MissingSwitchDefault"/-->
|
||||
<!--module name="RedundantThrows"/-->
|
||||
<!--module name="SimplifyBooleanExpression"/-->
|
||||
<!--module name="SimplifyBooleanReturn"/-->
|
||||
|
||||
<!-- Checks for class design -->
|
||||
<!-- See http://checkstyle.sf.net/config_design.html -->
|
||||
<!--module name="DesignForExtension"/-->
|
||||
<!--module name="FinalClass"/-->
|
||||
<!--module name="HideUtilityClassConstructor"/-->
|
||||
<!--module name="InterfaceIsType"/-->
|
||||
<!--module name="VisibilityModifier"/-->
|
||||
|
||||
|
||||
<!-- Miscellaneous other checks. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html -->
|
||||
<!--module name="ArrayTypeStyle"/-->
|
||||
<!--module name="FinalParameters"/-->
|
||||
<!--module name="TodoComment"/-->
|
||||
<!--module name="UpperEll"/-->
|
||||
</module>
|
||||
</module>
|
||||
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.viewpagerindicator</groupId>
|
||||
<artifactId>library</artifactId>
|
||||
<name>Android-ViewPagerIndicator</name>
|
||||
<packaging>apklib</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.viewpagerindicator</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>2.2.2</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>android</groupId>
|
||||
<artifactId>android</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>android.support</groupId>
|
||||
<artifactId>compatibility-v4</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
|
||||
<artifactId>maven-android-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<configLocation>${project.basedir}/checkstyle.xml</configLocation>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>checkstyle</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,40 @@
|
||||
-optimizationpasses 5
|
||||
-dontusemixedcaseclassnames
|
||||
-dontskipnonpubliclibraryclasses
|
||||
-dontpreverify
|
||||
-verbose
|
||||
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.BroadcastReceiver
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||
-keep public class * extends android.preference.Preference
|
||||
-keep public class com.android.vending.licensing.ILicensingService
|
||||
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet);
|
||||
}
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
public <init>(android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
-keepclassmembers class * extends android.app.Activity {
|
||||
public void *(android.view.View);
|
||||
}
|
||||
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
-keep class * implements android.os.Parcelable {
|
||||
public static final android.os.Parcelable$Creator *;
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
android.library=true
|
||||
# Project target.
|
||||
target=android-4
|
||||
@ -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>
|
||||
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<view
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
class="com.viewpagerindicator.TabPageIndicator$TabView"
|
||||
style="?attr/vpiTabPageIndicatorStyle">
|
||||
<TextView
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
style="?attr/vpiTabTextStyle" />
|
||||
</view>
|
||||
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 Patrik Åkerfeldt
|
||||
Copyright (C) 2011 Jake Wharton
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<declare-styleable name="ViewPagerIndicator">
|
||||
<!-- Style of the circle indicator. -->
|
||||
<attr name="vpiCirclePageIndicatorStyle" format="reference"/>
|
||||
|
||||
<!-- Style of the title indicator. -->
|
||||
<attr name="vpiTitlePageIndicatorStyle" format="reference"/>
|
||||
|
||||
<!-- Style of the tab indicator. -->
|
||||
<attr name="vpiTabPageIndicatorStyle" format="reference"/>
|
||||
<!-- Style of the text in a tab. -->
|
||||
<attr name="vpiTabTextStyle" format="reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="CirclePageIndicator">
|
||||
<!-- Whether or not the indicators should be centered. -->
|
||||
<attr name="centered" format="boolean" />
|
||||
<!-- Color of the filled circle that represents the current page. -->
|
||||
<attr name="fillColor" format="color" />
|
||||
<!-- Orientation of the indicator. -->
|
||||
<attr name="orientation">
|
||||
<enum name="horizontal" value="0" />
|
||||
<enum name="vertical" value="1" />
|
||||
</attr>
|
||||
<!-- 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" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="TitlePageIndicator">
|
||||
<!-- Screen edge padding. -->
|
||||
<attr name="clipPadding" format="dimension" />
|
||||
<!-- Color of the footer line and indicator. -->
|
||||
<attr name="footerColor" format="color" />
|
||||
<!-- Height of the footer line. -->
|
||||
<attr name="footerLineHeight" format="dimension" />
|
||||
<!-- Style of the indicator. Default is triangle. -->
|
||||
<attr name="footerIndicatorStyle">
|
||||
<enum name="none" value="0" />
|
||||
<enum name="triangle" value="1" />
|
||||
<enum name="underline" value="2" />
|
||||
</attr>
|
||||
<!-- Height of the indicator above the footer line. -->
|
||||
<attr name="footerIndicatorHeight" format="dimension" />
|
||||
<!-- Left and right padding of the underline indicator. -->
|
||||
<attr name="footerIndicatorUnderlinePadding" format="dimension" />
|
||||
<!-- Padding between the bottom of the title and the footer. -->
|
||||
<attr name="footerPadding" format="dimension" />
|
||||
<!-- Color of the selected title. -->
|
||||
<attr name="selectedColor" format="color" />
|
||||
<!-- Whether or not the selected item is displayed as bold. -->
|
||||
<attr name="selectedBold" format="boolean" />
|
||||
<!-- Color of regular titles. -->
|
||||
<attr name="textColor" format="color" />
|
||||
<!-- Size of title text. -->
|
||||
<attr name="textSize" format="dimension" />
|
||||
<!-- Padding between titles when bumping into each other. -->
|
||||
<attr name="titlePadding" format="dimension" />
|
||||
<!-- Padding between titles and the top of the View. -->
|
||||
<attr name="topPadding" format="dimension" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="vpi__background_holo_dark">#ff000000</color>
|
||||
<color name="vpi__background_holo_light">#fff3f3f3</color>
|
||||
<color name="vpi__bright_foreground_holo_dark">@color/vpi__background_holo_light</color>
|
||||
<color name="vpi__bright_foreground_holo_light">@color/vpi__background_holo_dark</color>
|
||||
<color name="vpi__bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
|
||||
<color name="vpi__bright_foreground_disabled_holo_light">#ffb2b2b2</color>
|
||||
<color name="vpi__bright_foreground_inverse_holo_dark">@color/vpi__bright_foreground_holo_light</color>
|
||||
<color name="vpi__bright_foreground_inverse_holo_light">@color/vpi__bright_foreground_holo_dark</color>
|
||||
</resources>
|
||||
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 Jake Wharton
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<bool name="default_circle_indicator_centered">true</bool>
|
||||
<color name="default_circle_indicator_fill_color">#FFFFFFFF</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_title_indicator_clip_padding">4dp</dimen>
|
||||
<color name="default_title_indicator_footer_color">#FF6899FF</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>
|
||||
<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">15sp</dimen>
|
||||
<dimen name="default_title_indicator_title_padding">5dp</dimen>
|
||||
<dimen name="default_title_indicator_top_padding">7dp</dimen>
|
||||
</resources>
|
||||
@ -0,0 +1,72 @@
|
||||
<?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="vpiCirclePageIndicatorStyle">@style/Widget.CirclePageIndicator</item>
|
||||
<item name="vpiTitlePageIndicatorStyle">@style/Widget.TitlePageIndicator</item>
|
||||
<item name="vpiTabPageIndicatorStyle">@style/Widget.TabPageIndicator</item>
|
||||
<item name="vpiTabTextStyle">@style/Widget.TabPageIndicator.Text</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget"></style>
|
||||
|
||||
<style name="Widget.CirclePageIndicator" parent="Widget">
|
||||
<item name="centered">@bool/default_circle_indicator_centered</item>
|
||||
<item name="fillColor">@color/default_circle_indicator_fill_color</item>
|
||||
<item name="orientation">@integer/default_circle_indicator_orientation</item>
|
||||
<item name="radius">@dimen/default_circle_indicator_radius</item>
|
||||
<item name="snap">@bool/default_circle_indicator_snap</item>
|
||||
<item name="strokeColor">@color/default_circle_indicator_stroke_color</item>
|
||||
<item name="strokeWidth">@dimen/default_circle_indicator_stroke_width</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.TitlePageIndicator" parent="Widget">
|
||||
<item name="clipPadding">@dimen/default_title_indicator_clip_padding</item>
|
||||
<item name="footerColor">@color/default_title_indicator_footer_color</item>
|
||||
<item name="footerLineHeight">@dimen/default_title_indicator_footer_line_height</item>
|
||||
<item name="footerIndicatorStyle">@integer/default_title_indicator_footer_indicator_style</item>
|
||||
<item name="footerIndicatorHeight">@dimen/default_title_indicator_footer_indicator_height</item>
|
||||
<item name="footerIndicatorUnderlinePadding">@dimen/default_title_indicator_footer_indicator_underline_padding</item>
|
||||
<item name="footerPadding">@dimen/default_title_indicator_footer_padding</item>
|
||||
<item name="selectedColor">@color/default_title_indicator_selected_color</item>
|
||||
<item name="selectedBold">@bool/default_title_indicator_selected_bold</item>
|
||||
<item name="textColor">@color/default_title_indicator_text_color</item>
|
||||
<item name="textSize">@dimen/default_title_indicator_text_size</item>
|
||||
<item name="titlePadding">@dimen/default_title_indicator_title_padding</item>
|
||||
<item name="topPadding">@dimen/default_title_indicator_top_padding</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.TabPageIndicator" parent="Widget">
|
||||
<item name="android:gravity">center_horizontal</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>
|
||||
</style>
|
||||
<style name="Widget.TabPageIndicator.Text" parent="Widget">
|
||||
<item name="android:textAppearance">@style/TextAppearance.TabPageIndicator</item>
|
||||
<item name="android:textColor">@color/vpi__dark_theme</item>
|
||||
<item name="android:textSize">12sp</item>
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:maxLines">1</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.TabPageIndicator" parent="Widget">
|
||||
|
||||
</style>
|
||||
</resources>
|
||||
@ -0,0 +1,526 @@
|
||||
/*
|
||||
* 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.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.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;
|
||||
|
||||
/**
|
||||
* Draws circles (one for each view). The current view position is filled and
|
||||
* others are only stroked.
|
||||
*/
|
||||
public class CirclePageIndicator extends View implements PageIndicator {
|
||||
public static final int HORIZONTAL = 0;
|
||||
public static final int VERTICAL = 1;
|
||||
|
||||
private float mRadius;
|
||||
private final Paint mPaintStroke;
|
||||
private final Paint mPaintFill;
|
||||
private ViewPager mViewPager;
|
||||
private ViewPager.OnPageChangeListener mListener;
|
||||
private int mCurrentPage;
|
||||
private int mSnapPage;
|
||||
private int mCurrentOffset;
|
||||
private int mScrollState;
|
||||
private int mPageSize;
|
||||
private int mOrientation;
|
||||
private boolean mCentered;
|
||||
private boolean mSnap;
|
||||
|
||||
private static final int INVALID_POINTER = -1;
|
||||
|
||||
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);
|
||||
|
||||
//Load defaults from resources
|
||||
final Resources res = getResources();
|
||||
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, R.style.Widget_CirclePageIndicator);
|
||||
|
||||
mCentered = a.getBoolean(R.styleable.CirclePageIndicator_centered, defaultCentered);
|
||||
mOrientation = a.getInt(R.styleable.CirclePageIndicator_orientation, defaultOrientation);
|
||||
mPaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mPaintStroke.setStyle(Style.STROKE);
|
||||
mPaintStroke.setColor(a.getColor(R.styleable.CirclePageIndicator_strokeColor, defaultStrokeColor));
|
||||
mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth));
|
||||
mPaintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
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);
|
||||
|
||||
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 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;
|
||||
updatePageSize();
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* (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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//Draw the filled circle according to the current scroll
|
||||
float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius;
|
||||
if (!mSnap && (mPageSize != 0)) {
|
||||
cx += (mCurrentOffset * 1.0f / mPageSize) * threeRadius;
|
||||
}
|
||||
if (mOrientation == HORIZONTAL) {
|
||||
dX = longOffset + cx;
|
||||
dY = shortOffset;
|
||||
} else {
|
||||
dX = shortOffset;
|
||||
dY = longOffset + cx;
|
||||
}
|
||||
canvas.drawCircle(dX, dY, mRadius - getResources().getDimension(R.dimen.default_circle_indicator_stroke_width)/2
|
||||
, mPaintFill);
|
||||
|
||||
//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;
|
||||
}
|
||||
canvas.drawCircle(dX, dY, mRadius, mPaintStroke);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(android.view.MotionEvent ev) {
|
||||
if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int action = ev.getAction();
|
||||
|
||||
switch (action & MotionEventCompat.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
|
||||
mLastMotionX = ev.getX();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
|
||||
final float x = MotionEventCompat.getX(ev, activePointerIndex);
|
||||
final float deltaX = x - mLastMotionX;
|
||||
|
||||
if (!mIsDragging) {
|
||||
if (Math.abs(deltaX) > mTouchSlop) {
|
||||
mIsDragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsDragging) {
|
||||
if (!mViewPager.isFakeDragging()) {
|
||||
mViewPager.beginFakeDrag();
|
||||
}
|
||||
|
||||
mLastMotionX = x;
|
||||
|
||||
mViewPager.fakeDragBy(deltaX);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (!mIsDragging) {
|
||||
final int count = mViewPager.getAdapter().getCount();
|
||||
final int width = getWidth();
|
||||
final float halfWidth = width / 2f;
|
||||
final float sixthWidth = width / 6f;
|
||||
|
||||
if ((mCurrentPage > 0) && (ev.getX() < halfWidth - sixthWidth)) {
|
||||
mViewPager.setCurrentItem(mCurrentPage - 1);
|
||||
return true;
|
||||
} else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) {
|
||||
mViewPager.setCurrentItem(mCurrentPage + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
mIsDragging = false;
|
||||
mActivePointerId = INVALID_POINTER;
|
||||
if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag();
|
||||
break;
|
||||
|
||||
case MotionEventCompat.ACTION_POINTER_DOWN: {
|
||||
final int index = MotionEventCompat.getActionIndex(ev);
|
||||
final float x = MotionEventCompat.getX(ev, index);
|
||||
mLastMotionX = x;
|
||||
mActivePointerId = MotionEventCompat.getPointerId(ev, index);
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEventCompat.ACTION_POINTER_UP:
|
||||
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
|
||||
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
|
||||
if (pointerId == mActivePointerId) {
|
||||
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
||||
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
|
||||
}
|
||||
mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId));
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@Override
|
||||
public void setViewPager(ViewPager view) {
|
||||
if (view.getAdapter() == null) {
|
||||
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||
}
|
||||
mViewPager = view;
|
||||
mViewPager.setOnPageChangeListener(this);
|
||||
updatePageSize();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void updatePageSize() {
|
||||
if (mViewPager != null) {
|
||||
mPageSize = (mOrientation == HORIZONTAL) ? mViewPager.getWidth() : mViewPager.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
mCurrentOffset = positionOffsetPixels;
|
||||
updatePageSize();
|
||||
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 = 0;
|
||||
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 = 0;
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
int specSize = MeasureSpec.getSize(measureSpec);
|
||||
|
||||
if (specMode == MeasureSpec.EXACTLY) {
|
||||
//We were told how big to be
|
||||
result = specSize;
|
||||
} else {
|
||||
//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);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
public void setViewPager(ViewPager view);
|
||||
|
||||
/**
|
||||
* Bind the indicator to a ViewPager.
|
||||
*
|
||||
* @param view
|
||||
* @param initialPosition
|
||||
*/
|
||||
public void setViewPager(ViewPager view, int initialPosition);
|
||||
|
||||
/**
|
||||
* <p>Set the current page of both the ViewPager and indicator.</p>
|
||||
*
|
||||
* <p>This <strong>must</strong> be used if you need to set the page before
|
||||
* the views are drawn on screen (e.g., default start page).</p>
|
||||
*
|
||||
* @param item
|
||||
*/
|
||||
public void setCurrentItem(int item);
|
||||
|
||||
/**
|
||||
* Set a page change listener which will receive forwarded events.
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
|
||||
|
||||
/**
|
||||
* Notify the indicator that the fragment list has changed.
|
||||
*/
|
||||
public void notifyDataSetChanged();
|
||||
}
|
||||
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* 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 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.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* This widget implements the dynamic action bar tab behavior that can change
|
||||
* across different configurations or circumstances.
|
||||
*/
|
||||
public class TabPageIndicator extends HorizontalScrollView implements PageIndicator {
|
||||
Runnable mTabSelector;
|
||||
|
||||
private OnClickListener mTabClickListener = new OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
TabView tabView = (TabView)view;
|
||||
mViewPager.setCurrentItem(tabView.getIndex());
|
||||
}
|
||||
};
|
||||
|
||||
private LinearLayout mTabLayout;
|
||||
private ViewPager mViewPager;
|
||||
private ViewPager.OnPageChangeListener mListener;
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
int mMaxTabWidth;
|
||||
private int mSelectedTabIndex;
|
||||
|
||||
public TabPageIndicator(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public TabPageIndicator(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setHorizontalScrollBarEnabled(false);
|
||||
|
||||
mInflater = LayoutInflater.from(context);
|
||||
|
||||
mTabLayout = new LinearLayout(getContext());
|
||||
addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.FILL_PARENT));
|
||||
}
|
||||
|
||||
@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(String text, int index) {
|
||||
//Workaround for not being able to pass a defStyle on pre-3.0
|
||||
final TabView tabView = (TabView)mInflater.inflate(R.layout.vpi__tab, null);
|
||||
tabView.init(this, text, index);
|
||||
tabView.setFocusable(true);
|
||||
tabView.setOnClickListener(mTabClickListener);
|
||||
|
||||
mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0, LayoutParams.FILL_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) {
|
||||
final PagerAdapter adapter = view.getAdapter();
|
||||
if (adapter == null) {
|
||||
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||
}
|
||||
if (!(adapter instanceof TitleProvider)) {
|
||||
throw new IllegalStateException("ViewPager adapter must implement TitleProvider to be used with TitlePageIndicator.");
|
||||
}
|
||||
mViewPager = view;
|
||||
view.setOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void notifyDataSetChanged() {
|
||||
mTabLayout.removeAllViews();
|
||||
TitleProvider adapter = (TitleProvider)mViewPager.getAdapter();
|
||||
final int count = ((PagerAdapter)adapter).getCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
addTab(adapter.getTitle(i), i);
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
public static class TabView extends LinearLayout {
|
||||
private TabPageIndicator mParent;
|
||||
private int mIndex;
|
||||
|
||||
public TabView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public void init(TabPageIndicator parent, String text, int index) {
|
||||
mParent = parent;
|
||||
mIndex = index;
|
||||
|
||||
TextView textView = (TextView)findViewById(android.R.id.text1);
|
||||
textView.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
// Re-measure if we went beyond our maximum size.
|
||||
if (mParent.mMaxTabWidth > 0 && getMeasuredWidth() > mParent.mMaxTabWidth) {
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(mParent.mMaxTabWidth, MeasureSpec.EXACTLY),
|
||||
heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return mIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,776 @@
|
||||
/*
|
||||
* 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.RectF;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v4.view.MotionEventCompat;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewConfigurationCompat;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Interface for a callback when the center item has been clicked.
|
||||
*/
|
||||
public static interface OnCenterItemClickListener {
|
||||
/**
|
||||
* Callback when the center item has been clicked.
|
||||
*
|
||||
* @param position Position of the current center item.
|
||||
*/
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
|
||||
private ViewPager mViewPager;
|
||||
private ViewPager.OnPageChangeListener mListener;
|
||||
private TitleProvider mTitleProvider;
|
||||
private int mCurrentPage;
|
||||
private int mCurrentOffset;
|
||||
private int mScrollState;
|
||||
private final Paint mPaintText = new Paint();
|
||||
private boolean mBoldText;
|
||||
private int mColorText;
|
||||
private int mColorSelected;
|
||||
private Path mPath;
|
||||
private final Paint mPaintFooterLine = new Paint();
|
||||
private IndicatorStyle mFooterIndicatorStyle;
|
||||
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);
|
||||
|
||||
//Load defaults from resources
|
||||
final Resources res = getResources();
|
||||
final int defaultFooterColor = res.getColor(R.color.default_title_indicator_footer_color);
|
||||
final float defaultFooterLineHeight = res.getDimension(R.dimen.default_title_indicator_footer_line_height);
|
||||
final int defaultFooterIndicatorStyle = res.getInteger(R.integer.default_title_indicator_footer_indicator_style);
|
||||
final float defaultFooterIndicatorHeight = res.getDimension(R.dimen.default_title_indicator_footer_indicator_height);
|
||||
final float defaultFooterIndicatorUnderlinePadding = res.getDimension(R.dimen.default_title_indicator_footer_indicator_underline_padding);
|
||||
final float defaultFooterPadding = res.getDimension(R.dimen.default_title_indicator_footer_padding);
|
||||
final int defaultSelectedColor = res.getColor(R.color.default_title_indicator_selected_color);
|
||||
final boolean defaultSelectedBold = res.getBoolean(R.bool.default_title_indicator_selected_bold);
|
||||
final int defaultTextColor = res.getColor(R.color.default_title_indicator_text_color);
|
||||
final float defaultTextSize = res.getDimension(R.dimen.default_title_indicator_text_size);
|
||||
final float defaultTitlePadding = res.getDimension(R.dimen.default_title_indicator_title_padding);
|
||||
final float defaultClipPadding = res.getDimension(R.dimen.default_title_indicator_clip_padding);
|
||||
final float defaultTopPadding = res.getDimension(R.dimen.default_title_indicator_top_padding);
|
||||
|
||||
//Retrieve styles attributes
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitlePageIndicator, defStyle, R.style.Widget_TitlePageIndicator);
|
||||
|
||||
//Retrieve the colors to be used for this view and apply them.
|
||||
mFooterLineHeight = a.getDimension(R.styleable.TitlePageIndicator_footerLineHeight, defaultFooterLineHeight);
|
||||
mFooterIndicatorStyle = IndicatorStyle.fromValue(a.getInteger(R.styleable.TitlePageIndicator_footerIndicatorStyle, defaultFooterIndicatorStyle));
|
||||
mFooterIndicatorHeight = a.getDimension(R.styleable.TitlePageIndicator_footerIndicatorHeight, defaultFooterIndicatorHeight);
|
||||
mFooterIndicatorUnderlinePadding = a.getDimension(R.styleable.TitlePageIndicator_footerIndicatorUnderlinePadding, defaultFooterIndicatorUnderlinePadding);
|
||||
mFooterPadding = a.getDimension(R.styleable.TitlePageIndicator_footerPadding, defaultFooterPadding);
|
||||
mTopPadding = a.getDimension(R.styleable.TitlePageIndicator_topPadding, defaultTopPadding);
|
||||
mTitlePadding = a.getDimension(R.styleable.TitlePageIndicator_titlePadding, defaultTitlePadding);
|
||||
mClipPadding = a.getDimension(R.styleable.TitlePageIndicator_clipPadding, defaultClipPadding);
|
||||
mColorSelected = a.getColor(R.styleable.TitlePageIndicator_selectedColor, defaultSelectedColor);
|
||||
mColorText = a.getColor(R.styleable.TitlePageIndicator_textColor, defaultTextColor);
|
||||
mBoldText = a.getBoolean(R.styleable.TitlePageIndicator_selectedBold, defaultSelectedBold);
|
||||
|
||||
final float textSize = a.getDimension(R.styleable.TitlePageIndicator_textSize, defaultTextSize);
|
||||
final int footerColor = a.getColor(R.styleable.TitlePageIndicator_footerColor, defaultFooterColor);
|
||||
mPaintText.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);
|
||||
|
||||
a.recycle();
|
||||
|
||||
final ViewConfiguration configuration = ViewConfiguration.get(context);
|
||||
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
|
||||
}
|
||||
|
||||
|
||||
public int getFooterColor() {
|
||||
return mPaintFooterLine.getColor();
|
||||
}
|
||||
|
||||
public void setFooterColor(int footerColor) {
|
||||
mPaintFooterLine.setColor(footerColor);
|
||||
mPaintFooterIndicator.setColor(footerColor);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getFooterLineHeight() {
|
||||
return mFooterLineHeight;
|
||||
}
|
||||
|
||||
public void setFooterLineHeight(float footerLineHeight) {
|
||||
mFooterLineHeight = footerLineHeight;
|
||||
mPaintFooterLine.setStrokeWidth(mFooterLineHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getFooterIndicatorHeight() {
|
||||
return mFooterIndicatorHeight;
|
||||
}
|
||||
|
||||
public void setFooterIndicatorHeight(float footerTriangleHeight) {
|
||||
mFooterIndicatorHeight = footerTriangleHeight;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getFooterIndicatorPadding() {
|
||||
return mFooterPadding;
|
||||
}
|
||||
|
||||
public void setFooterIndicatorPadding(float footerIndicatorPadding) {
|
||||
mFooterPadding = footerIndicatorPadding;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public IndicatorStyle getFooterIndicatorStyle() {
|
||||
return mFooterIndicatorStyle;
|
||||
}
|
||||
|
||||
public void setFooterIndicatorStyle(IndicatorStyle indicatorStyle) {
|
||||
mFooterIndicatorStyle = indicatorStyle;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getSelectedColor() {
|
||||
return mColorSelected;
|
||||
}
|
||||
|
||||
public void setSelectedColor(int selectedColor) {
|
||||
mColorSelected = selectedColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public boolean isSelectedBold() {
|
||||
return mBoldText;
|
||||
}
|
||||
|
||||
public void setSelectedBold(boolean selectedBold) {
|
||||
mBoldText = selectedBold;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getTextColor() {
|
||||
return mColorText;
|
||||
}
|
||||
|
||||
public void setTextColor(int textColor) {
|
||||
mPaintText.setColor(textColor);
|
||||
mColorText = textColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getTextSize() {
|
||||
return mPaintText.getTextSize();
|
||||
}
|
||||
|
||||
public void setTextSize(float textSize) {
|
||||
mPaintText.setTextSize(textSize);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getTitlePadding() {
|
||||
return this.mTitlePadding;
|
||||
}
|
||||
|
||||
public void setTitlePadding(float titlePadding) {
|
||||
mTitlePadding = titlePadding;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getTopPadding() {
|
||||
return this.mTopPadding;
|
||||
}
|
||||
|
||||
public void setTopPadding(float topPadding) {
|
||||
mTopPadding = topPadding;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public float getClipPadding() {
|
||||
return this.mClipPadding;
|
||||
}
|
||||
|
||||
public void setClipPadding(float clipPadding) {
|
||||
mClipPadding = clipPadding;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//Calculate views bounds
|
||||
ArrayList<RectF> bounds = calculateAllBounds(mPaintText);
|
||||
|
||||
//Make sure we're on a page that still exists
|
||||
if (mCurrentPage >= bounds.size()) {
|
||||
setCurrentItem(bounds.size()-1);
|
||||
}
|
||||
|
||||
final int countMinusOne = count - 1;
|
||||
final float halfWidth = getWidth() / 2f;
|
||||
final int left = getLeft();
|
||||
final float leftClip = left + mClipPadding;
|
||||
final int width = getWidth();
|
||||
final int height = getHeight();
|
||||
final int right = left + width;
|
||||
final float rightClip = right - mClipPadding;
|
||||
|
||||
int page = mCurrentPage;
|
||||
float offsetPercent;
|
||||
if (mCurrentOffset <= halfWidth) {
|
||||
offsetPercent = 1.0f * mCurrentOffset / width;
|
||||
} else {
|
||||
page += 1;
|
||||
offsetPercent = 1.0f * (width - mCurrentOffset) / width;
|
||||
}
|
||||
final boolean currentSelected = (offsetPercent <= SELECTION_FADE_PERCENTAGE);
|
||||
final boolean currentBold = (offsetPercent <= BOLD_FADE_PERCENTAGE);
|
||||
final float selectedPercent = (SELECTION_FADE_PERCENTAGE - offsetPercent) / SELECTION_FADE_PERCENTAGE;
|
||||
|
||||
//Verify if the current view must be clipped to the screen
|
||||
RectF curPageBound = bounds.get(mCurrentPage);
|
||||
float curPageWidth = curPageBound.right - curPageBound.left;
|
||||
if (curPageBound.left < leftClip) {
|
||||
//Try to clip to the screen (left side)
|
||||
clipViewOnTheLeft(curPageBound, curPageWidth, left);
|
||||
}
|
||||
if (curPageBound.right > rightClip) {
|
||||
//Try to clip to the screen (right side)
|
||||
clipViewOnTheRight(curPageBound, curPageWidth, right);
|
||||
}
|
||||
|
||||
//Left views starting from the current position
|
||||
if (mCurrentPage > 0) {
|
||||
for (int i = mCurrentPage - 1; i >= 0; i--) {
|
||||
RectF bound = bounds.get(i);
|
||||
//Is left side is outside the screen
|
||||
if (bound.left < leftClip) {
|
||||
float w = bound.right - bound.left;
|
||||
//Try to clip to the screen (left side)
|
||||
clipViewOnTheLeft(bound, w, left);
|
||||
//Except if there's an intersection with the right view
|
||||
RectF rightBound = bounds.get(i + 1);
|
||||
//Intersection
|
||||
if (bound.right + mTitlePadding > rightBound.left) {
|
||||
bound.left = rightBound.left - w - mTitlePadding;
|
||||
bound.right = bound.left + w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Right views starting from the current position
|
||||
if (mCurrentPage < countMinusOne) {
|
||||
for (int i = mCurrentPage + 1 ; i < count; i++) {
|
||||
RectF bound = bounds.get(i);
|
||||
//If right side is outside the screen
|
||||
if (bound.right > rightClip) {
|
||||
float w = bound.right - bound.left;
|
||||
//Try to clip to the screen (right side)
|
||||
clipViewOnTheRight(bound, w, right);
|
||||
//Except if there's an intersection with the left view
|
||||
RectF leftBound = bounds.get(i - 1);
|
||||
//Intersection
|
||||
if (bound.left - mTitlePadding < leftBound.right) {
|
||||
bound.left = leftBound.right + mTitlePadding;
|
||||
bound.right = bound.left + w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Now draw views
|
||||
for (int i = 0; i < count; i++) {
|
||||
//Get the title
|
||||
RectF bound = bounds.get(i);
|
||||
//Only if one side is visible
|
||||
if ((bound.left > left && bound.left < right) || (bound.right > left && bound.right < right)) {
|
||||
final boolean currentPage = (i == page);
|
||||
//Only set bold if we are within bounds
|
||||
mPaintText.setFakeBoldText(currentPage && currentBold && mBoldText);
|
||||
|
||||
//Draw text as unselected
|
||||
mPaintText.setColor(mColorText);
|
||||
canvas.drawText(mTitleProvider.getTitle(i), bound.left, bound.bottom + mTopPadding, mPaintText);
|
||||
|
||||
//If we are within the selected bounds draw the selected text
|
||||
if (currentPage && currentSelected) {
|
||||
mPaintText.setColor(mColorSelected);
|
||||
mPaintText.setAlpha((int)((mColorSelected >>> 24) * selectedPercent));
|
||||
canvas.drawText(mTitleProvider.getTitle(i), bound.left, bound.bottom + mTopPadding, mPaintText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Draw the footer line
|
||||
mPath = new Path();
|
||||
mPath.moveTo(0, height - mFooterLineHeight / 2f);
|
||||
mPath.lineTo(width, height - mFooterLineHeight / 2f);
|
||||
mPath.close();
|
||||
canvas.drawPath(mPath, mPaintFooterLine);
|
||||
|
||||
switch (mFooterIndicatorStyle) {
|
||||
case Triangle:
|
||||
mPath = new Path();
|
||||
mPath.moveTo(halfWidth, height - mFooterLineHeight - mFooterIndicatorHeight);
|
||||
mPath.lineTo(halfWidth + mFooterIndicatorHeight, height - mFooterLineHeight);
|
||||
mPath.lineTo(halfWidth - mFooterIndicatorHeight, height - mFooterLineHeight);
|
||||
mPath.close();
|
||||
canvas.drawPath(mPath, mPaintFooterIndicator);
|
||||
break;
|
||||
|
||||
case Underline:
|
||||
if (!currentSelected) {
|
||||
break;
|
||||
}
|
||||
|
||||
RectF underlineBounds = bounds.get(page);
|
||||
mPath = new Path();
|
||||
mPath.moveTo(underlineBounds.left - mFooterIndicatorUnderlinePadding, height - mFooterLineHeight);
|
||||
mPath.lineTo(underlineBounds.right + mFooterIndicatorUnderlinePadding, height - mFooterLineHeight);
|
||||
mPath.lineTo(underlineBounds.right + mFooterIndicatorUnderlinePadding, height - mFooterLineHeight - mFooterIndicatorHeight);
|
||||
mPath.lineTo(underlineBounds.left - mFooterIndicatorUnderlinePadding, height - mFooterLineHeight - mFooterIndicatorHeight);
|
||||
mPath.close();
|
||||
|
||||
mPaintFooterIndicator.setAlpha((int)(0xFF * selectedPercent));
|
||||
canvas.drawPath(mPath, mPaintFooterIndicator);
|
||||
mPaintFooterIndicator.setAlpha(0xFF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(android.view.MotionEvent ev) {
|
||||
if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int action = ev.getAction();
|
||||
|
||||
switch (action & MotionEventCompat.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
|
||||
mLastMotionX = ev.getX();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE: {
|
||||
final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
|
||||
final float x = MotionEventCompat.getX(ev, activePointerIndex);
|
||||
final float deltaX = x - mLastMotionX;
|
||||
|
||||
if (!mIsDragging) {
|
||||
if (Math.abs(deltaX) > mTouchSlop) {
|
||||
mIsDragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsDragging) {
|
||||
if (!mViewPager.isFakeDragging()) {
|
||||
mViewPager.beginFakeDrag();
|
||||
}
|
||||
|
||||
mLastMotionX = x;
|
||||
|
||||
mViewPager.fakeDragBy(deltaX);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (!mIsDragging) {
|
||||
final int count = mViewPager.getAdapter().getCount();
|
||||
final int width = getWidth();
|
||||
final float halfWidth = width / 2f;
|
||||
final float sixthWidth = width / 6f;
|
||||
final float leftThird = halfWidth - sixthWidth;
|
||||
final float rightThird = halfWidth + sixthWidth;
|
||||
final float eventX = ev.getX();
|
||||
|
||||
if (eventX < leftThird) {
|
||||
if (mCurrentPage > 0) {
|
||||
mViewPager.setCurrentItem(mCurrentPage - 1);
|
||||
return true;
|
||||
}
|
||||
} else if (eventX > rightThird) {
|
||||
if (mCurrentPage < count - 1) {
|
||||
mViewPager.setCurrentItem(mCurrentPage + 1);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
//Middle third
|
||||
if (mCenterItemClickListener != null) {
|
||||
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);
|
||||
final float x = MotionEventCompat.getX(ev, index);
|
||||
mLastMotionX = x;
|
||||
mActivePointerId = MotionEventCompat.getPointerId(ev, index);
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionEventCompat.ACTION_POINTER_UP:
|
||||
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
|
||||
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
|
||||
if (pointerId == mActivePointerId) {
|
||||
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
|
||||
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
|
||||
}
|
||||
mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId));
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set bounds for the right textView including clip padding.
|
||||
*
|
||||
* @param curViewBound
|
||||
* current bounds.
|
||||
* @param curViewWidth
|
||||
* width of the view.
|
||||
*/
|
||||
private void clipViewOnTheRight(RectF curViewBound, float curViewWidth, int right) {
|
||||
curViewBound.right = right - mClipPadding;
|
||||
curViewBound.left = curViewBound.right - curViewWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bounds for the left textView including clip padding.
|
||||
*
|
||||
* @param curViewBound
|
||||
* current bounds.
|
||||
* @param curViewWidth
|
||||
* width of the view.
|
||||
*/
|
||||
private void clipViewOnTheLeft(RectF curViewBound, float curViewWidth, int left) {
|
||||
curViewBound.left = left + mClipPadding;
|
||||
curViewBound.right = mClipPadding + curViewWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate views bounds and scroll them according to the current index
|
||||
*
|
||||
* @param paint
|
||||
* @param currentIndex
|
||||
* @return
|
||||
*/
|
||||
private ArrayList<RectF> calculateAllBounds(Paint paint) {
|
||||
ArrayList<RectF> list = new ArrayList<RectF>();
|
||||
//For each views (If no values then add a fake one)
|
||||
final int count = mViewPager.getAdapter().getCount();
|
||||
final int width = getWidth();
|
||||
final int halfWidth = width / 2;
|
||||
for (int i = 0; i < count; i++) {
|
||||
RectF bounds = calcBounds(i, paint);
|
||||
float w = (bounds.right - bounds.left);
|
||||
float h = (bounds.bottom - bounds.top);
|
||||
bounds.left = (halfWidth) - (w / 2) - mCurrentOffset + ((i - mCurrentPage) * width);
|
||||
bounds.right = bounds.left + w;
|
||||
bounds.top = 0;
|
||||
bounds.bottom = h;
|
||||
list.add(bounds);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the bounds for a view's title
|
||||
*
|
||||
* @param index
|
||||
* @param paint
|
||||
* @return
|
||||
*/
|
||||
private RectF calcBounds(int index, Paint paint) {
|
||||
//Calculate the text bounds
|
||||
RectF bounds = new RectF();
|
||||
bounds.right = paint.measureText(mTitleProvider.getTitle(index));
|
||||
bounds.bottom = paint.descent() - paint.ascent();
|
||||
return bounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setViewPager(ViewPager view) {
|
||||
final PagerAdapter adapter = view.getAdapter();
|
||||
if (adapter == null) {
|
||||
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
||||
}
|
||||
if (!(adapter instanceof TitleProvider)) {
|
||||
throw new IllegalStateException("ViewPager adapter must implement TitleProvider to be used with TitlePageIndicator.");
|
||||
}
|
||||
mViewPager = view;
|
||||
mViewPager.setOnPageChangeListener(this);
|
||||
mTitleProvider = (TitleProvider)adapter;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setViewPager(ViewPager view, int initialPosition) {
|
||||
setViewPager(view);
|
||||
setCurrentItem(initialPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
mCurrentOffset = positionOffsetPixels;
|
||||
invalidate();
|
||||
|
||||
if (mListener != null) {
|
||||
mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
|
||||
mCurrentPage = position;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
if (mListener != null) {
|
||||
mListener.onPageSelected(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@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 = 0;
|
||||
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
|
||||
RectF bounds = new RectF();
|
||||
bounds.bottom = mPaintText.descent()-mPaintText.ascent();
|
||||
height = bounds.bottom - bounds.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);
|
||||
}
|
||||
|
||||
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,28 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Patrik Akerfeldt
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.viewpagerindicator;
|
||||
|
||||
/**
|
||||
* A TitleProvider provides the title to display according to a view.
|
||||
*/
|
||||
public interface TitleProvider {
|
||||
/**
|
||||
* Returns the title of the view at position
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
public String getTitle(int position);
|
||||
}
|
||||
@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.viewpagerindicator</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>2.2.2</version>
|
||||
|
||||
<name>Android-ViewPagerIndicator (Parent)</name>
|
||||
<description>Android library for.</description>
|
||||
<url>https://github.com/JakeWharton/Android-ViewPagerIndicator</url>
|
||||
<inceptionYear>2011</inceptionYear>
|
||||
|
||||
<modules>
|
||||
<module>library</module>
|
||||
<module>sample</module>
|
||||
</modules>
|
||||
|
||||
<scm>
|
||||
<url>http://github.com/JakeWharton/Android-ViewPagerIndicator/</url>
|
||||
<connection>scm:git:git://github.com/JakeWharton/Android-ViewPagerIndicator.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:JakeWharton/Android-ViewPagerIndicator.git</developerConnection>
|
||||
</scm>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Jake Wharton</name>
|
||||
<email>jakewharton@gmail.com</email>
|
||||
<id>jakewharton</id>
|
||||
<url>http://jakewharton.com</url>
|
||||
<timezone>-5</timezone>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>personal-repository</id>
|
||||
<name>JakeWharton.com Maven Repository</name>
|
||||
<url>scp://r.jakewharton.com/home/jakewharton_repository/r.jakewharton.com/maven/release/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>personal-repository</id>
|
||||
<name>JakeWharton.com Maven Repository</name>
|
||||
<url>scp://r.jakewharton.com/home/jakewharton_repository/r.jakewharton.com/maven/snapshot/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
<organization>
|
||||
<name>Jake Wharton</name>
|
||||
<url>http://jakewharton.com</url>
|
||||
</organization>
|
||||
|
||||
<issueManagement>
|
||||
<system>GitHub Issues</system>
|
||||
<url>https://github.com/JakeWharton/Android-ViewPagerIndicator/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
|
||||
<java.version>1.6</java.version>
|
||||
<android.version>1.6_r3</android.version>
|
||||
<android.platform>4</android.platform>
|
||||
<android.support.version>r6</android.support.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>android</groupId>
|
||||
<artifactId>android</artifactId>
|
||||
<version>${android.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>android.support</groupId>
|
||||
<artifactId>compatibility-v4</artifactId>
|
||||
<version>${android.support.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>com.jakewharton</id>
|
||||
<url>http://r.jakewharton.com/maven/release</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
|
||||
<artifactId>android-maven-plugin</artifactId>
|
||||
<version>3.0.0-alpha-13</version>
|
||||
<configuration>
|
||||
<sdk>
|
||||
<platform>${android.platform}</platform>
|
||||
</sdk>
|
||||
<undeployBeforeDeploy>true</undeployBeforeDeploy>
|
||||
</configuration>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<failsOnError>true</failsOnError>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<configuration>
|
||||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-ssh</artifactId>
|
||||
<version>1.0-beta-7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||