From 5bc865e787b51ebbdebb14bf1eefc3a91f5f7c8d Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 18 Jul 2013 15:18:25 -0700 Subject: Adding workaround for page indicators to support many pages. - Tweaking assets until we get something proper Change-Id: Ie07946acb529ff747d76896ff38837f8db6a7258 --- src/com/android/launcher3/PageIndicator.java | 149 +++++++++++++++++++-- src/com/android/launcher3/PageIndicatorMarker.java | 44 ++++-- 2 files changed, 168 insertions(+), 25 deletions(-) (limited to 'src/com/android/launcher3') diff --git a/src/com/android/launcher3/PageIndicator.java b/src/com/android/launcher3/PageIndicator.java index ecaa8f544..d7778fb1a 100644 --- a/src/com/android/launcher3/PageIndicator.java +++ b/src/com/android/launcher3/PageIndicator.java @@ -19,6 +19,7 @@ package com.android.launcher3; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.LayoutTransition; +import android.animation.TimeInterpolator; import android.content.ComponentName; import android.content.Context; import android.content.res.Configuration; @@ -37,8 +38,22 @@ import java.util.ArrayList; public class PageIndicator extends LinearLayout { @SuppressWarnings("unused") private static final String TAG = "PageIndicator"; + // Want this to look good? Keep it odd + private static final boolean MODULATE_ALPHA_ENABLED = false; private LayoutInflater mLayoutInflater; + private int[] mWindowRange = new int[2]; + private int mMaxWindowSize; + + private ArrayList mMarkers = + new ArrayList(); + private int mActiveMarkerIndex; + + private TimeInterpolator mAlphaInterpolator = new TimeInterpolator() { + public float getInterpolation(float t) { + return t; + } + }; public PageIndicator(Context context) { this(context, null); @@ -50,16 +65,110 @@ public class PageIndicator extends LinearLayout { public PageIndicator(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.PageIndicator, defStyle, 0); + mMaxWindowSize = a.getInteger(R.styleable.PageIndicator_windowSize, 15); + mWindowRange[0] = 0; + mWindowRange[1] = 0; mLayoutInflater = LayoutInflater.from(context); + a.recycle(); + + // Set the layout transition properties + LayoutTransition transition = getLayoutTransition(); + transition.setDuration(175); + } + + private void enableLayoutTransitions() { + LayoutTransition transition = getLayoutTransition(); + transition.enableTransitionType(LayoutTransition.APPEARING); + transition.enableTransitionType(LayoutTransition.DISAPPEARING); + transition.enableTransitionType(LayoutTransition.CHANGE_APPEARING); + transition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); + } + private void disableLayoutTransitions() { LayoutTransition transition = getLayoutTransition(); - transition.setDuration(250); + transition.disableTransitionType(LayoutTransition.APPEARING); + transition.disableTransitionType(LayoutTransition.DISAPPEARING); + transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING); + transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); + } + + void offsetWindowCenterTo(int activeIndex, boolean allowAnimations) { + if (activeIndex < 0) { + new Throwable().printStackTrace(); + } + int windowSize = Math.min(mMarkers.size(), mMaxWindowSize); + int hWindowSize = (int) windowSize / 2; + float hfWindowSize = windowSize / 2f; + int windowStart = Math.max(0, activeIndex - hWindowSize); + int windowEnd = Math.min(mMarkers.size(), windowStart + mMaxWindowSize); + windowStart = windowEnd - Math.min(mMarkers.size(), windowSize); + int windowMid = windowStart + (windowEnd - windowStart) / 2; + boolean windowAtStart = (windowStart == 0); + boolean windowAtEnd = (windowEnd == mMarkers.size()); + boolean windowMoved = (mWindowRange[0] != windowStart) || + (mWindowRange[1] != windowEnd); + + if (!allowAnimations) { + disableLayoutTransitions(); + } + + // Remove all the previous children that are no longer in the window + for (int i = getChildCount() - 1; i >= 0; --i) { + PageIndicatorMarker marker = (PageIndicatorMarker) getChildAt(i); + int markerIndex = mMarkers.indexOf(marker); + if (markerIndex < windowStart || markerIndex >= windowEnd) { + removeView(marker); + } + } + + // Add all the new children that belong in the window + for (int i = 0; i < mMarkers.size(); ++i) { + PageIndicatorMarker marker = (PageIndicatorMarker) mMarkers.get(i); + if (windowStart <= i && i < windowEnd) { + if (indexOfChild(marker) < 0) { + addView(marker, i - windowStart); + } + if (i == activeIndex) { + marker.activate(windowMoved); + } else { + marker.inactivate(windowMoved); + } + } else { + marker.inactivate(true); + } + + if (MODULATE_ALPHA_ENABLED) { + // Update the marker's alpha + float alpha = 1f; + if (mMarkers.size() > windowSize) { + if ((windowAtStart && i > hWindowSize) || + (windowAtEnd && i < (mMarkers.size() - hWindowSize)) || + (!windowAtStart && !windowAtEnd)) { + alpha = 1f - Math.abs((i - windowMid) / hfWindowSize); + } + } + marker.animate().alpha(alpha).setDuration(500).start(); + } + } + + if (!allowAnimations) { + enableLayoutTransitions(); + } + + mWindowRange[0] = windowStart; + mWindowRange[1] = windowEnd; } void addMarker(int index) { - index = Math.max(0, Math.min(index, getChildCount())); - View marker = mLayoutInflater.inflate(R.layout.page_indicator_marker, this, false); - addView(marker, index); + index = Math.max(0, Math.min(index, mMarkers.size())); + + int mLayoutId = R.layout.page_indicator_marker; + PageIndicatorMarker marker = + (PageIndicatorMarker) mLayoutInflater.inflate(mLayoutId, this, false); + mMarkers.add(index, marker); + offsetWindowCenterTo(mActiveMarkerIndex, true); } void addMarkers(int count) { for (int i = 0; i < count; ++i) { @@ -68,25 +177,37 @@ public class PageIndicator extends LinearLayout { } void removeMarker(int index) { - if (getChildCount() > 0) { - index = Math.max(0, Math.min(index, getChildCount() - 1)); - removeViewAt(index); + if (mMarkers.size() > 0) { + index = Math.max(0, Math.min(mMarkers.size() - 1, index)); + mMarkers.remove(index); + offsetWindowCenterTo(mActiveMarkerIndex, true); } } void removeAllMarkers() { - while (getChildCount() > 0) { + while (mMarkers.size() > 0) { removeMarker(Integer.MAX_VALUE); } } void setActiveMarker(int index) { + // Center the active marker + mActiveMarkerIndex = index; + offsetWindowCenterTo(index, false); + } + + void dumpState(String txt) { + System.out.println(txt); + System.out.println("\tmMarkers: " + mMarkers.size()); + for (int i = 0; i < mMarkers.size(); ++i) { + PageIndicatorMarker m = mMarkers.get(i); + System.out.println("\t\t(" + i + ") " + m); + } + System.out.println("\twindow: [" + mWindowRange[0] + ", " + mWindowRange[1] + "]"); + System.out.println("\tchildren: " + getChildCount()); for (int i = 0; i < getChildCount(); ++i) { - PageIndicatorMarker marker = (PageIndicatorMarker) getChildAt(i); - if (index == i) { - marker.activate(); - } else { - marker.inactivate(); - } + PageIndicatorMarker m = (PageIndicatorMarker) getChildAt(i); + System.out.println("\t\t(" + i + ") " + m); } + System.out.println("\tactive: " + mActiveMarkerIndex); } } diff --git a/src/com/android/launcher3/PageIndicatorMarker.java b/src/com/android/launcher3/PageIndicatorMarker.java index 852ee518f..f64c14fdc 100644 --- a/src/com/android/launcher3/PageIndicatorMarker.java +++ b/src/com/android/launcher3/PageIndicatorMarker.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import android.animation.AnimatorListenerAdapter; import android.animation.LayoutTransition; import android.content.Context; import android.util.AttributeSet; @@ -29,10 +30,11 @@ public class PageIndicatorMarker extends FrameLayout { @SuppressWarnings("unused") private static final String TAG = "PageIndicator"; - private static final int MARKER_FADE_DURATION = 150; + private static final int MARKER_FADE_DURATION = 175; private View mActiveMarker; private View mInactiveMarker; + private boolean mIsActive = false; public PageIndicatorMarker(Context context) { this(context, null); @@ -51,16 +53,36 @@ public class PageIndicatorMarker extends FrameLayout { mInactiveMarker = findViewById(R.id.inactive); } - public void activate() { - mActiveMarker.animate().alpha(1f) - .setDuration(MARKER_FADE_DURATION).start(); - mInactiveMarker.animate().alpha(0f) - .setDuration(MARKER_FADE_DURATION).start(); + void activate(boolean immediate) { + if (immediate) { + mActiveMarker.animate().cancel(); + mActiveMarker.setAlpha(1f); + mInactiveMarker.animate().cancel(); + mInactiveMarker.setAlpha(0f); + } else { + mActiveMarker.animate().alpha(1f) + .setDuration(MARKER_FADE_DURATION).start(); + mInactiveMarker.animate().alpha(0f) + .setDuration(MARKER_FADE_DURATION).start(); + } + mIsActive = true; } - public void inactivate() { - mInactiveMarker.animate().alpha(1f) - .setDuration(MARKER_FADE_DURATION).start(); - mActiveMarker.animate().alpha(0f) - .setDuration(MARKER_FADE_DURATION).start(); + void inactivate(boolean immediate) { + if (immediate) { + mInactiveMarker.animate().cancel(); + mInactiveMarker.setAlpha(1f); + mActiveMarker.animate().cancel(); + mActiveMarker.setAlpha(0f); + } else { + mInactiveMarker.animate().alpha(1f) + .setDuration(MARKER_FADE_DURATION).start(); + mActiveMarker.animate().alpha(0f) + .setDuration(MARKER_FADE_DURATION).start(); + } + mIsActive = false; + } + + boolean isActive() { + return mIsActive; } } -- cgit v1.2.3