2011-10-15 2 views
5

У меня есть андроид gridview, в котором я использую какую-то пользовательскую прокрутку, чтобы прокручивать ее в двух измерениях - это означает, что прокрутка по умолчанию не вызывается.Force gridview, чтобы нарисовать все плитки

Я подозреваю, что это может быть причиной того, что строки, которые находятся за пределами экрана, невидимы. Я знаю, что они там, они влияют на макет и все, но они никогда не рисуют.

Таким образом, мой вопрос заключается в том, есть ли способ заставить gridview рисовать все свои плитки, когда он загружен, а не только видимые?

Спасибо.

Edit: Для того, чтобы уточнить - В моем 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> 

активность:

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

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

    } 

Вы можете заметить, я определяю маленький и большой размер здесь - двойной нажатие на экран позволяет переключаться между ними.

скроллинг (то, что вы помогли мне с ранее)

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

       } 

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; 
    } 
+0

Andreas, что-то JUST произошло у меня .... Попробуйте добавить 'myGridView.invalidate()' до конца свой 'ACTION_MOVE:' в свой 'onTouchEvent()' (после инструкции scrollBy() ....) –

+0

Я пробовал это раньше - ничего не происходит. Вызов getChildCount после этого приводит к тому же номеру (165), хотя запуск приложения на устройстве с меньшим вертикальным пространством уменьшает это число до видимых строк * 15. –

+0

Андреас, когда ваша награда закончится, я буду предлагать более высокий щедрость, чтобы мы могли больше смотреть на это. Таким образом, это не пропадает даром. –

ответ

4

Честно говоря, мое предложение состоит в том, чтобы прекратить удары по API платформы таким образом, чтобы оно явно не предназначалось для использования. Даже если через некоторые искажения вам удалось сыграть достаточно игр с базовым кодом GridView, чтобы сделать то, что вы хотите сделать ... насколько вы уверены, что ваш код будет продолжать работать с небольшими изменениями в реализации GridView в качестве платформы эволюционирует.

И на самом деле просто не нужно играть в эти игры. В GridView нет ничего особенного - это просто реализация представления, которое помещает вещи в сетку, которую вы можете прокручивать по горизонтали?

Если поведение GridView не то, что вы хотите, решение состоит в том, чтобы написать собственное представление, которое делает то, что вы хотите. И с Android это еще проще, потому что вы можете просто пойти и взять код GridView с платформы с открытым исходным кодом в качестве основы, получить эту компиляцию в своем приложении (вам, вероятно, придется подстроить несколько вещей, потому что код в его нынешнем виде не нужно писать только против SDK, так что, вероятно, это не так ... но есть ничего это делает то, что вы не можете сделать в обычной сборке приложений против SDK), а затем изменить этот код в ваше приложение к содержимому вашего сердца, чтобы оно делало то, что нужно. Без борьбы со встроенным виджетами, который фактически не делает то, что вы хотите. И, не опасаясь, что ваш тщательно построенный домик карт рухнет на вас, если базовая реализация GridView изменится в будущем.

+0

Я полагаю, вы правы. –

5

Andreas,

Если ваша проблема просто onDraw() вопрос. Вы можете сделать это довольно легко с переопределенным Draw(canvas) в своем GridView. Это имеет побочный эффект увеличения требований к процессору, когда ваша активность загружена, но может создать желаемый эффект. Такое переопределение будет выглядеть следующим образом:

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

Дополнительная техника (EDIT)

Иногда перекрывая 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(); 
    } 
} 

Это должно быть понятно, что этот метод не может форсировать ничью, когда вы хотите, а просто позволяет операционной системе знать, что он готов быть перерисованы, когда она доступна. Поскольку недействительность автоматически не каскадирует дерево View, если ваши ImageView s вложены глубже, чем GridView, вам придется настроить. Это может использоваться в сочетании с draw() или независимо. Кроме того, при использовании с соответствующим размещением инструкции invalidate() может снижаться ответ, но он должен помочь сохранить ваши образы.

Проблема может быть просто отсроченной макетом или проблемой ничьей. Если это так, решение Lazy Loading может быть лучше. Ленточный загрузчик - это способ загрузки содержимого, когда он необходим, так что он обычно использует меньше памяти и обрабатывает и показывает, что нужно, когда это необходимо. Теперь я не потрясающе в Lazy Loading, потому что у меня редко есть необходимость. Но есть БОЛЬШОЙ пример кода на this site. Он также предназначен для GridView.

