회사는 정말 싫어욧



InputStream is = getResources().openRawResource(R.raw.flag_names);
Scanner sc = new Scanner(is,"UTF-8");
int i = 0;

while (sc.hasNextLine()) {
Item item = new Item();
item.setImageID(R.drawable.flag_afghanistan + i);
item.setFlagName(sc.nextLine());
list.add(item);
i++;
}


Scanner와 Scanner의 nextLine, hasNextLine을 이용


그냥 gson쓰자

Dependencies에서 Library 검색으로 RecyclerView 추가


ListView보다 메모리 적게 잡아먹는다고 함 :)


Adapder 만들 때는 RecyclerView.Adapter<커스텀 뷰 홀더> 를 상속받는다


public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ItemViewHolder>{

class ItemViewHolder extends RecyclerView.ViewHolder {

public ItemViewHolder(View itemView) {
super(itemView);
}
}
}

먼저 RecyclerAdapter에 extends RecyclerView.Adapder<>를 작성하고


내부에 class ItemViewHolder extends RecyclerView.ViewHolder 작성


ItemViewHolder에 Alt+Enter로 생성자 추가(안드로이드 스튜디오에서 사용)


위에 비어있는 <>안에 어뎁터클래스이름.ItemViewHolder으로 작성 후 Alt+Enter로 메소드 오버라이딩



이때 만든 ItemViewHolder 클래스가 보여질 뷰에 대한 내용이다

class ItemViewHolder extends RecyclerView.ViewHolder {

TextView textView;


public ItemViewHolder(View itemView) {
super(itemView);

textView = itemView.findViewById(R.id.tv);
}
}

recyclerView가 사용할 layout에 있는 사용할 변수를 모두 선언하여 ItemViewHolder 작성


@NonNull
@Override
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item,parent,false);

return new ItemViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {
DataDTO data = list.get(position);
String msg = data.getH() + "(" + data.getK() + "):"+data.getT();
holder.textView.setText(msg);
}

오버라이딩된 메소드에 내용 작성




---------------------------------------



Item = int ImageId, String flagName을 가지고 있음

item.xml = ImageView (id:iv), TextView (id:tv)를 가지고 있음


public class RecyclerAdapter
extends RecyclerView.Adapter<RecyclerAdapter.ItemViewHolder>{
List<Item> list;

public RecyclerAdapter(List<Item> list) {
this.list = list;
}

@NonNull
@Override
public ItemViewHolder onCreateViewHolder
(@NonNull ViewGroup parent, int viewType) {

View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item,parent,false);

return new ItemViewHolder(view);
}

@Override
public void onBindViewHolder
(@NonNull ItemViewHolder holder, int position) {

Item data = list.get(position);
holder.imageView.setImageResource(data.getImageID());
holder.textView.setText(data.getFlagName());
}

@Override
public int getItemCount() {
return list.size();
}

class ItemViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textView;

public ItemViewHolder(View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.iv);
textView = itemView.findViewById(R.id.tv);
}
}
}

주황색으로 된 부분은 만든 클래스나 만든 Layout XML 파일을 참고하여 작성하면 된다

메소드는 상속(extends)가 끝난 후 안드로이드 스튜디오의 Alt+Enter를 이용하여 메소드 오버라이딩





Adapter에 notifysetchanged 하여 데이터 추가되었음을 View가 확인할 수 있게 해야함


안그러면 데이터 추가한걸로 리스트가 안돌아감

DB에 만들어진 필드랑 1:1 대응하는 변수 + getter&setter를 가진 클래스


부르는 의미에 따라서 VO라고 하기도 하고 DTO라고 하기도 한다..



DB에 위와 같은 필드를 가진 경우 DTO클래스 작성은 아래와 같다


public class BoardFilesDTO {


private int idx;

private int ref;

private String oriName;

private String convName;


public int getIdx() {

return idx;

}

public void setIdx(int idx) {

this.idx = idx;

}

public int getRef() {

return ref;

}

public void setRef(int ref) {

this.ref = ref;

}

public String getOriName() {

return oriName;

}

public void setOriName(String oriName) {

this.oriName = oriName;

}

public String getConvName() {

return convName;

}

public void setConvName(String convName) {

this.convName = convName;

}

}


이클립스로 만들 경우 위에 변수 선언 4줄만 만들고


우클릭해서 sources/generate gatters and setters 하고 전체 선택해서 OK하면 알아서 만들어준다 (매우 편함)


그리고 기본적인 DTO는 이게 끝 ;)


필요에 따라서 DB에 없지만 service에서 쓸 변수를 선언할 수 있다 (ex: 게시글 추천수 등)

<결과><결과>

<결과>

맨 처음 보여지는 리스트 = 부모리스트(GroupList)

부모를 클릭했을 때 나오는 리스트 = 자식리스트(ChildList)



1. 읽어올 Json파일의 VO(DTO)를 만든다


public class Chunja2 {

private int idx;
private String h;
private String k;
private String t;

public class Chunja {
private int idx;
private String h;
private String k;
private String m;

** VO(DTO)는 1:1 대응하는 데이터 + getter&setter만 만들어놓은 것


2. GroupView(리스트 중 부모)의 모양을 결정하는 Layout을 만들어준다 (res/layout/group.xml)

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/parentTV1"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:text="나는 한자"
android:textSize="12pt"
android:padding="5dp"
android:layout_marginLeft="30dp"/>
<TextView
android:id="@+id/parentTV2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="나는 음"
android:textSize="11pt"
android:padding="5dp"/>
</LinearLayout>
<TextView
android:id="@+id/parentTV3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="나는 뜻"
android:textSize="9pt"
android:padding="5dp"
android:layout_marginLeft="30dp"/>


</LinearLayout>

3. ChildView(리스트 중 자식)의 모양을 결정하는 Layout을 만들어준다 (res/layout/child.xml)

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

<TextView
android:id="@+id/childTV1"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="한자"
android:textSize="12pt"
android:padding="5dp"
android:layout_marginLeft="50dp"/>
<TextView
android:id="@+id/childTV2"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:text="뜻"
android:textSize="12pt"
android:padding="5dp"
android:gravity="right"
/>

</LinearLayout>


4. 각각의 View를 만들어준다 (부모View, 자식View)

 

[부모View]

**만든 layout파일을 가져올때는 LayoutInflater를 사용한다 (Class에 LinearLayout을 상속받아야함)

inflater.inflate(R.layout.만든파일이름,this,true)를 통해 만든 layout파일에 있는 id에 접근가능해짐


[자식View]



5. ListView에 붙일 Adapter를 만들어준다 (Class에 BaseExpandableListAdapter를 상속받아야함)


public class ChunjaAdapter extends BaseExpandableListAdapter{
private Context context;
private List<Chunja2> groupList = new ArrayList<>();
private List<List<Chunja>> childList = new ArrayList<>();

부모리스트에 붙일 데이터 타입과 자식리스트에 붙일 데이터 타입을 먼저 선언


public ChunjaAdapter(Context context, List<Chunja2> groupList, List<List<Chunja>> childList) {
this.context = context;
this.groupList = groupList;
this.childList = childList;
}

생성자를 만든다


@Override
public int getGroupCount() {
return groupList.size();
}

@Override
public int getChildrenCount(int groupPosition) {
return childList.get(groupPosition).size();
}

@Override
public Object getGroup(int groupPosition) {
return groupList.get(groupPosition);
}

@Override
public Object getChild(int groupPosition, int childPosition) {
return childList.get(groupPosition).get(childPosition);
}

@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}

@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}

@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}

메소드 오버라이딩 하여 return값을 지정해준다


getGroupCount() : 부모의 size

getChildrenCount() : 자식의 size (childList의 groupPosition위치를 통해 groupPosition 번째 부모의 자식~으로 접근가능)

getGroup() : 선택된 groupPosition의 객체 반환

getChild() : 선택된 childPosition의 객체 반환 (마찬가지로 groupPosition 번째 부모의 childPosition번째 자식으로 접근)

getGroupId() : groupPosition 반환

getChildId() : childPosition 반환

hasStableIds() : 뭔지 모르겠으나 안손댐

isChildSelectable() : 리턴이 false면 clickLister 안먹혀서 return true로 지정


6. getGroupView와 getChildView를 오버라이딩 해준다



먼저 선택된 리스트의 데이터를 읽어온다

반환할 View를 만든다

화면에 보여지는 convertView가 없으면     if (convertView == null) 

new로 View를 만들어준다                        groupView = new Chunja2View(context,data)

convertView가 있으면                           else 

해당 convertView를 재사용한다                 groupView = (Chunja2View) convertView

재사용할때는 데이터세팅도 함께                groupView.setChunja(data)




