четверг, 3 ноября 2011 г.

"Error" диалог в стиле iPhone. Только XML.

Source Code

English translation

В качестве следующего упражнения, я покажу как сделать диалог, похожий на iPhone AlertView.
Мы не будем использовать для этого какие-либо файлы с картинками. Только XML.

В действительности это не сложно. Для начала создадим define xml-drawable для кнопки:


<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item>
<shape android:shape="rectangle" >

            <corners android:radius="8dip" />

            <gradient
                android:angle="270"
                android:endColor="#FF440000"
                android:startColor="#FF990000"
                android:type="linear" />
        </shape></item>

    <item android:top="20dip">
<shape android:shape="rectangle" >

            <corners
                android:bottomLeftRadius="8dp"
                android:bottomRightRadius="8dp" />

            <solid android:color="#40000000" />
        </shape></item>

</layer-list>


Здесь у нас два слоя. Первый слой – прямоугольник с градиентом. Второй слой – прямоугольник, сдвинутый вверх на 20dip. Этот слой должен перекрывать половину первого слоя. В итоге, реальная кнопка должна быть высотой в 40dip .

Теперь определим содержимое диалога – заголовок, сообщение и кнопка OK:

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

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/alert_wrapper"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dip"
        android:layout_marginRight="20dip"
        android:gravity="center_horizontal"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/dialog_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dip"
            android:text="Header container"
            android:textColor="#ffffff"
            android:textSize="17dip"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/dialog_message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dip"
            android:gravity="center_horizontal"
            android:maxLines="5"
            android:scrollbars="vertical"
            android:text="Text container"
            android:textColor="#ffffff"
            android:textSize="15dip" />

        <LinearLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dip"
            android:layout_marginTop="10dip"
            android:gravity="center_horizontal"
            android:orientation="horizontal" >

            <Button
                android:id="@+id/ok"
                android:layout_width="fill_parent"
                android:layout_height="40dip"
                android:layout_marginBottom="10dip"
                android:layout_marginLeft="10dip"
                android:layout_marginRight="10dip"
                android:background="@drawable/iphone_style_button"
                android:text="@string/ok"
                android:textColor="@color/White"
                android:textSize="17dip"
                android:textStyle="bold" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>


И последнее - фон диалога будет определен в коде. На нужен будет "drawable" с тремя слоями – прямоугольник с белой окантовкой, прямоугольник с основным фоновым цветом и прямоугольник с глянцем.
Для того, чтобы белая окантовка была видна, в первом слое устанавливаем отступы:



// Layers array
  Drawable[] arr = new Drawable[3];

  float roundedCorner[] = new float[] { 8, 8, 8, 8, 8, 8, 8, 8 };

  // First layer - to make a border
  GradientDrawable first = new GradientDrawable();
  first.setShape(GradientDrawable.RECTANGLE);
  first.setCornerRadii(roundedCorner);
  first.setStroke(2, Color.WHITE);

  // Second layer - background
  GradientDrawable second = new GradientDrawable();
  second.setShape(GradientDrawable.RECTANGLE);
  second.setCornerRadii(roundedCorner);
  second.setColor(Color.argb(255, 127, 0, 0));

  // Third layer - for the gloss effect
  GlossDrawable third = new GlossDrawable();

  arr[0] = first;
  arr[1] = second;
  arr[2] = third;

  LayerDrawable background = new LayerDrawable(arr);





Более сложные вещи - в классе GlossDrawable. Перегружаем метод onDraw для расчета эффекта глянца.

Картинка, описывающая расчеты:



По теореме Пифагора находим стороны треугольника:

Далее, используя формулу Герона, находим площадь треугольника:



И радиус описанной окружности:


Теперь рисуем окружность чуть ниже (на 1/8 высоты прямоугольника). Центр окружности:


int centerX = (int) shape.getWidth() / 2;
  int centerY = (int) (-radius + shape.getHeight() / 2);


Прямоугольник для отрисовки окружности:

RectF rectf = new RectF(shape.getWidth() / 2 - radius,  
  shape.getHeight() / 4 - radius * 2, 
  shape.getWidth() / 2 + radius, shape.getHeight() / 4);

И, применяя градиент, получаем:


Используйте эту же технику для создания "info" и "confirm" диалогов. Все, что необходимо сделать - это поменять цвет фона и изменить лэйаут.

Спасибо за внимание.

Комментариев нет:

Отправить комментарий