안드로이드에서 제공하는 Layout은 ViewGroup의 subclass이다.
이 장에서는 그 중에서 일반적으로 사용되는 Layout Object를 살펴보기로 한다.

FrameLayout
  Framelayout은 Layout의 가장 간단한 타입이다. 기본적으로 single object로 채워질 수 있는 screen의 blank space 이다.
FlameLayout의 모든 child view는 screen의 좌측상단(0,0)에 고정되며 child view의 위치를 지정할 수 없다.

LinearLayout
  LinearLayout은 모든 child view를 단일방향으로 배치한다. - vertically or horizontally(XML의 orientation attribute 참조)
LinearLayout의 모든 child view는 순차적으로 stack되어 있어서 vertical인 경우 device의 width와 관계없이 row별로 하나의 child를 가진다. (horizontal일 경우도 유사함)
LinearLayout은 child view 사이의 margin과 각 chile view의 gravity(right, center or left)를 중요시 한다.
또한 개별 child view에 weight를 배정하도록 할 수있는데, 이는 parent view의 남은 공간을 채울 수 있는지에 대한 attribute로 중요한 값이다.
weight의 이해를 돕기 위해 아래 그림을 설명한다.

위의 그림에서 좌측은 Name과 Comments의 weight가 없는 상태이고, 우측은 Comments에 weight가 주어진 경우이다. weight가 없는 경우 default로 0이 된다.
혹시 layout과 관련된 부분을 정확히 읽었다면 button은 wrap_content로 설정되어있고, 다른 text box는 fill_parent로 되어있을 거라고 짐작할 것이다.

TableLayout
  TableLayout은 child view를 row와 column으로 포지셔닝한다. 단 border line을 출력하지 않고 cell에 대한 span을 지원하지 않는다.

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:stretchColumns="1">
    <TableRow>
        <TextView
            android:layout_column="1"
            android:text="Open..."
            android:padding="3dip" />
        <TextView
            android:text="Ctrl-O"
            android:gravity="right"
            android:padding="3dip" />
    </TableRow>
    <TableRow>
        <TextView
            android:layout_column="1"
            android:text="Save..."
            android:padding="3dip" />
        <TextView
            android:text="Ctrl-S"
            android:gravity="right"
            android:padding="3dip" />
    </TableRow>
</TableLayout>

RelativeLayout
  RelativeLayout은 chiled view에게 parent view나 서로간의 상대적인 position을 설정할 수 있도록 한다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/blue"
                android:padding="10px" >

    <TextView android:id="@+id/label"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:text="Type here:" />

    <EditText android:id="@+id/entry"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:background="@android:drawable/editbox_background"
              android:layout_below="@id/label" />
 
    <Button android:id="@+id/ok"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/entry"
            android:layout_alignParentRight="true"
            android:layout_marginLeft="10px"
            android:text="OK" />

    <Button android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@id/ok"
            android:layout_alignTop="@id/ok"
            android:text="Cancel" />
</RelativeLayout>



Summary of Important View Groups

Class Description
FrameLayout Layout that acts as a view frame to display a single object.
Gallery A horizontal scrolling display of images, from a bound list.
GridView Displays a scrolling grid of m columns and n rows.
LinearLayout A layout that organizes its children into a single horizontal or vertical row. It creates a scrollbar if the length of the window exceeds the length of the screen.
ListView Displays a scrolling single column list.
RelativeLayout Enables you to specify the location of child objects relative to each other (child A to the left of child B) or to the parent (aligned to the top of the parent).
ScrollView A vertically scrolling column of elements.
Spinner Displays a single item at a time from a bound list, inside a one-row textbox. Rather like a one-row listbox that can scroll either horizontally or vertically.
SurfaceView Provides direct access to a dedicated drawing surface. It can hold child views layered on top of the surface, but is intended for applications that need to draw pixels, rather than using widgets.
TabHost Provides a tab selection list that monitors clicks and enables the application to change the screen whenever a tab is clicked.
TableLayout A tabular layout with an arbitrary number of rows and columns, each cell holding the widget of your choice. The rows resize to fit the largest column. The cell borders are not visible.
ViewFlipper A list that displays one item at a time, inside a one-row textbox. It can be set to swap items at timed intervals, like a slide show.
ViewSwitcher Same as ViewFlipper.





Posted by 피의복수

