Форум программистов, компьютерный форум CyberForum.ru

Программирование Android

Войти
Регистрация
Восстановить пароль
 
Prostoplus
11 / 1 / 0
Регистрация: 21.09.2012
Сообщений: 122
#1

Diagonal panning ImageView - Android

01.08.2015, 18:19. Просмотров 275. Ответов 0
Метки нет (Все метки)

Здравствуйте, как создать ImageView, который плавно, с эффектом прокрутки по диагонали показывал бы слайд-шоу?
Пример на видео ниже или в приложении Google Play Press / the Fancy.
Хочу сделать прокрутку по диагонали. Использую код из примера: пример
Мой код:
XML
1
2
3
4
5
6
7
<com.inthecheesefactory.lab.designlibrary.PanningView.PanningView
                        xmlns:custom="http://schemas.android.com/apk/res-auto"
                        android:id="@+id/panningView"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:src="@drawable/nav_header_bg"
                        custom:panningDurationInMs="7000" />
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.inthecheesefactory.lab.designlibrary.PanningView;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.inthecheesefactory.lab.designlibrary.R;
 
public class PanningView extends ImageView {
    private final PanningViewAttacher mAttacher;
    private int mPanningDurationInMs;
    public PanningView(Context context) {
        this(context, null);
    }
 
    public PanningView(Context context, AttributeSet attr) {
        this(context, attr, 0);
    }
 
