gpt4 book ai didi

java - 膨胀 View 并调用scrollBy时 ScrollView 闪烁

转载 作者:太空宇宙 更新时间:2023-11-04 10:57:33 25 4
gpt4 key购买 nike

我正在开发一个 Android 应用程序,其中的 Activity 在 ScrollView 中显示内容。内容顶部有一个用于显示图像的占位符。该图像是从 Internet 下载的,可能需要几秒钟才能显示。图像占位符最初是空的。下载图像后,它会动态添加到占位符中。

最初我遇到了以下问题。

  • 用户启动 Activity 并向下滚动
  • 图像开始在后台下载。如果可用,它会添加到占位符
  • 将图像添加到占位符时, ScrollView 的内容会发生变化,并且用户体验会因发生不必要的滚动而中断

为了解决这个问题,我添加了代码,以便在将 ImageView 添加到占位符后调整滚动位置。这样做的问题是,在显示图像和调整 ScrollView 过程中, ScrollView 会出现闪烁。原因是scrollBy 函数是从可运行对象中调用的。在可运行对象之外调用scrollBy不会导致闪烁,但滚动位置不正确 - 原因是 ScrollView 上的项目没有足够的时间来重新计算/测量其尺寸/高度。

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

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>

关于如何解决这个问题有什么想法吗?

最佳答案

编辑:目前,您的布局正在闪烁,因为添加蓝色 View 会导致重绘布局(和滚动)。所以滚动发生了一次,接下来你滚动到你想要的位置。这是第二次搬家。

要解决这个问题,你需要知道android是如何绘制view的。 https://developer.android.com/guide/topics/ui/how-android-draws.html

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

https://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener.html

ps:我还是推荐使用漂亮可爱的图片库,Picasso。

固定代码是:在调用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。 http://square.github.io/picasso/

这一行将解决您的所有问题。

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

您可以将本地镜像文件或网络图像(url)加载到您的imageView中。


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

修复了displayImage():

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);
Picasso.with(this).load(imageFilename).into(img);

adjustScrolling(container);
}


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

  1. 不要调整滚动条。看来使用 scrollBy 来解决您的问题并不是真正的解决方案。真正的原因是导致 UI 重绘的代码。可能正在调用 invalidate() 或类似的东西。

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

  3. 看来将 ImageView 添加到 imageContainer 是真正的问题。 imageContainer 有 android:layout_height="wrap_content" 属性,这意味着它没有固定的高度,它取决于它自己的子容器。尝试更改为固定值,例如:android:layout_height="500dp"

关于java - 膨胀 View 并调用scrollBy时 ScrollView 闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47224536/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com