마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

view의 setOnTouchListener가 동작하지 않습니다.

0 추천
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
            var convertView:View? = convertView
            val context = parent.context
            val aprInfo = aprList[position]
            var textAprName: TextView? = null
            var textApr: TextView? = null
            var holder: AprItemHolder? = null
            if (convertView == null) {
                val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
                convertView = inflater.inflate(R.layout.apr_item_view, parent, false)
                textAprName = convertView?.findViewById(R.id.text_apr_name) as TextView
                textApr = convertView?.findViewById(R.id.text_apr) as TextView
                holder = AprItemHolder()
                holder.textAprName = textAprName
                holder.textApr = textApr
                convertView.tag = holder
            } else {
                holder = convertView.tag as AprItemHolder
                textAprName = holder.textAprName
                textApr = holder.textApr
            }
            textAprName?.text = aprInfo.name
            textApr?.text = aprInfo.description

            convertView?.setOnTouchListener @SuppressLint("ClickableViewAccessibility"){ v, event ->
                var action: Int = MotionEventCompat.getActionMasked(event)
                when (action) {
                    MotionEvent.ACTION_UP -> {
                        StandElin.instance!!.SendApr(aprInfo.name)
                        closeDialog()
                    }
                }
                true
            }
            return convertView
}

java에서는 동작하던 프로그램입니다. 코틀린으로 변환하여 프로젝트를 진행하고 있는데 

view에 textview 두개가 있습니다. 

textAprName의 textview에 setOnTouchListener를 사용하면 동작합니다.

view에다가 걸면 동작을 안합니다.

textview 두가지 모두가 동작을 하게 하고싶습니다. ㅠㅠㅠ

 

추가로 정상적으로 동작했던 java 소스 첨부합니다.

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			Context context = parent.getContext();
			final DlgAprInfo aprInfo = aprList.get(position);
			
			TextView textAprName = null;
			TextView textApr = null;
			AprItemHolder holder = null;
			if (convertView == null) {
				LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				convertView = inflater.inflate(R.layout.apr_item_view, parent, false);

				textAprName = (TextView) convertView.findViewById(R.id.text_apr_name);
				textApr = (TextView) convertView.findViewById(R.id.text_apr);

				holder = new AprItemHolder();
				holder.textAprName = textAprName;
				holder.textApr = textApr;
				convertView.setTag(holder);
			} else {
				holder = (AprItemHolder) convertView.getTag();
				textAprName = holder.textAprName;
				textApr = holder.textApr;
			}

			textAprName.setText(aprInfo.getName());

			textApr.setText(aprInfo.getDescription());


			convertView.setOnTouchListener(new OnTouchListener() {
				@SuppressLint("ClickableViewAccessibility")
				@Override
				public boolean onTouch(View v, MotionEvent event) 
				{
					switch (event.getAction()) 
			        {
			        			        
			        case MotionEvent.ACTION_UP:
			        	
			                //Main에 전달
			                StandElin.getInstance().SendApr(aprInfo.getName());
				            closeDialog(); 
			        	
			        	break;
			        }
			        return true;
				}
			});
			return convertView;
		}
		private class AprItemHolder {
			public TextView textAprName;
			public TextView textApr;
		}
	}

 

lissom (240 포인트) 님이 2021년 1월 7일 질문
lissom님이 2021년 1월 8일 수정

2개의 답변

0 추천

원래 동작하던 자바코드도 보여주셔야 제대로 변환이 되었는지 확인이 가능할 것 같은데요.

한가지 눈에 띄는 것은 convertView란 이름이 중복되어 있는 건데요, 로컬 변수인 convertView의 이름을 바꿔서 사용하세요.

님의 코드를 아래처럼 좀 정리해 봤습니다. 테스트는 안해봤으니,  코틀린으로 어떻게 간결하고 좀 더 안전한 코드를 짤 수 있는지 참고하시기 바랍니다.

override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
         fun createHolderView(): View = LayoutInflater.from(parent.context).inflate(R.layout.apr_item_view, parent, false) 

         val holderView = convertView ?: createHolderView()

         val holder = if (holderView.tag == null) {
                AprItemHolder(holderView).also {
                    convertedView.tag = it
                }
         } else {
               holderView.tag as AprItemHolder
         }

          holder.bind(aprList[position])
          holder.setOnActionUpCallback { v, event ->
                // Do something
                true
         }

         return holderView
}

class AprItemHolder(itemView: View) {

    private val textAprName: TextView = itemView.findViewById(R.id.text_apr_name)
    private val textApr: TextView = itemView.findViewById(R.id.text_apr)

   private var actionUpCallback: ((View, Event) -> Unit)? = null

    itemView.setOnTouchListener @SuppressLint("ClickableViewAccessibility"){ v, event ->
                when (val action = MotionEventCompat.getActionMasked(event)) {
                    MotionEvent.ACTION_UP -> {
                        actionUpCallback?.invoke(v, event)
                    }
                }
                true
    }


    fun bind(aprInfo: ApriInfo) {
           textAprName.text = aprInfo.name
           textApr.text = aprInfo.description
    }

   fun setOnActionUpCallback(callback: (View, Event) -> Unit) {
          actionUpCallback = callback
   }
}

 

더 좋은 옵션은 ListView를 RecyclerView로 변환하는 거지만, 그건 프로젝트의 상황과 관련이 깊기 때문에 넘어가겠습니다.

