Android 强制gridview绘制所有平铺

Android 强制gridview绘制所有平铺,android,android-gridview,Android,Android Gridview,我有一个android gridview,我正在使用一些自定义滚动,让它在两个维度上滚动-这意味着默认滚动不被调用 我怀疑这可能是屏幕外的行不可见的原因。我知道他们在那里,他们影响布局和一切,但他们从不画画 所以我的问题是,有没有办法强迫gridview在加载时绘制所有的分幅,而不仅仅是可见的分幅 谢谢 编辑:为了澄清-在我的TileDapter中,我将子计数精确设置为225。在我的gridview中,对getChildCount()的调用返回165 再次编辑:只有当gridview的高度大于屏

我有一个android gridview,我正在使用一些自定义滚动,让它在两个维度上滚动-这意味着默认滚动不被调用

我怀疑这可能是屏幕外的行不可见的原因。我知道他们在那里,他们影响布局和一切,但他们从不画画

所以我的问题是,有没有办法强迫gridview在加载时绘制所有的分幅,而不仅仅是可见的分幅

谢谢

编辑:为了澄清-在我的TileDapter中,我将子计数精确设置为225。在我的gridview中,对getChildCount()的调用返回165

再次编辑:只有当gridview的高度大于屏幕的高度时才会发生这种情况-y轴上屏幕外的子项只需从childcount中减去-将子项的大小设置为一个数字,使其与屏幕上的所有子项紧密匹配即可消除问题,但会扼杀滚动的目的

密码

活动的XML布局:

  <LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:theme="@style/Theme.Custom"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <TextView android:id="@+id/logmessage"
  android:theme="@style/Theme.Custom"
  android:layout_width="fill_parent"
  android:layout_height="25dip"
  android:text="LogMessage"/>

  <RelativeLayout android:id="@+id/boardwrap"
  android:layout_weight="1"
  android:layout_height="fill_parent"
  android:layout_width="fill_parent"
  android:gravity="center_vertical">
  <com.MyProject.GameGrid 
    android:id="@+id/board"
    android:theme="@style/Theme.Custom"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"
    android:numColumns="15"
    android:stretchMode="none"
    android:verticalSpacing="0dip"
    android:horizontalSpacing="0dip"
    android:padding="0dip"
    android:columnWidth="20dip"
    android:scrollbars="none"/>
</RelativeLayout>
<RelativeLayout 
    android:id="@+id/toolbar"
    android:layout_width="fill_parent"
    android:layout_height="60dip"
    android:background="#FFFFFFFF"/>
</LinearLayout>
游戏网格:

public GameGrid(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setNumColumns(15);

        DisplayMetrics metrics = new DisplayMetrics();
        ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
        scale = metrics.density;
        smallSize = Math.round(20 * scale);
        largeSize = Math.round(40 * scale);

        columnwidth = largeSize;
        this.setColumnWidth(columnwidth);
        Common.DebugMessage(Float.toString(columnwidth));

    }
你可能会注意到我在这里定义了一个小尺寸和一个大尺寸——双击屏幕可以在两者之间切换

滚动(您之前帮助过我的内容)

安德烈亚斯

如果您的问题只是一个
onDraw()
问题。在
GridView
中,使用覆盖的
Draw(canvas)
可以非常轻松地完成此操作。这有一个副作用,即在加载活动时增加处理器需求,但可以产生所需的效果。这种覆盖将如下所示:

 //This may be used in your GridView or Activity -- whichever provides the best result.
    public void draw(Canvas canvas)
    {   int _num = myGridView.getChildCount();
        for (int _i = _num; --_i >= 0; )
        {   View _child = (View)myGridView.getChildAt(_i);
            if (_child != null)
                _child.draw(canvas);
        }
    }
附加技术(编辑)

有时重写
draw()
会产生不利影响。我们真正想做的是在对象可用时触发对象进行绘制。以类似的方式重写
invalidate()
通常会产生影响,具体取决于问题所在。由于我们已经确定,通过重写
draw()
,我们会得到奇怪的结果,这似乎是下一步的行动

