Пользовательские шрифты и макеты XML (Android)


174

Я пытаюсь определить макет GUI, используя файлы XML в Android. Насколько я могу судить, нет никакого способа указать, что ваши виджеты должны использовать собственный шрифт (например, тот, который вы поместили в assets / font /) в XML-файлах, и вы можете использовать только системные шрифты.

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

Какие еще варианты у меня есть? Есть ли лучшие способы сделать виджеты, которые имеют индивидуальный вид? Я не хочу вручную менять шрифт для каждого нового виджета, который я добавляю.


68
DrDefrost - примите несколько ответов, вы получите больше ответов на этом сайте.
SK9

1
Вот еще один похожий вопрос: stackoverflow.com/questions/9030204/…
Vins

Обновлено 05/2017: «Бета-версия библиотеки поддержки 26.0 обеспечивает поддержку функции« Шрифты в XML »на устройствах с Android API версии 14 и выше». Смотрите: developer.android.com/preview/features/…
Альберт С

Ответы:


220

Вы можете расширить TextView для установки пользовательских шрифтов, как я узнал здесь .

TextViewPlus.java:

package com.example;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class TextViewPlus extends TextView {
    private static final String TAG = "TextView";

    public TextViewPlus(Context context) {
        super(context);
    }

    public TextViewPlus(Context context, AttributeSet attrs) {
        super(context, attrs);
        setCustomFont(context, attrs);
    }

    public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setCustomFont(context, attrs);
    }

    private void setCustomFont(Context ctx, AttributeSet attrs) {
        TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.TextViewPlus);
        String customFont = a.getString(R.styleable.TextViewPlus_customFont);
        setCustomFont(ctx, customFont);
        a.recycle();
    }

    public boolean setCustomFont(Context ctx, String asset) {
        Typeface tf = null;
        try {
        tf = Typeface.createFromAsset(ctx.getAssets(), asset);  
        } catch (Exception e) {
            Log.e(TAG, "Could not get typeface: "+e.getMessage());
            return false;
        }

        setTypeface(tf);  
        return true;
    }

}

attrs.xml: (в res / values)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TextViewPlus">
        <attr name="customFont" format="string"/>
    </declare-styleable>
</resources>

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:foo="http://schemas.android.com/apk/res/com.example"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <com.example.TextViewPlus
        android:id="@+id/textViewPlus1"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:text="@string/showingOffTheNewTypeface"
        foo:customFont="saxmono.ttf">
    </com.example.TextViewPlus>
</LinearLayout>

Вы должны поместить "saxmono.ttf" в папку ресурсов .

ОБНОВЛЕНИЕ 1/1/13

Есть серьезные проблемы с памятью с этим методом. Смотрите комментарий chedabob ниже.


5
Это выглядит хорошо, однако, я получаю ошибку, когда пытаюсь использовать «TextViewPlus» в main.xml. Я получаю следующее: - ошибка: ошибка синтаксического анализа XML: несвязанный префикс - префикс "foo" для атрибута "foo: customFont", связанного с типом элемента "supportLibs.TextViewPlus", не связан.
Маджуджи

79
Стоит отметить, что это сгенерирует десятки и десятки объектов TypeFace и израсходует память. В Android до версии 4.0 существует ошибка, которая не освобождает TypeFaces должным образом. Самое простое, что можно сделать - создать кэш TypeFace с помощью HashMap. Это привело к уменьшению использования памяти в моем приложении со 120+ МБ до 18 МБ. code.google.com/p/android/issues/detail?id=9904
chedabob

7
@Majjoodi: Обычно это происходит, если вы забыли добавить 2-е пространство имен в свой макет:xmlns:foo="http://schemas.android.com/apk/res/com.example
Тео

11
ОЧЕНЬ ВАЖНО - я бы хотел вдвойне подчеркнуть совет Чедабоба. Если вы не будете следовать этому, у вас будет утечка памяти в pre-ICS. Есть несколько решений, одно из которых находится в ссылке, предоставленной chedabob, другое здесь: stackoverflow.com/questions/8057010/listview-memory-leak . Питер - обнови свой ответ - это здорово, но не завершено
Михал К

