我以编程方式创建的按钮的动画在我的应用程序中表现得很奇怪
The animation for my programatically created button acts weird in my application
所以我遇到了一个我无法解释的奇怪错误 - 有时我什至无法重现它。
基本情况:
- 我有一个列出对象的应用程序。每个对象都有一个名称和一个点值。对于每个对象,addCustomSpinner 函数都会创建一个“票”(一种自定义视图,一种微调器)并在滚动视图中显示它们,以便用户可以 select 需要的那个。四种不同的对象有四种不同的 'containers' - 因此布局可以填充四种“票”包。
- 对象的数据是从数据库中收集的。 addCustomSpinner 为数据库中的每个对象调用一个 for 循环,并且 - 重要 - 在 for 方法之前,它用票证填充的布局被清除(removeAllViews)。
- 在 addCustomSpinner 中,所有内容都创建为“新”- 就像有问题的按钮。
- addCustomSpinner 创建此按钮并添加一个新的 onClickListener。在 onClickListener 内部,创建了一个新的布尔值 - 这用于在再次单击按钮时显示不同的动画。第一次点击 (boolean = true),箭头旋转 180 度并朝上,第二次点击 (boolean = false) 箭头旋转 180 度并朝下。像魅力一样工作,直到...
我面临的错误:
- 有时 - 正如我已经提到的,不是每次 - 如果我点击一张“票”的按钮,然后离开它 'opened' 然后点击另一个,然后离开它 'opened'此外,然后我选择使用不同类型的“票”包来填充布局 - 默认情况下,每个包中的每张票上的箭头都朝上!有时 - 再一次,只是有时 - 使用相同的模式我可以将其转回去,但它只是“偶然”发生的。
我不明白按钮的动画和状态如何连接,如果每个创建的工单都是新的,每个按钮都是新的,每个onClickListener 都是新的,onClickListener 中的每个布尔值都是新的。如果它们以某种方式连接,那么为什么每个行为对于按钮来说都是“独特的”,没有其他显示任何连接 - 即使这只是一个“有时”的错误,一个非常罕见的错误。
谁能帮我看看为什么会这样?
我尝试了什么:
好吧,试图追踪这个问题 - 但由于它只是偶然发生的,所以我没有任何线索,我只是搜索除了布尔值之外我是否可以做任何其他事情来为点击添加不同的动画。遗憾的是,使用 ObjectAnimator 对我来说不是一个好的解决方案 - 至少不是相同的结果,因为我的动画箭头不仅旋转,而且还改变了它的颜色。 Shapeshifter 似乎是一个轻松创建动画的好主意,但现在看来,也许简单的旋转将是我的最终解决方案。
这是按钮的代码:
customButton.setOnClickListener(new View.OnClickListener() {
boolean isCustomButtonClicked = true;
@Override
public void onClick(View v) {
if (isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue_back);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(View.VISIBLE);
isCustomButtonClicked = false;
} else if (!isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(GONE);
isCustomButtonClicked = true;
}
}
});
编辑:
完整的 addCustomSpinner():
private void addCustomSpinner(Routes mRouteItemToAdd, String placeName) {
//为我在 xml
中创建的自定义布局创建一个新视图
View customRoutesView = new View(this);
LinearLayout.LayoutParams customViewParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
customRoutesView.setLayoutParams(customViewParams);
customRoutesView = LayoutInflater.from(this).inflate(
R.layout.custom_view_layout, routeLayout, false
);
//在自定义视图中设置视图
ImageView imageViewDiffImage = customRoutesView.findViewById(R.id.routeDiffImageView);
TextView textViewRouteName = customRoutesView.findViewById(R.id.routeNameTextView);
TextView textViewRouteDiff = customRoutesView.findViewById(R.id.routeDiffTextView);
ImageButton customButton = customRoutesView.findViewById(R.id.customButton);
RadioButton climberNameOne = customRoutesView.findViewById(R.id.climberNameOne);
RadioButton climberNameTwo = customRoutesView.findViewById(R.id.climberNameTwo);
Button climbedItButton = customRoutesView.findViewById(R.id.climbed_it_button);
RadioGroup climberNameRadioGroup = customRoutesView.findViewById(R.id.climberNameRadioGroup);
RadioGroup climbingStyleRadioGroup = customRoutesView.findViewById(R.id.styleNameRadioGroup);
RelativeLayout routeWhoClimbed = customRoutesView.findViewById(R.id.routeWhoClimbedRelativeLayout);
imageViewDiffImage.setImageResource(R.mipmap.muscle);
textViewRouteName.setText(mRouteItemToAdd.name);
textViewRouteDiff.setText("Difficulty: " + (int) mRouteItemToAdd.difficulty);
climberNameOne.setText(climberName1);
climberNameTwo.setText(climberName2);
routeWhoClimbed.setVisibility(GONE);
//带动画的按钮来了
customButton.setOnClickListener(new View.OnClickListener() {
boolean isCustomButtonClicked = true;
@Override
public void onClick(View v) {
if (isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue_back);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(View.VISIBLE);
isCustomButtonClicked = false;
} else if (!isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(GONE);
isCustomButtonClicked = true;
}
}
});
//按钮,像 'OK' 之类的,我没有
//这个有问题
climbedItButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int checkedNameButton = climberNameRadioGroup.getCheckedRadioButtonId();
int checkedStyleButton = climbingStyleRadioGroup.getCheckedRadioButtonId();
RadioButton checkedNameRadioButton = (RadioButton) findViewById(checkedNameButton);
RadioButton checkedStyleRadioButton = (RadioButton) findViewById(checkedStyleButton);
String checkedName = (String) checkedNameRadioButton.getText();
String checkedStyle = (String) checkedStyleRadioButton.getText();
addClimbToDatabase(user.getUid(), checkedName, mRouteItemToAdd, placeName, checkedStyle);
}
});
//最后,我将这个带有自定义视图的新“票”添加到我想要显示的布局中。同样,这也很有效,这里没问题。
routeLayout.addView(customRoutesView);
}
最终,我并没有把问题搞明白,但还是能够排除它。
因此,在我的修复尝试中,我将问题缩小到动画可绘制状态 - 感谢@avalerio 的专业提示,但答案不是向按钮添加 id。我想不知何故有时,第一个动画的状态(将箭头旋转 180 度)停留在结束位置 - 导致使用此 animatedDrawable 的其他视图在开始时将其显示在结束位置。
.reset() 没有帮助,因为它重置了 animatedVectorDrawable 对象,而不是动画 xml 可绘制状态。我的解决方案是一种变通方法,但它确实有效:当使用动画可绘制图像按钮创建自定义视图 'ticket' 时,我将按钮的图像资源设置为非动画 xml drawable - 这个 drawable 基本上是我的动画 drawable 的开始位置。这样,当生成'tickets'时,imagebutton在起始位置是'hardcoded'。
不优雅,但有效。但是(!)如果有人能向我解释这种奇怪的行为是如何可能的,我将不胜感激——只是有时,随机的,没有我可以有意重现的模式。
所以我遇到了一个我无法解释的奇怪错误 - 有时我什至无法重现它。
基本情况:
- 我有一个列出对象的应用程序。每个对象都有一个名称和一个点值。对于每个对象,addCustomSpinner 函数都会创建一个“票”(一种自定义视图,一种微调器)并在滚动视图中显示它们,以便用户可以 select 需要的那个。四种不同的对象有四种不同的 'containers' - 因此布局可以填充四种“票”包。
- 对象的数据是从数据库中收集的。 addCustomSpinner 为数据库中的每个对象调用一个 for 循环,并且 - 重要 - 在 for 方法之前,它用票证填充的布局被清除(removeAllViews)。
- 在 addCustomSpinner 中,所有内容都创建为“新”- 就像有问题的按钮。
- addCustomSpinner 创建此按钮并添加一个新的 onClickListener。在 onClickListener 内部,创建了一个新的布尔值 - 这用于在再次单击按钮时显示不同的动画。第一次点击 (boolean = true),箭头旋转 180 度并朝上,第二次点击 (boolean = false) 箭头旋转 180 度并朝下。像魅力一样工作,直到...
我面临的错误:
- 有时 - 正如我已经提到的,不是每次 - 如果我点击一张“票”的按钮,然后离开它 'opened' 然后点击另一个,然后离开它 'opened'此外,然后我选择使用不同类型的“票”包来填充布局 - 默认情况下,每个包中的每张票上的箭头都朝上!有时 - 再一次,只是有时 - 使用相同的模式我可以将其转回去,但它只是“偶然”发生的。
我不明白按钮的动画和状态如何连接,如果每个创建的工单都是新的,每个按钮都是新的,每个onClickListener 都是新的,onClickListener 中的每个布尔值都是新的。如果它们以某种方式连接,那么为什么每个行为对于按钮来说都是“独特的”,没有其他显示任何连接 - 即使这只是一个“有时”的错误,一个非常罕见的错误。
谁能帮我看看为什么会这样?
我尝试了什么: 好吧,试图追踪这个问题 - 但由于它只是偶然发生的,所以我没有任何线索,我只是搜索除了布尔值之外我是否可以做任何其他事情来为点击添加不同的动画。遗憾的是,使用 ObjectAnimator 对我来说不是一个好的解决方案 - 至少不是相同的结果,因为我的动画箭头不仅旋转,而且还改变了它的颜色。 Shapeshifter 似乎是一个轻松创建动画的好主意,但现在看来,也许简单的旋转将是我的最终解决方案。
这是按钮的代码:
customButton.setOnClickListener(new View.OnClickListener() {
boolean isCustomButtonClicked = true;
@Override
public void onClick(View v) {
if (isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue_back);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(View.VISIBLE);
isCustomButtonClicked = false;
} else if (!isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(GONE);
isCustomButtonClicked = true;
}
}
});
编辑: 完整的 addCustomSpinner():
private void addCustomSpinner(Routes mRouteItemToAdd, String placeName) {
//为我在 xml
中创建的自定义布局创建一个新视图 View customRoutesView = new View(this);
LinearLayout.LayoutParams customViewParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
customRoutesView.setLayoutParams(customViewParams);
customRoutesView = LayoutInflater.from(this).inflate(
R.layout.custom_view_layout, routeLayout, false
);
//在自定义视图中设置视图
ImageView imageViewDiffImage = customRoutesView.findViewById(R.id.routeDiffImageView);
TextView textViewRouteName = customRoutesView.findViewById(R.id.routeNameTextView);
TextView textViewRouteDiff = customRoutesView.findViewById(R.id.routeDiffTextView);
ImageButton customButton = customRoutesView.findViewById(R.id.customButton);
RadioButton climberNameOne = customRoutesView.findViewById(R.id.climberNameOne);
RadioButton climberNameTwo = customRoutesView.findViewById(R.id.climberNameTwo);
Button climbedItButton = customRoutesView.findViewById(R.id.climbed_it_button);
RadioGroup climberNameRadioGroup = customRoutesView.findViewById(R.id.climberNameRadioGroup);
RadioGroup climbingStyleRadioGroup = customRoutesView.findViewById(R.id.styleNameRadioGroup);
RelativeLayout routeWhoClimbed = customRoutesView.findViewById(R.id.routeWhoClimbedRelativeLayout);
imageViewDiffImage.setImageResource(R.mipmap.muscle);
textViewRouteName.setText(mRouteItemToAdd.name);
textViewRouteDiff.setText("Difficulty: " + (int) mRouteItemToAdd.difficulty);
climberNameOne.setText(climberName1);
climberNameTwo.setText(climberName2);
routeWhoClimbed.setVisibility(GONE);
//带动画的按钮来了
customButton.setOnClickListener(new View.OnClickListener() {
boolean isCustomButtonClicked = true;
@Override
public void onClick(View v) {
if (isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue_back);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(View.VISIBLE);
isCustomButtonClicked = false;
} else if (!isCustomButtonClicked) {
customButton.setImageResource(R.drawable.avd_anim_arrow_blue);
Drawable d = customButton.getDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (d instanceof AnimatedVectorDrawable) {
animArrowAnim = (AnimatedVectorDrawable) d;
animArrowAnim.start();
}
}
routeWhoClimbed.setVisibility(GONE);
isCustomButtonClicked = true;
}
}
});
//按钮,像 'OK' 之类的,我没有 //这个有问题
climbedItButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int checkedNameButton = climberNameRadioGroup.getCheckedRadioButtonId();
int checkedStyleButton = climbingStyleRadioGroup.getCheckedRadioButtonId();
RadioButton checkedNameRadioButton = (RadioButton) findViewById(checkedNameButton);
RadioButton checkedStyleRadioButton = (RadioButton) findViewById(checkedStyleButton);
String checkedName = (String) checkedNameRadioButton.getText();
String checkedStyle = (String) checkedStyleRadioButton.getText();
addClimbToDatabase(user.getUid(), checkedName, mRouteItemToAdd, placeName, checkedStyle);
}
});
//最后,我将这个带有自定义视图的新“票”添加到我想要显示的布局中。同样,这也很有效,这里没问题。
routeLayout.addView(customRoutesView);
}
最终,我并没有把问题搞明白,但还是能够排除它。
因此,在我的修复尝试中,我将问题缩小到动画可绘制状态 - 感谢@avalerio 的专业提示,但答案不是向按钮添加 id。我想不知何故有时,第一个动画的状态(将箭头旋转 180 度)停留在结束位置 - 导致使用此 animatedDrawable 的其他视图在开始时将其显示在结束位置。
.reset() 没有帮助,因为它重置了 animatedVectorDrawable 对象,而不是动画 xml 可绘制状态。我的解决方案是一种变通方法,但它确实有效:当使用动画可绘制图像按钮创建自定义视图 'ticket' 时,我将按钮的图像资源设置为非动画 xml drawable - 这个 drawable 基本上是我的动画 drawable 的开始位置。这样,当生成'tickets'时,imagebutton在起始位置是'hardcoded'。
不优雅,但有效。但是(!)如果有人能向我解释这种奇怪的行为是如何可能的,我将不胜感激——只是有时,随机的,没有我可以有意重现的模式。