//This definitely goes in your GridView
public void invalidate()
{   int _num = myGridView.getChildCount();
    for (int _i = _num; --_i >= 0; )
    {   View _child = (View)myGridView.getChildAt(_i);
        if (_child != null)
            _child.invalidate();
    }
}
必须理解的是,这种技术可能不会在您想要的时候强制绘制,而只是让操作系统知道它已经准备好在可用时重新绘制。由于无效不会自动向下层叠
视图
树,因此如果
图像视图
嵌套的深度比
网格视图
更深,则必须进行调整。这可以与
draw()
一起使用,也可以独立使用。此外,当与
invalidate()
语句的适当位置一起使用时,可能会降低响应,但有助于保持图像的绘制

问题可能只是延迟布局或绘图问题。如果是这种情况,那么延迟加载解决方案可能是最好的。惰性加载程序是一种在需要时加载内容的方法,因此它通常使用较少的内存和处理,并在需要时显示所需内容。现在我不擅长延迟加载,因为我很少有这种需要。但在这里有一个很好的代码示例。它也是为GridView定制的

认为不适用(但可能对其他人有用)

我认为唯一的另一种问题可能是内存不足问题,它不会导致强制关闭(是的,它们确实存在)。这些都是特别难以捉摸和痛苦的照顾。在加载或滚动过程中,只有在LogCat中选择错误视图,才能发现这些错误。或者,您可以查看整个LogCat转储(我建议在您首先运行应用程序之前清除日志)

对于此类问题,了解图像的生命周期是如何工作的就变得非常重要。如果你的图像缩小到缩略图大小以便显示,我会考虑在全尺寸图像旁边制作真实的缩略图。因为在运行时临时收缩图像需要比保持原始大小更多的内存。由于这一切都发生在一个下降扫描,这可能是一个暂时的问题,表现出永久性。这将大大降低内存需求。(例如,2x2图像需要16个字节加上标题,而4x4图像需要64个字节加上标题[400%表示大小加倍!!])

此外,将System.gc()添加到代码中的关键位置将强制执行垃圾收集,从而更频繁地释放更多内存。(这并不能保证释放内存,但它的工作频率更高)


最好的解决方案可能是将这三者结合起来,但需要的信息比我们对这个问题的了解多一点。例如,我们需要查看您是否覆盖了
draw()
onMeasure()
onLayout()
以及其他一些细节。

我提交了另一个答案,因为经过澄清,这个问题肯定与我最初认为的不同。但是,不应忘记前面答案中的技巧,它们是其他相关问题的重要资源,因此我将保留在这里

问题:

GridView现在绘制(有点),但是一遍又一遍地重复相同的图像,导致可怕的伪影。结果的工件非常糟糕,以至于不能很好地指示其他视图是否存在。这个问题实际上是由一个“透明度太高”的问题引起的

安卓和透明度

Android在处理透明度方面做得很好,它允许在当前视图下绘制对象,而顶视图处于焦点位置。然而,如果所有视图都是透明的,那么当Android需要刷新时,它就没有任何东西可以隐藏在所有视图后面。通常,这不是一个问题

通常,开发人员使用我们提供的工具,并尝试使用它们来实现一些整洁的事情。(耶!)
public TileAdapter(Context c) {
        mContext = c;
    }

    @Override
    public int getCount() {
        return 225;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView imageView;
        int colWidth = ((GameGrid)parent).getColumnWidth();
        if (convertView == null) {
            imageView = new ImageView(mContext);
            imageView.setLayoutParams(new GridView.LayoutParams(colWidth , colWidth));
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageView.setPadding(0, 0, 0, 0);
        }
        else {
            imageView = (ImageView)convertView;
        }
        imageView.setImageResource(R.drawable.tile);
        return imageView;
    }
 //This may be used in your GridView or Activity -- whichever provides the best result.
    public void draw(Canvas canvas)
    {   int _num = myGridView.getChildCount();
        for (int _i = _num; --_i >= 0; )
        {   View _child = (View)myGridView.getChildAt(_i);
            if (_child != null)
                _child.draw(canvas);
        }
    }
//This definitely goes in your GridView
public void invalidate()
{   int _num = myGridView.getChildCount();
    for (int _i = _num; --_i >= 0; )
    {   View _child = (View)myGridView.getChildAt(_i);
        if (_child != null)
            _child.invalidate();
    }
}