在onAnimationEnd的一个视图上播放动画序列

时间:2019-05-08 23:50:10

标签: java android animation

我正在尝试在同一进度条上播放超过1个动画的序列。我实际上正在使用一个名为 AnimateHorizo​​ntalProgressBar 的库,该库允许进度条充满动画。该栏是游戏中的体验栏,如果玩家一次获得足够的经验,我希望该栏可以填满尽可能多的次数。 (例如,从1级角色升级到3级角色时,他们的经验栏将填满2次,每次填满就重置一次,然后再从3级升级到4级时再进行一次重置)

我尝试的解决方案是在 AnimateHorizo​​ntalProgressBar 上设置AnimateProgressListener,并在onAnimationEnd函数中调用下一个要播放的动画。包含这些动画的列表是arraylist的自定义POJO,其中包含对视图(进度条)的引用以及将其设置为的百分比。

public class MonsterBattleResolutionFragment extends MMOBaseFragment {


private static final String TAG = "Resolution Frag";

boolean isVictorious;
boolean playerCapturedMonster;

private String wildMonsterId;

ToolTipManager tooltips;

int monsterLevel;
private FirebaseFunctions mFunctions;

private ArrayList<String> monsterKeys;
private ArrayList<PlayerMonster> monstersList;

private BattleResolutionXpGainedAdapter battleResolutionXpGainedAdapter;
private Typeface typeface;

TextView victoryTextView;

private ListView xpGainedLayoutContainer;

private RecyclerView itemRecyclerView;
private PlayerItemAdapter playerItemAdapter;
ArrayList<PlayerItem> playerItems;

private FirebaseUser user;
private DatabaseReference mDatabase;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_monster_battle_resolution, container, false);

    mFunctions = FirebaseFunctions.getInstance();
    typeface = CustomTypeFace.getNovemberTypeface(getContext());

    victoryTextView = view.findViewById(R.id.monster_battle_resolution_text_view);
    victoryTextView.setTypeface(typeface);

    tooltips = new ToolTipManager(getActivity());

    itemRecyclerView = view.findViewById(R.id.monster_battle_resolution_item_recycler_view);
    itemRecyclerView.setNestedScrollingEnabled(false);
    itemRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

    playerItems = new ArrayList<>();
    playerItemAdapter = new PlayerItemAdapter(playerItems);
    itemRecyclerView.setAdapter(playerItemAdapter);

    isVictorious = getArguments().getBoolean("victory");
    playerCapturedMonster = getArguments().getBoolean("playerCapturedMonster");
    monsterLevel = getArguments().getInt("monsterLevel");
    monsterKeys = getArguments().getStringArrayList("monsterKeys");
    monstersList = getArguments().getParcelableArrayList("monstersList");

    for (int i = 0; i < monstersList.size(); i++){
        Log.e(TAG, monstersList.get(i).getMonsterStringName());
    }

    wildMonsterId = getArguments().getString("wildMonsterId");

    ArrayList<String> playerMonsterIds = new ArrayList<>();

    for (int i = 0; i < monstersList.size(); i++){
        Log.e(TAG, "fb id is " + monstersList.get(i).getFirebaseId());
        playerMonsterIds.add(monstersList.get(i).getFirebaseId());
    }

    Task<HashMap<String, Integer>> test = firebaseResolveCombat(wildMonsterId, playerMonsterIds);
    test.addOnCompleteListener(new OnCompleteListener<HashMap<String, Integer>>() {
        @Override
        public void onComplete(@NonNull Task<HashMap<String, Integer>> task) {
            Object gainedXp = task.getResult().get("experience");
            Object items = task.getResult().get("items");
            Object skills = task.getResult().get("skills");
            Object newMonsterLevels = task.getResult().get("newMonsterLevels");
            // gainedXp is the xp gained for each monster involved in the fight

            if (gainedXp != null){
                Log.e(TAG, "experience earned: " + gainedXp);
                updateXpBars((int) gainedXp);
            }

            if (items != null){
                Log.e(TAG, "items earned: " + items.toString());
                HashMap<String, Integer> itemsEarnedMap = (HashMap<String, Integer>) items;
                for (Map.Entry<String, Integer> item : itemsEarnedMap.entrySet()) {
                    Log.e(TAG, "key: " + item.getKey() + ", value: " + item.getValue());
                    // add new item to list for adapter. NOTE: as of now, key is a string, while value (quantity) is an int. slight issue on javascript side, fine for now.
                    playerItems.add(ItemDirectory.itemLookup(Integer.parseInt(item.getKey()), item.getValue()));
                }
            }

            if (skills != null){
                Log.e(TAG, "new skills: " + skills.toString());
                HashMap<String, ArrayList<Integer>> newSkills = (HashMap<String, ArrayList<Integer>>) skills;

                for (Map.Entry<String, ArrayList<Integer>> item : newSkills.entrySet()) {

                    for (Integer skill : item.getValue()) {
                        String skillName = SkillDirectory.skillLookup(skill).getName();
                        Log.e(TAG, item.getKey() + " learned skill " + skillName);


                        for (int i = 0; i < monstersList.size(); i++){
                            Log.e(TAG, "fb id is " + monstersList.get(i).getFirebaseId());
                            if (monstersList.get(i).getFirebaseId().equals(item.getKey())){
                                Toast.makeText(getContext(), monstersList.get(i).getMonsterStringName() + " learned skill " + skillName + "!", Toast.LENGTH_SHORT).show();
                            }
                        }

                    }

                }
            }

            if (newMonsterLevels != null){
                Log.e(TAG, "new levels: " + newMonsterLevels.toString());
            }

        }
    });

    xpGainedLayoutContainer = view.findViewById(R.id.monster_battle_resolution_xp_gained_layout_container);

    battleResolutionXpGainedAdapter = new BattleResolutionXpGainedAdapter(getActivity(), R.layout.battle_resolution_xp_gained_layout, monstersList);
    xpGainedLayoutContainer.setAdapter(battleResolutionXpGainedAdapter);
    justifyListViewHeightBasedOnChildren(xpGainedLayoutContainer);

    // if the player did not win, don't show items won, give them half xp
    if (!isVictorious) {
        victoryTextView.setText(R.string.defeat);
    }

    // listener for button to return to map
    FloatingActionButton b = view.findViewById(R.id.monster_battle_resolution_return_to_map_button);
    b.setOnClickListener(view1 -> {

        Intent intent = new Intent(getActivity(), MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(intent);
    });

    return view;
}