Adapterview는 몇가지 타입의 데이터를 bind하는 Adapter에 의해 Child View가 결정되는 ViewGroup의 subclass이다.
이는 저장된 data(resource나 drawable이 아닌)를 layout에 출력할때 유용하게 사용된다.
AdapterView의 subclass는 Gallery, ListView 및 Spinner 등이 있으며, 이들은 특정 타입의 데이터를 bind하고 특정 방법으로 그것들을 출력하는데 사용된다.
AdapterView는 두가지의 기능을 가지고 있다.

Filling the layout woth data
  Layout에 데이터를 삽입하는 방식은 외부 소스로부터 데이터를 조회하는 Adapter를 AdapterView에 bind함을로써 가능하다.
// Get a Spinner and bind it to an ArrayAdapter that
// references a String array.
Spinner s1 = (Spinner) findViewById(R.id.spinner1);
ArrayAdapter adapter = ArrayAdapter.createFromResource(
    this, R.array.colors, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s1.setAdapter(adapter);

Handling user selections
AdapterView.OnItemClickListner member에 listner를 설정하고 selection의 변화를 catch함으로써 사용자의 선택을 다룰 수 있다.
// Create a message handling object as an anonymous class.
private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View v, int position, long id)
    {
        // Display a messagebox.
        Toast.makeText(mContext,"You've got an event",Toast.LENGTH_SHORT).show();
    }
};

// Now hook into our object and set its onItemClickListener member
// to our class handler object.
mHistoryView = (ListView)findViewById(R.id.history);
mHistoryView.setOnItemClickListener(mMessageClickedHandler);



Posted by 피의복수


안드로이드는 View 또는 ViewGroup의 subclass를 제공하여 사용자 UI를 구성할 수 있다.
하지만 사용자의 요구에 맞는 Component가 없을 경우 View subclass를 생성할 수 있는데, 기존의 widget이나 layout을 약간만 수정하여 생성이 가능하다. 

다음은 사용자 정의 Component를 생성하는 방법과 스 사용법에 대해 정리한다.

The Basic Approach
사용자가 정의하는 Component를 생성하기 위한 기본적인 접근은 아래와 같다.
1. 기존 View class 또는 subclass를 상속한다.
2. superclass의 method 중 필요한 것을 override한다. (override하는 metod는 onDraw(), onKeyDown() 등 'on'으로 시작하는 method 이다.)
3. Extension class를 사용한다.
Tip: Extension class는 사용하려는 Activitiy의 inner class로 정의될 수 있으며, 이렇게 함으로써 접근에 대한 제어를 할 수 있다.

Fully Customized Components
Fully customized component를 생성하기 위해서
1. View class를 상속한다.
2. XML 에서 정의된 attribute와 parameter를 가질수 있는 생성자를 제공할 수 있고, 그러한 attribute와 parameter를 소비할 수도 있다.
3. 자신만의 event listner, property 접근자 및 수정자 그리고 component내에서의 좀 더 정교한 작업을 생성할 수 있다.
4. 화면의 출력과 관련된 Component를 만든다면 onMeasure와 onDraw와 같은 method를 override한다.
5. 필요에 따라서 다른 'on...' method를 override하면 된다.

View에서 Framework이 호출하는 표준 method 는 다음과 같다.

Category Methods Description
Creation Constructors There is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file.
onFinishInflate() Called after a view and all of its children has been inflated from XML.
Layout onMeasure(int, int) Called to determine the size requirements for this view and all of its children.
onLayout(boolean, int, int, int, int) Called when this view should assign a size and position to all of its children.
onSizeChanged(int, int, int, int) Called when the size of this view has changed.
Drawing onDraw(Canvas) Called when the view should render its content.
Event processing onKeyDown(int, KeyEvent) Called when a new key event occurs.
onKeyUp(int, KeyEvent) Called when a key up event occurs.
onTrackballEvent(MotionEvent) Called when a trackball motion event occurs.
onTouchEvent(MotionEvent) Called when a touch screen motion event occurs.
Focus onFocusChanged(boolean, int, Rect) Called when the view gains or loses focus.
onWindowFocusChanged(boolean) Called when the window containing the view gains or loses focus.
Attaching onAttachedToWindow() Called when the view is attached to a window.
onDetachedFromWindow() Called when the view is detached from its window.
onWindowVisibilityChanged(int) Called when the visibility of the window containing the view has changed.

Compound Controls 
Compound component를 생성하기 위해서
1. Compound Component는 layout을 상속하여 생성된다.
2. 신규 class의 생성자는 superclass가 원하는 parameter를 가지게 되며, 이를 superclass의 constructor를 통해 전달한다.
3. 사용자 View가 생성하는 event를 위한 listner를 생성할 수도 있다.
4. 접근자와 수정자로 자신만의 property를 생성할 수도 있다.
5. layout을 상속하는 경우는 onDraw()와 onMeasure() method를 override하지 않아도 된다.

Custom Control을 위해 Layout을 사용하면 여러가지의 유용한 점이 있다.
1. Activity Screen과 같이 XML을 사용하여 layout을 표현할 수 있다거나, 소스 코드내에서 View를 만들 수 있다.
2. onDraw()와 onMeasure() method를 override하지 않아도 된다.
3. 복잡한 compound view를 생성할 수 있고 만일 single component 처럼 재사용이 가능하다.

Modifying an Existing View Type
  어떠한 환경에서 유용한 custom View를 생성하기 위해서 좀 더 쉬운 방법은, 원하는 기능과 유사한 기능을 가진 Component가 있다면 이를 상속해서 원하는 부분을 override하는 것이다.
1. class 정의
2. class initialization
3. override method
4. custom component 사용




Posted by 피의복수

Application Design시 다양한 화면 및 UI elements에 적용할 Style과 Theme을 사용할 수 있다.
Style은 Layout XML에 단일 elements에 적용할 수 있는 하나 또는 그 이상의 formatting attribute의 세트이다.
Theme란 Application의 모든 Activity 또는 단일 Activity에 적용알 수 있는 하나 또는 그 이상의 formatting attribute의 세트이다.
즉 Activity에 대해서는 Theme, Activity의 element에 대해서는 Style이 적용된다고 보면 되겠다.
Style이나 Theme는 모두 resource이고 안드로이드는 기본 style과 theme를 제공한다. 하지만 사용자가 정의하는 style과 theme를 제작할 수 있다.
Style과 Theme를 만들기 위해서는
  1) res/value/style.xml을 생성한다.
  2) <style> element에 "name" attribute를 생성한다.(name은 unique해야 한다.) 또한 상속하는 style resource를 지정하기 위해 "parent" attribute를 사용할 수 있다.
  3) <style> element 하위에 <item> element를 선언한다. item element는 name attribute와 element value를 갖는다.
  4) 이렇게 정의된 style은 다른 XML resource, manifest 또는 Application source code에서 사용된다.

Style
다음은 style.xml의 예제이다.
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="SpecialText" parent="@style/Text">
        <item name="android:textSize">18sp</item>
        <item name="android:textColor">#008</item>
    </style>
</resources>

위에 정의한 style은 아래와 같이 layout XML에 사용될 수 있다.
<EditText id="@+id/text1"
          style="@style/SpecialText"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:text="Hello, World!" />

Theme
다음은 style.xml의 예제이다.
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <style name="CustomTheme">       
    <item name="android:windowNoTitle">true</item>
    <item name="windowFrame">@drawable/screen_frame</item>
    <item name="windowBackground">@drawable/screen_background_white</item>
    <item name="panelForegroundColor">#FF000000</item>
    <item name="panelBackgroundColor">#FFFFFFFF</item>
    <item name="panelTextColor">?panelForegroundColor</item>
    <item name="panelTextSize">14</item>
    <item name="menuItemTextColor">?panelTextColor</item>
    <item name="menuItemTextSize">?panelTextSize</item>
  </style>
</resources>

1. manifest에서 Theme 사용하기
  1) Application의 모든 Activity에서 Theme를 사용하려 한다면 manifest의 <application> element에 Theme를 정의한다.
<application android:theme="@style/CustomTheme">

  2) Application의 특정 Activity에서만 Theme를 사용하려고 한다면 <activity> element에 Theme를 정의한다.
<activity android:theme="@style/CustomTheme">

  3) 안드로이드가 제공하는 Theme를 사용할 수 있으며, 또한 이를 상속받아 자신만의 Theme로 만들 수 도 있다.
  안드로이드가 제공하는 Dialog Theme를 사용하는 경우
<activity android:theme="@android:style/Theme.Dialog">

위의 Theme를 상속받아 사용하는 경우 아래과 같이 정의하며, 제공되는 Theme내 item의 속성을 변경하여 사용할 수 있다.
<style name="CustomDialogTheme" parent="@android:style/Theme.Dialog">

2. Application에서 Theme 사용하기
  setTheme() method를 이용하여 Application의 Activity에서 Theme를 사용할 수 있다.
단 Context애에 View의 instance를 생성하기 전에 Theme를 설정하여야 한다.
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    setTheme(android.R.style.Theme_Light);
    setContentView(R.layout.linear_layout_3);
}

Theme는 Activity를 시작하기 위해 사용되는 Animation에는 적용되지 않기 때문에, 만일 mainscreen에 Theme를 적용하고자 한다면, 소스에서보다는 XML에서 설정하는 것이 더 바람직하다.

Posted by 피의복수

Application에서 발생하는 Event에 대해 사용자에게 알려주어야 하는 경우가 발생할 수 있다.
예를 들면,
1. 파일을 저장하는 경우 파일 저장이 완료되었을 때 사용자에게 알려주는 경우
2. Application이 background에서 실행되고 있고 사용자의 주의가 필요한 경우
3. Application이 사용자의 대기를 기다리는 일을 수행하는 경우

이러한 사용자 Notify를 구현하는 다양한 기술이 있는데 아래에서는 이러한 방법에 대해 정리를 한다.

Toast Notification
  Toast Notification은 단말 Window의 앞에 표시되는 팝업 메시지이다. 지정된 영역에 대한 메시지 처리가 되며, 현재 Application의 Activity에 대해서는 그 상태를 유지시킨다.
사용자의 Action이 없어도 화면에 나타나고 사라지게 된다.
Toast는 Activity나 Service에서 생성되고 출력되며, Service에서 생성되면 현재 화면의 Activity의 위에 출력이 되게 된다. 또한 Service에서 생성되면 Applicaiton이 invisible하더라도 화면을 표시할 수 있다. 

기본적인 Toast는 아래와 같이 생성할 수 있다.
Context context = getApplicationContext();
CharSequence text = "Hello toast!";
int duration = Toast.LENGTH_SHORT;

Toast toast = Toast.makeText(context, text, duration);
toast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0);
toast.show();


또한 사용자가 정의하는 Toast를 생성할 수도 있다.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/toast_layout_root"
              android:orientation="horizontal"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:padding="10dp"
              android:background="#DAAA"
              >
    <ImageView android:id="@+id/image"
               android:layout_width="wrap_content"
               android:layout_height="fill_parent"
               android:layout_marginRight="10dp"
               />
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="fill_parent"
              android:textColor="#FFF"
              />
</LinearLayout>

LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast_layout,
                               (ViewGroup) findViewById(R.id.toast_layout_root));

ImageView image = (ImageView) layout.findViewById(R.id.image);
image.setImageResource(R.drawable.android);
TextView text = (TextView) layout.findViewById(R.id.text);
text.setText("Hello! This is a custom toast!");

Toast toast = new Toast(getApplicationContext());
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.setDuration(Toast.LENGTH_LONG);
toast.setView(layout);
toast.show();


주의사항: 생성하려는 Toast가 setView()를 통해서 Layout을 정의하는것이 아니라면 public 생성자를 사용하면 안된다고 한다.

Status Bar Notification
  Status bar Notification은 단말 status bar에 icon 및 "Notification" window에 확장 메시지를 추가한다. (Status bar에 ticker message가 추가될 수도 있다.)
사용자가 확장 메시지를 선택하면, 안드로이드는 notification에 의해 정의된 intent를 fire(이게 뭘까? 기존 걸 죽인다는 뜻?)한다.(일반적으로 Activity를 실행한다.) Status bar Notification에는 sound, vibration 및 flashlight로 alert을 설정할 수 있다.
Status Bar Notification은 사용자의 Actin이 필요한 Event가 background Service에서 발생하는 경우에 사용된다.
결국은 Background Service가 Visible한 UI가 없기 때문에 이를 표현하기 위해 Status Bar Notification을 사용하여 사용자에게 지정된 Activity를 띄우게 끔 유도하자는데 있는 것 같다.

                                                   <Status Bar>

< expanded message in the "Notifications" window>

