이렇게 하시면 됩니다. CommentItem 이 하는 일을 들여다 보는 액티비티가 하는 일과 아주 비슷합니다. 레이아웃을 inflate하고 이걸 뷰트리에 붙여넣고, 필요한 유저 interaction 을 처리하는 거죠. 기존 CommentItem은 건드리지 마시고 다음과 같이 생성된 CommentItem을 관리하는 코드를 넣으시면 됩니다.
item_comment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/comment_edit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:imeOptions="actionNext"
android:inputType="text"
android:maxLength="22"
android:singleLine="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Hello World!" />
<ImageButton
android:id="@+id/delete_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_menu_delete" />
</LinearLayout>
public class Comment {
private int id;
private String content;
public Comment(int id, String content) {
this.id = id;
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Comment comment = (Comment) o;
return id == comment.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
public class CommentItem {
interface Listener {
void onCommentChanged(CommentItem item);
void onEnterPressed(CommentItem item);
void onDeleteClicked(CommentItem item);
}
@Nullable
private CommentItem.Listener listener;
private EditText commentEdit;
private ImageButton deleteBtn;
private final View rootView;
private int commentId;
public CommentItem(@NonNull LayoutInflater layoutInflater, @Nullable ViewGroup parent) {
rootView = layoutInflater.inflate(R.layout.item_comment, parent, false);
initView();
}
private void initView() {
commentEdit = this.findViewById(R.id.comment_edit);
commentEdit.setSingleLine(true);
commentEdit.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_NEXT) {
if (listener != null) {
listener.onEnterPressed(this);
return true;
}
}
return false;
});
commentEdit.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (listener != null) {
listener.onCommentChanged(CommentItem.this);
}
}
});
deleteBtn = this.findViewById(R.id.delete_button);
deleteBtn.setOnClickListener(v -> {
if (listener != null) {
listener.onDeleteClicked(this);
}
});
}
public void addListener(CommentItem.Listener listener) {
this.listener = listener;
}
public void removeListener() {
this.listener = null;
}
public void setFocus() {
commentEdit.requestFocus();
}
public int getCommentId() {
return commentId;
}
public void setCommentId(int id) {
this.commentId = id;
}
public String getText() {
return commentEdit.getText().toString();
}
public void setText(String text) {
commentEdit.setText(text);
}
public Comment toComment() {
return new Comment(commentId, getText());
}
public View getRootView() {
return rootView;
}
private Context getContext() {
return rootView.getContext();
}
private <T extends View> T findViewById(@IdRes int id) {
return rootView.findViewById(id);
}
public static CommentItem newCommentItem(LayoutInflater layoutInflater, ViewGroup parent, int id, CommentItem.Listener listener) {
CommentItem commentItem = new CommentItem(layoutInflater, parent);
commentItem.setCommentId(id);
commentItem.setFocus();
commentItem.addListener(listener);
return commentItem;
}
}
//MainActivity
public class AppCompatActivity implements CommentItem.Listener {
private LinearLayout commentContainer;
private final View rootView;
private final LayoutInflater layoutInflater;
private final List<Comment> comments = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindViews();
addComment();
}
private void bindViews() {
commentContainer = findViewById(R.id.comment_container);
}
@Override
public void onCommentChanged(CommentItem item) {
for (Comment comment : comments) {
if (comment.getId() == item.getCommentId()) {
comment.setContent(item.getText());
}
}
}
@Override
public void onEnterPressed(CommentItem item) {
if (comments.size() >= 5) {
return;
}
addComment();
}
@Override
public void onDeleteClicked(CommentItem item) {
Comment toBeDeleted = item.toComment();
comments.remove(toBeDeleted);
updateUi();
}
private void addComment() {
Comment comment = new Comment(comments.size(), "");
comments.add(comment);
updateUi();
}
private void updateUi() {
commentContainer.removeAllViews();
for (Comment comment : comments) {
CommentItem commentItem = CommentItem.newCommentItem(layoutInflater, null, comment.getId(), this);
commentItem.setText(comment.getContent());
commentItem.addListener(this);
commentContainer.addView(commentItem.getRootView());
}
}
}
커스텀 컴포넌트를 쓴다던지, CommentItem에 Comment instance를 포함한다던지 다양한 구현방법이 있을 수 있습니다. 짧은 시간 안에 테스트 했기 때문에, 데이터와 뷰를 어떻게 분리했는지에 포커스를 두시고, 제 코드를 그냥 복사 붙여넣기 하지는 마시기를 권장드립니다. 키 포인트는 Comment가 실제 데이터를 포함하고 있고 List<Comment>를 통해 뷰를 관리하는다는 점입니다.