向上或向下滑动时,ImageViewer的Viewpager过渡不平滑

Viewpager Transition not smooth for ImageViewer when swiping up or down

提问人:Elfie 提问时间:11/9/2023 最后编辑:Elfie 更新时间:11/19/2023 访问量:56

问:

我有一个过渡效果,可以从一张图片滑动到下一张图片,然后滑动到上一张图片。滑动的图像在屏幕外移动,上一个/下一个图像从屏幕的另一侧进入。

我无法理解的是,当我向上或向下滑动时,我会得到类似的垂直转换。 我让它工作,但它仍然不顺利。缓慢滑动时,图像会上下跳跃(仅在垂直滑动时)。

ImageViewerActivity(图像查看器活动)

public class ImageViewerActivity extends ActivityBase {

private ArrayList<Uri> mImageUris;
private int mCurrentImageIndex = 0;
private ViewPager mViewPager;
private ImagePagerAdapter mPagerAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_image_viewer);

    initializeUI();
    setupToolbar();

    mImageUris = getIntent().getParcelableArrayListExtra("image_uris");
    mCurrentImageIndex = getIntent().getIntExtra("current_image_index", 0);

    mPagerAdapter = new ImagePagerAdapter(this, mImageUris);
    mViewPager.setAdapter(mPagerAdapter);

    mViewPager.setCurrentItem(mCurrentImageIndex);
    mPagerAdapter.instantiateItem(mViewPager, mCurrentImageIndex);
    mPagerAdapter.notifyDataSetChanged();
    // Set the PageTransformer to apply the custom animation
    mViewPager.setPageTransformer(false, new DepthPageTransformer());
}

private void initializeUI() {
    mViewPager = findViewById(R.id.viewPager);

    mViewPager.setOnTouchListener(new View.OnTouchListener() {
        private float startX = 0;
        private float startY = 0;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    startX = event.getX();
                    startY = event.getY();
                    break;

                case MotionEvent.ACTION_MOVE:
                    float endX = event.getX();
                    float endY = event.getY();

                    float deltaX = Math.abs(endX - startX);
                    float deltaY = Math.abs(endY - startY);

                    // Set a threshold value to determine primary direction
                    float threshold = 200; // Adjust this value as needed

                    if (deltaX > threshold && deltaX > deltaY) {
                        // Horizontal swipe
                        break;
                    }

                    // Vertical swipe
                    float translationY = endY - startY;
                    v.setTranslationY(translationY);
                    break;

                case MotionEvent.ACTION_UP:
                    float endYUp = event.getY();
                    float deltaYUp = endYUp - startY;

                    // Set a threshold value for vertical swiping
                    float verticalThreshold = 100; // Adjust this value as needed

                    // Check if it's a vertical swipe and exceeds a certain threshold
                    if (deltaYUp < -verticalThreshold) {
                        // Swipe up, perform dismiss animation
                        v.animate().translationYBy(-v.getHeight()).withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                onBackPressed();
                                v.setTranslationY(0); // Reset translation after dismissal
                            }
                        });
                        return true;
                    } else if (deltaYUp > verticalThreshold) {
                        // Swipe down, perform dismiss animation
                        final float translation = endYUp > startY ? v.getHeight() : -v.getHeight();
                        v.animate().translationYBy(translation).withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                onBackPressed();
                                v.setTranslationY(0); // Reset translation after dismissal
                            }
                        });
                        return true;
                    }

                    // Reset translation on other cases
                    v.animate().translationY(0);
                    break;
            }
            return false;
        }
    });
}