1
Как мне установить этот пользовательский атрибут в styles.xml в дополнение к другим атрибутам textview, таким как ширина и высота?
loeschg

35

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

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

Вот как будет выглядеть ваш XML-макет, когда вы его используете.

<com.mobsandgeeks.ui.TypefaceTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world"
    geekui:customTypeface="fonts/custom_font.ttf" />

Привет @ Ragunath-jawahar, как бы я импортировал библиотеку для проекта gradle? Я пытался, compile 'com.mobsandgeeks:android-typeface-textview:1.0'но это не сработало.
Айманго

1
Вам понадобится AAR, чтобы использовать его таким образом. Это еще не там. Вы можете скопировать исходные коды и создать проект библиотеки Android Studio.
Рагунат Джавахар

2
откуда доза твой geekui тег?
сефиросу

3
Из пространства имен, указанного в родительском теге -xmlns:geekui="http://schemas.android.com/apk/res-auto"
Рагунат Джавахар

1
@MuhammedRefaat, да, это так :)
Рагунат Джавахар

18

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

Класс TypeFace:

public class OpenSans {

private static OpenSans instance;
private static Typeface typeface;

public static OpenSans getInstance(Context context) {
    synchronized (OpenSans.class) {
        if (instance == null) {
            instance = new OpenSans();
            typeface = Typeface.createFromAsset(context.getResources().getAssets(), "open_sans.ttf");
        }
        return instance;
    }
}

public Typeface getTypeFace() {
    return typeface;
}
}

Пользовательский TextView:

public class NativelyCustomTextView extends TextView {

    public NativelyCustomTextView(Context context) {
        super(context);
        setTypeface(OpenSans.getInstance(context).getTypeFace());
    }

    public NativelyCustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setTypeface(OpenSans.getInstance(context).getTypeFace());
    }

    public NativelyCustomTextView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        setTypeface(OpenSans.getInstance(context).getTypeFace());
    }

}

По xml:

<com.yourpackage.views.NativelyCustomTextView
            android:id="@+id/natively_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_margin="20dp"
            android:text="@string/natively"
            android:textSize="30sp" /> 

Программный:

TextView programmaticallyTextView = (TextView) 
       findViewById(R.id.programmatically_text_view);

programmaticallyTextView.setTypeface(OpenSans.getInstance(this)
                .getTypeFace());

Кажется, работает во время выполнения, но это должно работать и в дизайнере?
Магнус Йоханссон

Конечно. Вы можете использовать как XML. @Magnus
Леонардо Кардосо

Я думаю , вы поняли, это не похоже на работу в дизайн времени (конструктор предпросмотр). (xml! = дизайнер). Он отлично работает, указанный в файле макета Xml, скомпилированном во время выполнения. В любом случае, я использую это расширение github.com/danh32/Fontify , которое работает намного лучше для моих нужд (оно поддерживает несколько стилей шрифтов, обычный, полужирный и т. Д., А также различные имена шрифтов, а также другие элементы управления помимо TextView)
Магнус Йоханссон

2
GetTypeFace создает новую гарнитуру при каждом вызове ... это отрицательно сказывается на цели синглтона. Он должен иметь статическое поле, которое устанавливается при первом вызове, и возвращает значение поля при последующих вызовах.
Стивен Пена

1
@ Чивай, ты прав! По первому вопросу это не нужно. О второй это была опечатка.
Леонардо Кардосо

13

Старый вопрос, но я уверен, что хотел бы прочитать этот ответ здесь, прежде чем я начал собственный поиск хорошего решения. Каллиграфия расширяет android:fontFamilyатрибут, добавляя поддержку пользовательских шрифтов в папке ресурсов, например:

<TextView 
  android:text="@string/hello_world"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:fontFamily="fonts/Roboto-Bold.ttf"/>

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

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(new CalligraphyContextWrapper(newBase));
}

Вы также можете указать свой собственный атрибут для замены android:fontFamily

Он также работает в темах, включая AppTheme.


8

Использование DataBinding :

