android - 如何使用微调器解决奇怪的 S Pen 错误?
问题描述
在使用Spinner
所有默认设置时,我在使用 S Pen 时发现了一些奇怪的错误:
- 如果您打开微调器并将 S Pen 悬停在列表底部,使其滚动到底部,然后向上提起 S Pen(使“悬停圆圈”消失),列表跳回顶部
- 如果您打开微调器并将 S Pen 悬停在列表底部,使其滚动到底部,然后选择一个选项,有时(间歇性 - 可能大约 4 次中的 1 次)它会忽略所选选项并跳回到顶部
我正在横向的平板设备上进行测试,该设备运行的是 Android 9,但我已经在其他设备上进行了一些测试,并且似乎是相同的。
为了比较,我尝试使用我经常使用的应用程序,它大量使用微调器 - dotnetideas 的“装箱单”。该应用程序最后一次更新是在 2019 年,目标 SDK 为 27。您可以通过进入设置并添加多件行李,然后尝试编辑任何装箱单项目上的行李,轻松测试应用程序中的微调器。我发现 S Pen 可以很好地配合这个应用程序,而且它没有上面描述的错误,所以必须有一些方法可以解决它。那不是一个开源应用程序,所以我无法从他们的源代码中获得想法。我尝试将我的目标 SDK 更改为 27,但没有任何区别。
这是我的代码,在我看来,这是一个具有所有默认设置的完全普通的微调器实现 - 并且仍然具有这些相同的“S Pen 错误”,这些错误在装箱单中无法重现。
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.penpoc">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SPenControlExperiment">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.java:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow();
}
}
}
main_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" />
MainFragment.java:
public class MainFragment extends Fragment {
public static MainFragment newInstance() {
return new MainFragment();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.main_fragment, container, false);
Spinner spDefault = root.findViewById(R.id.spDefault);
ArrayAdapter<String> defaultSpinnerAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item);
defaultSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spDefault.setAdapter(defaultSpinnerAdapter);
defaultSpinnerAdapter.addAll(getExampleList());
defaultSpinnerAdapter.notifyDataSetChanged();
return root;
}
private List<String> getExampleList() {
List<String> list = new ArrayList<>();
list.add("Alpha");
list.add("Bravo");
list.add("Charlie");
list.add("Delta");
list.add("Echo");
list.add("Foxtrot");
list.add("Golf");
list.add("Hotel");
list.add("India");
list.add("Juliet");
list.add("Kilo");
list.add("Lima");
list.add("Mike");
list.add("November");
list.add("Oscar");
list.add("Papa");
list.add("Quebec");
list.add("Romeo");
return list;
}
}
main_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainFragment">
<!-- Add some text views to push the spinner further down the page, this is not strictly necessary -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="one" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="two" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="three" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="four" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="five" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="six" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="seven" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="eight" />
<Spinner
android:layout_width="350dp"
android:layout_height="wrap_content"
android:id="@+id/spDefault" />
</LinearLayout>
Gradle 部门:
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
解决方案
我在使用 S Pen 时也遇到了同样的问题。对于旧应用程序,API 25 Spinner
s 运行良好,但 API 30 不再适用。我可以解决它的唯一方法是将 s 替换Spinner
为AutoCompleteTextView
s。它生成的下拉菜单似乎可以在 S Pen 上正常工作。
需要进行一些修改以使其看起来像Spinner
:
1.AutoCompleteTextView
不可编辑
从文档中,您可以通过添加android:inputType="none"
. 但是,正如MaterialAutoCompleteTextView
代码中所说:
// Due to a framework bug, setting android:inputType="none" on xml has no effect. Therefore,
// we check it here in case the autoCompleteTextView should be non-editable.
所以你有两个选择:
- 以编程方式设置输入类型
autoComplete.setInputType(InputType.TYPE_NULL)
- 使用
MaterialAutoCompleteTextView
解决方法
2. 处理点击显示下拉列表
默认行为AutoCompleteTextView
是通过键入几个字符来显示建议。因此,当视图聚焦时,您必须强制下拉显示。
autoComplete.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
autoComplete.showDropDown();
}
}
});
autoComplete.setOnDismissListener(new AutoCompleteTextView.OnDismissListener() {
@Override
void onDismiss() {
// Force focus change after selection
autoComplete.clearFocus()
}
});
3.样式下拉列表
与Spinner
调用 bothgetView()
和getDropDownView()
from不同Adapter
,AutoCompleteTextView
只调用getView()
。因此,要提供正确的视图,您需要检查getView()
调用中的父类型:
@Override
public @NonNull View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
// Workaround for AutoCompleteTextView using only this method
if (parent instanceof ListView) {
return getDropDownView(position, convertView, parent);
} else {
return super.getView(position, convertView, parent);
}
}
4.风格AutoCompleteTextView
最后一件事是在末尾添加小插入符号,AutoCompleteTextView
使其看起来像Spinner
. 您可以使用android:drawableEnd
XML 布局文件中的属性来处理此问题。
5. 其他提示
AutoCompleteTextView
下拉列表选择触发AdapterView.OnItemClickListener
而不是AdapterView.OnItemSelectedListener
像Spinner
s 那样。方法签名几乎相同。- 没有适当的方法来触发此侦听器的初始值。作为一种解决方法,您可以设置初始值,然后附加侦听器并将您的第一个验证逻辑放入其构造函数中。