Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/231.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 打开视图并调用scrollBy时Scrollview闪烁_Java_Android_Scrollview - Fatal编程技术网

Java 打开视图并调用scrollBy时Scrollview闪烁

Java 打开视图并调用scrollBy时Scrollview闪烁,java,android,scrollview,Java,Android,Scrollview,我正在开发一个Android应用程序,其中活动在滚动视图中显示内容。在内容的顶部有一个用于显示图像的占位符。图像是从Internet下载的,可能需要几秒钟才能显示出来。图像占位符最初为空。下载图像时,图像将动态添加到占位符中 起初我有以下问题 用户启动活动并向下滚动 图像开始在后台下载。如果可用,则会将其添加到占位符中 将图像添加到占位符时,scrollview的内容会发生更改,用户体验会因出现不必要的滚动而中断 为了解决这个问题,我添加了代码,以便在图像视图添加到占位符后调整滚动位置。问题

我正在开发一个Android应用程序,其中活动在滚动视图中显示内容。在内容的顶部有一个用于显示图像的占位符。图像是从Internet下载的,可能需要几秒钟才能显示出来。图像占位符最初为空。下载图像时,图像将动态添加到占位符中

起初我有以下问题

  • 用户启动活动并向下滚动
  • 图像开始在后台下载。如果可用,则会将其添加到占位符中
  • 将图像添加到占位符时,scrollview的内容会发生更改,用户体验会因出现不必要的滚动而中断
为了解决这个问题,我添加了代码,以便在图像视图添加到占位符后调整滚动位置。问题在于,在显示图像和调整scrollview过程中,scrollview会闪烁。原因是scrollBy函数是从runnable调用的。在runnable外部调用scrollBy不会导致闪烁,但滚动位置不正确-原因是滚动视图上的项目没有足够的时间重新计算/测量其尺寸/高度

下面是一个示例应用程序,说明了此问题:

public class MainActivity extends AppCompatActivity {

    ScrollView scrollView;

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

        scrollView = findViewById(R.id.scrollview);

        startImageDownload();
        simulateImageScroll();
    }

    private void simulateImageScroll() {
        // scroll to the bottom of the scroll view
        scrollView.post(new Runnable() {
            @Override
            public void run() {
                scrollView.scrollTo(0, scrollView.getMaxScrollAmount());
            }
        });
    }

    private void startImageDownload() {
        Handler handler = new Handler(getMainLooper());
        // simulate a delay for the image download to illustrate the flashing problem in the scrollview
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                displayImage("");
            }
        }, 2000);

    }

    // when the image is downloaded we add it to the image container
    private void displayImage(String imageFilename) {
        // dynamically create an image and add it to the image container layout
        RelativeLayout container = findViewById(R.id.imageContainer);
        ImageView img = new ImageView(this);

        // image should be loaded from the given filename - for now use a solid background and fixed height
        img.setBackgroundColor(Color.BLUE);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.MATCH_PARENT, 500);
        container.addView(img, params);

        adjustScrolling(container);
    }

    private void adjustScrolling(RelativeLayout container) {
        // adjust scroll if the image is loaded before the current content
        if (scrollView.getScrollY() > container.getTop()) {
            container.measure(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            final int amountToScroll = container.getMeasuredHeight();

            // the following does not cause flickering but scrolls to the wrong position
            //scrollView.scrollBy(0, amountToScroll);

            // adjust the scrollview so that it keeps the current view unchanged
            scrollView.post(new Runnable() {
                @Override
                public void run() {
                    // this causes flickering but scrolls to the correct position
                    scrollView.scrollBy(0, amountToScroll);
                }
            });
        }
    }

}
这是布局文件:

<ScrollView
    android:id="@+id/scrollview"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <RelativeLayout
            android:id="@+id/imageContainer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:background="#aa0000" >

        </RelativeLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:background="#aa0000" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="1"
                android:textColor="#ffffff"
                android:textSize="128dp"/>
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:background="#aa0000" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="2"
                android:textColor="#ffffff"
                android:textSize="128dp"/>
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:background="#aa0000" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="3"
                android:textColor="#ffffff"
                android:textSize="128dp"/>
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:background="#aa0000" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="4"
                android:textColor="#ffffff"
                android:textSize="128dp"/>
        </RelativeLayout>

    </LinearLayout>
</ScrollView>


有关如何解决此问题的任何想法?

编辑: 当前,您的布局正在闪烁,因为添加蓝色视图会导致重新绘制布局(和滚动)。所以滚动出现一次,然后滚动到想要的位置。这是第二步

要解决这个问题,您需要知道android如何绘制视图。

简单地说,
onMeasure()
-
onLayout()
-
onDraw()
。您可以通过
ViewTreeObserver().addOnGlobalLayoutListener()
onLayout()和
onDraw()之间添加布局代码