@BindingAdapter({"bind:font"})
public static void setFont(TextView textView, String fontName){
 textView.setTypeface(Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + fontName));
}

В XML:

<TextView
app:font="@{`Source-Sans-Pro-Regular.ttf`}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

файл шрифта должен быть в assets/fonts/


7

Если у вас есть только одна гарнитура, которую вы хотите добавить, и вы хотите писать меньше кода, вы можете создать выделенный TextView для вашего конкретного шрифта. Смотрите код ниже.

package com.yourpackage;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;

public class FontTextView extends TextView {
    public static Typeface FONT_NAME;


    public FontTextView(Context context) {
        super(context);
        if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
        this.setTypeface(FONT_NAME);
    }
    public FontTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
        this.setTypeface(FONT_NAME);
    }
    public FontTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
        this.setTypeface(FONT_NAME);
    }
}

В main.xml теперь вы можете добавить свой textView так:

<com.yourpackage.FontTextView
    android:id="@+id/tvTimer"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="" />

сделайте это на init () и сохраните себя 3 раза тем же вызовом.
ericosg

@ericosg Я получаю эту ошибку, когда использую ваше решение android.view.InflateException: строка двоичного XML-файла # 9: ошибка надувания класса com.ascent.adwad.utils.CustomTextView
Сагар Деванга

@SagarDevanga, трудно помочь без дополнительной информации. Возможно, возьмите это как можно дальше и задайте новый вопрос.
ericosg

7

Лучший способ сделать это в предварительной версии Android O:
1.) Щелкните правой кнопкой мыши по папке res и выберите « Создать»> «Каталог ресурсов Android» . Откроется
окно «Новый каталог ресурсов».
2.) В списке Тип ресурса выберите шрифт и нажмите кнопку ОК.
3.) Добавьте файлы шрифтов в папку шрифтов . Структура папок ниже генерирует R.font.dancing_script, R.font.la_la и R.font.ba_ba.
4.) Дважды щелкните файл шрифта, чтобы просмотреть шрифты файла в редакторе.

Далее мы должны создать семейство шрифтов

1.) Щелкните правой кнопкой мыши папку шрифтов и выберите « Создать»> «Файл ресурсов шрифта» . Откроется окно «Новый файл ресурсов».
2.) Введите имя файла и нажмите кнопку ОК . Новый ресурс шрифта XML открывается в редакторе.
3.) Включите каждый файл шрифта, стиль и атрибут веса в элемент тега шрифта. Следующий XML-код иллюстрирует добавление связанных со шрифтом атрибутов в XML-код ресурса шрифта:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
    <font
    android:fontStyle="normal"
    android:fontWeight="400"
    android:font="@font/hey_regular" />
    <font
    android:fontStyle="italic"
    android:fontWeight="400"
    android:font="@font/hey_bababa" />
</font-family>

Добавление шрифтов в TextView:

   <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    **android:fontFamily="@font/ba_ba"**/>

Как из документации

Работа со шрифтами

все шаги верны.


1
Лучший ответ! Имя файла шрифта должно быть в нижнем регистре.
Дмитрий

Вы также можете создать собственный стиль, который будет применяться к вашему приложению (в файле AndroidManifest), и он будет предоставлен для ВСЕХ представлений. Например, вместо того, чтобы просто поместить его в один TextView, это не повлияет на панель инструментов.
goldenmaza

5

Расширьте TextViewи присвойте ему собственный атрибут или просто используйте атрибут android: tag, чтобы передать строку того шрифта, который вы хотите использовать. Вам нужно будет выбрать соглашение и придерживаться его, так как я помещу все свои шрифты в папку res / assets / fonts /, чтобы ваш класс TextView знал, где их найти. Затем в вашем конструкторе вы просто устанавливаете шрифт вручную после супер вызова.


4

Единственный способ использовать пользовательские шрифты - через исходный код.

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


«Просто помните, что Android работает на устройствах с очень ограниченными ресурсами» -> так становится все меньше и меньше. Четырехъядерный телефон? В самом деле??
Сэнди