private void updateXpBars(int xpPerMonster){

    ArrayList<LevelUpBarAnimation> animationList = new ArrayList<>();

    // First build the list of animations
    Log.e(TAG, "There are " + battleResolutionXpGainedAdapter.getCount() + " xp bars to animate");
    for (int i = 0; i < battleResolutionXpGainedAdapter.getCount(); i++){

        int currentXp = monstersList.get(i).getExperience();
        int level = monstersList.get(i).getLevel();
        int newXp = currentXp + xpPerMonster;
        int lastLevelXp = getExperienceRequiredForNextLevel(level-1);
        boolean isLevelUp = false;

        int xpNumerator = newXp - lastLevelXp;
        int xpDenominator = getExperienceRequiredForNextLevel(level) - lastLevelXp;

        Log.e(TAG, "Monster was level: " + level + ", and had " + currentXp + " xp");
        Log.e(TAG, "now has " + newXp + " xp. level now: " + getLevelBasedOnExperience(newXp));

        // In a loop, build up every animation which needs to be done on this particular xp bar. Loop is so multiple animations may be played for multiple level ups\
        // do while because even when the monster does not level up, they still will get some xp so at least 1 anim needs to be played
        do {
            isLevelUp = false;  // Need to reset to know when we have not leveled up

            AnimateHorizontalProgressBar bar = xpGainedLayoutContainer.getChildAt(i).findViewById(R.id.battle_resolution_xp_gained_xp_bar);
            bar.setMax(10000);

            if (newXp > getExperienceRequiredForNextLevel(level)){
                isLevelUp = true;
                level++;
                xpNumerator = xpDenominator;    // Sets the xp bar to full before resetting at 0 for the next level
            }

            Log.e(TAG, "Added new anim for bar at position " + i + ", " + "out of 10000: " + (int) (((double) xpNumerator / (double) xpDenominator) * 10000.0));

            // TODO: clean up messy cast
            LevelUpBarAnimation levelUpBarAnimation = new LevelUpBarAnimation(bar, (int) (((double) xpNumerator / (double) xpDenominator) * 10000.0), level);
            levelUpBarAnimation.setLevelUp(isLevelUp);

            Log.e(TAG, "islevelup set to " + String.valueOf(levelUpBarAnimation.isLevelUp()) + ", going from level " + (level-1) + " to " + (level));
            levelUpBarAnimation.setLevelTxtView(xpGainedLayoutContainer.getChildAt(i).findViewById(R.id.battle_resolution_xp_gained_level_text_view));

            animationList.add(levelUpBarAnimation);

        } while(isLevelUp);

    }

    final int[] animNumber = {0};

    Log.e(TAG, "animlist size " + animationList.size() + " playing across " + battleResolutionXpGainedAdapter.getCount() + " xp bars");
    for (int i = 0; i < battleResolutionXpGainedAdapter.getCount(); i++) {

        AnimateHorizontalProgressBar bar = animationList.get(i).getXpBar();

        bar.setAnimateProgressListener(new AnimateHorizontalProgressBar.AnimateProgressListener() {
            @Override
            public void onAnimationStart(int progress, int max) {

                Log.e(TAG, "anim #" + animNumber[0] + " starting");

            }
            @Override
            public void onAnimationEnd(int progress, int max) {

                // If this xp bar filled up, play a flash sort of animation, and update the lvl text
                if (animationList.get(animNumber[0]).isLevelUp()){

                    int newLvl = animationList.get(animNumber[0]).getLevel();

                    Log.e(TAG, "level up animation playing. anim number " + animNumber[0] + ", now level " + newLvl);
                    // Update the lvl txt
                    animationList.get(animNumber[0]).getLevelTxtView().setText("LVL: " + newLvl);

                    // Then set the progress on this bar back to 0
                    animationList.get(animNumber[0]).getXpBar().setProgress(0);
                }

                Log.e(TAG, "anim number " + animNumber[0] + " finished, next playing " + (animNumber[0] + 1));

                // Do not attempt to play the next animation if this one was the last
                if (animNumber[0] < animationList.size() - 1){
                    animNumber[0]++;
                    Log.e(TAG, "playing anim number " + animNumber[0] + " to " + animationList.get(animNumber[0]).getProgressPercent() + "% full");
                    animationList.get(animNumber[0]).getXpBar().setProgressWithAnim(animationList.get(animNumber[0]).getProgressPercent());  // TODO: this not getting called
                }
            }
        });
    }

    Log.e(TAG, "playing anim number 0");
    animationList.get(0).getXpBar().setProgressWithAnim(animationList.get(0).getProgressPercent());

}