    public PanningView(Context context, AttributeSet attr, int defStyle) {
        super(context, attr, defStyle);
        readStyleParameters(context, attr);
        super.setScaleType(ScaleType.MATRIX);
        mAttacher = new PanningViewAttacher(this, mPanningDurationInMs);
    }
    private void readStyleParameters(Context context, AttributeSet attributeSet) {
        TypedArray a = context.obtainStyledAttributes(attributeSet,
                R.styleable.PanningView);
        try {
            mPanningDurationInMs = a.getInt(
                    R.styleable.PanningView_panningDurationInMs,
                    PanningViewAttacher.DEFAULT_PANNING_DURATION_IN_MS);
        } finally {
            a.recycle();
        }
    }
    @Override
    // setImageBitmap calls through to this method
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        stopUpdateStartIfNecessary();
    }
    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        stopUpdateStartIfNecessary();
    }
    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        stopUpdateStartIfNecessary();
    }
    private void stopUpdateStartIfNecessary() {
        if (null != mAttacher) {
            boolean wasPanning = mAttacher.isPanning();
            mAttacher.stopPanning();
            mAttacher.update();
            if (wasPanning) {
                mAttacher.startPanning();
            }
        }
    }
    @Override
    protected void onDetachedFromWindow() {
        mAttacher.cleanup();
        super.onDetachedFromWindow();
    }
    public void startPanning() {
        mAttacher.startPanning();
    }
    public void stopPanning() {
        mAttacher.stopPanning();
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
package com.inthecheesefactory.lab.designlibrary.PanningView;
import android.content.res.Configuration;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.util.Log;
import android.view.ViewTreeObserver;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
 
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.animation.ValueAnimator;
 
import java.lang.ref.WeakReference;
 
public class PanningViewAttacher implements ViewTreeObserver.OnGlobalLayoutListener {
 
    public static final int DEFAULT_PANNING_DURATION_IN_MS = 500;
    private static final String TAG = "PanningViewAttacher";
    private WeakReference<ImageView> mImageView;
 
    private int mIvTop, mIvRight, mIvBottom, mIvLeft;
    private ViewTreeObserver mViewTreeObserver;
    private Matrix mMatrix;
    private RectF mDisplayRect = new RectF();
    private ValueAnimator mCurrentAnimator;
    //--
    private ValueAnimator mCurrentAnimatorX;
    private ValueAnimator mCurrentAnimatorY;
    //--
    private LinearInterpolator mLinearInterpolator;
    private boolean mIsPortrait;
    private long mDuration;
    private long mCurrentPlayTime;
    private long mTotalTime;
    private Way mWay;
    private boolean mIsPanning;
 
    public PanningViewAttacher(ImageView imageView, long duration) {
        if (imageView == null) {
            throw new IllegalArgumentException("imageView must not be null");
        }
        if (!hasDrawable(imageView)) {
            throw new IllegalArgumentException("drawable must not be null");
        }
        mLinearInterpolator = new LinearInterpolator();
 
        mDuration = duration;
        mImageView = new WeakReference<>(imageView);
        mViewTreeObserver = imageView.getViewTreeObserver();
        mViewTreeObserver.addOnGlobalLayoutListener(this);
        setImageViewScaleTypeMatrix(imageView);
        mMatrix = imageView.getImageMatrix();
        if (mMatrix == null) {
            mMatrix = new Matrix();
        }
        mIsPortrait = imageView.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
        update();
    }
 
    /**
     * Set's the ImageView's ScaleType to Matrix.
     */
    private static void setImageViewScaleTypeMatrix(ImageView imageView) {
        if (null != imageView && !(imageView instanceof PanningView)) {
            imageView.setScaleType(ImageView.ScaleType.MATRIX);
        }
    }
    /**
     * @return true if the ImageView exists, and it's Drawable exists
     */
    private static boolean hasDrawable(ImageView imageView) {
        return null != imageView && null != imageView.getDrawable();
    }
    public void update() {
        mWay = null;
        mTotalTime = 0;
        mCurrentPlayTime = 0;
        getImageView().post(new Runnable() {
 
            @Override
            public void run() {
                scale();
                refreshDisplayRect();
            }
 
        });
    }
 
    public boolean isPanning() {
        return mIsPanning;
    }
    public void startPanning() {
        if (mIsPanning) {
            return;
        }
        mIsPanning = true;
        final Runnable panningRunnable = new Runnable() {
            @Override
            public void run() {
                animate_();
            }
        };
        getImageView().post(panningRunnable);
    }
    public void stopPanning() {
        if (!mIsPanning) {
            return;
        }
        mIsPanning = false;
        Log.d(TAG, "panning animation stopped by user");
        if (mCurrentAnimator != null) {
            mCurrentAnimator.removeAllListeners();
            mCurrentAnimator.cancel();
            mCurrentAnimator = null;
        }
        mTotalTime += mCurrentPlayTime;
        Log.d(TAG, "mTotalTime : " + mTotalTime);
    }
    public final void cleanup() {
        if (null != mImageView) {
            getImageView().getViewTreeObserver().removeGlobalOnLayoutListener(this);
        }
        mViewTreeObserver = null;
        stopPanning();
        // Finally, clear ImageView
        mImageView = null;
    }
    public final ImageView getImageView() {
        ImageView imageView = null;
        if (null != mImageView) {
            imageView = mImageView.get();
        }
        // If we don't have an ImageView, call cleanup()
        if (null == imageView) {
            cleanup();
            throw new IllegalStateException(
                    "ImageView no longer exists. You should not use this PanningViewAttacher any more.");
        }
        return imageView;
    }
    private int getDrawableIntrinsicHeight() {
        return getImageView().getDrawable().getIntrinsicHeight();
    }
    private int getDrawableIntrinsicWidth() {
        return getImageView().getDrawable().getIntrinsicWidth();
    }
    private int getImageViewWidth() {
        return getImageView().getWidth();
    }
    private int getImageViewHeight() {
        return getImageView().getHeight();
    }
    @Override
    public void onGlobalLayout() {
        ImageView imageView = getImageView();
        if (null != imageView) {
            final int top = imageView.getTop();
            final int right = imageView.getRight();
            final int bottom = imageView.getBottom();
            final int left = imageView.getLeft();
      
            if (top != mIvTop || bottom != mIvBottom || left != mIvLeft || right != mIvRight) {
                update();
                // Update values as something has changed
                mIvTop = top;
                mIvRight = right;
                mIvBottom = bottom;
                mIvLeft = left;
            }
        }
    }
    private void animate_() {
        refreshDisplayRect();
        if (mWay == null) {
            //mWay = mIsPortrait ? Way.R2L : Way.B2T;
            mWay = Way.LB2RT;
        }
        Log.d(TAG, "mWay : " + mWay);
        Log.d(TAG, "mDisplayRect : " + mDisplayRect);
        long remainingDuration = mDuration - mTotalTime;
 
        //if(mWay == Way.LB2RT)
        {
            final float imgWidth = getImageViewWidth();
            final float imgHeight = getImageViewHeight();
 
            float startX    =  mDisplayRect.left;
            float endX      =  mDisplayRect.left - (mDisplayRect.right - getImageViewWidth());
            float startY    =  mDisplayRect.top - (mDisplayRect.bottom - getImageViewHeight());
            float endY      =  mDisplayRect.top;//mDisplayRect.top;
            animate(startX, endX, startY, endY, remainingDuration);
        }
    }
    private void changeWay() {
        //...
        if(mWay == Way.LB2RT){
            mWay = Way.LT2RB;
        }else if(mWay == Way.LT2RB){
            mWay = Way.LB2RT;
        }
        mCurrentPlayTime = 0;
        mTotalTime = 0;
    }
    //diagonal panning
    private void animate(float startX, float endX, float startY, float endY, long duration) {
        Log.d(TAG, "startPanning : [" + startX + ";" + startY + "] to [" + endX + ";" + endY + "], in " + duration + "ms");
 
        AnimatorSet animSetXY = new AnimatorSet();
        mCurrentAnimatorX = ValueAnimator.ofFloat(startX, endX);
        mCurrentAnimatorY = ValueAnimator.ofFloat(startY, endY);
        ///
        mCurrentAnimatorX
                .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float value = (Float) animation.getAnimatedValue();
                        mMatrix.reset();
                        applyScaleOnMatrix(true);
 
                        mMatrix.postTranslate(value, 0);
 
                        refreshDisplayRect();
                        mCurrentPlayTime = animation.getCurrentPlayTime();
                        setCurrentImageMatrix();
                    }
                });
        //****Y
        mCurrentAnimatorY
                .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float value = (Float) animation.getAnimatedValue();
                        mMatrix.reset();
                        applyScaleOnMatrix(false);
 
                        mMatrix.postTranslate(0, value);
 
                        refreshDisplayRect();
                        mCurrentPlayTime = animation.getCurrentPlayTime();
                        setCurrentImageMatrix();
                    }
                });
        //--
        animSetXY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
            }
            @Override
            public void onAnimationCancel(Animator animation) {
                Log.d(TAG, "panning animation canceled");
            }
            @Override
            public void onAnimationEnd(Animator animation) {
                Log.d(TAG, "animation has finished, startPanning in the other way");
                changeWay();
                animate_();
            }
            @Override
            public void onAnimationRepeat(Animator animation) {
                super.onAnimationRepeat(animation);
            }
        });
        animSetXY.playTogether(mCurrentAnimatorX, mCurrentAnimatorY);
 
        animSetXY.setInterpolator(mLinearInterpolator);
        animSetXY.setDuration(duration);
        animSetXY.start();
    }
    private void setCurrentImageMatrix() {
        getImageView().setImageMatrix(mMatrix);
        getImageView().invalidate();
        getImageView().requestLayout();
    }
    private void refreshDisplayRect() {
        mDisplayRect.set(0, 0, getDrawableIntrinsicWidth(),
                getDrawableIntrinsicHeight());
        mMatrix.mapRect(mDisplayRect);
    }
    private void scale() {
        mMatrix.reset();
        applyScaleOnMatrix();
        setCurrentImageMatrix();
    }
    private void applyScaleOnMatrix(boolean isPortrait) {
        int drawableSize = isPortrait ? getDrawableIntrinsicHeight()
                : getDrawableIntrinsicWidth();
        int imageViewSize = isPortrait ? getImageViewHeight()
                : getImageViewWidth();
        float scaleFactor = (float) imageViewSize / (float) drawableSize;
        mMatrix.postScale(scaleFactor, scaleFactor);
    }
    private enum Way {
        R2L, L2R, T2B, B2T, LT2RB, LB2RT
    }
}


Проблема: в классе PanningViewAttacher, метод animate:
Если написать:
Java
1
animSetXY.playTogether(mCurrentAnimatorX, mCurrentAnimatorY);
то идет прокрутка только по оси Y, а если
Java
1
animSetXY.playTogether(mCurrentAnimatorY, mCurrentAnimatorX);
то только по оси X. Как сделать анимацию по диагонали? Возможно, уже есть готовые решения.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.08.2015, 18:19     Diagonal panning ImageView
Посмотрите здесь:

Android Квадратный ImageView
Снова ImageView Android
Android Взаимодействие с ImageView
Использование ImageView Android
Android Наследование от ImageView
Кастомный ImageView Android
На счет ImageView Android
Сохранение ImageView Android
Сохранить ImageView Android
Координаты ImageView Android
Android Таблица из ImageView
ImageView вращение Android

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Ответ Создать тему
Опции темы

Текущее время: 00:50. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru