어제는 PopupWindow를 통해 main이 되는 View 에 말풍선처럼 popup을 띄우는 방식을 살펴보았다. 그런데 기존 App.들에서는 안내 메시지 창 자체가 따로 위에 뜨는 느낌이었던 터라 뭐 다른게 있나 싶어 찾아봤더니, AlertDialog를 사용한 것이었다. 이번엔 AlertDialog.builder를 통해 메시지 창을 만들어 동작시켜 보자.

1. 목적 : AlertDialog 의 사용법을 익히고 App.에 적용해 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Android Developers - AlertDialog Reference (http://developer.android.com/reference/android/app/AlertDialog.html)
 2) 남시언의 문화지식탐험 - AlertDialog 생성 예제 (http://namsieon.com/313)

4. 과정
 1) 어제와 같이 AlertDialog를 띄울 ImageButton와 return 여부를 확인할 TextView를 activity_main.xml 에 생성한다. AlertDialog에서 돌아왔을 때 return 여부를 보여주기 위해서 TextView의 text는 비워둔다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <ImageButton
        android:id="@+id/imgbtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="15dp"
        android:src="@mipmap/ic_launcher"/>
    <TextView
        android:id="@+id/returnval"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/imgbtn"/>
</RelativeLayout>

 

 2) App.의 전체적인 activity를 구성하는 MainActivity.java에 위의 ImageButton과 연결할 변수를 생성 및 연결하고, 해당 Button을 Click하면 AlertDialog 가 나타나도록 다음과 같이 설계한다.

public class MainActivity extends AppCompatActivity {

    public ImageButton imgBtn;
    public TextView returnVal;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imgBtn = (ImageButton)findViewById(R.id.imgbtn); // ImageButton의 activity 내 생성 및 연결
        returnVal = (TextView)findViewById(R.id.returnval);
        imgBtn.setOnClickListener(new View.OnClickListener() { // ImageButton을 Click시 AlertDialog가 생성되도록 아래과 같이 설계
            @Override
            public void onClick(View v) {
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); // AlertDialog를 띄울 activity를 argument로 지정해야 한다.
                builder.setTitle("앱을 종료하시겠습니까?"); // AlertDialog.builder를 통해 Title text를 입력
                builder.setPositiveButton("네", new DialogInterface.OnClickListener() { // AlertDialog.Builder에 Positive Button을 생성
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish(); // App.의 종료. Activity 생애 주기 참고
                    }
                });
                builder.setNegativeButton("아니오", new DialogInterface.OnClickListener() { // AlertDialog.Builder에 Negative Button을 생성
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        returnVal.setText("앱을 종료하지 않고 돌아왔음");
                        dialog.dismiss(); // "아니오" button이 받은 DialogInterface를 dismiss 하여 MainView로 돌아감
                    }
                });
                AlertDialog dialog = builder.create(); // 위의 builder를 생성할 AlertDialog 객체 생성
                dialog.show(); // dialog를 화면에 뿌려 줌
            }
        });
    }
}

(위의 code 실행 결과)

   

  

 

  앞서 기본 ListView code를 보다가 Adapter를 잘 이용하면 사용자의 입맛에 맞는 ListView layout을 적용하여 Custom ListView를 생성할 수 있지 않을까 싶었다. 실제로 검색해보니 많은 분들이 CustomListView를 구성하여 활용하였고, 그 방법 또한 구체적으로 설명을 하고 있었다. 이제 나도 Customizing을 해 봐야지.



[사진 1] Android Studio에서 해당 App의 External Libraries 중 Android API로 주어진 자료들을 뒤져보면 앞서 Adapter에 적용된 'simple_list_view_1.xml'을 사진과 같이 찾을 수 있었다. 이를 통해서 Custom ListView를 만들려면 ListView에 대한 .xml 작성이 필요할 것이라는 추측이 들었다.


1. 목적 : 기본 ListView를 customizing하여 사용해 보자.

2. 개발 환경
 - PC : Windows 7, Android Studio 1.4.1(64-bit)
 - Phone : LG G pro Lollipop(API 21)

3. 참고자료
 1) Using lists in Android (ListView) - Tutorial (http://www.vogella.com/tutorials/AndroidListView/article.html)
 2) berabue 블로그 - ListView의 사용 및 Customizing (http://berabue.blogspot.kr/2014/05/android-listview.html)
 3) 미르의 IT 정복기 (http://itmir.tistory.com/477)

4. 과정
 1) 원하는 모양의 ListView Layout을 만들기 위해 listview_custom.xml을 다음과 같이 만든다. 필요에 따라 TextView를 추가하고 그림(ImageView)를 빼는 등 사용자의 입맛에 맞게 제작하면 된다. 나는 ImageView 1개와 TextView 2개를 다음과 같이 구성하였다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:padding="10dp">

    <ImageView
        android:id="@+id/listview_pic01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:src="@mipmap/ic_launcher"/>
    <TableLayout
        android:id="@+id/text_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/listview_pic01"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:padding="5dp">
        <TableRow>
            <TextView
                android:id="@+id/listview_text01"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_toRightOf="@id/listview_pic01"
                android:padding="2dp"
                android:text="Text01" />
            </TableRow>
        <TableRow>
            <TextView
                android:id="@+id/listview_text02"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:padding="2dp"
                android:text="Text02"/>
        </TableRow>
    </TableLayout>

</RelativeLayout>

 

 

 

 

 

[사진 2] Custom ListView의 Layout으로 TextView  2개와 ImageView 1개로 위 사진과 같이 구성하려 한다.

 2) Layout을 Customizing했으면 해당 Layout을 받을 ListViewAdapter도 Customizing한다. BaseAdapter를 받아 필수 요소는 아래와 같이 Override하는데, 특히 해당 위치를 보여주는 getView() 같은 경우에는 미리 Custom ListView의 요소를 Holder하여 값을 받도록 지정한다.


