앱을 만들다 보면 listview 혹인 recyclelistview 등을 사용할 일이 있다. 그런데, 그 안에 있는 item 으로 checkbox, button 등을 넣어 화면을 구성해 보면 (focus 가 도달하는 것들) listview 의 item click 이 제어되지 않고 그 안에 있는 checkbox나 button 등이 클릭 되는 현상을 보인다.
이럴 떄 어떻게 하면 listview 의 item 으로 제어를 옮길 수 있는 것인가에 대한 고민이 생긴다.
구글신에게 물어보고 찾아보는 방법이 있기는 하지만, 그럴 시간이면 간단하게...
<CheckBox
android:id="@+id/ckSendSeqNo"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="8"
android:focusable="false"
android:clickable="false" />
checkbox 나 button 에게 focus가 가지 못하게 false 처리를 해 주는 것이다. click 도 못하게 false 을 해 준다.
그리고 listview 의 setOnItemClickListener 을 이용해서
데이터 값을 조정해 주고 adapter 에서 checkbox 의 값을 설정해 주는 방식으로 처리를 해본다.
binding.listSendMessage.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int iCnt = 0 ;
for(int i=0; i < beans.size() ; i++) {
if (beans.get(i).isSelectedMsg()) iCnt++;
}
if (iCnt > 0) {
beans.get(position).setSelectedMsg(false);
adapter.notifyDataSetChanged(beans);
Toast.makeText(getContext(), iCnt +"개 이상 선택할 수 없습니다.", Toast.LENGTH_SHORT).show();
return;
}
beans.get(position).setSelectedMsg(!beans.get(position).isSelectedMsg());
adapter.notifyDataSetChanged(beans);
}
});
beans.get(position).setSelectedMsg(false); 이렇게 false 로 하던지 아니면 true 로 설정을 한 다음...
import android.content.Context;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
import com.example.smssend0823.R;
import com.example.smssend0823.databinding.DataitemBinding;
import java.util.ArrayList;
public class MsgSendAdapter extends BaseAdapter {
DataitemBinding binding ;
ArrayList<MsgTargetBean> msgTargetBeans ;
LayoutInflater inflater;
Context context ;
int nListCnt ;
public MsgSendAdapter(ArrayList<MsgTargetBean> odata, Context context) {
this.msgTargetBeans = odata ;
this.context = context ;
this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return msgTargetBeans.size();
}
@Override
public Object getItem(int position) {
return msgTargetBeans.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public void notifyDataSetChanged(ArrayList<MsgTargetBean> odata) {
this.msgTargetBeans = odata ;
nListCnt = msgTargetBeans.size();
this.notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
binding = DataitemBinding.inflate(inflater);
CustomViewHolder holder ;
if (convertView == null) {
convertView = binding.getRoot() ;
holder = new CustomViewHolder();
holder.ckSendSeqNo = binding.ckSendSeqNo ;
holder.txtSendMessage = binding.txtSendMessage ;
holder.txtReceivedPhoneNum = binding.txtReceivedPhoneNum ;
holder.txtSendTy = binding.txtSendTy ;
convertView.setTag(holder);
} else {
holder = (CustomViewHolder) convertView.getTag();
}
holder.ckSendSeqNo.setChecked(msgTargetBeans.get(position).getSelectSend());
holder.ckSendSeqNo.setText(msgTargetBeans.get(position).getSendSeqNo());
holder.txtSendMessage.setText(msgTargetBeans.get(position).getSendMessage());
holder.txtReceivedPhoneNum.setText(msgTargetBeans.get(position).getReceivePhoneNum());
if ("Y".equals(msgTargetBeans.get(position).getSendTy())) {
holder.txtSendTy.setText("전송완료");
holder.txtSendTy.setBackgroundColor(context.getColor(R.color.softBlue));
holder.txtSendTy.setTextColor(context.getColor(R.color.white));
} else {
holder.txtSendTy.setText("");
holder.txtSendTy.setBackgroundColor(context.getColor(R.color.white));
holder.txtSendTy.setTextColor(context.getColor(R.color.white));
}
return convertView;
}
public class CustomViewHolder {
CheckBox ckSendSeqNo ;
TextView txtSendTy ;
TextView txtSendMessage ;
TextView txtReceivedPhoneNum ;
}
}
holder.ckSendSeqNo.setChecked(msgTargetBeans.get(position).getSelectSend()); 처럼 실행해 주면 그것으로 끝.
adapter 을 호출하는 전체 소스는 아래와 같다.
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment;
import com.example.smssend0823.Database.DBHandler;
import com.example.smssend0823.Database.MsgTargetBean;
import com.example.smssend0823.Database.SendMessageAdapter;
import com.example.smssend0823.Database.SendMessageBean;
import com.example.smssend0823.Utils.OnBackPressedListener;
import com.example.smssend0823.databinding.FragmentMsgselectBinding;
import java.util.ArrayList;
public class MsgSelectFragment extends Fragment implements OnBackPressedListener {
private static final String TAG = "MsgSelectFragment";
private FragmentMsgselectBinding binding;
ArrayList<SendMessageBean> beans;
SendMessageAdapter adapter;
DBHandler dbHandler ;
String phoneNo ;
String message ;
private static final int PERMISSION_RQST_SEND = 101;
public static Fragment newInstance() {
MsgSelectFragment fragment = new MsgSelectFragment();
return fragment;
}
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
binding = FragmentMsgselectBinding.inflate(inflater, container, false);
return binding.getRoot();
}
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
beans = new ArrayList<>();
doDisplaySendMessage();
binding.listSendMessage.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int iCnt = 0 ;
for(int i=0; i < beans.size() ; i++) {
if (beans.get(i).isSelectedMsg()) iCnt++;
}
if (iCnt > 0) {
beans.get(position).setSelectedMsg(false);
adapter.notifyDataSetChanged(beans);
Toast.makeText(getContext(), iCnt +"개 이상 선택할 수 없습니다.", Toast.LENGTH_SHORT).show();
return;
}
beans.get(position).setSelectedMsg(!beans.get(position).isSelectedMsg());
adapter.notifyDataSetChanged(beans);
}
});
binding.btnSendMessage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = 0 ; int iCnt = 0 ;
for(int i=0; i < beans.size() ; i++) {
if (beans.get(i).isSelectedMsg()) {
position = i;
iCnt++;
break;
};
}
if (iCnt == 0) {
Toast.makeText(getContext(), "전송할 메시지를 선택하세요.", Toast.LENGTH_SHORT).show();
return;
}
message = beans.get(position).getSendMessage() ;
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("메시지 전송")
.setMessage("[" + beans.get(position).getSendMessage() + "] 로 전송할까요?")
.setPositiveButton("확인", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dbHandler = DBHandler.open(getContext());
Cursor rs = dbHandler.selectAll();
while(rs.moveToNext()) {
MsgTargetBean msgTargetBean = new MsgTargetBean();
msgTargetBean.setId(rs.getInt(rs.getColumnIndex("_id")));
msgTargetBean.setSendSeqNo(rs.getString(rs.getColumnIndex("sendSeqNo")));
msgTargetBean.setReceivePhoneNum(rs.getString(rs.getColumnIndex("receivePhoneNum")));
msgTargetBean.setSendMessage(rs.getString(rs.getColumnIndex("sendMessage")));
msgTargetBean.setSendTy(rs.getString(rs.getColumnIndex("sendTy")));
if("S".equals(msgTargetBean.getSendTy())) {
phoneNo = msgTargetBean.getReceivePhoneNum();
if (sendSMSMessage()) {
msgTargetBean.setSendTy("Y");
msgTargetBean.setSendMessage(message);
dbHandler.update(msgTargetBean);
}
}
}
dbHandler.close();
}
})
.setNegativeButton("취소", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
});
}
private void doDisplaySendMessage() {
beans.clear();
dbHandler = DBHandler.open(getContext());
Cursor rs = dbHandler.selectMsgAll();
while (rs.moveToNext()) {
SendMessageBean bean = new SendMessageBean();
bean.setSendMessage(rs.getString(rs.getColumnIndex("messageString")));
beans.add(bean);
}
adapter = new SendMessageAdapter(beans, getContext());
adapter.notifyDataSetChanged(beans);
binding.listSendMessage.setAdapter(adapter);
}
protected boolean sendSMSMessage() {
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(getContext(), "SMS 전송 권한에 대한 허가가 필요합니다.", Toast.LENGTH_SHORT).show();
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),Manifest.permission.SEND_SMS)) {
Log.e(TAG, "shouldShowRequestPermissionRationale");
}
else { ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.SEND_SMS}, PERMISSION_RQST_SEND);
Log.e(TAG, "requestPermissions");
}
} else {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNo, null, message, null, null);
Toast.makeText(getContext(), "메시지가 전송 되었습니다.",Toast.LENGTH_LONG).show();
return true ;
}
return false;
}
//Now once the permission is there or not would be checked
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_RQST_SEND: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {Toast.makeText(getContext(), "SMS 발송이 되지 않았습니다. 잠시 뒤에 다시 시도 하세요.", Toast.LENGTH_LONG).show();
return;
}
}
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
@Override
public void onBackPressed() {
getParentFragmentManager().beginTransaction()
.replace(R.id.container, MsgSendListFragment.newInstance())
.commitNow();
}
}
그럼 오늘도 즐~ 코딩...
'모바일 앱(안드로이드)' 카테고리의 다른 글
안드로이드 앱 만들기 문자 한번에 보내기는 어떻게 ? (15) | 2021.09.06 |
---|---|
안드로이드 앱 만들기 도전 5일차 구글 플레이스토어 앱 등록 (54) | 2021.09.01 |
안드로이드 앱 만들기 도전 4일차 admob 달아 보기 (4) | 2021.08.24 |
안드로이드 앱 만들기 도전 3일차 geofences 을 활용한 앱 (2) | 2021.08.21 |
안드로이드 스튜디오 의 power save mode 에 대한 이해 (2) | 2021.08.17 |