Android EditText:仅启用滚动但停止点击
Posted
技术标签:
【中文标题】Android EditText:仅启用滚动但停止点击【英文标题】:Android EditText: enable only scrolling but stop comsuming clicks 【发布时间】:2020-11-13 02:24:39 【问题描述】:我正在为一个应用项目做贡献,但我遇到了这个问题。
我有一个带有 ArrayAdapter 项目列表的 Horizontal LinearLayout:image -- EditText -- image
我使用 EditText 来启用水平滚动长文本字段,同时禁用光标和单击事件。父布局需要管理项目上的点击事件+水平滑动以更改主视图中的选项卡
代码运行正常:
如果 EditText 有很长的文本:我可以水平滚动文本以阅读全部内容。在文本的末尾,父布局进行滑动并可以更改选项卡 我可以长按 EditText 以启用父布局中的选择复选标记 光标和滑块正确隐藏在 EditText 中唯一的问题是 EditText 使用简单的点击事件并且从不将它们传递给父布局。当我单击图像或单击 EditText 的右侧/左侧时,父布局会正确捕获适配器项上的单击操作。如果我直接单击 EditText,则事件被消耗并且永远不会到达父布局 setOnItemClickListener。
这是一个简短的视频,介绍了它现在的工作方式。视频中10秒位置的点击必须在文字外进行:https://www.youtube.com/watch?v=P306p7AcwAI
这是 xml 示例: https://github.com/PhilZ-cwm6/SMBSync2/blob/philz/SMBSync2/src/main/res/layout/sync_task_item_view.xml
<LinearLayout
android:id="@+id/profile_list_sync_layout"
android:layout_
android:layout_
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp" >
<LinearLayout
android:layout_
android:layout_
android:layout_weight="1"
android:orientation="vertical" >
<LinearLayout
android:layout_
android:layout_
android:orientation="horizontal" >
<ImageView
android:id="@+id/sync_task_master_icon"
android:layout_
android:layout_
android:layout_gravity="center_vertical|top"
android:src="@drawable/ic_16_server" />
<EditText
android:id="@+id/sync_task_master_info"
android:layout_
android:layout_
android:inputType="none"
android:background="@android:color/transparent"
android:cursorVisible="false"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="true"
android:ellipsize="end"
android:lines="1"
android:text="Master"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<LinearLayout
android:layout_
android:layout_
android:orientation="horizontal" >
<ImageView
android:id="@+id/sync_task_direction_image"
android:layout_
android:layout_
android:layout_gravity="center"
android:scaleType="fitXY"
android:src="@drawable/arrow_right_enabled" />
<ImageView
android:id="@+id/sync_task_target_icon"
android:layout_
android:layout_
android:layout_gravity="top"
android:src="@drawable/ic_16_server" />
<EditText
android:id="@+id/sync_task_target_info"
android:layout_
android:layout_
android:inputType="none"
android:background="@android:color/transparent"
android:cursorVisible="false"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="true"
android:ellipsize="end"
android:lines="1"
android:text="Target"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
适配器代码提取: https://github.com/PhilZ-cwm6/SMBSync2/blob/philz/SMBSync2/src/main/java/com/sentaroh/android/SMBSync2/AdapterSyncTask.java
public class AdapterSyncTask extends ArrayAdapter<SyncTaskItem>
final public View getView(int position, View convertView, ViewGroup parent)
ViewHolder holder;
final SyncTaskItem o = getItem(position);
View v = convertView;
if (v == null)
LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
holder = new ViewHolder();
holder.tv_row_master = (EditText) v.findViewById(R.id.sync_task_master_info);
holder.tv_row_target = (EditText) v.findViewById(R.id.sync_task_target_info);
if (o != null)
holder.tv_row_master.setText("source dir path");
holder.tv_row_master.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); //disable auto-correct highlight in EditText
holder.tv_row_target.setText(destination dir path);
holder.tv_row_target.setTextColor(mTextColor);
holder.tv_row_target.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); //disable auto-correct highlight in EditText
return v;
static class ViewHolder
EditText tv_row_master, tv_row_target;
以及需要 onClick 事件的 ActivityMain: https://github.com/PhilZ-cwm6/SMBSync2/blob/philz/SMBSync2/src/main/java/com/sentaroh/android/SMBSync2/ActivityMain.java
private void setSyncTaskListItemClickListener()
mGp.syncTaskListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
SyncTaskItem item = mGp.syncTaskAdapter.getItem(position);
editSyncTask(item.getSyncTaskName(), item.isSyncTaskAuto(), position);
);
这些都是非常简单的sn-ps代码
基本上,原始代码与 TextView 一起正常工作,但无法在一行中查看/滚动长文本路径。使用 HorizontalScrollView 也可以,但不会传递任何事件,如果单击发生在文本字段上,则包括滑动和长按到父级。
EditText 技巧修复了所有在 EditTex 框上发生的简单单击事件之外的所有事件。有线,因为长触摸和滑动正确传递。此外,setOnItemClickListener 在单击 EditText 时不会捕获任何事件,但如果它是 TextView 则会捕获它们
知道如何解决这个问题吗?我考虑过自定义 EditText,但最终不确定 ArrayAdapter 如何获得 EditText 位置。我是否必须为 EditText 使用第二个适配器?
最好的问候
编辑:我可以将此代码添加到适配器的 getView() 中:
holder.tv_row_target.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//click events of EditText are captured
);
但是,我无法将它们从 onClick()
传播到 ListView 或父视图
这将避免基于父级在单击时应执行的操作而对代码进行大量重写
【问题讨论】:
你检查android:editable="false"
了吗?
我刚试过android:editable="false"
,但没有帮助。 OnClick 事件由 EditText 使用
【参考方案1】:
编辑:查看下一篇文章并进行适当修复以保留原生 ListView 动画
我是这样解决的: 在适配器中:
holder.tv_row_target.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
((ActivityMain) mContext).dispatchSyncTaskListItemClick(o, position);
);
在 MainActivity 中:
public void dispatchSyncTaskListItemClick(SyncTaskItem item, int position)
// my actions
这样,我可以将所需的信息(位置、对象项)传递给活动
我愿意接受任何其他建议,只需将点击传播到父 ListView 以便它直接处理它
【讨论】:
【参考方案2】:正确修复:
我为遇到相同问题的任何人发布此信息。我在这方面看到了很多线程,但没有人提出一个好的解决方案
我之前的回答有一个问题:它没有保留原生 ListView onClick 褪色动画
我试过 performclick() 还是一样。
我终于完全修复了它,使用 MotionEvent 将触摸事件传递给列表视图
在适配器中:我为单击和长按设置了 onClick 侦听器,并将操作发送到存在 ListView 操作代码的 MainActivity
适配器监听器:
holder.tv_row_target.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
((ActivityMain) mContext).dispatchSyncTaskListItemClick(o, position);
);
holder.tv_row_target.setOnLongClickListener(new View.OnLongClickListener()
public boolean onLongClick(View v)
v.setHapticFeedbackEnabled(false);
((ActivityMain) mContext).dispatchSyncTaskListLongClick(o, position);
return true;//notify long touch event is consumed
);
在主要活动中:setOnItemLongClickListener
和 setOnItemClickListener
必须在那里设置。问题是单击 EditText 或处理触摸并执行 ListView 动作和动画的图标
// simulate click on teh ListView item
public void dispatchSyncTaskListItemClick(SyncTaskItem item, int position)
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
int first_visible_pos = mGp.syncTaskListView.getFirstVisiblePosition();
View v = mGp.syncTaskListView.getChildAt(position - first_visible_pos);
float x = v.getX() + 1;//view items start at 0, MotionEvent doesn't handle the UP action at 0
float y = v.getY();
//first touch
MotionEvent motionDown = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
motionDown.setSource(InputDevice.SOURCE_TOUCHSCREEN);
mGp.syncTaskListView.onTouchEvent(motionDown);
//release touch
downTime = SystemClock.uptimeMillis();
eventTime = SystemClock.uptimeMillis();
MotionEvent motionUp = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
motionUp.setSource(InputDevice.SOURCE_TOUCHSCREEN);
mGp.syncTaskListView.onTouchEvent(motionUp);
motionUp.recycle();
motionDown.recycle();
// simulate long touch
public void dispatchSyncTaskListLongClick(SyncTaskItem item, int position)
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
int first_visible_pos = mGp.syncTaskListView.getFirstVisiblePosition();
View v = mGp.syncTaskListView.getChildAt(position - first_visible_pos);
MotionEvent motion = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, v.getX(), v.getY(), 0);
motion.setSource(InputDevice.SOURCE_TOUCHSCREEN);
mGp.syncTaskListView.onTouchEvent(motion);
motion.recycle();
最难的部分是x+1
,因为我的视图从 float x = 0.0 开始,直到 > 0 才考虑 UP 操作。不知道为什么? ACTION_DOWN 处理得当
要注意的另一件事是getChildAt
:它返回从第一个可见位置开始的视图位置,而不是适配器传递的位置。否则,您会得到一个 null 返回的视图。
现在,它就像与 ListView 交互时一样工作
新编辑:添加了v.setHapticFeedbackEnabled(false);
以删除长触摸时重复的触觉反馈!
剩下的问题:我觉得这一切都是一种解决方法。长按时动画触发仍有少许延迟。理想的情况是 EditText 视图完全让 ListView 处理 onClick
所以可能只有自定义的 HorizontalScrollView 或自定义的 EditText 可以修复它
【讨论】:
以上是关于Android EditText:仅启用滚动但停止点击的主要内容,如果未能解决你的问题,请参考以下文章
Android键盘将第一个EditText推送到AppBar下,并且仅可以向上滚动
在Android中滚动recyclelerview时,Edittext值消失