public class CustomListViewAdapter extends BaseAdapter {
    // CustomListView의 원소를 각각 배열(Array)로 보관할 ArrayList.
   // 현재 Code에서는 선언만 했을 뿐 사용하지 않았다. 제작자의 기호에 따라 고치면 되겠다.

    private ArrayList<ImageView> m_ListPic;
    private ArrayList<String> m_List01;
    private ArrayList<String> m_List02;

    // CustomListView의 ImageView와 TextView들을 묶어서 Array로 보관할 ArrayList와 자료를 받을 Context, adapter 선언
    private Context mContext = null;
    public ArrayList<CustomListData> mListData = new ArrayList<CustomListData>();
    private CustomListViewAdapter mAdapter = this;

    public CustomListViewAdapter(Context mContext) { // CustomListViewAdapter 생성자
        super();
        this.mContext = mContext;
    }

    @Override
    public int getCount() { // List에 속한 원소의 갯수 count method
        return mListData.size();
    }

    @Override
    public Object getItem(int position) { // CustomListView의 position 위치에 있는 Item을 반환
        return mListData.get(position);
    }

    @Override
    public long getItemId(int position) { // CustomListView의 Item의 position을 반환
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) { // CustomListView를 목록으로 보여줌
        CustomListViewHolder holder; // 이전에 정의한 CustomListView의 원소에 맞춘 Holder를 선언
        if (convertView == null) { // 아직 CustomListView의 구성이 반영되지 않은 경우, 다음과 같이 listview_custom.xml을 반영
            holder = new CustomListViewHolder();

            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.listview_custom, null);

            holder.mListPicHolder = (ImageView) convertView.findViewById(R.id.listview_pic01);
            holder.mListText01Holder = (TextView) convertView.findViewById(R.id.listview_text01);
            holder.mListText02Holder = (TextView) convertView.findViewById(R.id.listview_text02);
            convertView.setTag(holder);
        }else{ // convertView에 구성이 이미 반영되어 있으면(null이 아니면) holder에 연결
            holder = (CustomListViewHolder) convertView.getTag();
        }

        CustomListData mData = mListData.get(position); // 위와 같이 layout 연결 후, position에 ListData를 받아와 
        if (mData.mListPic != null) { // ImageView에 입력될 data가 있을 경우 반영하고
            holder.mListPicHolder.setVisibility(View.VISIBLE);
            holder.mListPicHolder.setImageDrawable(mData.mListPic);
        }else{
            holder.mListPicHolder.setVisibility(View.GONE);
        }

        // holder에 text도 각각 반영. 필요에 따라 위와 같이 mText01/mText02 == null 여부를 따져 반영할 수 있다.
        holder.mListText01Holder.setText(mData.mText01);
        holder.mListText02Holder.setText(mData.mTest02);

        return convertView;
    }

    public void addItem(Drawable icon, String mTitle, String mDate){ // 필수 method는 아니나 ListView에 item을 반영하기 위해 필요
        CustomListData addInfo = null;
        addInfo = new CustomListData();
        addInfo.mListPic = icon;
        addInfo.mText01 = mTitle;
        addInfo.mTest02 = mDate;

        mListData.add(addInfo); // 앞에서 선언한 CustomListData를 받아 ArrayList에 통째로 add
    }

    public void remove(int position){ // 해당 position의 값을 제거하는 method
        mListData.remove(position);
        dataChange();
    }
    public void dataChange(){ // 위 remove(int position) method에서 CustomAdapter에 변경사항이 반영되도록 하는 method
        mAdapter.notifyDataSetChanged();
    }
}

public class CustomListData {
    /* CustomListView가 담을 객체에 대한 Class 생성 */
    // ImageView에 상응
    public Drawable mListPic;
    // TextView01에 상응
    public String mText01;
    // TextView02에 상응
    public String mTest02;
}
public class CustomListViewHolder {
    / * CustomListView의 구성요소에 대한 Holder 생성 */
    // Drawable을 받을 ImageView
    public ImageView mListPicHolder;
    // String mText01을 받을 TextView
    public TextView mListText01Holder;
    // String mText02를 받을 TextView
    public TextView mListText02Holder;
}

 3) 마지막으로 CustomListView를 App에 반영한다. 여기서는 MainActivity.java에 다음과 같이 사용하였다.


public class
MainActivity extends AppCompatActivity {

    public ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView)findViewById(R.id.listview); // 이전에 activity_main.xml에 선언되어 있던 ListView와 연결
        final CustomListViewAdapter mAdapter = new CustomListViewAdapter(this);
        listView.setAdapter(mAdapter);

        // CustomListViewAdapter의 addItem() method를 통해 Item 추가
        mAdapter.addItem(getResources().getDrawable(R.mipmap.apple), "과일", "사과");
        mAdapter.addItem(getResources().getDrawable(R.mipmap.pair), "과일", "배");
        mAdapter.addItem(getResources().getDrawable(R.mipmap.potato), "채소", "감자");
        mAdapter.addItem(getResources().getDrawable(R.mipmap.pumpkin), "채소", "호박");
        mAdapter.addItem(getResources().getDrawable(R.mipmap.onion), "채소", "양파");

        // CustomListView의 Item을 누를 경우 Toast를  출력하도록 작성
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
            @Override
            public void onItemClick(AdapterView<?> parent, final View view, int position, long id){
                CustomListData mData = mAdapter.mListData.get(position);
                Toast.makeText(getApplicationContext(), mData.mText01+" "+mData.mTest02+" is selected!", Toast.LENGTH_SHORT).show();
            }
        });
    }
}


(위 Code의 실행 결과)

     

 

+ Recent posts