7. MainActivity에서 만든 Adapter를 new하여 ExpandableListView에 setAdapter로 붙인다







Gson을 사용할 경우 Open Module Settings의 dependencies에서 gson을 미리 추가할것!!

(오른쪽의 +버튼 누르고 Library Dependency에서 gson 검색)

main.xml 에서 ExpandableListView를 만듬 (id:elv)


ExpandableListView elv;

List<Chunja2> groupList = new ArrayList<>(); // 부모
List<List<Chunja>> childList = new ArrayList<>(); // 자식

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

elv = findViewById(R.id.elv);

Gson gson = new Gson();
try {
// 부모 읽기
InputStream is = getResources().openRawResource(R.raw.chunja2);
InputStreamReader isr = new InputStreamReader(is,"UTF-8");
groupList = gson.fromJson(isr,new TypeToken<List<Chunja2>>(){}.getType());

// 자식읽기
InputStream is2 = getResources().openRawResource(R.raw.chunja);
InputStreamReader isr2 = new InputStreamReader(is2,"UTF-8");
List<Chunja> list = gson.fromJson(isr2,new TypeToken<List<Chunja>>(){}.getType());
// 4개씩 자식으로 만들기
for(int i=0;i<list.size();i+=4){
List<Chunja> list2 = new ArrayList<>();
list2.add(list.get(i));
list2.add(list.get(i+1));
list2.add(list.get(i+2));
list2.add(list.get(i+3));
childList.add(list2);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

ChunjaAdapter adapter = new ChunjaAdapter(this,groupList,childList);
elv.setAdapter(adapter);
}


InputStream의 getResources().openRawResource를 이용해 json 파일을 연다

위에서 만든 IS로 InputStreanReader를 만든다 ("UTF-8"을 붙여줘야 한글이 안깨짐)

fromJson을 이용해 파일을 읽어온다 (new TypeToken 쓰는 방법 주의)


Raw폴더의 경우 getResources().openRawResource 사용


assets 폴더의 경우 getAssets().open("chunja2.json");




단순 리소스 정보들은 res/values/*.xml 파일로 정의한다

파일 이름이 지정되어 있는 것은 아니며 xml파일 위치는 반드시 res/values 밑에 있어야 한다


1. 문자열 리소스 정보


<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">appName</string>
</resources>

!! <resources> 를 루트로 사용

!! 문자열 리소스 정의할 경우 <string>을 사용



2. 문자열 배열 리소스 정보


<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="array1">
<item>사과</item>
<item>포도</item>
<item>딸기</item>
</string-array>
</resources>

!! <string-array>를 사용하고 데이터는 <item>으로 정의


3. 색상 리소스 정보


!!<color> 사용

!!비트수 + 알파값으로 데이터 형태는 4가지


#RGB , #ARGB, #RRGGBB, #AARRGGBB


일반적으로는 #RRGGBB나 #AARRGGBB를 많이 쓰는듯 (ex: #ffdde1, #22ffdde1)


4. 크기 리소스 정보


!!<dimen> 사용

!! 크기 단위 : px,in,mm,pt,dp,sp


dp나 sp쓰는듯..


5. 이미지 리소스


탐색기에서 복사(ctrl+c) 한다음에 drawble 폴더 밑에다가 붙여넣기(ctrl+v)하고 엔터누르면 들어감

배경이미지 같은 경우 9-patch 이미지 권장

(9-patch 이미지 : 이미지 만들고 1픽셀 늘려서 늘어나도 되는 곳만 검정색으로 칠하고 파일 이름 하고 확장자 사이에 .9를 붙인다        sample.9.png    이런식으로)

draw9patch 툴로 png파일을 9-patch png로 변경도 가능한 듯 (안해봄)


6. xml 리소스

!!res/xml 경로 밑에 넣으면 됨


7. 기타 원본 리소스

res/raw 밑에 넣으면 됨


8. 디렉토리에 한정자 붙여서 지역별로 리소스 관리 가능


res/values-en : 영어 리소스

res/values-kr : 한글 리소스


ISO 639-1 언어코드 기준으로 사용하면 된다




android:windowFullscreen = 풀스크린 설정

windowNoTitle = 타이틀바 안보이기


true/false로 설정가능한듯



**버전에 따라서 android:windowNoTitle도 쓰고 그러는듯.. 쓰기전에 찾아보고 쓰자!