android - Android EditText:仅启用滚动但停止点击
问题描述
我正在为一个应用程序项目做贡献,我遇到了这个问题。
我有一个带有 ArrayAdapter 项目列表的 Horizontal LinearLayout: image -- EditText -- image
我使用 EditText 来启用水平滚动长文本字段,同时禁用光标和单击事件。父布局需要管理项目上的单击事件+水平滑动以更改主视图中的选项卡
代码正常工作:
- 如果 EditText 有很长的文本:我可以水平滚动文本以阅读所有内容。在文本的末尾,父布局采用滑动并可以更改选项卡
- 我可以长按 EditText 以启用父布局中的选择复选标记
- 光标和滑块在 EditText 中正确隐藏
唯一的问题是 EditText 使用简单的点击事件并且从不将它们传递给父布局。当我单击图像或单击 EditText 的右侧/左侧时,父布局会正确捕获适配器项上的单击操作。如果我直接单击 EditText,则事件被消耗并且永远不会到达父布局 setOnItemClickListener。
这是一个关于它现在如何工作的简短视频。视频中 10 秒位置的点击必须在文本之外进行:https ://www.youtube.com/watch?v=P306p7AcwAI
<LinearLayout
android:id="@+id/profile_list_sync_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/sync_task_master_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical|top"
android:src="@drawable/ic_16_server" />
<EditText
android:id="@+id/sync_task_master_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="@+id/sync_task_direction_image"
android:layout_width="12dp"
android:layout_height="18dp"
android:layout_gravity="center"
android:scaleType="fitXY"
android:src="@drawable/arrow_right_enabled" />
<ImageView
android:id="@+id/sync_task_target_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="top"
android:src="@drawable/ic_16_server" />
<EditText
android:id="@+id/sync_task_target_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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>
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);
}
});
}
这些是非常简单的代码片段
基本上,原始代码与 TextView 一起正常工作,但无法在一行中查看/滚动长文本路径。使用 HorizontalScrollView 也可以,但不会传递任何事件,如果单击发生在文本字段上,则包括滑动和长按到父级。
当 EditTex 框上发生简单的单击事件时,EditText 技巧可以修复所有这些事件。有线,因为长触摸和滑动正确传递。此外,当单击 EditText 时,setOnItemClickListener 不会捕获任何事件,但如果它是 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
}
});
但是,我无法将它们传播到 ListView 或 Parent 视图,onClick()
这将避免基于 Parent 在单击时应执行的操作对代码进行大量重写
解决方案
适当的修复:
我为任何有同样问题的人发布这个。我在这方面看到了很多线程,但没有人提供一个好的解决方案
我之前的回答有一个问题:它不保留原生 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 可以修复它
推荐阅读
- javascript - 如何找到与提供的 slug 匹配的某个对象的索引
- android - 使用 cordova-plugin-firebase-messaging 显示来自 Ionic 的通知
- r - 使用 %in% 进行字符串搜索(包含特殊字符)在 str_detect 工作时不起作用
- vba - VBA:设置工作簿,并激活工作簿错误
- vba - How to copy data from csv file to other excel files
- shell - Awk the command output
- javascript - React-Redux TypeError: this.props.getAnimals is not a function
- javascript - 使用 javascript 获取选定的文件名
- sql - 如何查询数据库以返回某个演员演过的电影?
- python-3.x - Python 无法将浮点对象隐式转换为 str