You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现服务器图片加载与SeekBar切换无闪烁平滑旋转效果?

解决Picasso切换图片时的闪烁问题,实现平滑旋转过渡

核心问题分析

你遇到的闪烁是因为Picasso默认加载新图时会先清空ImageView,直到新图完全加载完成才会显示。加上拖动SeekBar时频繁触发加载请求,缓存或网络延迟就会导致旧图消失、新图延迟出现的闪烁现象。下面是两种具体实现方案,不需要复杂动画经验就能完成。


方案1:双ImageView叠加实现无缝切换

通过两个叠加的ImageView,始终保持一个显示当前图,另一个加载新图,加载完成后再切换显示状态,完全保留旧图直到新图就绪。

步骤1:修改布局

把原来的单个ImageView替换成FrameLayout包裹两个ImageView:

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/platina1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"/>
    <ImageView
        android:id="@+id/platina2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"
        android:visibility="gone"/>
</FrameLayout>

步骤2:修改Java代码

public class FichaOpacos extends AppCompatActivity {
    private String urlParalelos;
    private ImageView currentView;
    private ImageView loadView;
    private boolean isFirstViewActive = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ficha_opacos);
        
        Intent intent = getIntent();
        String id = intent.getStringExtra("id");
        Database myDb = new Database(this);
        String mineral = myDb.getMineral(id);
        
        currentView = findViewById(R.id.platina1);
        loadView = findViewById(R.id.platina2);
        urlParalelos = myDb.getURL1(mineral);
        myDb.closeDatabase();

        // 加载初始图片
        String initialUrl = urlParalelos + "1.jpg";
        Picasso.get().load(initialUrl).into(currentView);

        SeekBar seekBar = findViewById(R.id.seek);
        seekBar.setProgress(0);
        seekBar.setMax(71);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (!fromUser) return;

                String targetUrl = urlParalelos + (progress + 1) + ".jpg";
                // 确定当前加载目标和显示视图
                ImageView targetLoadView = isFirstViewActive ? loadView : currentView;
                ImageView targetDisplayView = isFirstViewActive ? currentView : loadView;

                Picasso.get()
                        .load(targetUrl)
                        .noPlaceholder() // 禁用占位符,避免提前清空视图
                        .into(targetLoadView, new Callback() {
                            @Override
                            public void onSuccess() {
                                // 新图加载完成,切换显示状态
                                targetDisplayView.setVisibility(View.GONE);
                                targetLoadView.setVisibility(View.VISIBLE);
                                // 交换视图角色
                                isFirstViewActive = !isFirstViewActive;
                                // 可选:添加淡入动画提升平滑度
                                targetLoadView.setAlpha(0f);
                                targetLoadView.animate().alpha(1f).setDuration(100).start();
                            }

                            @Override
                            public void onError(Exception e) {
                                // 加载失败的 fallback 逻辑,比如显示错误图
                            }
                        });
            }
        });
    }
}

方案2:单ImageView + Picasso Target回调实现

不需要修改布局,通过Picasso的Target接口监听加载完成事件,在新图就绪后再替换并添加淡入动画,避免加载时清空旧图。

修改后的Java代码

public class FichaOpacos extends AppCompatActivity {
    private String urlParalelos;
    private ImageView platina;
    private int currentProgress = 0; // 避免重复加载相同进度的图片

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ficha_opacos);
        
        Intent intent = getIntent();
        String id = intent.getStringExtra("id");
        Database myDb = new Database(this);
        String mineral = myDb.getMineral(id);
        
        platina = findViewById(R.id.platina);
        urlParalelos = myDb.getURL1(mineral);
        myDb.closeDatabase();

        String initialUrl = urlParalelos + "1.jpg";
        Picasso.get().load(initialUrl).into(platina);

        SeekBar seekBar = findViewById(R.id.seek);
        seekBar.setProgress(0);
        seekBar.setMax(71);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {}

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {}

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (!fromUser || progress == currentProgress) return;

                currentProgress = progress;
                String targetUrl = urlParalelos + (progress + 1) + ".jpg";

                Picasso.get()
                        .load(targetUrl)
                        .noPlaceholder()
                        .into(new Target() {
                            @Override
                            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                                // 新图加载完成,添加淡入动画替换
                                platina.setAlpha(0f);
                                platina.setImageBitmap(bitmap);
                                platina.animate().alpha(1f).setDuration(100).start();
                            }

                            @Override
                            public void onBitmapFailed(Exception e, Drawable errorDrawable) {}

                            @Override
                            public void onPrepareLoad(Drawable placeHolderDrawable) {}
                        });
            }
        });
    }
}

额外优化:预加载相邻图片

拖动SeekBar时用户可能快速滑动,预加载当前进度前后3-5张图到缓存,能大幅提升切换流畅度:

private void preloadAdjacentImages(int currentProgress) {
    // 预加载当前进度前后3张图片
    for (int i = -3; i <= 3; i++) {
        int targetProgress = currentProgress + i;
        if (targetProgress >= 0 && targetProgress <= 71) {
            String preloadUrl = urlParalelos + (targetProgress + 1) + ".jpg";
            Picasso.get().load(preloadUrl).fetch(); // 只加载到缓存,不显示
        }
    }
}

在onProgressChanged方法的末尾调用这个方法即可。

内容的提问来源于stack exchange,提问作者user19643881

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 01:52:54