SlotView.java revision 8bc5bebba780ca4a322b466b06fc909331697cf4
1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.ui; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Rect; 218bc5bebba780ca4a322b466b06fc909331697cf4Owen Linimport android.os.Handler; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.GestureDetector; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.animation.DecelerateInterpolator; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 26dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport com.android.gallery3d.anim.Animation; 27dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport com.android.gallery3d.common.Utils; 28dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport com.android.gallery3d.ui.PositionRepository.Position; 29dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport com.android.gallery3d.util.LinkedNode; 30dbf4ba12afba115888493caa34937643257e2bb1Ray Chen 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList; 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.HashMap; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class SlotView extends GLView { 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "SlotView"; 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final boolean WIDE = true; 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int INDEX_NONE = -1; 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public interface Listener { 43bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang public void onDown(int index); 44bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang public void onUp(); 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onSingleTapUp(int index); 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onLongTap(int index); 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onScrollPositionChanged(int position, int total); 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static class SimpleListener implements Listener { 51bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang public void onDown(int index) {} 52bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang public void onUp() {} 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onSingleTapUp(int index) {} 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onLongTap(int index) {} 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onScrollPositionChanged(int position, int total) {} 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final GestureDetector mGestureDetector; 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ScrollerHelper mScroller; 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Paper mPaper = new Paper(); 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Listener mListener; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private UserInteractionListener mUIListener; 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Use linked hash map to keep the rendering order 66dbf4ba12afba115888493caa34937643257e2bb1Ray Chen private final HashMap<DisplayItem, ItemEntry> mItems = 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new HashMap<DisplayItem, ItemEntry>(); 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public LinkedNode.List<ItemEntry> mItemList = LinkedNode.newList(); 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // This is used for multipass rendering 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ArrayList<ItemEntry> mCurrentItems = new ArrayList<ItemEntry>(); 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ArrayList<ItemEntry> mNextItems = new ArrayList<ItemEntry>(); 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mMoreAnimation = false; 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private MyAnimation mAnimation = null; 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Position mTempPosition = new Position(); 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Layout mLayout = new Layout(); 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private PositionProvider mPositions; 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mStartIndex = INDEX_NONE; 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // whether the down action happened while the view is scrolling. 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mDownInScrolling; 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mOverscrollEffect = OVERSCROLL_3D; 858bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin private final Handler mHandler; 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int OVERSCROLL_3D = 0; 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int OVERSCROLL_SYSTEM = 1; 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int OVERSCROLL_NONE = 2; 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public SlotView(Context context) { 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mGestureDetector = 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new GestureDetector(context, new MyGestureListener()); 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScroller = new ScrollerHelper(context); 958bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin mHandler = new Handler(context.getMainLooper()); 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setCenterIndex(int index) { 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int slotCount = mLayout.mSlotCount; 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index < 0 || index >= slotCount) { 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Rect rect = mLayout.getSlotRect(index); 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int position = WIDE 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ? (rect.left + rect.right - getWidth()) / 2 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin : (rect.top + rect.bottom - getHeight()) / 2; 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setScrollPosition(position); 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void makeSlotVisible(int index) { 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Rect rect = mLayout.getSlotRect(index); 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int visibleBegin = WIDE ? mScrollX : mScrollY; 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int visibleLength = WIDE ? getWidth() : getHeight(); 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int visibleEnd = visibleBegin + visibleLength; 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int slotBegin = WIDE ? rect.left : rect.top; 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int slotEnd = WIDE ? rect.right : rect.bottom; 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int position = visibleBegin; 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (visibleLength < slotEnd - slotBegin) { 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = visibleBegin; 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (slotBegin < visibleBegin) { 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = slotBegin; 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (slotEnd > visibleEnd) { 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = slotEnd - visibleLength; 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setScrollPosition(position); 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setScrollPosition(int position) { 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = Utils.clamp(position, 0, mLayout.getScrollLimit()); 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScroller.setPosition(position); 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScrollPosition(position, false); 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1369201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public void setSlotSpec(Spec spec) { 1379201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mLayout.setSlotSpec(spec); 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void addComponent(GLView view) { 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new UnsupportedOperationException(); 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean removeComponent(GLView view) { 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new UnsupportedOperationException(); 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onLayout(boolean changeSize, int l, int t, int r, int b) { 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!changeSize) return; 15377dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang 15477dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang // Make sure we are still at a resonable scroll position after the size 15577dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang // is changed (like orientation change). We choose to keep the center 15677dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang // visible slot still visible. This is arbitrary but reasonable. 15777dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int visibleIndex = 15877dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang (mLayout.getVisibleStart() + mLayout.getVisibleEnd()) / 2; 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLayout.setSize(r - l, b - t); 16077dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang makeSlotVisible(visibleIndex); 16177dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin onLayoutChanged(r - l, b - t); 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mOverscrollEffect == OVERSCROLL_3D) { 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPaper.setSize(r - l, b - t); 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onLayoutChanged(int width, int height) { 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void startTransition(PositionProvider position) { 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositions = position; 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mAnimation = new MyAnimation(); 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mAnimation.start(); 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mItems.size() != 0) invalidate(); 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void savePositions(PositionRepository repository) { 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin repository.clear(); 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin LinkedNode.List<ItemEntry> list = mItemList; 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ItemEntry entry = list.getFirst(); 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Position position = new Position(); 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (entry != null) { 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position.set(entry.target); 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position.x -= mScrollX; 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position.y -= mScrollY; 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin repository.putPosition(entry.item.getIdentity(), position); 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin entry = list.nextOf(entry); 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateScrollPosition(int position, boolean force) { 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!force && (WIDE ? position == mScrollX : position == mScrollY)) return; 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScrollX = position; 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScrollY = position; 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLayout.setScrollPosition(position); 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin onScrollPositionChanged(position); 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onScrollPositionChanged(int newPosition) { 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int limit = mLayout.getScrollLimit(); 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener.onScrollPositionChanged(newPosition, limit); 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void putDisplayItem(Position target, Position base, DisplayItem item) { 2099201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang item.setBox(mLayout.getSlotWidth(), mLayout.getSlotHeight()); 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ItemEntry entry = new ItemEntry(item, target, base); 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemList.insertLast(entry); 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItems.put(item, entry); 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void removeDisplayItem(DisplayItem item) { 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ItemEntry entry = mItems.remove(item); 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (entry != null) entry.remove(); 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Rect getSlotRect(int slotIndex) { 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mLayout.getSlotRect(slotIndex); 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected boolean onTouch(MotionEvent event) { 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mUIListener != null) mUIListener.onUserInteraction(); 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mGestureDetector.onTouchEvent(event); 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (event.getAction()) { 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MotionEvent.ACTION_DOWN: 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDownInScrolling = !mScroller.isFinished(); 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScroller.forceFinished(); 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 23377dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang case MotionEvent.ACTION_UP: 23477dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang mPaper.onRelease(); 23577dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang invalidate(); 23677dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang break; 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setListener(Listener listener) { 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener = listener; 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setUserInteractionListener(UserInteractionListener listener) { 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUIListener = listener; 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setOverscrollEffect(int kind) { 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mOverscrollEffect = kind; 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScroller.setOverfling(kind == OVERSCROLL_SYSTEM); 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void render(GLCanvas canvas) { 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super.render(canvas); 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long currentTimeMillis = canvas.currentAnimationTimeMillis(); 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean more = mScroller.advanceAnimation(currentTimeMillis); 26077dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int oldX = mScrollX; 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScrollPosition(mScroller.getPosition(), false); 26277dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang 26377dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang boolean paperActive = false; 26477dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang if (mOverscrollEffect == OVERSCROLL_3D) { 26577dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang // Check if an edge is reached and notify mPaper if so. 26677dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int newX = mScrollX; 26777dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int limit = mLayout.getScrollLimit(); 26877dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang if (oldX > 0 && newX == 0 || oldX < limit && newX == limit) { 26977dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang float v = mScroller.getCurrVelocity(); 27077dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang if (newX == limit) v = -v; 271da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang 272da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang // I don't know why, but getCurrVelocity() can return NaN. 273da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang if (!Float.isNaN(v)) { 274da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang mPaper.edgeReached(v); 275da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang } 27677dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang } 27777dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang paperActive = mPaper.advanceAnimation(); 27877dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang } 27977dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang 28077dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang more |= paperActive; 28177dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float interpolate = 1f; 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mAnimation != null) { 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin more |= mAnimation.calculate(currentTimeMillis); 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin interpolate = mAnimation.value; 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.translate(-mScrollX, 0, 0); 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.translate(0, -mScrollY, 0); 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin LinkedNode.List<ItemEntry> list = mItemList; 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (ItemEntry entry = list.getLast(); entry != null;) { 296da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang int r = renderItem(canvas, entry, interpolate, 0, paperActive); 297da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang if ((r & DisplayItem.RENDER_MORE_PASS) != 0) { 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mCurrentItems.add(entry); 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 300da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang more |= ((r & DisplayItem.RENDER_MORE_FRAME) != 0); 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin entry = list.previousOf(entry); 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int pass = 1; 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (!mCurrentItems.isEmpty()) { 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = mCurrentItems.size(); i < n; i++) { 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ItemEntry entry = mCurrentItems.get(i); 308da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang int r = renderItem(canvas, entry, interpolate, pass, paperActive); 309da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang if ((r & DisplayItem.RENDER_MORE_PASS) != 0) { 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNextItems.add(entry); 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 312da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang more |= ((r & DisplayItem.RENDER_MORE_FRAME) != 0); 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mCurrentItems.clear(); 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // swap mNextItems with mCurrentItems 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<ItemEntry> tmp = mNextItems; 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNextItems = mCurrentItems; 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mCurrentItems = tmp; 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin pass += 1; 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.translate(mScrollX, 0, 0); 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.translate(0, mScrollY, 0); 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (more) invalidate(); 3298bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin 3308bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin final UserInteractionListener listener = mUIListener; 3318bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin if (mMoreAnimation && !more && listener != null) { 3328bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin mHandler.post(new Runnable() { 3338bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin @Override 3348bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin public void run() { 3358bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin listener.onUserInteractionEnd(); 3368bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin } 3378bc5bebba780ca4a322b466b06fc909331697cf4Owen Lin }); 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMoreAnimation = more; 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 342da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang private int renderItem(GLCanvas canvas, ItemEntry entry, 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float interpolate, int pass, boolean paperActive) { 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.save(GLCanvas.SAVE_FLAG_ALPHA | GLCanvas.SAVE_FLAG_MATRIX); 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Position position = entry.target; 346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mPositions != null) { 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = mTempPosition; 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position.set(entry.target); 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position.x -= mScrollX; 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position.y -= mScrollY; 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Position source = mPositions 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin .getPosition(entry.item.getIdentity(), position); 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin source.x += mScrollX; 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin source.y += mScrollY; 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position = mTempPosition; 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Position.interpolate( 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin source, entry.target, position, interpolate); 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.multiplyAlpha(position.alpha); 360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (paperActive) { 361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.multiplyMatrix(mPaper.getTransform( 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin position, entry.base, mScrollX, mScrollY), 0); 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.translate(position.x, position.y, position.z); 365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.rotate(position.theta, 0, 0, 1); 367da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang int more = entry.item.render(canvas, pass); 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.restore(); 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return more; 370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static class MyAnimation extends Animation { 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public float value; 374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MyAnimation() { 376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setInterpolator(new DecelerateInterpolator(4)); 377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setDuration(1500); 378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onCalculate(float progress) { 382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin value = progress; 383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static class ItemEntry extends LinkedNode { 387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public DisplayItem item; 388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Position target; 389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Position base; 390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public ItemEntry(DisplayItem item, Position target, Position base) { 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin this.item = item; 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin this.target = target; 394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin this.base = base; 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 3989201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // This Spec class is used to specify the size of each slot in the SlotView. 3999201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // There are two ways to do it: 4009201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // 4019201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // (1) Specify slotWidth and slotHeight: they specify the width and height 4029201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // of each slot. The number of rows and the gap between slots will be 4039201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // determined automatically. 4049201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // (2) Specify rowsLand, rowsPort, and slotGap: they specify the number 4059201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // of rows in landscape/portrait mode and the gap between slots. The 4069201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // width and height of each slot is determined automatically. 4079201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // 4089201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // The initial value of -1 means they are not specified. 4099201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public static class Spec { 4109201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int slotWidth = -1; 4119201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int slotHeight = -1; 4129201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 4139201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int rowsLand = -1; 4149201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int rowsPort = -1; 4159201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int slotGap = -1; 4169201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 4179201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang static Spec newWithSize(int width, int height) { 4189201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang Spec s = new Spec(); 4199201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang s.slotWidth = width; 4209201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang s.slotHeight = height; 4219201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return s; 4229201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 4239201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 4249201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang static Spec newWithRows(int rowsLand, int rowsPort, int slotGap) { 4259201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang Spec s = new Spec(); 4269201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang s.rowsLand = rowsLand; 4279201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang s.rowsPort = rowsPort; 4289201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang s.slotGap = slotGap; 4299201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return s; 4309201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 4319201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 4329201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static class Layout { 434f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 435f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mVisibleStart; 436f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mVisibleEnd; 437f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 438f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSlotCount; 439f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSlotWidth; 440f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSlotHeight; 4419201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang private int mSlotGap; 4429201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 4439201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang private Spec mSpec; 444f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 445f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mWidth; 446f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mHeight; 447f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 448f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mUnitCount; 449f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentLength; 450f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mScrollPosition; 451f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 452f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mVerticalPadding; 453f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mHorizontalPadding; 454f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4559201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public void setSlotSpec(Spec spec) { 4569201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSpec = spec; 457f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 458f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 459f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean setSlotCount(int slotCount) { 460f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSlotCount = slotCount; 461f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int hPadding = mHorizontalPadding; 462f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int vPadding = mVerticalPadding; 463f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin initLayoutParameters(); 464f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return vPadding != mVerticalPadding || hPadding != mHorizontalPadding; 465f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 466f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 467f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Rect getSlotRect(int index) { 468f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int col, row; 469f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 470f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin col = index / mUnitCount; 471f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin row = index - col * mUnitCount; 472f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 473f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin row = index / mUnitCount; 474f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin col = index - row * mUnitCount; 475f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 476f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4779201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int x = mHorizontalPadding + col * (mSlotWidth + mSlotGap); 4789201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int y = mVerticalPadding + row * (mSlotHeight + mSlotGap); 479f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return new Rect(x, y, x + mSlotWidth, y + mSlotHeight); 480f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 481f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4829201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int getSlotWidth() { 4839201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return mSlotWidth; 4849201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 4859201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 4869201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang public int getSlotHeight() { 4879201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return mSlotHeight; 4889201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 4899201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 490f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getContentLength() { 491f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mContentLength; 492f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 493f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 494f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Calculate 495f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // (1) mUnitCount: the number of slots we can fit into one column (or row). 496f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // (2) mContentLength: the width (or height) we need to display all the 497f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // columns (rows). 498f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // (3) padding[]: the vertical and horizontal padding we need in order 499f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // to put the slots towards to the center of the display. 500f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // 501f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The "major" direction is the direction the user can scroll. The other 502f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // direction is the "minor" direction. 503f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // 504f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The comments inside this method are the description when the major 505f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // directon is horizontal (X), and the minor directon is vertical (Y). 506f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void initLayoutParameters( 507f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int majorLength, int minorLength, /* The view width and height */ 508f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int majorUnitSize, int minorUnitSize, /* The slot width and height */ 509f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int[] padding) { 5109201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int unitCount = (minorLength + mSlotGap) / (minorUnitSize + mSlotGap); 511f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (unitCount == 0) unitCount = 1; 512f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUnitCount = unitCount; 513f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 514f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We put extra padding above and below the column. 515f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int availableUnits = Math.min(mUnitCount, mSlotCount); 5169201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int usedMinorLength = availableUnits * minorUnitSize + 5179201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang (availableUnits - 1) * mSlotGap; 5189201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang padding[0] = (minorLength - usedMinorLength) / 2; 519f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 520f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Then calculate how many columns we need for all slots. 521f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int count = ((mSlotCount + mUnitCount - 1) / mUnitCount); 5229201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mContentLength = count * majorUnitSize + (count - 1) * mSlotGap; 523f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 524f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If the content length is less then the screen width, put 525f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // extra padding in left and right. 526f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin padding[1] = Math.max(0, (majorLength - mContentLength) / 2); 527f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 528f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 529f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void initLayoutParameters() { 5309201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // Initialize mSlotWidth and mSlotHeight from mSpec 5319201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang if (mSpec.slotWidth != -1) { 5329201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotGap = 0; 5339201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotWidth = mSpec.slotWidth; 5349201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotHeight = mSpec.slotHeight; 5359201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } else { 5369201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int rows = (mWidth > mHeight) ? mSpec.rowsLand : mSpec.rowsPort; 5379201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotGap = mSpec.slotGap; 5389201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotHeight = Math.max(1, (mHeight - (rows - 1) * mSlotGap) / rows); 5399201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSlotWidth = mSlotHeight; 5409201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 5419201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 542f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int[] padding = new int[2]; 543f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 544f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin initLayoutParameters(mWidth, mHeight, mSlotWidth, mSlotHeight, padding); 545f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVerticalPadding = padding[0]; 546f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHorizontalPadding = padding[1]; 547f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 548f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin initLayoutParameters(mHeight, mWidth, mSlotHeight, mSlotWidth, padding); 549f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVerticalPadding = padding[1]; 550f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHorizontalPadding = padding[0]; 551f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 552f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateVisibleSlotRange(); 553f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 554f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 555f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setSize(int width, int height) { 556f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mWidth = width; 557f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHeight = height; 558f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin initLayoutParameters(); 559f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 560f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 561f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateVisibleSlotRange() { 562f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int position = mScrollPosition; 563f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 564f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (WIDE) { 5659201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int startCol = position / (mSlotWidth + mSlotGap); 5669201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int start = Math.max(0, mUnitCount * startCol); 5679201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int endCol = (position + mWidth + mSlotWidth + mSlotGap - 1) / 5689201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang (mSlotWidth + mSlotGap); 5699201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int end = Math.min(mSlotCount, mUnitCount * endCol); 570f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setVisibleRange(start, end); 571f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 5729201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int startRow = position / (mSlotHeight + mSlotGap); 5739201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int start = Math.max(0, mUnitCount * startRow); 5749201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int endRow = (position + mHeight + mSlotHeight + mSlotGap - 1) / 5759201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang (mSlotHeight + mSlotGap); 5769201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int end = Math.min(mSlotCount, mUnitCount * endRow); 577f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setVisibleRange(start, end); 578f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 579f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 580f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 581f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setScrollPosition(int position) { 582f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mScrollPosition == position) return; 583f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScrollPosition = position; 584f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateVisibleSlotRange(); 585f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 586f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 587f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void setVisibleRange(int start, int end) { 588f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == mVisibleStart && end == mVisibleEnd) return; 589f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start < end) { 590f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVisibleStart = start; 591f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVisibleEnd = end; 592f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 593f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVisibleStart = mVisibleEnd = 0; 594f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 595f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 596f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 597f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getVisibleStart() { 598f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mVisibleStart; 599f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 600f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 601f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getVisibleEnd() { 602f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mVisibleEnd; 603f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 604f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 605f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getSlotIndexByPosition(float x, float y) { 6069201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int absoluteX = Math.round(x) + (WIDE ? mScrollPosition : 0); 6079201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int absoluteY = Math.round(y) + (WIDE ? 0 : mScrollPosition); 6089201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 609f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin absoluteX -= mHorizontalPadding; 6109201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang absoluteY -= mVerticalPadding; 6119201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 612003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang if (absoluteX < 0 || absoluteY < 0) { 613003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang return INDEX_NONE; 614003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang } 615003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang 6169201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int columnIdx = absoluteX / (mSlotWidth + mSlotGap); 6179201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int rowIdx = absoluteY / (mSlotHeight + mSlotGap); 6189201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 619003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang if (!WIDE && columnIdx >= mUnitCount) { 620f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return INDEX_NONE; 621f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 622f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 623003328e9d121b31fec76e3599300931bb356e1bdChih-Chung Chang if (WIDE && rowIdx >= mUnitCount) { 624f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return INDEX_NONE; 625f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 6269201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 6279201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang if (absoluteX % (mSlotWidth + mSlotGap) >= mSlotWidth) { 6289201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return INDEX_NONE; 6299201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 6309201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 6319201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang if (absoluteY % (mSlotHeight + mSlotGap) >= mSlotHeight) { 6329201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang return INDEX_NONE; 6339201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 6349201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang 635f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = WIDE 636f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ? (columnIdx * mUnitCount + rowIdx) 637f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin : (rowIdx * mUnitCount + columnIdx); 638f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 639f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return index >= mSlotCount ? INDEX_NONE : index; 640f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 641f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 642f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getScrollLimit() { 643f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int limit = WIDE ? mContentLength - mWidth : mContentLength - mHeight; 644f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return limit <= 0 ? 0 : limit; 645f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 646f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 647f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 648bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang private class MyGestureListener implements 649bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang GestureDetector.OnGestureListener { 650bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang private boolean isDown; 651bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang 652bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang // We call the listener's onDown() when our onShowPress() is called and 653bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang // call the listener's onUp() when we receive any further event. 654bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang @Override 655bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang public void onShowPress(MotionEvent e) { 656bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang if (isDown) return; 657bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); 658bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang if (index != INDEX_NONE) { 659bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang isDown = true; 660bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang mListener.onDown(index); 661bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang } 662bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang } 663bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang 664bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang private void cancelDown() { 665bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang if (!isDown) return; 666bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang isDown = false; 667bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang mListener.onUp(); 668bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang } 669bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang 670bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang @Override 671bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang public boolean onDown(MotionEvent e) { 672bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang return false; 673bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang } 674f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 675f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 676f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onFling(MotionEvent e1, 677f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MotionEvent e2, float velocityX, float velocityY) { 678bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang cancelDown(); 679f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int scrollLimit = mLayout.getScrollLimit(); 680f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (scrollLimit == 0) return false; 681f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float velocity = WIDE ? velocityX : velocityY; 682f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScroller.fling((int) -velocity, 0, scrollLimit); 683f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mUIListener != null) mUIListener.onUserInteractionBegin(); 684f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin invalidate(); 685f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 686f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 687f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 688f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 689f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onScroll(MotionEvent e1, 690f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MotionEvent e2, float distanceX, float distanceY) { 691bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang cancelDown(); 692f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float distance = WIDE ? distanceX : distanceY; 69377dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang int overDistance = mScroller.startScroll( 694f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Math.round(distance), 0, mLayout.getScrollLimit()); 69577dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang if (mOverscrollEffect == OVERSCROLL_3D && overDistance != 0) { 69677dcf07756dcf918c56afb0a8f7605577a7ce8e0Chih-Chung Chang mPaper.overScroll(overDistance); 697f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 698f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin invalidate(); 699f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 700f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 701f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 702f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 703f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onSingleTapUp(MotionEvent e) { 704bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang cancelDown(); 705f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mDownInScrolling) return true; 706f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); 707f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index != INDEX_NONE) mListener.onSingleTapUp(index); 708f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 709f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 710f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 711f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 712f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onLongPress(MotionEvent e) { 713bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang cancelDown(); 714f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mDownInScrolling) return; 715f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin lockRendering(); 716f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 717f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); 718f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index != INDEX_NONE) mListener.onLongTap(index); 719f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } finally { 720f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin unlockRendering(); 721f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 722f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 723f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 724f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 725f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setStartIndex(int index) { 726f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mStartIndex = index; 727f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 728f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 729f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Return true if the layout parameters have been changed 730f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean setSlotCount(int slotCount) { 731f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean changed = mLayout.setSlotCount(slotCount); 732f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 733f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // mStartIndex is applied the first time setSlotCount is called. 734f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mStartIndex != INDEX_NONE) { 735f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setCenterIndex(mStartIndex); 736f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mStartIndex = INDEX_NONE; 737f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 738f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScrollPosition(WIDE ? mScrollX : mScrollY, true); 739f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return changed; 740f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 741f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 742f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getVisibleStart() { 743f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mLayout.getVisibleStart(); 744f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 745f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 746f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getVisibleEnd() { 747f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mLayout.getVisibleEnd(); 748f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 749f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 750f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getScrollX() { 751f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mScrollX; 752f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 753f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 754f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getScrollY() { 755f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mScrollY; 756f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 757f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 758