强制gridview绘制所有图块

And*_*son 5 android android-gridview

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

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

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

谢谢.

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

再次编辑:这只发生在gridview的高度大于屏幕的高度时 - y轴上屏幕外的子项只是从子计数中减去 - 将子项的大小设置为一个数字紧贴在屏幕上可以消除问题,但会破坏滚动的目的.

码!

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>
Run Code Online (Sandbox Code Playgroud)

活动:

public class GameBoardActivity extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gameboard);

        GameGrid Board = (GameGrid)findViewById(R.id.board);
        Board.setAdapter(new TileAdapter(this));
    }
}
Run Code Online (Sandbox Code Playgroud)

GameGrid:

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));

    }
Run Code Online (Sandbox Code Playgroud)

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

滚动(你之前帮助过我的)

if (myState == TOUCH_STATE_SCROLLING) {
                    final int deltaX = (int) (mLastX - x);
                    final int deltaY = (int) (mLastY - y);
                    mLastX = x;
                    mLastY = y;

                    int xpos = this.getScrollX();
                    int ypos = this.getScrollY();

                    int maxX = (columnwidth * 15) - super.getWidth();
                    int maxY = (columnwidth * 15) - super.getHeight();

                    if (xpos + deltaX >= 0 && xpos + deltaX <= maxX && ypos + deltaY >= 0 && ypos + deltaY <= maxY )
                    {
                        this.scrollBy(deltaX, deltaY);
                    }
                    else {
                        this.scrollTo(xpos + deltaX <= 0 ? 0 : xpos + deltaX >= maxX ? maxX : xpos + deltaX,
                                      ypos + deltaY <= 0 ? 0 : ypos + deltaY >= maxY ? maxY : ypos + deltaY);
                    }
                    Common.DebugMessage(this.getChildCount());

                }
Run Code Online (Sandbox Code Playgroud)

Common.DebugMessage只是一个帮助方法,用于将调试消息打印到LogCat

TileAdapter:

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;
    }
Run Code Online (Sandbox Code Playgroud)

Fuz*_*gic 5

安德烈亚斯,

如果您的问题只是一个onDraw()问题.你可以很容易地Draw(canvas)在你的过程中被覆盖GridView.这会产生在加载Activity时增加处理器要求的副作用,但可以创建所需的效果.这种覆盖如下:

 //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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

附加技术(编辑)

有时压倒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();
    }
}
Run Code Online (Sandbox Code Playgroud)

必须要理解的是,这种技术可能不会在您需要时强制抽取,而只是让操作系统知道它可以在可用时重新绘制.因为失效不会自动级联View树,如果你的ImageViews嵌套深度超过GridView你必须调整.这可以与draw()独立使用或独立使用.此外,与适当放置invalidate()语句一起使用时,可能会降低响应但应有助于保持图像的绘制.

问题可能只是延迟布局或绘制问题.如果是这种情况,延迟加载解决方案可能是最好的.延迟加载器是一种在需要时加载内容的方法,因此它通常使用较少的内存和处理,并在需要时显示所需内容.现在我在Lazy Loading上并不是很棒,因为我很少有需要.但是这个站点有一个很好的代码示例.它也是为GridView量身定制的.

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

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

有了这种问题,了解图像的生命周期如何工作变得很重要.如果您的图像缩小到缩略图大小以便显示,我会考虑在全尺寸图像旁边制作真正的缩略图.因为在运行时缩小图像暂时需要比保持原始大小更多的内存.由于这一切都是一次性发生,这可能是一个暂时的问题,永久地展现出来.这将大大降低内存需求.(例如,2x2图像需要16个字节加上标题,而4x4图像需要64个字节加上标题[400%,大小加倍!!].)

此外,将System.gc()添加到代码中的关键位置将强制进行垃圾回收,从而更频繁地释放更多内存.(这不是释放内存的保证,但比不使用更常见).

最佳解决方案可能是所有三种解决方案的组合,但需要的信息比我们对此问题的信息要多一些.例如,我们需要看到,如果你已覆盖draw()onMeasure()onLayout(),也许一些其他细节.


hac*_*bod 4

老实说,我的建议是停止以显然不适合使用的方式对平台 API 进行攻击。即使通过一些扭曲,您设法使用基本 GridView 代码玩了足够多的游戏,使其完成您想做的事情...您对您的代码将继续与 GridView 实现作为平台的细微更改一起工作有多大信心?进化。

事实上,根本没有必要玩这类游戏。GridView 没有什么特别的——它只是一个视图的实现,将内容放入可以水平滚动的网格中?

如果 GridView 的行为不是您想要的,解决方案是编写您自己的视图来执行您想要的操作。对于 Android,这甚至更容易,因为您可以直接从开源平台获取 GridView 代码作为基础,在您的应用程序中进行编译(您可能需要调整一些东西,因为现有的代码需要不需要纯粹针对 SDK 编写,所以可能不是......但它所做的一切都是您在针对 SDK 的常规应用程序构建中不能做的),然后在您的应用程序中修改该代码随心所欲,让它做你想做的事。无需与实际上无法执行您想要的操作的内置小部件进行斗争。如果将来底层 GridView 实现发生变化,您不必担心精心构建的纸牌屋会倒塌。