private void setupToolbar() {
    Toolbar toolbar = findViewById(R.id.activity_gallery_view_toolbar);
    setSupportActionBar(toolbar);

    ActionBar actionBar = getSupportActionBar();
    if (actionBar != null) {
        actionBar.setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setTitle("");
    }
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

DepthPageTransformer(深度页面转换器)

public class DepthPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.75f;

public void transformPage(View view, float position) {
    int pageWidth = view.getWidth();

    if (position < -1) {
        view.setAlpha(0f);
    } else if (position <= 0) {
        view.setAlpha(1f);
        view.setTranslationX(0f);
        view.setScaleX(1f);
        view.setScaleY(1f);
    } else if (position <= 1) {
        view.setAlpha(1 - position);
        view.setTranslationX(pageWidth * -position);

        float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
        view.setScaleX(scaleFactor);
        view.setScaleY(scaleFactor);
    } else {
        view.setAlpha(0f);
    }
}

ImagePager适配器

public class ImagePagerAdapter extends PagerAdapter {
private Context mContext;
private HashMap<Integer, Bitmap> mImages;
private ArrayList<Uri> mImageUris;
private static final String TAG = ImagePagerAdapter.class.getSimpleName();

public ImagePagerAdapter(Context context, ArrayList<Uri> imageUris) {
    mContext = context;
    mImageUris = imageUris;
    Log.d(TAG, "mImageUris: " + mImageUris);
    mImages = new HashMap<>(imageUris.size());
    if(imageUris.size() > 0) {
        notifyDataSetChanged();
    }
}

@Override
public int getCount() {
    return mImageUris.size();
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    //Log.d(TAG, "instantiating position: " + position);
    LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    final View itemView = inflater.inflate(R.layout.image_pager_item, container, false);
    Glide.with(mContext)
            .asBitmap()
            .load(mImageUris.get(position))
            .into(new CustomTarget<Bitmap>() {
                @Override
                public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
                    // Add the loaded image to the list
                    mImages.put(position, resource);
                    ImageView imageView = itemView.findViewById(R.id.imageView);
                    imageView.setImageBitmap(mImages.get(position));

                    container.addView(itemView);
                    //Log.d(TAG, "added image: " + position);
                }

                @Override
                public void onLoadCleared(@Nullable Drawable placeholder) {
                    // Handle the case when the resource is cleared (e.g., due to recycling)
                    //imagesLoaded.getAndIncrement(); // Increment the count in this case
                }

            });

    return itemView;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
}

@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
    return view == object;
}

public void updateData(ArrayList<Uri> imageUris) {
    mImageUris = imageUris;
    notifyDataSetChanged();
}
android-viewpager 图像查看 android-adapter android-transitions

评论


答:

-1赞 Rob 11/19/2023 #1

我认为您在 Transformation 类中的计算有问题

这是MIN_SCALE可能会弄乱你的整个 cacluculations

    public class DepthPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;

    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();

        if (position < -1) {
            view.setAlpha(0f);
        } else if (position <= 0) {
            view.setAlpha(1f);
            view.setTranslationX(0f);
            view.setScaleX(1f);
            view.setScaleY(1f);
        } else if (position <= 1) {
            view.setAlpha(1 - position);
            view.setTranslationX(pageWidth * -position);
            // actually this is can really make your image jumping
            float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); 
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
        } else {
            view.setAlpha(0f);
        }
     }

尝试使用这个

public class DepthTransformation implements ViewPager.PageTransformer{
@Override
public void transformPage(View page, float position) {

    if (position < -1){    // [-Infinity,-1)
        // This page is way off-screen to the left.
        page.setAlpha(0);

    }
    else if (position <= 0){    // [-1,0]
        page.setAlpha(1);
        page.setTranslationX(0);
        page.setScaleX(1);
        page.setScaleY(1);

    }
    else if (position <= 1){    // (0,1]
        page.setTranslationX(-position*page.getWidth());
        page.setAlpha(1-Math.abs(position));
        page.setScaleX(1-Math.abs(position));
        page.setScaleY(1-Math.abs(position));

    }
    else {    // (1,+Infinity]
        // This page is way off-screen to the right.
        page.setAlpha(0);

    }
}

}

评论

0赞 Elfie 11/21/2023
转换还可以,并且完美无缺。问题出在 onTouch 方法的某个地方,它使垂直滑动成为可能。如果我不将 DepthTransformation 绑定到 imagepager,抖动仍然存在
0赞 Rob 11/21/2023
理解。可能是您正在使用导致抖动的大图像?我还注意到,您仅在加载图像时才添加视图寻呼机的子视图 - 也许您应该在调用图像加载乐趣之前尝试添加它们,然后加载图像 - 对于未加载图像的情况,您可以显示一些占位符(或者可能删除尝试加载图像的子视图?
0赞 Elfie 11/22/2023
图像只有 512x512
0赞 Rob 11/23/2023
尝试在发送图像加载请求之前将视图添加到寻呼机 - 然后请求图像,您创建项目的方式似乎不正常