我正在开发一个Android应用程序,其中活动在滚动视图中显示内容。在内容的顶部有一个占位符,用于显示图像。图像从Internet下载,可能需要几秒钟才能显示。图像占位符最初为空。下载映像时,会将其动态添加到占位符。
最初我遇到了以下问题。
为了解决这个问题,我添加了代码,以便在将图像视图添加到占位符后调整滚动位置。这样的问题是在显示图像和调整 - 滚动视图过程期间在滚动视图上引起闪烁。原因是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>
有关如何解决此问题的任何想法?
答案 0 :(得分:0)
编辑: 目前,您的布局是闪烁的,因为添加蓝色视图会导致重绘布局(和滚动)。因此滚动发生一次,然后滚动到您想要的位置。那是第二次搬家。
要解决这个问题,你需要知道android如何绘制视图。 https://developer.android.com/guide/topics/ui/how-android-draws.html
简单地说,onMeasure()
- onLayout()
- onDraw()
。您可以在onLayout()
之间添加onDraw()
和ViewTreeObserver().addOnGlobalLayoutListener()
之间的布局代码。
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);
您可以将本地图片文件或网络图片(网址)加载到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);
}
或者,如果您想出于学术原因直接解决此问题,
请勿调整滚动条。使用scrollBy
来解决您的问题似乎不是一个真正的解决方案。真正的原因是导致UI重绘的代码。可以打电话给invalidate()
或类似的东西。
以编程方式添加ImageView并不是一个好主意。因为ListView的RecyclerView或ViewHolder无法重用视图,所以它会导致性能下降。如果你能避免它,那就去做吧。 (例如,使用xml)
似乎将ImageView添加到imageContainer是一个真正的问题。 imageContainer具有android:layout_height="wrap_content"
属性,这意味着它没有固定的高度,这取决于它自己的孩子。尝试更改为固定值,例如:android:layout_height="500dp"
答案 1 :(得分:0)
首先,如果它是顶部的单个图像,那么您不必动态创建imageview,只需在没有相对布局的XML文件中使用它。设置为默认图像。使用带有adjustViewBounds =“true”和scaleType =“fitCenter”的Image-View,您无需担心图像缩放。
<ImageView
android:id="@id/img"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter" />
您可以使用“Stanley Kou”建议的Picasso http://square.github.io/picasso/库来加载图片。
答案 2 :(得分:0)
我的建议是使用进度条,在图像开始下载时启动进度条,并在图像加载完成后隐藏它,然后让用户看到活动。
<ProgressBar
android:id="@+id/indeterminateBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
有关详情,请查看 -
https://developer.android.com/reference/android/widget/ProgressBar.html