наносящими Не применимо (но может быть полезным для других)

Единственный вид вопроса, который я думаю, что это может быть является Из выпуска памяти, не вызывая принудительное закрытие (да , они существуют). Они особенно неуловимы и болезненны, чтобы заботиться. Единственный способ определить их - в вашем LogCat во время загрузки или прокрутки с отображением ошибки. Или вы можете пройти весь дамп LogCat (я рекомендую очистить журнал до того, как вы запустите приложение в первую очередь).

С такой проблемой важно знать, как работает жизненный цикл изображения. Если ваши изображения уменьшаются до размера эскизов, чтобы отображать их, я бы подумал о создании реальных эскизов наряду с изображениями полного размера. Поскольку сокращение изображения во время выполнения временно требует большего объема памяти, чем сохранение исходного размера. Так как это происходит в одной падающей развертке, это может быть временной проблемой, проявляющейся навсегда. Это значительно снизит требования к памяти. (Например, для изображения 2x2 требуется 16 байтов плюс заголовок, тогда как для изображения 4x4 требуется 64 байта плюс заголовок [400% для двойного размера !!].)

Кроме того, добавление System.gc() к критическим местам в вашем коде, заставит сборку мусора, освобождая больше памяти, чаще. (Это не гарантия свободной памяти, но работает чаще, чем нет).

Решение BEST, вероятно, будет комбинацией всех трех, но для этого потребуется немного больше информации, чем у нас с этим вопросом. Например, нам нужно будет увидеть, были ли вы переопределены draw() и onMeasure() и onLayout() и, возможно, некоторые другие детали.

+0

Хороший человек, я попробую все ваши предложения. Я точно знаю, что проблема не исключение из памяти. Я пробовал программу на множестве устройств Android, и проблема всегда одна и та же: строки, которые не видны при первом загрузке gridview, не рисуются, неважно, сколько из них вне экрана. Я скоро приведу иллюстрации. –

+0

Что касается других вещей - я не переоценил ничью, onMeasure или onLayout.Однако я выполняю свое кодирование в подклассе GridView, а не в отношении активности, если это имеет значение. Я также просто попробовал переопределенный метод draw-method, который вы предоставили, с наименьшими интересными результатами - this.getChildCount() возвращает 165 (в соответствии с количеством детей на экране при загрузке), когда фактическое число равно 225. Также только рисует первую плитку, когда переопределяется, по какой-то причине, даже если она вызывает призыв на всех детей. –

+0

Это действительно интересно ... Он должен привлечь ВСЕ детей (без учета видового экрана). Хорошо, так что это не из памяти. Это определенно проблема рисования. Это полезно знать ... Поскольку ваш код в основном находится в вашем «GridView», мне нужно спросить ... был ли код 'draw()' в 'GridView' или' Activity'? Я спрашиваю, потому что WHERE ваша draw() может сильно повлиять на WHAT. Я был удивлен, узнав, что дочерний элемент 'View' не является недействительным, если родительский' View' похож на некоторые другие языки, например. * P.S. Я ненавижу проблемы с рисованием ... ROFL * –

0

Вместо этого я представил другой ответ, потому что после выяснения вопрос определенно отличается от того, что я изначально считал. Однако методы в предыдущем ответе не должны быть забыты и являются отличным ресурсом для других связанных с этим проблем, поэтому я держу его там.

Проблема:

Элемент GridView Теперь рисует (своего рода), но повторяет те же изображения снова и снова, в результате чего ужасные артефакты. Результирующие артефакты настолько плохи, что на самом деле не дают хорошего указания относительно того, присутствуют ли другие представления. Эта проблема на самом деле вызвана проблемой с «слишком высокой прозрачностью».

Android и прозрачность

Android делает замечательную работу обработки прозрачности, позволяя объекты ниже текущий вид, который можно сделать в то время как вид сверху находится в фокусе. Однако, если все представления прозрачны, то для Android нет ничего, что могло бы обойти все, когда нужно обновить. Обычно это не проблема.

Как правило, разработчики используют предоставленные нами инструменты и просто пытаются сделать некоторые аккуратные вещи с ними. (YAY!) И пока мы их используем, Android говорит (в значительной степени) «Я знаю, что делать!» Однако, когда мы начинаем с пользовательских представлений, Android может немного испугаться, особенно когда дело доходит до рисования.