// On receiving a new skill, this tooltip will appear momentarily to notify the player
public void showNewSkillTooltip(String skillName, View view) {
    Log.e(TAG, "Showing new skill tooltip. skill learned: " + skillName);

    // Dynamically build a layout here, as it cannot already have a parent layout if we want to assign it to the tooltip
    LinearLayout tooltipLayout = new LinearLayout(getContext());
    tooltipLayout.setOrientation(LinearLayout.VERTICAL);

    TextView talentTitleText = new TextView(getContext());
    talentTitleText.setTextSize(18f);
    talentTitleText.setText(skillName);
    tooltipLayout.addView(talentTitleText);

    ToolTip toolTip = new ToolTip()
            .withColor(getResources().getColor(R.color.grey_300)) //or whatever you want
            .withAnimationType(ToolTip.AnimationType.FROM_MASTER_VIEW)
            .withContentView(tooltipLayout)
            .withShadow();
    tooltips.showToolTip(toolTip, view);

}

private Task<HashMap<String, Integer>> firebaseResolveCombat(String wildMonsterFirebaseId, ArrayList<String> playerMonsterIds) {
    // Create the arguments to the callable function.
    Map<String, Object> data = new HashMap<>();
    data.put("wildMonsterId", wildMonsterFirebaseId);
    data.put("playerMonsterIds", playerMonsterIds);

    return mFunctions
            .getHttpsCallable("resolveWildMonsterCombat")
            .call(data)
            .continueWith(new Continuation<HttpsCallableResult, HashMap<String, Integer>>() {
                @Override
                public HashMap then(@NonNull Task<HttpsCallableResult> task) throws Exception {
                    // This continuation runs on either success or failure, but if the task
                    // has failed then getResult() will throw an Exception which will be
                    // propagated down.
                    HashMap<String, Integer> result = (HashMap<String, Integer>) task.getResult().getData();
                    return result;
                }
            });
}
}

我增加了全班。原谅凌乱的代码。

问题在于,在我显式开始的第一个动画之后,它运行onAnimationEnd函数,并撞上一行以运行下一个动画,但它从未开始。第二动画甚至不会调用onAnimationStart函数。关于为什么会这样的任何想法?

我还将添加此操作在对话框片段中进行。不确定是否相关。

0 个答案:

没有答案