Android 方向改变后翻转动画闪烁
Android flip animation flashes after orientation change
我正在开发类似应用程序的抽认卡,我一直在努力处理翻转动画。我的代码基于 android 中的 AnimationsDemo,不同之处在于它是在片段而不是 activity 中完成的。
它工作正常,不完全是上述演示的预览,但足够好。除了...在改变方向之后。
如果该应用程序以横向模式启动,它在横向模式下运行良好,但在纵向模式下运行异常,如果该应用程序以纵向模式启动,则它在纵向模式下运行正常,而在横向模式下运行异常。
这是我的代码(我明显浏览了数据模型)
public class MyFlashCardFragment extends Fragment {
private MyDataModel model;
private Handler mHandler = new Handler();
private boolean mShowingBack = false;
FrameLayout frameLayout;
public static MyFlashCardFragment create(MyDataModel m) {
MyFlashCardFragment fragment = new MyFlashCardFragment();
Bundle bundle = new Bundle();
bundle.putString(AppKeys.FRONT_KEY,m.getFrontText());
bundle.putString(AppKeys.BACK_KEY,m.getBackText());
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!getArguments().isEmpty()) {
model = new MyDataModel();
model.setFrontText(getArguments().getString(AppKeys.FRONT_KEY));
model.setBackText(getArguments().getString(AppKeys.BACK_KEY));
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
if (model == null) {
return super.onCreateView(inflater, container, savedInstanceState);
} else {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_flashcard, container, false);
frameLayout = (FrameLayout) root.findViewById(R.id.chilfd_frame);
Button btn_overlay = (Button) root.findViewById(R.id.overlaybutton);
btn_overlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
flipCard();
}
});
return root;
}
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if(savedInstanceState == null) {
getChildFragmentManager()
.beginTransaction()
.add(R.id.chilfd_frame, CardFrontFragment.create(model.getFrontText()))
.commit();
} else {
mShowingBack = (getChildFragmentManager().getBackStackEntryCount() > 0);
}
getChildFragmentManager().addOnBackStackChangedListener(new android.app.FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
mShowingBack = (getChildFragmentManager().getBackStackEntryCount() > 0);
getActivity().invalidateOptionsMenu();
}
});
}
private void flipCard() {
if (mShowingBack) {
getChildFragmentManager().popBackStack();
return;
}
mShowingBack = true;
getChildFragmentManager()
.beginTransaction()
.setCustomAnimations(
R.animator.card_flip_right_in, R.animator.card_flip_right_out,
R.animator.card_flip_left_in, R.animator.card_flip_left_out)
.replace(frameLayout.getId(), CardBackFragment.create(model.getBackText()))
.addToBackStack(null)
.commit();
mHandler.post(new Runnable() {
@Override
public void run() {
getActivity().invalidateOptionsMenu();
}
});
}
/**
* A fragment representing the front of the card.
*/
public static class CardFrontFragment extends Fragment {
String frontText;
public static CardFrontFragment create(String frontText) {
CardFrontFragment fragment = new CardFrontFragment();
Bundle bundle = new Bundle();
bundle.putString(AppKeys.FRONT_KEY,frontText);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!getArguments().isEmpty()) {
frontText = getArguments().getString(AppKeys.FRONT_KEY);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (TextUtils.isEmpty(frontText)) {
return super.onCreateView(inflater, container, savedInstanceState);
} else {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_flashcard_front, container, false);
((TextView) rootView.findViewById(R.id.tv_name)).setText(frontText);
return rootView;
}
}
}
/**
* A fragment representing the back of the card.
*/
public static class CardBackFragment extends Fragment {
String backText;
public static CardBackFragment create(String backText) {
CardBackFragment fragment = new CardBackFragment();
Bundle bundle = new Bundle();
bundle.putString(AppKeys.BACK_KEY,backText);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!getArguments().isEmpty()) {
backText = getArguments().getString(AppKeys.BACK_KEY);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (TextUtils.isEmpty(backText)) {
return super.onCreateView(inflater, container, savedInstanceState);
} else {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_flashcard_back, container, false);
((TextView) rootView.findViewById(R.id.tv_name)).setText(backText);
return rootView;
}
}
}
}
parentfragment 是从 viewpager 加载的:
pager = (ViewPager) findViewById(R.id.pager);
adapter = new FlashCardPageAdapter(getFragmentManager(), getAllFrom(ref));
pager.setAdapter(adapter);
pager.setCurrentItem(position,true);
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
invalidateOptionsMenu();
}
});
并且使用的适配器是:
public class FlashCardPageAdapter extends FragmentStatePagerAdapter {
private ArrayList<MyDataModel> Models;
public FlashCardPageAdapter(FragmentManager fm, ArrayList<MyDataModel> list) {
super(fm);
this.Models = list;
}
@Override
public Fragment getItem(int position) {
return FlashCardFragment.create(Models.get(position));
}
@Override
public int getCount() {
return Models.size();
}
}
我还尝试从 Animator 对象创建动画并将其添加到透明按钮和动画视图进出以及切换可见性,结果是相同的。
欢迎任何ideas/suggestions。
事实证明我的代码没有遗漏任何内容,问题与模拟器有关。好吧,至少看起来是这样。我在 2 台真实设备(1 phone/1 平板电脑)上尝试过,但问题并未在它们身上出现,因此可能是 AVD 错误或模拟方向更改的简单缺陷。
我正在开发类似应用程序的抽认卡,我一直在努力处理翻转动画。我的代码基于 android 中的 AnimationsDemo,不同之处在于它是在片段而不是 activity 中完成的。 它工作正常,不完全是上述演示的预览,但足够好。除了...在改变方向之后。 如果该应用程序以横向模式启动,它在横向模式下运行良好,但在纵向模式下运行异常,如果该应用程序以纵向模式启动,则它在纵向模式下运行正常,而在横向模式下运行异常。
这是我的代码(我明显浏览了数据模型)
public class MyFlashCardFragment extends Fragment {
private MyDataModel model;
private Handler mHandler = new Handler();
private boolean mShowingBack = false;
FrameLayout frameLayout;
public static MyFlashCardFragment create(MyDataModel m) {
MyFlashCardFragment fragment = new MyFlashCardFragment();
Bundle bundle = new Bundle();
bundle.putString(AppKeys.FRONT_KEY,m.getFrontText());
bundle.putString(AppKeys.BACK_KEY,m.getBackText());
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!getArguments().isEmpty()) {
model = new MyDataModel();
model.setFrontText(getArguments().getString(AppKeys.FRONT_KEY));
model.setBackText(getArguments().getString(AppKeys.BACK_KEY));
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
if (model == null) {
return super.onCreateView(inflater, container, savedInstanceState);
} else {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_flashcard, container, false);
frameLayout = (FrameLayout) root.findViewById(R.id.chilfd_frame);
Button btn_overlay = (Button) root.findViewById(R.id.overlaybutton);
btn_overlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
flipCard();
}
});
return root;
}
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if(savedInstanceState == null) {
getChildFragmentManager()
.beginTransaction()
.add(R.id.chilfd_frame, CardFrontFragment.create(model.getFrontText()))
.commit();
} else {
mShowingBack = (getChildFragmentManager().getBackStackEntryCount() > 0);
}
getChildFragmentManager().addOnBackStackChangedListener(new android.app.FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
mShowingBack = (getChildFragmentManager().getBackStackEntryCount() > 0);
getActivity().invalidateOptionsMenu();
}
});
}
private void flipCard() {
if (mShowingBack) {
getChildFragmentManager().popBackStack();
return;
}
mShowingBack = true;
getChildFragmentManager()
.beginTransaction()
.setCustomAnimations(
R.animator.card_flip_right_in, R.animator.card_flip_right_out,
R.animator.card_flip_left_in, R.animator.card_flip_left_out)
.replace(frameLayout.getId(), CardBackFragment.create(model.getBackText()))
.addToBackStack(null)
.commit();
mHandler.post(new Runnable() {
@Override
public void run() {
getActivity().invalidateOptionsMenu();
}
});
}
/**
* A fragment representing the front of the card.
*/
public static class CardFrontFragment extends Fragment {
String frontText;
public static CardFrontFragment create(String frontText) {
CardFrontFragment fragment = new CardFrontFragment();
Bundle bundle = new Bundle();
bundle.putString(AppKeys.FRONT_KEY,frontText);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!getArguments().isEmpty()) {
frontText = getArguments().getString(AppKeys.FRONT_KEY);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (TextUtils.isEmpty(frontText)) {
return super.onCreateView(inflater, container, savedInstanceState);
} else {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_flashcard_front, container, false);
((TextView) rootView.findViewById(R.id.tv_name)).setText(frontText);
return rootView;
}
}
}
/**
* A fragment representing the back of the card.
*/
public static class CardBackFragment extends Fragment {
String backText;
public static CardBackFragment create(String backText) {
CardBackFragment fragment = new CardBackFragment();
Bundle bundle = new Bundle();
bundle.putString(AppKeys.BACK_KEY,backText);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!getArguments().isEmpty()) {
backText = getArguments().getString(AppKeys.BACK_KEY);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (TextUtils.isEmpty(backText)) {
return super.onCreateView(inflater, container, savedInstanceState);
} else {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_flashcard_back, container, false);
((TextView) rootView.findViewById(R.id.tv_name)).setText(backText);
return rootView;
}
}
}
}
parentfragment 是从 viewpager 加载的:
pager = (ViewPager) findViewById(R.id.pager);
adapter = new FlashCardPageAdapter(getFragmentManager(), getAllFrom(ref));
pager.setAdapter(adapter);
pager.setCurrentItem(position,true);
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
invalidateOptionsMenu();
}
});
并且使用的适配器是:
public class FlashCardPageAdapter extends FragmentStatePagerAdapter {
private ArrayList<MyDataModel> Models;
public FlashCardPageAdapter(FragmentManager fm, ArrayList<MyDataModel> list) {
super(fm);
this.Models = list;
}
@Override
public Fragment getItem(int position) {
return FlashCardFragment.create(Models.get(position));
}
@Override
public int getCount() {
return Models.size();
}
}
我还尝试从 Animator 对象创建动画并将其添加到透明按钮和动画视图进出以及切换可见性,结果是相同的。
欢迎任何ideas/suggestions。
事实证明我的代码没有遗漏任何内容,问题与模拟器有关。好吧,至少看起来是这样。我在 2 台真实设备(1 phone/1 平板电脑)上尝试过,但问题并未在它们身上出现,因此可能是 AVD 错误或模拟方向更改的简单缺陷。