Ваш GridView на самом деле не является GridView. Это номер GridView. В качестве расширения Android View Android не делает никаких предположений о том, как его следует рисовать, soooo .... В результате обычный непрозрачный фон для вашего GridView не существует. Казалось бы, «но у меня это в RelativeLayout. Разве этого недостаточно?» Ответ отрицательный. Объектами макета являются объекты макета. У них нет фона, если мы не укажем их.

Это усугубляется, когда вы выполняете прокрутку и другие подобные движения или анимации. В этих случаях Android пытается кэшировать. Кэширование происходит ниже всех Представлений, но в результате все прозрачно, вы видите весь процесс. И он не сбрасывается, пока не потребуется очистить кеш. Вот почему становится более уродливым и уродливым.

Другими словами, «Окно» может появиться черный, но на самом деле не черный ...

Solution (Часть I):

Таким образом, ответ должен установить непрозрачный фон для либо расширенный GridView, либо один из его родительских представлений. Это должно разрешить артефакты, которые вы видите при прокрутке. И это должно позволить вам правильно видеть, как и рендеринг других представлений. В конечном счете, вы хотите попробовать применить фон к самому верхнему представлению, которое охватывает все виды. Фон может быть таким же простым, как установка цвета фона (поскольку он создает непрозрачную вытягиваемую).

Следующие шаги:

Я заметил, что вы опустили некоторые уместную код. Мне действительно нужно знать, какой вид Adapter ваш TileAdapter расширяет и как он получает свою базовую информацию. Это может повлиять на то, как он набирает и присваивает события ничьей. Как только мы это узнаем, мы можем работать над исправлением остального.

Мне также нужно знать, как вы позиционируете плитки (код позиционирования отсутствует). Поскольку код позиционирования отсутствует, нет способа узнать, действительно ли добавляются представления. Поведение по умолчанию для ImageViews по умолчанию состоит в том, что если хотя бы часть их не видна, они не добавляются в иерархию до тех пор, пока они не будут. Мы хотим заставить этот вопрос

Конечный результат может по-прежнему требовать корректировки макета, мер или ничьих, но мы не узнаем, пока не получим точное представление о том, что происходит.

Альтернативный Результат

Что-то я хотел бы это случилось с более часто прокрутки игры, если они начали с увеличенной из положения, и мы могли бы «двигаться» к увеличенной в положении .. Это может легко разрешите свой ChildCount, как вы сказали, если он подходит аккуратно на экране, все они рисуют. И начальное масштабирование может произойти после того, как все будет загружено. Тогда у вас есть хороший графический эффект, показывающий, что загрузка завершена. Уменьшение - это просто нормальная анимация, поэтому ее легко реализовать. и вы знаете, что все ваши дети загружены. Кроме того, он может ограничить введенный вами код, чтобы он работал правильно. Наконец, все это можно сделать с помощью одного и того же объекта GameGrid. :)

Я не знаю, если бы вы подумали об этом, но я подумал: «Эй, это похоже на простой способ убить более двух птиц одним камнем».

+0

Здравствуйте, и еще раз спасибо за интерес к моей проблеме. Одна вещь, на которую я могу ответить прямо сейчас, заключается в том, что TileAdapter расширяет BaseAdapter. Начиная с сетки «вырезать» не много, я вижу всех 225 детей, но как только я увеличиваю масштаб, он возвращается к 165 детям. Как вы могли заметить, мое масштабирование на самом деле просто удваивает размер всех детей. Вы не видели никакого кода позиции, потому что его нет. Я доверял GridView для обработки этой части, потому что иначе я мог бы использовать холст или что-то в этом роде. –

+0

Awesome. Это абсолютно нормально. Мне просто нужно было знать, что происходит, если угодно, в ботне этих районов. Итак, когда вы увеличиваете масштаб, эти дети удаляются из иерархии? –

+0

Я полагаю, что раньше им было 225, а при увеличении, строки, которые не могут поместиться на экране, удаляются. –

0

переопределить getCount() вашего адаптера и вернуть длину базового массива для вашего адаптера. Затем используйте mAdapter.getCount вместо mGrid.getChildCount. getChildCount возвращает только видимых детей, тогда как getCount даст вам общее количество детей в вашем наборе данных.

Смежные вопросы