summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml13
-rw-r--r--res/anim/button_elevation.xml51
-rw-r--r--res/drawable/fab_accent.xml27
-rw-r--r--res/drawable/floating_action_button.xml34
-rw-r--r--res/layout-sw600dp/suggestion_item.xml2
-rw-r--r--res/layout/new_folder_layout.xml48
-rw-r--r--res/layout/qc_menu_item.xml2
-rw-r--r--res/layout/suggestion_item.xml2
-rw-r--r--res/layout/tab_title.xml2
-rw-r--r--res/values-sw600dp/styles.xml8
-rw-r--r--res/values/dimensions.xml1
-rw-r--r--res/values/styles.xml6
-rw-r--r--src/com/android/browser/NavScreen.java64
-rw-r--r--src/com/android/browser/NavTabScroller.java1066
14 files changed, 665 insertions, 661 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c85ed3b..ce6ba36 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -148,7 +148,7 @@
</activity>
<activity android:name="ShortcutActivity"
- android:theme="@style/PreferencesTheme"
+ android:theme="@style/PreferencesTheme"
android:label="@string/shortcut_bookmark"
android:icon="@mipmap/ic_launcher_shortcut_browser_bookmark">
<intent-filter>
@@ -158,7 +158,9 @@
</activity>
- <activity android:name="BrowserPreferencesPage" android:label="@string/menu_preferences" android:theme="@style/PreferencesTheme">
+ <activity android:name="BrowserPreferencesPage"
+ android:label="@string/menu_preferences"
+ android:theme="@style/PreferencesTheme">
<intent-filter>
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
<category android:name="android.intent.category.DEFAULT" />
@@ -178,7 +180,8 @@
android:resource="@xml/bookmarks_searchable" />
</activity>
- <activity android:name="AddBookmarkPage" android:label="@string/bookmarks_add_page"
+ <activity android:name="AddBookmarkPage"
+ android:label="@string/bookmarks_add_page"
android:theme="@style/PreferencesTheme"
android:configChanges="orientation|keyboardHidden|screenSize"
android:windowSoftInputMode="adjustResize">
@@ -186,11 +189,11 @@
<action android:name="android.intent.action.INSERT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.dir/bookmark"/>
- android:theme="@style/PreferencesTheme" </intent-filter>
+ </intent-filter>
</activity>
<activity android:name="ComboViewActivity"
- android:theme="@style/PreferencesTheme">
+ android:theme="@style/PreferencesTheme">
</activity>
<!-- Bookmark thumbnail homescreen widget -->
diff --git a/res/anim/button_elevation.xml b/res/anim/button_elevation.xml
index 9159646..21dd654 100644
--- a/res/anim/button_elevation.xml
+++ b/res/anim/button_elevation.xml
@@ -1,33 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The CyanogenMod Project
+<!--
+ Copyright (C) 2014 The CyanogenMod 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
+ 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
+ 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.
+ 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_pressed="true">
- <objectAnimator
- android:propertyName="translationZ"
- android:duration="@android:integer/config_shortAnimTime"
- android:valueFrom="@dimen/elevation_low"
- android:valueTo="@dimen/elevation_high"
- android:valueType="floatType"/>
+ <item android:state_pressed="true">
+ <objectAnimator
+ android:propertyName="translationZ"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:valueFrom="@dimen/elevation_low"
+ android:valueTo="@dimen/elevation_high"
+ android:valueType="floatType"/>
</item>
<item>
- <objectAnimator
- android:propertyName="translationZ"
- android:duration="@android:integer/config_shortAnimTime"
- android:valueFrom="@dimen/elevation_high"
- android:valueTo="@dimen/elevation_low"
- android:valueType="floatType"/>
- </item>
- </selector>
+ <objectAnimator
+ android:propertyName="translationZ"
+ android:duration="@android:integer/config_shortAnimTime"
+ android:valueFrom="@dimen/elevation_high"
+ android:valueTo="@dimen/elevation_low"
+ android:valueType="floatType"/>
+ </item>
+</selector>
diff --git a/res/drawable/fab_accent.xml b/res/drawable/fab_accent.xml
index fabd583..01aa084 100644
--- a/res/drawable/fab_accent.xml
+++ b/res/drawable/fab_accent.xml
@@ -1,19 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The CyanogenMod Project
+<!--
+ Copyright (C) 2014 The CyanogenMod 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
+ 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
+ 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.
+ 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.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
- <solid android:color="@color/primary" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="@color/primary" />
</shape>
diff --git a/res/drawable/floating_action_button.xml b/res/drawable/floating_action_button.xml
index 0f313cb..ef95367 100644
--- a/res/drawable/floating_action_button.xml
+++ b/res/drawable/floating_action_button.xml
@@ -1,24 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The CyanogenMod Project
+<!--
+ Copyright (C) 2014 The CyanogenMod 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
+ 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
+ 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.
+ 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.
-->
-
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/floating_action_button_touch_tint">
- <item android:id="@android:id/mask">
- <shape android:shape="oval">
- <solid android:color="@color/primary" />
- </shape>
- </item>
+ android:color="@color/floating_action_button_touch_tint">
+ <item android:id="@android:id/mask">
+ <shape android:shape="oval">
+ <solid android:color="@color/primary" />
+ </shape>
+ </item>
</ripple>
diff --git a/res/layout-sw600dp/suggestion_item.xml b/res/layout-sw600dp/suggestion_item.xml
index 020ba58..b1a809b 100644
--- a/res/layout-sw600dp/suggestion_item.xml
+++ b/res/layout-sw600dp/suggestion_item.xml
@@ -81,5 +81,5 @@
android:background="?android:attr/selectableItemBackground"
android:paddingRight="@dimen/suggest_item_padding"
android:paddingLeft="@dimen/suggest_item_padding"
- />
+ />
</LinearLayout>
diff --git a/res/layout/new_folder_layout.xml b/res/layout/new_folder_layout.xml
index 7db5b38..76cc2f2 100644
--- a/res/layout/new_folder_layout.xml
+++ b/res/layout/new_folder_layout.xml
@@ -27,30 +27,30 @@
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:src="@drawable/ic_folder_dark" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@*android:drawable/edit_text_holo_dark"
- android:gravity="center_vertical"
- android:paddingBottom="5dip"
- android:orientation="horizontal">
- <EditText
- android:id="@+id/folder_namer"
- android:layout_width="0dip"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:background="@null"
+ android:background="@*android:drawable/edit_text_holo_dark"
android:gravity="center_vertical"
- android:paddingLeft="6dip"
- />
- <ImageView
- android:id="@+id/close"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:src="@drawable/ic_tab_close"
- android:contentDescription="@string/cancel"
- />
- </LinearLayout>
+ android:paddingBottom="5dip"
+ android:orientation="horizontal">
+ <EditText
+ android:id="@+id/folder_namer"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:background="@null"
+ android:gravity="center_vertical"
+ android:paddingLeft="6dip"
+ />
+ <ImageView
+ android:id="@+id/close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:src="@drawable/ic_tab_close"
+ android:contentDescription="@string/cancel"
+ />
+ </LinearLayout>
</LinearLayout>
diff --git a/res/layout/qc_menu_item.xml b/res/layout/qc_menu_item.xml
index 99c1eb9..ae05362 100644
--- a/res/layout/qc_menu_item.xml
+++ b/res/layout/qc_menu_item.xml
@@ -28,4 +28,4 @@
android:paddingTop="4dip"
android:paddingBottom="4dip"
android:elevation="8dp"
- />
+ />
diff --git a/res/layout/suggestion_item.xml b/res/layout/suggestion_item.xml
index 0adea1b..9a08517 100644
--- a/res/layout/suggestion_item.xml
+++ b/res/layout/suggestion_item.xml
@@ -77,5 +77,5 @@
android:background="?android:attr/selectableItemBackground"
android:paddingRight="@dimen/suggest_item_padding"
android:paddingLeft="@dimen/suggest_item_padding"
- />
+ />
</LinearLayout>
diff --git a/res/layout/tab_title.xml b/res/layout/tab_title.xml
index 3f72753..954ffa3 100644
--- a/res/layout/tab_title.xml
+++ b/res/layout/tab_title.xml
@@ -31,7 +31,7 @@
android:layout_height="match_parent"
android:gravity="center_vertical"
android:src="@drawable/ic_search_category_history"
- android:contentDescription="@string/accessibility_state_frozen"
+ android:contentDescription="@string/accessibility_state_frozen"
android:visibility="gone" />
<ImageView
android:id="@+id/favicon"
diff --git a/res/values-sw600dp/styles.xml b/res/values-sw600dp/styles.xml
index f03cac1..20e42f4 100644
--- a/res/values-sw600dp/styles.xml
+++ b/res/values-sw600dp/styles.xml
@@ -28,11 +28,11 @@
<item name="android:actionBarSize">64dip</item>
</style>
<style name="Suggestions" parent="@android:style/Widget.Material.Light.AutoCompleteTextView">
- <item name="android:textColor">@color/white</item>
- <item name="android:textColorHint">@color/white</item>
- <item name="android:dropDownVerticalOffset">0dip</item>
+ <item name="android:textColor">@color/white</item>
+ <item name="android:textColorHint">@color/white</item>
+ <item name="android:dropDownVerticalOffset">0dip</item>
</style>
<style name="ActionBarStyle" parent="@android:style/ThemeOverlay.Material.Dark.ActionBar">
<item name="android:background">@color/primary</item>
- </style>
+ </style>
</resources>
diff --git a/res/values/dimensions.xml b/res/values/dimensions.xml
index 019a173..b285344 100644
--- a/res/values/dimensions.xml
+++ b/res/values/dimensions.xml
@@ -78,5 +78,4 @@
<dimen name="elevation_low">1dp</dimen>
<dimen name="elevation_high">4dp</dimen>
<dimen name="add_button_margin">16dp</dimen>
-
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 7e3c30a..0ad7ffe 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -30,9 +30,9 @@
<item name="android:colorAccent">@color/accent</item>
</style>
<style name="PreferencesTheme" parent="@android:Theme.Material.Light.DarkActionBar">
- <item name="android:colorPrimary">@color/primary</item>
- <item name="android:colorPrimaryDark">@color/primary_dark</item>
- <item name="android:colorAccent">@color/accent</item>
+ <item name="android:colorPrimary">@color/primary</item>
+ <item name="android:colorPrimaryDark">@color/primary_dark</item>
+ <item name="android:colorAccent">@color/accent</item>
</style>
<style name="DialogWhenLarge" parent="@android:style/Theme.Material.DialogWhenLarge" >
<item name="android:windowActionBar">false</item>
diff --git a/src/com/android/browser/NavScreen.java b/src/com/android/browser/NavScreen.java
index 7730cae..85eaa41 100644
--- a/src/com/android/browser/NavScreen.java
+++ b/src/com/android/browser/NavScreen.java
@@ -114,38 +114,38 @@ public class NavScreen extends RelativeLayout
}
private void init() {
- LayoutInflater.from(mContext).inflate(R.layout.nav_screen, this);
- setContentDescription(mContext.getResources().getString(
- R.string.accessibility_transition_navscreen));
- mBookmarks = (ImageButton) findViewById(R.id.bookmarks);
- mNewTab = (ImageButton) findViewById(R.id.newtab);
- mMore = (ImageButton) findViewById(R.id.more);
- mBookmarks.setOnClickListener(this);
- mNewTab.setOnClickListener(this);
- mMore.setOnClickListener(this);
- mScroller = (NavTabScroller) findViewById(R.id.scroller);
- TabControl tc = mUiController.getTabControl();
- mTabViews = new HashMap<Tab, View>(tc.getTabCount());
- mAdapter = new TabAdapter(mContext, tc);
- mScroller.setOrientation(mOrientation == Configuration.ORIENTATION_LANDSCAPE
- ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
- // update state for active tab
- mScroller.setAdapter(mAdapter,
- mUiController.getTabControl().getTabPosition(mUi.getActiveTab()));
- mScroller.setOnRemoveListener(new OnRemoveListener() {
- public void onRemovePosition(int pos) {
- Tab tab = mAdapter.getItem(pos);
- onCloseTab(tab);
- }
- });
- mNewTabFab = (ImageView) findViewById(R.id.floating_action_button);
- mNewTabFab.setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- openNewTab();
- }
- });
+ LayoutInflater.from(mContext).inflate(R.layout.nav_screen, this);
+ setContentDescription(mContext.getResources().getString(
+ R.string.accessibility_transition_navscreen));
+ mBookmarks = (ImageButton) findViewById(R.id.bookmarks);
+ mNewTab = (ImageButton) findViewById(R.id.newtab);
+ mMore = (ImageButton) findViewById(R.id.more);
+ mBookmarks.setOnClickListener(this);
+ mNewTab.setOnClickListener(this);
+ mMore.setOnClickListener(this);
+ mScroller = (NavTabScroller) findViewById(R.id.scroller);
+ TabControl tc = mUiController.getTabControl();
+ mTabViews = new HashMap<Tab, View>(tc.getTabCount());
+ mAdapter = new TabAdapter(mContext, tc);
+ mScroller.setOrientation(mOrientation == Configuration.ORIENTATION_LANDSCAPE
+ ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
+ // update state for active tab
+ mScroller.setAdapter(mAdapter,
+ mUiController.getTabControl().getTabPosition(mUi.getActiveTab()));
+ mScroller.setOnRemoveListener(new OnRemoveListener() {
+ public void onRemovePosition(int pos) {
+ Tab tab = mAdapter.getItem(pos);
+ onCloseTab(tab);
+ }
+ });
+ mNewTabFab = (ImageView) findViewById(R.id.floating_action_button);
+ mNewTabFab.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openNewTab();
+ }
+ });
}
@Override
diff --git a/src/com/android/browser/NavTabScroller.java b/src/com/android/browser/NavTabScroller.java
index f1f8e35..b24acb3 100644
--- a/src/com/android/browser/NavTabScroller.java
+++ b/src/com/android/browser/NavTabScroller.java
@@ -1,18 +1,18 @@
/*
-* 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.
-*/
+ * 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.
+ */
package com.android.browser;
@@ -35,535 +35,535 @@ import android.widget.LinearLayout;
import com.android.browser.view.ScrollerView;
/**
-* custom view for displaying tabs in the nav screen
-*/
+ * custom view for displaying tabs in the nav screen
+ */
public class NavTabScroller extends ScrollerView {
- static final int INVALID_POSITION = -1;
- static final float[] PULL_FACTOR = { 2.5f, 0.9f };
-
- interface OnRemoveListener {
- public void onRemovePosition(int position);
- }
-
- interface OnLayoutListener {
- public void onLayout(int l, int t, int r, int b);
- }
-
- private ContentLayout mContentView;
- private BaseAdapter mAdapter;
- private OnRemoveListener mRemoveListener;
- private OnLayoutListener mLayoutListener;
- private int mGap;
- private int mGapPosition;
- private ObjectAnimator mGapAnimator;
-
- // after drag animation velocity in pixels/sec
- private static final float MIN_VELOCITY = 1500;
- private AnimatorSet mAnimator;
-
- private float mFlingVelocity;
- private boolean mNeedsScroll;
- private int mScrollPosition;
-
- DecelerateInterpolator mCubic;
- int mPullValue;
-
- public NavTabScroller(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init(context);
- }
-
- public NavTabScroller(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context);
- }
-
- public NavTabScroller(Context context) {
- super(context);
- init(context);
- }
-
- private void init(Context ctx) {
- mCubic = new DecelerateInterpolator(1.5f);
- mGapPosition = INVALID_POSITION;
- setHorizontalScrollBarEnabled(false);
- setVerticalScrollBarEnabled(false);
- mContentView = new ContentLayout(ctx, this);
- mContentView.setOrientation(LinearLayout.HORIZONTAL);
- addView(mContentView);
- mContentView.setLayoutParams(
- new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
- // ProGuard !
- setGap(getGap());
- mFlingVelocity = getContext().getResources().getDisplayMetrics().density
- * MIN_VELOCITY;
- }
-
- protected int getScrollValue() {
- return mHorizontal ? mScrollX : mScrollY;
- }
-
- protected void setScrollValue(int value) {
- scrollTo(mHorizontal ? value : 0, mHorizontal ? 0 : value);
- }
-
- protected NavTabView getTabView(int pos) {
- return (NavTabView) mContentView.getChildAt(pos);
- }
-
- protected boolean isHorizontal() {
- return mHorizontal;
- }
-
- public void setOrientation(int orientation) {
- mContentView.setOrientation(orientation);
- if (orientation == LinearLayout.HORIZONTAL) {
- mContentView.setLayoutParams(
- new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
- } else {
- mContentView.setLayoutParams(
- new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
- }
- super.setOrientation(orientation);
- }
-
- @Override
- protected void onMeasure(int wspec, int hspec) {
- super.onMeasure(wspec, hspec);
- calcPadding();
- }
-
- private void calcPadding() {
- if (mAdapter.getCount() > 0) {
- View v = mContentView.getChildAt(0);
- if (mHorizontal) {
- int pad = (getMeasuredWidth() - v.getMeasuredWidth()) / 2 + 2;
- mContentView.setPadding(pad, 0, pad, 0);
- } else {
- int pad = (getMeasuredHeight() - v.getMeasuredHeight()) / 2 + 2;
- mContentView.setPadding(0, pad, 0, pad);
- }
- }
- }
-
- public void setAdapter(BaseAdapter adapter) {
- setAdapter(adapter, 0);
- }
-
-
- public void setOnRemoveListener(OnRemoveListener l) {
- mRemoveListener = l;
- }
-
- public void setOnLayoutListener(OnLayoutListener l) {
- mLayoutListener = l;
- }
-
- protected void setAdapter(BaseAdapter adapter, int selection) {
- mAdapter = adapter;
- mAdapter.registerDataSetObserver(new DataSetObserver() {
-
- @Override
- public void onChanged() {
- super.onChanged();
- handleDataChanged();
- }
-
- @Override
- public void onInvalidated() {
- super.onInvalidated();
- }
- });
- handleDataChanged(selection);
- }
-
- protected ViewGroup getContentView() {
- return mContentView;
- }
-
- protected int getRelativeChildTop(int ix) {
- return mContentView.getChildAt(ix).getTop() - mScrollY;
- }
-
- protected void handleDataChanged() {
- handleDataChanged(INVALID_POSITION);
- }
-
- void handleDataChanged(int newscroll) {
- int scroll = getScrollValue();
- if (mGapAnimator != null) {
- mGapAnimator.cancel();
- }
- mContentView.removeAllViews();
- for (int i = 0; i < mAdapter.getCount(); i++) {
- View v = mAdapter.getView(i, null, mContentView);
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- lp.gravity = (mHorizontal ? Gravity.CENTER_VERTICAL : Gravity.CENTER_HORIZONTAL);
- mContentView.addView(v, lp);
- if (mGapPosition > INVALID_POSITION){
- adjustViewGap(v, i);
- }
- }
- if (newscroll > INVALID_POSITION) {
- newscroll = Math.min(mAdapter.getCount() - 1, newscroll);
- mNeedsScroll = true;
- mScrollPosition = newscroll;
- requestLayout();
- } else {
- setScrollValue(scroll);
- }
- }
-
- protected void finishScroller() {
- mScroller.forceFinished(true);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- if (mNeedsScroll) {
- mScroller.forceFinished(true);
- snapToSelected(mScrollPosition, false);
- mNeedsScroll = false;
- }
- if (mLayoutListener != null) {
- mLayoutListener.onLayout(l, t, r, b);
- mLayoutListener = null;
- }
- }
-
- void clearTabs() {
- mContentView.removeAllViews();
- }
-
- void snapToSelected(int pos, boolean smooth) {
- if (pos < 0) return;
- View v = mContentView.getChildAt(pos);
- if (v == null) return;
- int sx = 0;
- int sy = 0;
- if (mHorizontal) {
- sx = (v.getLeft() + v.getRight() - getWidth()) / 2;
- } else {
- sy = (v.getTop() + v.getBottom() - getHeight()) / 2;
- }
- if ((sx != mScrollX) || (sy != mScrollY)) {
- if (smooth) {
- smoothScrollTo(sx,sy);
- } else {
- scrollTo(sx, sy);
- }
- }
- }
-
- protected void animateOut(View v) {
- if (v == null) return;
- animateOut(v, -mFlingVelocity);
- }
-
- private void animateOut(final View v, float velocity) {
- float start = mHorizontal ? v.getTranslationY() : v.getTranslationX();
- animateOut(v, velocity, start);
- }
-
- private void animateOut(final View v, float velocity, float start) {
- if ((v == null) || (mAnimator != null)) return;
- final int position = mContentView.indexOfChild(v);
- int target = 0;
- if (velocity < 0) {
- target = mHorizontal ? -getHeight() : -getWidth();
- } else {
- target = mHorizontal ? getHeight() : getWidth();
- }
- int distance = target - (mHorizontal ? v.getTop() : v.getLeft());
- long duration = (long) (Math.abs(distance) * 1000 / Math.abs(velocity));
- int scroll = 0;
- int translate = 0;
- int gap = mHorizontal ? v.getWidth() : v.getHeight();
- int centerView = getViewCenter(v);
- int centerScreen = getScreenCenter();
- int newpos = INVALID_POSITION;
- if (centerView < centerScreen - gap / 2) {
- // top view
- scroll = - (centerScreen - centerView - gap);
- translate = (position > 0) ? gap : 0;
- newpos = position;
- } else if (centerView > centerScreen + gap / 2) {
- // bottom view
- scroll = - (centerScreen + gap - centerView);
- if (position < mAdapter.getCount() - 1) {
- translate = -gap;
- }
- } else {
- // center view
- scroll = - (centerScreen - centerView);
- if (position < mAdapter.getCount() - 1) {
- translate = -gap;
- } else {
- scroll -= gap;
- }
- }
- mGapPosition = position;
- final int pos = newpos;
- ObjectAnimator trans = ObjectAnimator.ofFloat(v,
- (mHorizontal ? TRANSLATION_Y : TRANSLATION_X), start, target);
- ObjectAnimator alpha = ObjectAnimator.ofFloat(v, ALPHA, getAlpha(v,start),
- getAlpha(v,target));
- AnimatorSet set1 = new AnimatorSet();
- set1.playTogether(trans, alpha);
- set1.setDuration(duration);
- mAnimator = new AnimatorSet();
- ObjectAnimator trans2 = null;
- ObjectAnimator scroll1 = null;
- if (scroll != 0) {
- if (mHorizontal) {
- scroll1 = ObjectAnimator.ofInt(this, "scrollX", getScrollX(), getScrollX() + scroll);
- } else {
- scroll1 = ObjectAnimator.ofInt(this, "scrollY", getScrollY(), getScrollY() + scroll);
- }
- }
- if (translate != 0) {
- trans2 = ObjectAnimator.ofInt(this, "gap", 0, translate);
- }
- final int duration2 = 200;
- if (scroll1 != null) {
- if (trans2 != null) {
- AnimatorSet set2 = new AnimatorSet();
- set2.playTogether(scroll1, trans2);
- set2.setDuration(duration2);
- mAnimator.playSequentially(set1, set2);
- } else {
- scroll1.setDuration(duration2);
- mAnimator.playSequentially(set1, scroll1);
- }
- } else {
- if (trans2 != null) {
- trans2.setDuration(duration2);
- mAnimator.playSequentially(set1, trans2);
- }
- }
- mAnimator.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator a) {
- if (mRemoveListener != null) {
- mRemoveListener.onRemovePosition(position);
- mAnimator = null;
- mGapPosition = INVALID_POSITION;
- mGap = 0;
- handleDataChanged(pos);
+ static final int INVALID_POSITION = -1;
+ static final float[] PULL_FACTOR = { 2.5f, 0.9f };
+
+ interface OnRemoveListener {
+ public void onRemovePosition(int position);
+ }
+
+ interface OnLayoutListener {
+ public void onLayout(int l, int t, int r, int b);
+ }
+
+ private ContentLayout mContentView;
+ private BaseAdapter mAdapter;
+ private OnRemoveListener mRemoveListener;
+ private OnLayoutListener mLayoutListener;
+ private int mGap;
+ private int mGapPosition;
+ private ObjectAnimator mGapAnimator;
+
+ // after drag animation velocity in pixels/sec
+ private static final float MIN_VELOCITY = 1500;
+ private AnimatorSet mAnimator;
+
+ private float mFlingVelocity;
+ private boolean mNeedsScroll;
+ private int mScrollPosition;
+
+ DecelerateInterpolator mCubic;
+ int mPullValue;
+
+ public NavTabScroller(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ public NavTabScroller(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public NavTabScroller(Context context) {
+ super(context);
+ init(context);
+ }
+
+ private void init(Context ctx) {
+ mCubic = new DecelerateInterpolator(1.5f);
+ mGapPosition = INVALID_POSITION;
+ setHorizontalScrollBarEnabled(false);
+ setVerticalScrollBarEnabled(false);
+ mContentView = new ContentLayout(ctx, this);
+ mContentView.setOrientation(LinearLayout.HORIZONTAL);
+ addView(mContentView);
+ mContentView.setLayoutParams(
+ new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
+ // ProGuard !
+ setGap(getGap());
+ mFlingVelocity = getContext().getResources().getDisplayMetrics().density
+ * MIN_VELOCITY;
+ }
+
+ protected int getScrollValue() {
+ return mHorizontal ? mScrollX : mScrollY;
+ }
+
+ protected void setScrollValue(int value) {
+ scrollTo(mHorizontal ? value : 0, mHorizontal ? 0 : value);
+ }
+
+ protected NavTabView getTabView(int pos) {
+ return (NavTabView) mContentView.getChildAt(pos);
+ }
+
+ protected boolean isHorizontal() {
+ return mHorizontal;
+ }
+
+ public void setOrientation(int orientation) {
+ mContentView.setOrientation(orientation);
+ if (orientation == LinearLayout.HORIZONTAL) {
+ mContentView.setLayoutParams(
+ new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
+ } else {
+ mContentView.setLayoutParams(
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
- }
- });
- mAnimator.start();
- }
-
- public void setGap(int gap) {
- if (mGapPosition != INVALID_POSITION) {
- mGap = gap;
- postInvalidate();
- }
- }
-
- public int getGap() {
- return mGap;
- }
-
- void adjustGap() {
- for (int i = 0; i < mContentView.getChildCount(); i++) {
- final View child = mContentView.getChildAt(i);
- adjustViewGap(child, i);
- }
- }
-
- private void adjustViewGap(View view, int pos) {
- if ((mGap < 0 && pos > mGapPosition)
- || (mGap > 0 && pos < mGapPosition)) {
- if (mHorizontal) {
- view.setTranslationX(mGap);
- } else {
- view.setTranslationY(mGap);
- }
- }
- }
-
- private int getViewCenter(View v) {
- if (mHorizontal) {
- return v.getLeft() + v.getWidth() / 2;
- } else {
- return v.getTop() + v.getHeight() / 2;
- }
- }
-
- private int getScreenCenter() {
- if (mHorizontal) {
- return getScrollX() + getWidth() / 2;
- } else {
- return getScrollY() + getHeight() / 2;
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- if (mGapPosition > INVALID_POSITION) {
- adjustGap();
- }
- super.draw(canvas);
- }
-
- @Override
- protected View findViewAt(int x, int y) {
- x += mScrollX;
- y += mScrollY;
- final int count = mContentView.getChildCount();
- for (int i = count - 1; i >= 0; i--) {
- View child = mContentView.getChildAt(i);
- if (child.getVisibility() == View.VISIBLE) {
- if ((x >= child.getLeft()) && (x < child.getRight())
- && (y >= child.getTop()) && (y < child.getBottom())) {
- return child;
+ super.setOrientation(orientation);
+ }
+
+ @Override
+ protected void onMeasure(int wspec, int hspec) {
+ super.onMeasure(wspec, hspec);
+ calcPadding();
+ }
+
+ private void calcPadding() {
+ if (mAdapter.getCount() > 0) {
+ View v = mContentView.getChildAt(0);
+ if (mHorizontal) {
+ int pad = (getMeasuredWidth() - v.getMeasuredWidth()) / 2 + 2;
+ mContentView.setPadding(pad, 0, pad, 0);
+ } else {
+ int pad = (getMeasuredHeight() - v.getMeasuredHeight()) / 2 + 2;
+ mContentView.setPadding(0, pad, 0, pad);
+ }
}
- }
- }
- return null;
- }
-
- @Override
- protected void onOrthoDrag(View v, float distance) {
- if ((v != null) && (mAnimator == null)) {
- offsetView(v, distance);
- }
- }
-
- @Override
- protected void onOrthoDragFinished(View downView) {
- if (mAnimator != null) return;
- if (mIsOrthoDragged && downView != null) {
- // offset
- float diff = mHorizontal ? downView.getTranslationY() : downView.getTranslationX();
- if (Math.abs(diff) > (mHorizontal ? downView.getHeight() : downView.getWidth()) / 2) {
- // remove it
- animateOut(downView, Math.signum(diff) * mFlingVelocity, diff);
- } else {
- // snap back
- offsetView(downView, 0);
- }
- }
- }
-
- @Override
- protected void onOrthoFling(View v, float velocity) {
- if (v == null) return;
- if (mAnimator == null && Math.abs(velocity) > mFlingVelocity / 2) {
- animateOut(v, velocity);
- } else {
- offsetView(v, 0);
- }
- }
-
- private void offsetView(View v, float distance) {
- v.setAlpha(getAlpha(v, distance));
- if (mHorizontal) {
- v.setTranslationY(distance);
- } else {
- v.setTranslationX(distance);
- }
- }
-
- private float getAlpha(View v, float distance) {
- return 1 - (float) Math.abs(distance) / (mHorizontal ? v.getHeight() : v.getWidth());
- }
-
- private float ease(DecelerateInterpolator inter, float value, float start,
- float dist, float duration) {
- return start + dist * inter.getInterpolation(value / duration);
- }
-
- @Override
- protected void onPull(int delta) {
- boolean layer = false;
- int count = 2;
- if (delta == 0 && mPullValue == 0) return;
- if (delta == 0 && mPullValue != 0) {
- // reset
- for (int i = 0; i < count; i++) {
- View child = mContentView.getChildAt((mPullValue < 0)
- ? i
- : mContentView.getChildCount() - 1 - i);
- if (child == null) break;
- ObjectAnimator trans = ObjectAnimator.ofFloat(child,
- mHorizontal ? "translationX" : "translationY",
- mHorizontal ? getTranslationX() : getTranslationY(),
- 0);
- ObjectAnimator rot = ObjectAnimator.ofFloat(child,
- mHorizontal ? "rotationY" : "rotationX",
- mHorizontal ? getRotationY() : getRotationX(),
- 0);
- AnimatorSet set = new AnimatorSet();
- set.playTogether(trans, rot);
- set.setDuration(100);
- set.start();
- }
- mPullValue = 0;
- } else {
- if (mPullValue == 0) {
- layer = true;
- }
- mPullValue += delta;
- }
- final int height = mHorizontal ? getWidth() : getHeight();
- int oscroll = Math.abs(mPullValue);
- int factor = (mPullValue <= 0) ? 1 : -1;
- for (int i = 0; i < count; i++) {
- View child = mContentView.getChildAt((mPullValue < 0)
- ? i
- : mContentView.getChildCount() - 1 - i);
- if (child == null) break;
- if (layer) {
- }
- float k = PULL_FACTOR[i];
- float rot = -factor * ease(mCubic, oscroll, 0, k * 2, height);
- int y = factor * (int) ease(mCubic, oscroll, 0, k*20, height);
- if (mHorizontal) {
- child.setTranslationX(y);
- } else {
- child.setTranslationY(y);
- }
- if (mHorizontal) {
- child.setRotationY(-rot);
- } else {
- child.setRotationX(rot);
- }
- }
- }
-
- static class ContentLayout extends LinearLayout {
-
- NavTabScroller mScroller;
-
- public ContentLayout(Context context, NavTabScroller scroller) {
- super(context);
- mScroller = scroller;
+ }
+
+ public void setAdapter(BaseAdapter adapter) {
+ setAdapter(adapter, 0);
+ }
+
+
+ public void setOnRemoveListener(OnRemoveListener l) {
+ mRemoveListener = l;
+ }
+
+ public void setOnLayoutListener(OnLayoutListener l) {
+ mLayoutListener = l;
+ }
+
+ protected void setAdapter(BaseAdapter adapter, int selection) {
+ mAdapter = adapter;
+ mAdapter.registerDataSetObserver(new DataSetObserver() {
+
+ @Override
+ public void onChanged() {
+ super.onChanged();
+ handleDataChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ super.onInvalidated();
+ }
+ });
+ handleDataChanged(selection);
+ }
+
+ protected ViewGroup getContentView() {
+ return mContentView;
+ }
+
+ protected int getRelativeChildTop(int ix) {
+ return mContentView.getChildAt(ix).getTop() - mScrollY;
+ }
+
+ protected void handleDataChanged() {
+ handleDataChanged(INVALID_POSITION);
+ }
+
+ void handleDataChanged(int newscroll) {
+ int scroll = getScrollValue();
+ if (mGapAnimator != null) {
+ mGapAnimator.cancel();
+ }
+ mContentView.removeAllViews();
+ for (int i = 0; i < mAdapter.getCount(); i++) {
+ View v = mAdapter.getView(i, null, mContentView);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ lp.gravity = (mHorizontal ? Gravity.CENTER_VERTICAL : Gravity.CENTER_HORIZONTAL);
+ mContentView.addView(v, lp);
+ if (mGapPosition > INVALID_POSITION){
+ adjustViewGap(v, i);
+ }
+ }
+ if (newscroll > INVALID_POSITION) {
+ newscroll = Math.min(mAdapter.getCount() - 1, newscroll);
+ mNeedsScroll = true;
+ mScrollPosition = newscroll;
+ requestLayout();
+ } else {
+ setScrollValue(scroll);
+ }
+ }
+
+ protected void finishScroller() {
+ mScroller.forceFinished(true);
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mScroller.getGap() != 0) {
- View v = getChildAt(0);
- if (v != null) {
- if (mScroller.isHorizontal()) {
- int total = v.getMeasuredWidth() + getMeasuredWidth();
- setMeasuredDimension(total, getMeasuredHeight());
- } else {
- int total = v.getMeasuredHeight() + getMeasuredHeight();
- setMeasuredDimension(getMeasuredWidth(), total);
- }
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ if (mNeedsScroll) {
+ mScroller.forceFinished(true);
+ snapToSelected(mScrollPosition, false);
+ mNeedsScroll = false;
}
+ if (mLayoutListener != null) {
+ mLayoutListener.onLayout(l, t, r, b);
+ mLayoutListener = null;
+ }
+ }
- }
+ void clearTabs() {
+ mContentView.removeAllViews();
}
- }
+ void snapToSelected(int pos, boolean smooth) {
+ if (pos < 0) return;
+ View v = mContentView.getChildAt(pos);
+ if (v == null) return;
+ int sx = 0;
+ int sy = 0;
+ if (mHorizontal) {
+ sx = (v.getLeft() + v.getRight() - getWidth()) / 2;
+ } else {
+ sy = (v.getTop() + v.getBottom() - getHeight()) / 2;
+ }
+ if ((sx != mScrollX) || (sy != mScrollY)) {
+ if (smooth) {
+ smoothScrollTo(sx,sy);
+ } else {
+ scrollTo(sx, sy);
+ }
+ }
+ }
+
+ protected void animateOut(View v) {
+ if (v == null) return;
+ animateOut(v, -mFlingVelocity);
+ }
+
+ private void animateOut(final View v, float velocity) {
+ float start = mHorizontal ? v.getTranslationY() : v.getTranslationX();
+ animateOut(v, velocity, start);
+ }
+
+ private void animateOut(final View v, float velocity, float start) {
+ if ((v == null) || (mAnimator != null)) return;
+ final int position = mContentView.indexOfChild(v);
+ int target = 0;
+ if (velocity < 0) {
+ target = mHorizontal ? -getHeight() : -getWidth();
+ } else {
+ target = mHorizontal ? getHeight() : getWidth();
+ }
+ int distance = target - (mHorizontal ? v.getTop() : v.getLeft());
+ long duration = (long) (Math.abs(distance) * 1000 / Math.abs(velocity));
+ int scroll = 0;
+ int translate = 0;
+ int gap = mHorizontal ? v.getWidth() : v.getHeight();
+ int centerView = getViewCenter(v);
+ int centerScreen = getScreenCenter();
+ int newpos = INVALID_POSITION;
+ if (centerView < centerScreen - gap / 2) {
+ // top view
+ scroll = - (centerScreen - centerView - gap);
+ translate = (position > 0) ? gap : 0;
+ newpos = position;
+ } else if (centerView > centerScreen + gap / 2) {
+ // bottom view
+ scroll = - (centerScreen + gap - centerView);
+ if (position < mAdapter.getCount() - 1) {
+ translate = -gap;
+ }
+ } else {
+ // center view
+ scroll = - (centerScreen - centerView);
+ if (position < mAdapter.getCount() - 1) {
+ translate = -gap;
+ } else {
+ scroll -= gap;
+ }
+ }
+ mGapPosition = position;
+ final int pos = newpos;
+ ObjectAnimator trans = ObjectAnimator.ofFloat(v,
+ (mHorizontal ? TRANSLATION_Y : TRANSLATION_X), start, target);
+ ObjectAnimator alpha = ObjectAnimator.ofFloat(v, ALPHA, getAlpha(v,start),
+ getAlpha(v,target));
+ AnimatorSet set1 = new AnimatorSet();
+ set1.playTogether(trans, alpha);
+ set1.setDuration(duration);
+ mAnimator = new AnimatorSet();
+ ObjectAnimator trans2 = null;
+ ObjectAnimator scroll1 = null;
+ if (scroll != 0) {
+ if (mHorizontal) {
+ scroll1 = ObjectAnimator.ofInt(this, "scrollX", getScrollX(), getScrollX() + scroll);
+ } else {
+ scroll1 = ObjectAnimator.ofInt(this, "scrollY", getScrollY(), getScrollY() + scroll);
+ }
+ }
+ if (translate != 0) {
+ trans2 = ObjectAnimator.ofInt(this, "gap", 0, translate);
+ }
+ final int duration2 = 200;
+ if (scroll1 != null) {
+ if (trans2 != null) {
+ AnimatorSet set2 = new AnimatorSet();
+ set2.playTogether(scroll1, trans2);
+ set2.setDuration(duration2);
+ mAnimator.playSequentially(set1, set2);
+ } else {
+ scroll1.setDuration(duration2);
+ mAnimator.playSequentially(set1, scroll1);
+ }
+ } else {
+ if (trans2 != null) {
+ trans2.setDuration(duration2);
+ mAnimator.playSequentially(set1, trans2);
+ }
+ }
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator a) {
+ if (mRemoveListener != null) {
+ mRemoveListener.onRemovePosition(position);
+ mAnimator = null;
+ mGapPosition = INVALID_POSITION;
+ mGap = 0;
+ handleDataChanged(pos);
+ }
+ }
+ });
+ mAnimator.start();
+ }
+
+ public void setGap(int gap) {
+ if (mGapPosition != INVALID_POSITION) {
+ mGap = gap;
+ postInvalidate();
+ }
+ }
+
+ public int getGap() {
+ return mGap;
+ }
+
+ void adjustGap() {
+ for (int i = 0; i < mContentView.getChildCount(); i++) {
+ final View child = mContentView.getChildAt(i);
+ adjustViewGap(child, i);
+ }
+ }
+
+ private void adjustViewGap(View view, int pos) {
+ if ((mGap < 0 && pos > mGapPosition)
+ || (mGap > 0 && pos < mGapPosition)) {
+ if (mHorizontal) {
+ view.setTranslationX(mGap);
+ } else {
+ view.setTranslationY(mGap);
+ }
+ }
+ }
+
+ private int getViewCenter(View v) {
+ if (mHorizontal) {
+ return v.getLeft() + v.getWidth() / 2;
+ } else {
+ return v.getTop() + v.getHeight() / 2;
+ }
+ }
+
+ private int getScreenCenter() {
+ if (mHorizontal) {
+ return getScrollX() + getWidth() / 2;
+ } else {
+ return getScrollY() + getHeight() / 2;
+ }
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mGapPosition > INVALID_POSITION) {
+ adjustGap();
+ }
+ super.draw(canvas);
+ }
+
+ @Override
+ protected View findViewAt(int x, int y) {
+ x += mScrollX;
+ y += mScrollY;
+ final int count = mContentView.getChildCount();
+ for (int i = count - 1; i >= 0; i--) {
+ View child = mContentView.getChildAt(i);
+ if (child.getVisibility() == View.VISIBLE) {
+ if ((x >= child.getLeft()) && (x < child.getRight())
+ && (y >= child.getTop()) && (y < child.getBottom())) {
+ return child;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onOrthoDrag(View v, float distance) {
+ if ((v != null) && (mAnimator == null)) {
+ offsetView(v, distance);
+ }
+ }
+
+ @Override
+ protected void onOrthoDragFinished(View downView) {
+ if (mAnimator != null) return;
+ if (mIsOrthoDragged && downView != null) {
+ // offset
+ float diff = mHorizontal ? downView.getTranslationY() : downView.getTranslationX();
+ if (Math.abs(diff) > (mHorizontal ? downView.getHeight() : downView.getWidth()) / 2) {
+ // remove it
+ animateOut(downView, Math.signum(diff) * mFlingVelocity, diff);
+ } else {
+ // snap back
+ offsetView(downView, 0);
+ }
+ }
+ }
+
+ @Override
+ protected void onOrthoFling(View v, float velocity) {
+ if (v == null) return;
+ if (mAnimator == null && Math.abs(velocity) > mFlingVelocity / 2) {
+ animateOut(v, velocity);
+ } else {
+ offsetView(v, 0);
+ }
+ }
+
+ private void offsetView(View v, float distance) {
+ v.setAlpha(getAlpha(v, distance));
+ if (mHorizontal) {
+ v.setTranslationY(distance);
+ } else {
+ v.setTranslationX(distance);
+ }
+ }
+
+ private float getAlpha(View v, float distance) {
+ return 1 - (float) Math.abs(distance) / (mHorizontal ? v.getHeight() : v.getWidth());
+ }
+
+ private float ease(DecelerateInterpolator inter, float value, float start,
+ float dist, float duration) {
+ return start + dist * inter.getInterpolation(value / duration);
+ }
+
+ @Override
+ protected void onPull(int delta) {
+ boolean layer = false;
+ int count = 2;
+ if (delta == 0 && mPullValue == 0) return;
+ if (delta == 0 && mPullValue != 0) {
+ // reset
+ for (int i = 0; i < count; i++) {
+ View child = mContentView.getChildAt((mPullValue < 0)
+ ? i
+ : mContentView.getChildCount() - 1 - i);
+ if (child == null) break;
+ ObjectAnimator trans = ObjectAnimator.ofFloat(child,
+ mHorizontal ? "translationX" : "translationY",
+ mHorizontal ? getTranslationX() : getTranslationY(),
+ 0);
+ ObjectAnimator rot = ObjectAnimator.ofFloat(child,
+ mHorizontal ? "rotationY" : "rotationX",
+ mHorizontal ? getRotationY() : getRotationX(),
+ 0);
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(trans, rot);
+ set.setDuration(100);
+ set.start();
+ }
+ mPullValue = 0;
+ } else {
+ if (mPullValue == 0) {
+ layer = true;
+ }
+ mPullValue += delta;
+ }
+ final int height = mHorizontal ? getWidth() : getHeight();
+ int oscroll = Math.abs(mPullValue);
+ int factor = (mPullValue <= 0) ? 1 : -1;
+ for (int i = 0; i < count; i++) {
+ View child = mContentView.getChildAt((mPullValue < 0)
+ ? i
+ : mContentView.getChildCount() - 1 - i);
+ if (child == null) break;
+ if (layer) {
+ }
+ float k = PULL_FACTOR[i];
+ float rot = -factor * ease(mCubic, oscroll, 0, k * 2, height);
+ int y = factor * (int) ease(mCubic, oscroll, 0, k*20, height);
+ if (mHorizontal) {
+ child.setTranslationX(y);
+ } else {
+ child.setTranslationY(y);
+ }
+ if (mHorizontal) {
+ child.setRotationY(-rot);
+ } else {
+ child.setRotationX(rot);
+ }
+ }
+ }
+
+ static class ContentLayout extends LinearLayout {
+
+ NavTabScroller mScroller;
+
+ public ContentLayout(Context context, NavTabScroller scroller) {
+ super(context);
+ mScroller = scroller;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (mScroller.getGap() != 0) {
+ View v = getChildAt(0);
+ if (v != null) {
+ if (mScroller.isHorizontal()) {
+ int total = v.getMeasuredWidth() + getMeasuredWidth();
+ setMeasuredDimension(total, getMeasuredHeight());
+ } else {
+ int total = v.getMeasuredHeight() + getMeasuredHeight();
+ setMeasuredDimension(getMeasuredWidth(), total);
+ }
+ }
+
+ }
+ }
+
+ }
}