spark (227,470 포인트) 님이 2021년 1월 7일 답변
spark님이 2021년 1월 7일 수정
답변 정말 감사드립니다. 알려주신대로 수정해봤는데 역시나 동작을 하지 않네요ㅠㅠ...

영문을 포함하여 검색하여 나오는 모든 결과의 방법은 정말 다해본것 같은데 참으로 이상하네요

동작했던 자바 소스 추가하여 원본 글 수정했습니다.
올리신 메소드에서 일어나는 문제인게 확실하신거죠? 혹 다른 메소드 문제인지 디버깅은 해보셨는지 모르겠네요.
0 추천

먼저 자바 쪽의 소스 중에 setOnTouchListener는 코드를 이해하기 쉽게 setOnClickListener로 변경해 주세요. 제가 보기에는  OnTouchListener의 역할이 OnClickListener와 같아 보이네요.

convertView.setOnClickListener(new View.SetOnClickListener) {
     @Override
      public void onClick(View view) {
            StandElin.getInstance().SendApr(aprInfo.getName());
            closeDialog(); 
      }               
});

그리고 제가  테스트 코드를 만들어서 실행해 보니 코드변환에 문제가 있는 것이 아니라 다른 부분에서 문제가 있는 것으로 보입니다. 님의 보여주신 코틀린으로 변환한 부분은 문제가 없어 보여요. 다른 부분을 체크해 보세요.

아래에 테스해 본 코드입니다. 둘다 정확하게 같은 동작을 합니다.

// Java
public class ListViewAdapter extends BaseAdapter {

    private final List<DlgAprInfo> aprList;

    public ListViewAdapter(List<DlgAprInfo> aprList) {
        this.aprList = aprList;
    }

    @Override
    public int getCount() {
        return aprList.size();
    }

    @Override
    public Object getItem(int position) {
        return aprList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Context context = parent.getContext();
        final DlgAprInfo aprInfo = aprList.get(position);

        TextView textAprName = null;
        TextView textApr = null;
        AprItemHolder holder = null;
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.apr_item_view, parent, false);

            textAprName = convertView.findViewById(R.id.text_apr_name);
            textApr = convertView.findViewById(R.id.text_apr);

            holder = new AprItemHolder();
            holder.textAprName = textAprName;
            holder.textApr = textApr;
            convertView.setTag(holder);
        } else {
            holder = (AprItemHolder) convertView.getTag();
            textAprName = holder.textAprName;
            textApr = holder.textApr;
        }

        textAprName.setText(aprInfo.getName());

        textApr.setText(aprInfo.getDescription());

        convertView.setOnClickListener(v -> {
            System.out.println("============  ItemClicked!!!");
        });
        return convertView;
    }

    private class AprItemHolder {
        public TextView textAprName;
        public TextView textApr;
    }
}


//Kotlin
class KListAdapter(private val aprList: List<DlgAprInfo>) : BaseAdapter() {

    override fun getCount(): Int = aprList.size

    override fun getItem(position: Int): DlgAprInfo = aprList[position]

    override fun getItemId(position: Int): Long = position.toLong()

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val aprInfo = getItem(position)

        val holderView = convertView ?: LayoutInflater.from(parent.context)
            .inflate(R.layout.apr_item_view, parent, false)

        val itemHolder = if (holderView.tag == null) {
            KAprItemHolder(holderView).also {
                holderView.tag = it
            }
        } else {
            holderView.tag as KAprItemHolder
        }

        itemHolder.bind(aprInfo)

        holderView.setOnClickListener {
            println("========== ItemClicked!!!")
        }

        return holderView
    }
}

data class KAprItemHolder(val itemView: View) {

    private val textAprName: TextView = itemView.findViewById(R.id.text_apr_name)
    private val textApr: TextView = itemView.findViewById(R.id.text_apr)

    fun bind(aprInfo: DlgAprInfo) {
        textAprName.text = aprInfo.name
        textApr.text = aprInfo.description
    }
}

따라서, 다른 부분을 체크해 보세요. 그리고 코틀린으로 변환하실 때 바로 하지마시고 !! 기호같은 것이 생기지 않도록, 자바코드를 좀 정리하신 다음에 하시는게 좋아요. 자바코드에 @Nullable @NonNull 등의 어노테이션을 가능하면 붙여주신 상태에서 변환을 하세요.

spark (227,470 포인트) 님이 2021년 1월 8일 답변
spark님이 2021년 1월 8일 수정
다른 부분 디버깅은 문제가 없다고 생각을 하고 있습니다. 연관되는 부분 혹은 호출하는 부분들을 점검해봤지만 이상이 없습니다.

터치가 아예 안되는게 아니라 어쩌다 한번씩 UI 아무데나 누르다보면 한번씩은 터치가 먹힙니다.
textview 두개로 구성되어있는데 UI의 끝부분을 살짝 길게 누르면 동작합니다.
하지만 textView를 누르면 동작하지않네요ㅠㅠ 7일째 이거와 씨름중인데 괴롭네요

이게 터치를 하면 살짝 UI가 바뀌잖아요? 제가 설정을 안해도 그렇게 끝부분만 누르면 살짝 바뀌면서 동작은 하네요 ;;
해당 getView함수는 자바랑 똑같이 동작해야 하니까 R.layout.apr_item_view 파일을 체크해 보세요. 뭔가 수정사항이 생겼는지, 아니면 원래 자바코드의 동작도 문제가 있던 것인지.
getView 자체는 함수는 자바코드와 100% 동일합니다.
...