9
Я бы сделал больше, чтобы показать контекст ответа tareqHs, который предшествует вашему комментарию на добрых 2 с половиной года.
SK9

Первая часть вашего ответа, возможно, была правдой, когда вы написали свой ответ в 2010 году. Последний является лишним и не имеет смысла: «Дроид был плохим, от него отказались от Google в 2012 году в пользу Робото». Отсутствие выбора в типографии в Android - недостаток, а не особенность; Начиная с 2008 года разработчики iOS имели несколько доступных шрифтов для примитивных устройств по современным стандартам.
Cosmix

Этот ответ больше не действителен.
Мартин Конечни

2

У меня мог бы быть простой ответ на вопрос без расширения TextView и реализации длинного кода.

Код:

 TextView tv = (TextView) findViewById(R.id.textview1);
    tv.setTypeface(Typeface.createFromAsset(getAssets(), "font.ttf"));

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


2

Также может быть определен в XML без создания пользовательских классов

style.xml

<style name="ionicons" parent="android:TextAppearance">
    <!-- Custom Attr-->
    <item name="fontPath">fonts/ionicons.ttf</item>
</style>

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical" >
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="@style/ionicons"
        android:text=""/>
</LinearLayout>

Небольшое замечание, потому что я просто всегда забывал, куда помещать шрифты, потому что шрифт должен быть внутри, assetsи эта папка находится на том же уровне, что resи src, в моем случае, егоassets/fonts/ionicons.ttf

Обновлено Добавлен корневой макет, потому что этот метод должен xmlns:app="http://schemas.android.com/apk/res-auto"работать

Обновление 2 Забыл о библиотеке, которую я установил прежде, под названием Каллиграфия


Это не работает для меня. Когда я пытаюсь построить это, я получаю сообщение об ошибке: Ошибка: (49, 5) Не найдено ни одного ресурса, соответствующего имени: attr 'fontPath'.
Стеф

Попробуйте добавить xmlns:app="http://schemas.android.com/apk/res-auto"в свой корневой макет, проверьте обновленный ответ также
norman784

Ошибка не в XML-файле макета, а в XML-файле стилей. Кажется, он не «знает», что такое fontPath.
Стеф

Ваше право, забыл, что у меня есть библиотека под названием
Каллигерапия

1

Ответ Питера - лучший, но его можно улучшить, используя файл styles.xml из Android, чтобы настроить шрифты для всех текстовых представлений в вашем приложении.

Мой код здесь


1

Есть два способа настройки шрифтов:

!!! мой собственный шрифт в assets / fonts / iran_sans.ttf

Способ 1: Refrection Typeface.class ||| лучший способ

вызов FontsOverride.setDefaultFont () в классе расширяет приложение, этот код приведет к изменению всех программных шрифтов, даже шрифтов Toasts

AppController.java

public class AppController extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        //Initial Font
        FontsOverride.setDefaultFont(getApplicationContext(), "MONOSPACE", "fonts/iran_sans.ttf");

    }
}

FontsOverride.java

public class FontsOverride {

    public static void setDefaultFont(Context context, String staticTypefaceFieldName, String fontAssetName) {
        final Typeface regular = Typeface.createFromAsset(context.getAssets(), fontAssetName);
        replaceFont(staticTypefaceFieldName, regular);
    }

    private static void replaceFont(String staticTypefaceFieldName, final Typeface newTypeface) {
        try {
            final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName);
            staticField.setAccessible(true);
            staticField.set(null, newTypeface);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

Способ 2: использовать setTypeface

для особого просмотра просто вызовите setTypeface (), чтобы изменить шрифт.

CTextView.java

public class CTextView extends TextView {

    public CTextView(Context context) {
        super(context);
        init(context,null);
    }

    public CTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context,attrs);
    }

    public void init(Context context, @Nullable AttributeSet attrs) {

        if (isInEditMode())
            return;

        // use setTypeface for change font this view
        setTypeface(FontUtils.getTypeface("fonts/iran_sans.ttf"));

    }
}

FontUtils.java

public class FontUtils {

