3

Я создаю календарное представление, и я хочу создать фон для LineairLayout, который является clickabe.Ninepatch Drawable with ColorFilter

Поэтому я создаю StateListDrawable с двумя изображениями:

  1. Изображение для фона
  2. Изображение когда деталь была нажата

Пока что работает с этим куском кода :

NinePatchDrawable background = (NinePatchDrawable) context.getResources().getDrawable(R.drawable.calendar_item); 
    Drawable backgroundFocus = context.getResources().getDrawable(R.drawable.calendar_focus); 

    int stateFocused = android.R.attr.state_focused; 
    int statePressed = android.R.attr.state_pressed; 

    StateListDrawable sld = new StateListDrawable(); 
    sld.addState(new int[]{ stateFocused, statePressed}, backgroundFocus); 
    sld.addState(new int[]{-stateFocused, statePressed}, backgroundFocus); 
    sld.addState(new int[]{-stateFocused}, background); 
    return sld; 

Но я хотел бы сделать что-то дополнительное. Я хотел бы, чтобы пользователь мог передать цвет, который он хочет использовать для отображения фона. Таким образом, фон var должен быть переменным, но он должен быть основан на использовании девяти патчей.

Так я думал, что я мог бы просто сделать что-то вроде этого:

background.setColorFilter(Color.RED, PorterDuff.Mode.DST_IN); 

Где Color.RED должны быть заменены цветом выбора пользователя.

Но это, похоже, не работает. Девять патчей создаются отлично, но без примененного цветного флиптера.

Я также попробовал другие PoterDuff.Mode «s:

  • SRC
  • SRC_ATOP
  • DST_IN
  • ...

Если у вас есть какие-либо понятия, что я делая что-то неправильно или что я мог бы сделать еще, чтобы решить мою проблему, пожалуйста, дайте мне знать! :-)

Kr,

Dirk

+0

Статуэтки AFAIK удаляют все цветные фильтры, прикрепленные к чертежам. Таким образом, проблема, возможно, не в части 9patch, возможно, это сборщик статей. Не могли бы вы протестировать, чтобы удалить стат-лист, применить цветной фильтр к выноски и дать обратную связь? – chuck258

ответ

2

Я не думаю, что вы можете назначить ColorFilters для каждого Drawable в StateListDrawable. Причина: ColorFilter будет удален/заменен при изменении состояния StateListDrawable. Чтобы увидеть это в действии, изменить порядок заявлений, что:

background.setColorFilter(Color.RED, PorterDuff.Mode.DST_IN); 

приходит после создания StateListDrawable. Вы увидите, что применяется ColorFilter IS. Но, как только состояние изменится (нажмите, затем отпустите), ColorFilter больше не существует.

StateListDrawables позволяет установить ColorFilter: StateListDrawable#setColorFilter(ColorFilter).Это как используется входящий в комплект поставки (или ноль) ColorFilter:

StateListDrawable # onStateChange (ИНТ []):

@Override 
protected boolean onStateChange(int[] stateSet) { 
    .... 
    if (selectDrawable(idx)) { // DrawableContainer#selectDrawable(int) 
     return true; 
    } 
    .... 
} 

DrawableContainer # selectDrawable (интермедиат):

public boolean selectDrawable(int idx) { 
    .... 
    if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { 
     Drawable d = mDrawableContainerState.mDrawables[idx]; 
     mCurrDrawable = d; 
     mCurIndex = idx; 

     if (d != null) { 
      .... 

      // So, at this stage, any ColorFilter you might have supplied 
      // to `d` will be replaced by the ColorFilter you 
      // supplied to the StateListDrawable, or `null` 
      // if you didn't supply any.     
      d.setColorFilter(mColorFilter); 

      .... 
     } 
    } else { 
     .... 
    } 
} 

Обходное решение:

Если это вообще возможно, используйте визуализацию ImageView (match_parent для измерений). Установите StateListDrawable, который вы создали в качестве фона ImageView. Создайте еще один StateListDrawable для наложения:

StateListDrawable sldOverlay = new StateListDrawable(); 

// Match Colors with states (and ultimately, Drawables) 
sldOverlay.addState(new int[] { statePressed }, 
         new ColorDrawable(Color.TRANSPARENT)); 

sldOverlay.addState(new int[] { -statePressed }, 
         new ColorDrawable(Color.parseColor("#50000000"))); 

// Drawable that you already have 
iv1.setBackground(sld); 

// Drawable that you just created 
iv1.setImageDrawable(sldOverlay); 

Другая возможность: использовать FrameLayout вместо LinearLayout. LinearLayouts не имеют свойства переднего плана.

// StateListDrawable 
frameLayout.setBackground(sld); 

// For tint 
frameLayout.setForeground(sldOverlay); 

Это связано с чрезмерным использованием, что делает его субоптимальным решением/обходным решением. Возможно, вы можете посмотреть расширение StateListDrawable и DrawableContainer. И поскольку вы не используете ColorFilter для StateListDrawable, вы можете удалить d.setColorFilter(mColorFilter); с переопределенного DrawableContainer#selectDrawable(int).

+0

Хммм ... Мне придется обдумать это. Хотя я не являюсь первоначальным вопросом о вопросе, он аккуратно охватывает сценарий, который я представил в чате чата в офисе и нашел интересным. Возможность выбрать цвет во время выполнения, чтобы применить к девяти патчам, в значительной степени требует «ColorFilter» AFAIK, хотя я далек от эксперта в этом уголке Android. 'StateListDrawable' состоит в том, что во многих случаях этот девятипакет будет применен к тому, что должно быть элементом, который можно использовать для кликов. Спасибо за вход! – CommonsWare

+0

@CommonsWare '... этот 9-патч будет применен к чему-то, что должно быть кликабельным элементом'. Это немного удивительно, что' StateListDrawable' реализован таким образом. 'ColorFilters' для отдельных Drawables, переданных в качестве дополнительного аргумента в' StateListDrawable # addState() ', предложили бы больше контроля/выбора. Или, нулевая проверка перед установкой/переписыванием ColorFilter для отдельных Drawables с помощью набора ColorFilter _on_ сама 'StateListDrawable' тоже работала бы. Ну, может быть, надо, «расширять» ... – Vikram