Android Spinner点击旋转箭头问题求助:实现箭头上下切换
实现Spinner点击时箭头旋转切换效果
我懂你想要的效果——点击Spinner展开下拉列表时箭头从向上转为向下,收起时再转回去。你现在用单独ImageView做箭头的思路没问题,只需要给箭头加上旋转动画,再监听Spinner的展开/收起状态就行,我给你两个简单的实现方案:
方案1:用Android属性动画(无需额外XML文件)
这种方法最简洁,直接用代码控制箭头旋转:
步骤1:在Activity中获取控件并设置监听
先拿到Spinner和箭头ImageView的实例,然后添加触摸监听判断展开,再通过反射获取Spinner的PopupWindow监听收起事件(这样不管是选了item还是点击空白处都能触发):
private boolean isSpinnerExpanded = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_layout); // 替换成你的布局文件名 Spinner ss = findViewById(R.id.pricespinner); ImageView spinnerArrow = findViewById(R.id.spnrimg); // 设置Spinner适配器(你的原有代码) ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(this, R.layout.spinner_item, getResources().getStringArray(R.array.pricearray)); spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line); ss.setAdapter(spinnerArrayAdapter); // 监听Spinner触摸事件,触发展开时的箭头旋转 ss.setOnTouchListener((v, event) -> { if (event.getAction() == MotionEvent.ACTION_UP && !isSpinnerExpanded) { // 箭头从向上旋转180度到向下,300ms完成动画 spinnerArrow.animate().rotation(180).setDuration(300).start(); isSpinnerExpanded = true; } return false; }); // 通过反射获取Spinner的PopupWindow,监听收起事件 try { Field popupField = Spinner.class.getDeclaredField("mPopup"); popupField.setAccessible(true); PopupWindow popupWindow = (PopupWindow) popupField.get(ss); popupWindow.setOnDismissListener(() -> { if (isSpinnerExpanded) { // 箭头从向下旋转回0度(向上) spinnerArrow.animate().rotation(0).setDuration(300).start(); isSpinnerExpanded = false; } }); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } }
注意:
如果你的初始箭头是向下的(比如你布局里用的ic_down_arrow),那把旋转度数反过来:展开时旋转到0度,收起时旋转到180度就行。
方案2:用XML动画资源
如果你习惯用XML定义动画,可以这么做:
步骤1:创建两个动画XML文件
在res/anim目录下创建:
rotate_down.xml(展开时的动画):
<rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="180" />
rotate_up.xml(收起时的动画):
<rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromDegrees="180" android:pivotX="50%" android:pivotY="50%" android:toDegrees="0" />
步骤2:在Activity中使用动画
和方案1类似,只是把属性动画换成加载XML动画:
private boolean isSpinnerExpanded = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_layout); Spinner ss = findViewById(R.id.pricespinner); ImageView spinnerArrow = findViewById(R.id.spnrimg); // 设置Spinner适配器(你的原有代码) ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(this, R.layout.spinner_item, getResources().getStringArray(R.array.pricearray)); spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line); ss.setAdapter(spinnerArrayAdapter); // 展开时的触摸监听 ss.setOnTouchListener((v, event) -> { if (event.getAction() == MotionEvent.ACTION_UP && !isSpinnerExpanded) { spinnerArrow.startAnimation(AnimationUtils.loadAnimation(this, R.anim.rotate_down)); isSpinnerExpanded = true; } return false; }); // 监听PopupWindow收起 try { Field popupField = Spinner.class.getDeclaredField("mPopup"); popupField.setAccessible(true); PopupWindow popupWindow = (PopupWindow) popupField.get(ss); popupWindow.setOnDismissListener(() -> { if (isSpinnerExpanded) { spinnerArrow.startAnimation(AnimationUtils.loadAnimation(this, R.anim.rotate_up)); isSpinnerExpanded = false; } }); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } }
为什么不用OnItemSelectedListener?因为用户点击空白处收起Spinner时,这个回调不会触发,所以用PopupWindow的OnDismissListener更可靠,能覆盖所有收起场景。
内容的提问来源于stack exchange,提问作者Hasmukh Kachhatiya
相关产品推荐
相关产品推荐