    private static Hashtable<String, Typeface> fontCache = new Hashtable<>();

    public static Typeface getTypeface(String fontName) {
        Typeface tf = fontCache.get(fontName);
        if (tf == null) {
            try {
                tf = Typeface.createFromAsset(AppController.getInstance().getApplicationContext().getAssets(), fontName);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            fontCache.put(fontName, tf);
        }
        return tf;
    }

}

0

Вот учебник, в котором показано, как настроить собственный шрифт, например, описанный @peter: http://responsiveandroid.com/2012/03/15/custom-fonts-in-android-widgets.html

он также учитывает потенциальные утечки памяти, аля http://code.google.com/p/android/issues/detail?id=9904 . Также в учебнике приведен пример установки пользовательского шрифта для кнопки.


0

Вы можете легко сделать пользовательский класс textview: -

Итак, что вам нужно сделать в первую очередь, создать Custom textviewкласс с расширением AppCompatTextView.

public class CustomTextView extends AppCompatTextView {
    private int mFont = FontUtils.FONTS_NORMAL;
    boolean fontApplied;

    public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, context);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, context);
    }

    public CustomTextView(Context context) {
        super(context);
        init(null, context);
    }

    protected void init(AttributeSet attrs, Context cxt) {
        if (!fontApplied) {
            if (attrs != null) {
                mFont = attrs.getAttributeIntValue(
                        "http://schemas.android.com/apk/res-auto", "Lato-Regular.ttf",
                        -1);
            }
            Typeface typeface = getTypeface();
            int typefaceStyle = Typeface.NORMAL;
            if (typeface != null) {
                typefaceStyle = typeface.getStyle();
            }
            if (mFont > FontUtils.FONTS) {
                typefaceStyle = mFont;
            }
            FontUtils.applyFont(this, typefaceStyle);
            fontApplied = true;
        }
    }
}

Теперь каждый раз при вызове Custom text view мы получим значение int из атрибута int fontValue = attrs.getAttributeIntValue("http://schemas.android.com/apk/res-auto","Lato-Regular.ttf",-1).

Или

Мы также можем получить getTypeface () из представления, которое мы установили в нашем xml ( android:textStyle="bold|normal|italic"). Так что делай, что хочешь.

Теперь мы делаем FontUtilsдля установки любого шрифта .ttf на наш взгляд.

public class FontUtils {

    public static final int FONTS = 1;
    public static final int FONTS_NORMAL = 2;
    public static final int FONTS_BOLD = 3;
    public static final int FONTS_BOLD1 = 4;

    private static Map<String, Typeface> TYPEFACE = new HashMap<String, Typeface>();

    static Typeface getFonts(Context context, String name) {
        Typeface typeface = TYPEFACE.get(name);
        if (typeface == null) {
            typeface = Typeface.createFromAsset(context.getAssets(), name);
            TYPEFACE.put(name, typeface);
        }
        return typeface;
    }

    public static void applyFont(TextView tv, int typefaceStyle) {

        Context cxt = tv.getContext();
        Typeface typeface;

        if(typefaceStyle == Typeface.BOLD_ITALIC) {
            typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
        }else if (typefaceStyle == Typeface.BOLD || typefaceStyle == SD_FONTS_BOLD|| typefaceStyle == FONTS_BOLD1) {
            typeface = FontUtils.getFonts(cxt, "FaktPro-SemiBold.ttf");
        } else if (typefaceStyle == Typeface.ITALIC) {
            typeface = FontUtils.getFonts(cxt, "FaktPro-Thin.ttf");
        } else {
            typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
        }
        if (typeface != null) {
            tv.setTypeface(typeface);
        }
    }
}

0

Может быть полезно знать, что начиная с Android 8.0 (уровень API 26) вы можете использовать собственный шрифт в XML .

Вы можете применить собственный шрифт ко всему приложению следующим образом.

  1. Поместите шрифт в папку res/font.

  2. В res/values/styles.xmlиспользовании это в теме приложения. <style name="AppTheme" parent="{whatever you like}"> <item name="android:fontFamily">@font/myfont</item> </style>



Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.