Всем единообразия, или доброго времени суток!
Листая тут хабр наткнулся на статейку Подключение шрифтов в своем проекте автора mcavalon, думал подчерпнуть чего-нить интересное… Но увидев очередной TextView.setTypeface how-to, зевнул и пошел читать другую статью (rus1f1kat0r, привет кстати :)).
Так вот, несколько минут назад (на момент написания этих строк это были еще минуты, а не часы, совершенно непреднамеренно меня выдернули девушки) я выпустил HoloEverywhere 1.6.8, основной фичей этого релиза является продвинутый FontLoader, ну и еще несколько плюшек, как всегда.
Давайте сначала посмотрим на старый FontLoader и посмотрим, что он умел (точнее не умел).
// Regular font
myFontRegular = HoloFont.makeFont(R.raw.font_regular);
// Bold font
myFontBold = HoloFont.makeFont(R.raw.font_bold);
// Italic font
myFontItalic = HoloFont.makeFont(R.raw.font_italic);
// BoldItalic font
myFontBoldItalic = HoloFont.makeFont(R.raw.font_bold_italic);
// Super-puper merger
myFont = HoloFont.makeFont(myFontRegular, myFontBold, myFontItalic, myFontBoldItalic);
FontLoader.setDefaultFont(myFont);
… Все. Абсолютно никакой гибкости, никаких дополнительных шрифтов, да нихрена, если честно.
(Не, был еще вариант с FontLoader.apply(View, HoloFont), но он работал посредственно).
А теперь какие возможности предоставляет новый FontLoader:
- Нормальное разделение шрифтов по семейству (font family)
- Нормальное разделение шрифтов по стилю (bold/italic)
- Возможность добавлять свои стили (по дефолту идет normal, bold, italic, black, condensed, light, medium, thin) (не более 31го стиля, включая уже встроеные, т.е. для вас остается 24 свободных стиля (normal за стиль не считается))
- Возможность комбинировать стили в любой комбинации (извините за тавтологию). Никто не мешает сделать thin и bold стиль одновременно
- Поддержка этого всего одной строкой в xml (в том числе и для ваших шрифтов, а не встроенного roboto): android:fontFamily=«roboto-light»
- Шрифты загружаются по требованию и только один раз.
- Появились очень ленивые шрифты. Или шрифты Шрёдингера, называйте как хотите. Они вроде-бы и есть, но если их нету — краш приложения.
Это я о чем вообще: раньше для создания шрифта требовалася прямой id шрифта из res/raw (R.raw.my_font). Теперь можно просто указать строковый ресурс этого id («my_font»). Кстати, теперь все roboto шрифты, кроме regular, bold, italic и bolditalic, теперь являются ленивыми. Да, они в ядре библиотеки, но работать будут только если вы положите соответствующий им файл в res/raw. Вот хотите вы использовать Roboto Light, вот пишете вы android:fontFamily=«roboto-light», вот тырим из demo/res/raw/roboto_light.ttf и ложим его в свой проект — и все работает. - Поддержка из коробки (почти) всех TextView-based виджетов. Т.е.: Сам TextView, Button, CheckedTextView, EditText, AutoCompleteTextView, CheckBox, CompoundButton, MultiAutoCompleteTextView, RadioButton, Switch, ToggleButton. Исключение из этого списка составили совсем уж редкие виджеты: Chronometer, DigitalClock, TextClock, и ExtractEditText
- Поддержка textAppereance во всех его проявлениях.
- Оно работает вообще везде. Кроме App Widget's. ActionBar, любые сторонние библиотеки, вообще все короче.
Добавляем свой шрифт для отдельного элемента
Я возьму шрифт Toscuchet CM by Alisson Depizol. Ну и сконвертирую его в TrueType, ибо нефиг. Ложим его в res/raw/toscuchet.ttf.
Создаем MainApplication, который расширяет org.holoeverywhere.app.Application, создаем статичный блок кода (static {} добавляем т.е.) (и вообще все настройки библиотеки лучше всего делать в одном месте и именно здесь), медитируем.
Содзаем объект RawFont со ссылкой на наш ttf файл:
public class MainApplication extends Application {
private static final Font sToscuchet;
static {
sToscuchet = new RawFont(R.raw.toscuchet);
}
}
Хм, как-то мало кода. Но принцип KISS в Java неприменим, поэтому нагрохаем еще пару никому ненужных строчек.
Мы должны создать еще объект типа FontCollector, который собирает множество разрозненых шрифтов в один большой и послушный объект.
Поскольку мы хотим задать наш шрифт только для одного конкретного TextView, мы должны добавить в наш FontCollector шрифт Toscuchet и добавить стандартное семейство Roboto. Ну и заодно предоставим метаинформацию о нашем новом стиле. Вуаля:
public class MainApplication extends Application {
private static final Font sToscuchet;
private static final FontCollector sDefaultFont;
static {
sToscuchet = new RawFont(R.raw.toscuchet);
sToscuchet.setFontFamily("toscuchet");
sToscuchet.setFontStyle(FontLoader.TEXT_STYLE_NORMAL);
sDefaultFont = new FontCollector();
sDefaultFont.register(sToscuchet);
sDefaultFont.register(FontLoader.ROBOTO);
FontLoader.setDefaultFont(sDefaultFont);
}
}
Ну вот, уже культурно, а то где вы видели такие короткие блоки кода?..
Идем в нашу супер разметку, вешаем на нее android:fontFamily=«toscuchet-normal», запускаем, при этом радуемся как дети:
Шрифт по умолчанию
Самый простой способ: вызвать FontLoader.setDefaultFont(sToscuchet). Но при этом шрифты будут одинаковые вообще везде, даже там, где нужно bold или italic начертание. Не катит.
И вот тут настает небольшая проблемка: FontCollector ищет нужный шрифт исходя из пары параметров fontFamily и fontStyle. Семейство шрифтов мы уже задали (sToscuchet.setFontFamily(«toscuchet»);). Можно конечно переопределить textViewStyle и там указать нужный fontFamily, но ну его нафиг. Мы просто скажем FontCollector'y: ей, а может ты перестанешь использовать fontFamily?
sDefaultFont = new FontCollector().allowAnyFontFamily();
Ну… Можно убрать android:fontFamily из нашей разметки, собрать и запустить проект:
Теперь fontFamily игнорируется для нашего шрифта. Любой TextView без дополнительных модификаторов (т.е. fontStyle = normal) будет няшненьким.
Стили
Если у вас есть несколько начертаний шрифта (regular, bold, italic), то вы можете его собрать в один шрифт. Примерно так:
public class MainApplication extends Application {
private static final Font sToscuchetRegular, sToscuchetBold, sToscuchetItalic;
private static final FontCollector sToscuchet, sDefaultFont;
static {
sToscuchetRegular = new RawFont(R.raw.toscuchet_regular).setFontStyle(FontLoader.TEXT_STYLE_NORMAL);
sToscuchetBold = new RawFont(R.raw.toscuchet_bold).setFontStyle(FontLoader.TEXT_STYLE_BOLD);
sToscuchetItalic = new RawFont(R.raw.toscuchet_italic).setFontStyle(FontLoader.TEXT_STYLE_ITALIC);
sToscuchet = new FontCollector().allowAnyFontFamily();
sToscuchet.setFontFamily("toscuchet");
sToscuchet.register(sToscuchetRegular).asDefaultFont();
sToscuchet.register(sToscuchetBold);
sToscuchet.register(sToscuchetItalic);
sDefaultFont = new FontCollector();
sDefaultFont.register(sToscuchet).asDefaultFont();
sDefaultFont.register(FontLoader.ROBOTO);
FontLoader.setDefaultFont(sDefaultFont);
}
}
Тут появился дополнительный вызов asDefaultFont(), который означает что предыдущий шрифт надо сделать шрифтом по умолчанию. Если ничего подходящего не найдется, будет использоваться именно этот шрифт.
Т.к. bold и italic начертаний для этого шрифта нет, обойдемся без примера :)
Ну вот примерно такой FontLoader у меня вышел. Если будут вопросы — обращайтесь. В комментарии, в личку или на почту.
А, чуть не забыл. Вы так много ныли по поводу навигации в Slider'e из демки, что вся навигации из демо приложения перенесена в Slider addon в виде SliderMenu. А код главной активити демо приложения (немного упрощенный) выглядит сейчас так:
@Addons(Activity.ADDON_SLIDER)
public class DemoActivity extends Activity {
public AddonSliderA addonSlider() {
return addon(AddonSlider.class);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final SliderMenu sliderMenu = addonSlider().obtainDefaultSliderMenu();
sliderMenu.add(R.string.demo, MainFragment.class, SliderMenu.BLUE);
sliderMenu.add(R.string.settings, SettingsFragment.class, SliderMenu.GREEN);
sliderMenu.add(R.string.other, OtherFragment.class, SliderMenu.ORANGE);
sliderMenu.add(R.string.about, AboutFragment.class, SliderMenu.PURPLE);
}
}
Круто, да? Почти ничего не делая, мы получаем отличную реализацию Navigation Drawer, с поддержкой планшетов и нормальной обработкой Home/Back кнопок. SliderMenu так-же кастомизируется, дерзайте :)
Список изменений с версии 1.5.0:
- Собственно, Slider addon вместо SlidingMenu
- Уменьшен размер билиотеки за счет оптимизации png файлов
- Обновлен фон для белой темы, который изменился в API 16 (или 17, не помню)
- Исправлены цвета в options/overflow menu. Задрали, если честно. То там что-то не так, то там отвалилось после того...
- Facebook SDK аддон
- TabSwipeFragment/TawSwipeActivity. Фрагменты и активити, которые реализуют Tabs + Swipe (или без swipe, по желанию) навигацию без лишней мороки. Сохранение состояний и все такое прочее на месте
- Устранены утечки памяти в системе аддонов и _SharedPreferencesImpl_XML
- Исходные файлы для генерации тем были отрефракторены, а то там бардак был небольшой
- .DialogWhenLarge темы
- IntentCompat.createChooser для holo-like диалога с выбором приложения для продолжения
- Исправлено поведение, когда после registerForContextMenu необходимо было вызвать setLongClickable, иначе фига
- Более полная поддержка диалогов
- Полная поддержка choicemode/headerview/footerview для ListView/GridView.
- Куча, просто куча багфиксов
Репозиторий проекта, APK демо приложения
Автор: Prototik