附言:我仍然推荐使用漂亮可爱的图像库,毕加索

固定代码是:在调用
draw()之前设置滚动。这样,你只能画一次

public class MainActivity extends AppCompatActivity {

    ScrollView scrollView;
    int amountToScroll = 0;

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

        scrollView = findViewById(R.id.scrollview);
        scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                scrollView.scrollBy(0, amountToScroll);
                amountToScroll = 0;
            }
        });
        startImageDownload();
        simulateImageScroll();
    }

    private void simulateImageScroll() {
        // scroll to the bottom of the scroll view
        scrollView.post(new Runnable() {
            @Override
            public void run() {
                scrollView.scrollTo(0, scrollView.getMaxScrollAmount());
            }
        });
    }

    private void startImageDownload() {
        Handler handler = new Handler(getMainLooper());
        // simulate a delay for the image download to illustrate the flashing problem in the scrollview
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                displayImage("");
            }
        }, 2000);

    }

    // when the image is downloaded we add it to the image container
    private void displayImage(String imageFilename) {
        // dynamically create an image and add it to the image container layout
        RelativeLayout container = findViewById(R.id.imageContainer);
        ImageView img = new ImageView(this);

        // image should be loaded from the given filename - for now use a solid background and fixed height
        img.setBackgroundColor(Color.BLUE);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.MATCH_PARENT, 500);
        container.addView(img, params);

        adjustScrolling(container);
    }

    private void adjustScrolling(RelativeLayout container) {
        // adjust scroll if the image is loaded before the current content
        if (scrollView.getScrollY() > container.getTop()) {
            container.measure(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            amountToScroll = container.getMeasuredHeight();
        }
    }
}

我强烈建议使用毕加索。

这一行可以解决你所有的问题

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
您可以将本地图像文件或网络图像(url)加载到imageView中


在您的情况下,删除
startImageDownload()
simulateImageScroll()
,并在
onResume()
上调用
displayImage()

已修复displayImage():


或,如果您出于学术原因想直接解决此问题

  • 不要调整你的卷轴。使用
    scrollBy
    来解决问题似乎不是一个真正的解决方案。真正的原因是导致UI重新绘制的代码。可能正在调用
    invalidate()
    或类似的东西

  • 以编程方式添加ImageView不是一个好主意。因为您的RecyclerView或ListView的ViewHolder无法重用该视图,因此会导致性能下降。如果你能避免,就这样做。(例如,使用xml)

  • 似乎将ImageView添加到imageContainer才是真正的问题。imageContainer具有android:layout\u height=“wrap\u content”
  • 属性,这意味着它没有固定的高度,这取决于它自己的子级。尝试更改为固定值,例如:
    android:layout\u height=“500dp”


    首先,如果它是位于顶部的单个图像,那么您不必动态创建imageview,只需在XML文件中使用它,而无需相对布局。设置为默认图像。使用带有adjustViewBounds=“true”和scaleType=“fitCenter”的图像视图,则不必担心图像缩放

    <ImageView
        android:id="@id/img"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter" />
    
    
    

    您可以按照“Stanley Kou”的建议使用毕加索库加载图像。

    我的建议是使用进度条,在图像开始下载时启动进度条,并在图像加载完成后将其隐藏,然后让用户查看活动

      <ProgressBar
      android:id="@+id/indeterminateBar"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"/>
    
    
    
    有关更多详细信息,请查看-


    谢谢您的建议。不幸的是,它们不能解决问题。下载图像所需的时间并不是问题的原因——我尝试了本地图像,但问题是相同的。关于第二种解决方案,同样,它不起作用,因为图像的高度在设计时未知,因此无法手动设置。问题很明显是scrollview刷新了两次,这导致了闪烁。@user501223哦,那太糟糕了。设置ImageView的固定高度如何?您可以进行中心裁剪或缩放。这不是一个选项。我不想手动设置图像高度。无论如何,谢谢,创建一个简单的例子来重现这个问题是一个很好的方法。创建一个新的应用程序,并将应用程序和应用程序布局文件替换为我上面发布的文件。运行应用程序,它将自动滚动到底部,并在2000毫秒内加载虚拟图像-这将导致屏幕闪烁。问题是图像视图将随着图像加载而调整大小,因此将导致闪烁。我认为你需要尝试一种不同的方法。例如:a)尝试在图像加载时设置视图动画。这将不是理想的答案,但它将使用户体验更好。b) 您还可以下载图像,但在用户滚动到顶部之前,不能将其添加到容器中。如果你不想保持图像高度不变,以下是一些建议。谢谢,但这仍然不能解决问题。我所寻找的基本上是一种方法,使scrollview不更新其内容,直到
      <ProgressBar
      android:id="@+id/indeterminateBar"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"/>