다음과 같은 과정으로 기본적인 Status bar Notification을 생성할 수 있다.
1. Notification 생성하기
  1) NotificationManager는 모든 Notification을 관리하는 시스템 서비스 이다. getSystemService() Method를 통해 NotificationManager를 가져온다.
  2) Status bar에 사용할 icon을 정의한다.
  3) title과 확장 message를 정의한다.
  4) Notification이 사용자에게 선택되었을 경우에 종료되는 PendingIntent를 정의한다.
  5) notification object와  setLatestEventInfo() method를 정의한다.
  6) Status Bar Notification을 보내기 위해서는 Notification Object를 생성하여 NotificationManager에 전달하면 되는데 전달하는 방법은 NotificationManager의 notify() method를 이용한다.
사용자가 Notification 을 선택하여 해당 Notification을 지워야 할 경우는 Notificaion Object에 "FLAG_AUTO_CANCEL" Flag를 사용하거나 NotificationManager의 cancel() method를 이용하며, 모든 Notification을 지울 경우는 cancelAll() method를 이용한다.

String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
int icon = R.drawable.notification_icon;
CharSequence tickerText = "Hello";
long when = System.currentTimeMillis();
Notification notification = new Notification(icon, tickerText, when);
Context context = getApplicationContext();
CharSequence contentTitle = "My notification";
CharSequence contentText = "Hello World!";
Intent notificationIntent = new Intent(this, MyClass.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

private static final int HELLO_ID = 1;
mNotificationManager.notify(HELLO_ID, notification);

2. Notification 수정하기
  각각의 Notification은 Unique ID를 가지고 있기 때문에(위 샘플의 HELLO_ID와 같은), setLatestEventInfo method를 호출하고, Notification object의 value를 변경, 그리고 notify() method를 다시 호출함으로써 기존의 notification을 변경할 수 있다.

3. Optional Settings 
  Notification에 다음과 같은 부가적인 설정을 할 수 있다.
  1) Sound
    사용자에 의해 지정된 기본 음악을 사용하는 경우

notification.defaults |= Notification.DEFAULT_SOUND;

    단말에 저장되어 있는 파일을 사용하는 경우

notification.sound = Uri.parse(file:///sdcard/notification/ringer.mp3);

    단말 내부의 MediaStore의 ContentProvider를 이용하는 경우

notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");

  2) vibration
    기본 패턴 사용하는 경우

notification.defaults |= Notification.DEFAULT_VIBRATE;

    사용자 정의 패턴 생성하는 경우

long[] vibrate = {0,100,200,300};
notification.vibrate = vibrate;

  3) flashing lights 
    기본 패턴 사용하는 경우

notification.defaults |= Notification.DEFAULT_LIGHTS;

    사용자 정의 패턴 생성하는 경우

notification.ledARGB = 0xff00ff00;
notification.ledOnMS = 300;
notification.ledOffMS = 1000;
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
 
4. 사용자 정의 확장 View
  RemoteViews Object를 사용하여 사용자 정의 expanded View를 정의할 수 있다.
  1) Layout XML을 생성한다.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:padding="3dp"
              >
    <ImageView android:id="@+id/image"
              android:layout_width="wrap_content"
              android:layout_height="fill_parent"
              android:layout_marginRight="10dp"
              />
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="fill_parent"
              android:textColor="#000"
              />
</LinearLayout>

  2) Source Code에서 생성된 RemoteViews를 Notification에 설정한다.
RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification_layout);
contentView.setImageViewResource(R.id.image, R.drawable.notification_image);
contentView.setTextViewText(R.id.text, "Hello, this message is in a custom expanded view");
notification.contentView = contentView;

  3) Notification에 사용할 Intent를 정의한다. 사용자 정의 View를 사용할 경우는 setLatestEventInfo() method 를 사용할 필요가 없다.
Intent notificationIntent = new Intent(this, MyClass.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.contentIntent = contentIntent;
mNotificationManager.notify(CUSTOM_VIEW_ID, notification);

Dialog Notification
이전에 설명한 Dialof를 참조하기 바란다.
Posted by 피의복수

BLOG main image
일에 필요한 자료 by 피의복수

카테고리

분류 전체보기 (40)
프로그램이야기 (38)
끄적끄적 (1)
취미 (0)
서비스이야기 (1)
빅데이터 (0)

최근에 올라온 글