From e78541f2edf2f02660c34660114e76d53b32ab8b Mon Sep 17 00:00:00 2001 From: Angus Kong Date: Tue, 28 May 2013 12:30:33 -0700 Subject: Add UI for insertion in FilmStripView. Change-Id: Iff389525e3811c5018365b6e6c3b9f8b95b9da9a --- src/com/android/camera/NewCameraActivity.java | 2 + src/com/android/camera/ui/FilmStripView.java | 173 ++++++++++++++++++++------ 2 files changed, 138 insertions(+), 37 deletions(-) (limited to 'src/com/android/camera') diff --git a/src/com/android/camera/NewCameraActivity.java b/src/com/android/camera/NewCameraActivity.java index 8ce5ce43b..9751e3d24 100644 --- a/src/com/android/camera/NewCameraActivity.java +++ b/src/com/android/camera/NewCameraActivity.java @@ -151,6 +151,8 @@ public class NewCameraActivity extends Activity mDataAdapter = new CameraDataAdapter( new ColorDrawable(getResources().getColor(R.color.photo_placeholder))); mFilmStripView = (FilmStripView) findViewById(R.id.filmstrip_view); + mFilmStripView.setViewGap( + getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap)); // Set up the camera preview first so the preview shows up ASAP. mDataAdapter.setCameraPreviewInfo(rootLayout, FilmStripView.ImageData.SIZE_FULL, FilmStripView.ImageData.SIZE_FULL); diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java index 917289f4e..f9a4ec038 100644 --- a/src/com/android/camera/ui/FilmStripView.java +++ b/src/com/android/camera/ui/FilmStripView.java @@ -17,6 +17,7 @@ package com.android.camera.ui; import android.animation.Animator; +import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; @@ -34,7 +35,6 @@ public class FilmStripView extends ViewGroup { private static final int BUFFER_SIZE = 5; // Horizontal padding of children. - private static final int H_PADDING = 100; // Duration to go back to the first. private static final int DURATION_BACK_ANIM = 500; private static final int DURATION_SCROLL_TO_FILMSTRIP = 350; @@ -45,12 +45,12 @@ public class FilmStripView extends ViewGroup { private Context mContext; private FilmStripGestureRecognizer mGestureRecognizer; private DataAdapter mDataAdapter; + private int mViewGap; private final Rect mDrawArea = new Rect(); private final int mCurrentInfo = (BUFFER_SIZE - 1) / 2; private float mScale; private MyController mController; - private LinearInterpolator mLinearInterpolator; private int mCenterX = -1; private ViewInfo[] mViewInfo = new ViewInfo[BUFFER_SIZE]; @@ -59,6 +59,8 @@ public class FilmStripView extends ViewGroup { private View mCameraView; private ImageData mCameraData; + private TimeInterpolator mViewAnimInterpolator; + // This is used to resolve the misalignment problem when the device // orientation is changed. If the current item is in fullscreen, it might // be shifted because mCenterX is not adjusted with the orientation. @@ -248,7 +250,7 @@ public class FilmStripView extends ViewGroup { mContext = context; mScale = 1.0f; mController = new MyController(context); - mLinearInterpolator = new LinearInterpolator(); + mViewAnimInterpolator = new LinearInterpolator(); mGestureRecognizer = new FilmStripGestureRecognizer(context, new MyGestureReceiver()); } @@ -261,6 +263,10 @@ public class FilmStripView extends ViewGroup { mListener = l; } + public void setViewGap(int viewGap) { + mViewGap = viewGap; + } + public float getScale() { return mScale; } @@ -287,6 +293,30 @@ public class FilmStripView extends ViewGroup { } } + // returns [width, height] preserving image aspect ratio + private int[] calculateChildDimension( + int imageWidth, int imageHeight, + int boundWidth, int boundHeight) { + + if (imageWidth == ImageData.SIZE_FULL + || imageHeight == ImageData.SIZE_FULL) { + imageWidth = boundWidth; + imageHeight = boundHeight; + } + + int[] ret = new int[2]; + ret[0] = boundWidth; + ret[1] = boundHeight; + + if (imageWidth * ret[1] > ret[0] * imageHeight) { + ret[1] = imageHeight * ret[0] / imageWidth; + } else { + ret[0] = imageWidth * ret[1] / imageHeight; + } + + return ret; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -297,33 +327,21 @@ public class FilmStripView extends ViewGroup { mDataAdapter.suggestDecodeSize(boundWidth / 2, boundHeight / 2); } - int wMode = View.MeasureSpec.EXACTLY; - int hMode = View.MeasureSpec.EXACTLY; - for (int i = 0; i < mViewInfo.length; i++) { ViewInfo info = mViewInfo[i]; if (mViewInfo[i] == null) continue; - int imageWidth = mDataAdapter.getImageData(info.getID()).getWidth(); - int imageHeight = mDataAdapter.getImageData(info.getID()).getHeight(); - if (imageWidth == ImageData.SIZE_FULL) { - imageWidth = boundWidth; - } - if (imageHeight == ImageData.SIZE_FULL) { - imageHeight = boundHeight; - } + int id = info.getID(); + int[] dim = calculateChildDimension( + mDataAdapter.getImageData(id).getWidth(), + mDataAdapter.getImageData(id).getHeight(), + boundWidth, boundHeight); - int scaledWidth = boundWidth; - int scaledHeight = boundHeight; - - if (imageWidth * scaledHeight > scaledWidth * imageHeight) { - scaledHeight = imageHeight * scaledWidth / imageWidth; - } else { - scaledWidth = imageWidth * scaledHeight / imageHeight; - } mViewInfo[i].getView().measure( - View.MeasureSpec.makeMeasureSpec(scaledWidth, wMode) - , View.MeasureSpec.makeMeasureSpec(scaledHeight, hMode)); + View.MeasureSpec.makeMeasureSpec( + dim[0], View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec( + dim[1], View.MeasureSpec.EXACTLY)); } setMeasuredDimension(boundWidth, boundHeight); } @@ -460,7 +478,7 @@ public class FilmStripView extends ViewGroup { if (curr != null) { ViewInfo next = mViewInfo[infoID + 1]; curr.setLeftPosition( - next.getLeftPosition() - curr.getView().getMeasuredWidth() - H_PADDING); + next.getLeftPosition() - curr.getView().getMeasuredWidth() - mViewGap); curr.layoutIn(mDrawArea, mCenterX, mScale); } } @@ -471,7 +489,7 @@ public class FilmStripView extends ViewGroup { if (curr != null) { ViewInfo prev = mViewInfo[infoID - 1]; curr.setLeftPosition( - prev.getLeftPosition() + prev.getView().getMeasuredWidth() + H_PADDING); + prev.getLeftPosition() + prev.getView().getMeasuredWidth() + mViewGap); curr.layoutIn(mDrawArea, mCenterX, mScale); } } @@ -514,12 +532,13 @@ public class FilmStripView extends ViewGroup { .translationX(0) .alpha(1f) .setDuration(DURATION_GEOMETRY_ADJUST) + .setInterpolator(mViewAnimInterpolator) .start(); } private void updateRemoval(int removedInfo, final ImageData data) { final View removedView = mViewInfo[removedInfo].getView(); - final int offsetX = (int) (removedView.getMeasuredWidth() + H_PADDING); + final int offsetX = (int) (removedView.getMeasuredWidth() + mViewGap); for (int i = removedInfo + 1; i < BUFFER_SIZE; i++) { if (mViewInfo[i] != null) { @@ -597,7 +616,7 @@ public class FilmStripView extends ViewGroup { removedView.animate() .alpha(0f) .translationYBy(transY) - .setInterpolator(mLinearInterpolator) + .setInterpolator(mViewAnimInterpolator) .setDuration(DURATION_GEOMETRY_ADJUST) .withEndAction(new Runnable() { @Override @@ -609,6 +628,84 @@ public class FilmStripView extends ViewGroup { layoutChildren(); } + // returns -1 on failure. + private int findInfoByDataID(int dataID) { + for (int i = 0; i < BUFFER_SIZE; i++) { + if (mViewInfo[i] != null + && mViewInfo[i].getID() == dataID) return i; + } + return -1; + } + + private void updateInsertion(int dataID) { + int insertedInfo = findInfoByDataID(dataID); + if (insertedInfo == -1) { + // Not in the current info buffers. Check if it's inserted + // at the end. + if (dataID == mDataAdapter.getTotalNumber() - 1) { + int prev = findInfoByDataID(dataID - 1); + if (prev >= 0 && prev < BUFFER_SIZE - 1) { + // The previous data is in the buffer and we still + // have room for the inserted data. + insertedInfo = prev + 1; + } + } + } + + // adjust the data id to be consistent + for (int i = 0; i < BUFFER_SIZE; i++) { + if (mViewInfo[i] == null || mViewInfo[i].getID() < dataID) continue; + mViewInfo[i].setID(mViewInfo[i].getID() + 1); + } + if (insertedInfo == -1) return; + + final ImageData data = mDataAdapter.getImageData(dataID); + int[] dim = calculateChildDimension( + data.getWidth(), data.getHeight(), + getMeasuredWidth(), getMeasuredHeight()); + final int offsetX = dim[0] + mViewGap; + ViewInfo viewInfo = buildInfoFromData(dataID); + + if (insertedInfo >= mCurrentInfo) { + if (insertedInfo == mCurrentInfo) { + viewInfo.setLeftPosition(mViewInfo[mCurrentInfo].getLeftPosition()); + } + // Shift right to make rooms for newly inserted item. + removeInfo(BUFFER_SIZE - 1); + for (int i = BUFFER_SIZE - 1; i > insertedInfo; i--) { + mViewInfo[i] = mViewInfo[i - 1]; + if (mViewInfo[i] != null) { + mViewInfo[i].setTranslationX(-offsetX, mScale); + slideViewBack(mViewInfo[i].getView()); + } + } + } else { + // Shift left. Put the inserted data on the left instead of the found position. + --insertedInfo; + if (insertedInfo < 0) return; + removeInfo(0); + for (int i = 1; i <= insertedInfo; i++) { + if (mViewInfo[i] != null) { + mViewInfo[i].setTranslationX(offsetX, mScale); + slideViewBack(mViewInfo[i].getView()); + mViewInfo[i - 1] = mViewInfo[i]; + } + } + } + + mViewInfo[insertedInfo] = viewInfo; + View insertedView = mViewInfo[insertedInfo].getView(); + insertedView.setAlpha(0f); + insertedView.setTranslationY(getHeight() / 8); + insertedView.animate() + .alpha(1f) + .translationY(0f) + .setInterpolator(mViewAnimInterpolator) + .setDuration(DURATION_GEOMETRY_ADJUST) + .start(); + invalidate(); + } + public void setDataAdapter(DataAdapter adapter) { mDataAdapter = adapter; mDataAdapter.suggestDecodeSize(getMeasuredWidth(), getMeasuredHeight()); @@ -625,17 +722,19 @@ public class FilmStripView extends ViewGroup { @Override public void onDataInserted(int dataID, ImageData data) { + if (mViewInfo[mCurrentInfo] == null) { + // empty now, simply do a reload. + reload(); + return; + } + updateInsertion(dataID); } @Override public void onDataRemoved(int dataID, ImageData data) { - int removedInfo = 0; - for (; removedInfo < BUFFER_SIZE; removedInfo++) { - if (mViewInfo[removedInfo] != null - && mViewInfo[removedInfo].getID() == dataID) break; - } - if (removedInfo == BUFFER_SIZE) return; - updateRemoval(removedInfo, data); + int info = findInfoByDataID(dataID); + if (info == -1) return; + updateRemoval(info, data); } }); } @@ -840,13 +939,13 @@ public class FilmStripView extends ViewGroup { } private int estimateMinX(int dataID, int leftPos, int viewWidth) { - return (leftPos - (dataID + 100) * (viewWidth + H_PADDING)); + return (leftPos - (dataID + 100) * (viewWidth + mViewGap)); } private int estimateMaxX(int dataID, int leftPos, int viewWidth) { return (leftPos + (mDataAdapter.getTotalNumber() - dataID + 100) - * (viewWidth + H_PADDING)); + * (viewWidth + mViewGap)); } @Override -- cgit v1.2.3