ExpandableList自定义动画效果

项目中使用ExpandableList,要求分组展开时显示一个动画,


问题:

动画效果位于GroupView上,适配器中getGroupView方法通过判断当前项是点击的分组,

然后进行展开和收起的动画。

原实现方法:

@Override
public View getGroupView(int groupPosition, final boolean isExpanded,

View convertView, ViewGroup parent) {
final ViewHolderGroup holder;

{省略}
if (CommonDetailActivity.onClickPosition == groupPosition) {
if(isExpanded) {
ObjectAnimator animation = ObjectAnimator.ofFloat(holder.right, "rotation", 0, 90);
animation.setDuration(250);
animation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {


}


@Override
public void onAnimationEnd(Animator animator) {
CommonDetailActivity.onClickPosition = -1;
}


@Override
public void onAnimationCancel(Animator animator) {


}


@Override
public void onAnimationRepeat(Animator animator) {


}
});
animation.start();
} else {
ObjectAnimator animation = ObjectAnimator.ofFloat(holder.right, "rotation", 90, 0);
animation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {


}


@Override
public void onAnimationEnd(Animator animator) {
CommonDetailActivity.onClickPosition = -1;
}


@Override
public void onAnimationCancel(Animator animator) {


}


@Override
public void onAnimationRepeat(Animator animator) {


}
});
animation.setDuration(250);
animation.start();
}
}
return convertView;
}


此种实现方法存在的问题,当展开播放动画时,发现经常出现两个分组都在播放

动画的效果。例如点击一个分组展开,当前分组和其他一个分组箭头的动画

同时播放的现象。


发生原因:

这是因为安卓Adapter的视图缓存复用机制引起的。例如,点击第二个分组展开,

通过日志发现,



生成分组视图时,getGroupView会执行9次,分组视图GV1,GV2,GV3对应的数据项

是随机分配的,例如第一轮时可能GV1对应的position=0,因此GV1播放动画;

第二轮时GV3对应position=0,GV3播放动画。因此,这种缓存视图复用的情况,

可能导致两个分组视图同时响应的情况。其实是初始化过程中视图复用,

对应的数据项变化引起的。


解决方法和思路:

既然初始化过程缓存视图是动态变化的,因此初始化getGroupView过程中,

不进行动画播放处理。初始化完成后,视图对应的数据项稳定时,

再进行动画播放处理。


1)Adapter部分:

记录每个分组数据对应的View的状态,通过groupInfo保存,不需要记录中间视图缓存

复用的过程;初始化过程中不播放动画,直接初始化。根据数据直接显示结果,

例如,展开的分组,箭头角度直接设置为90度,其他的箭头角度为0。


public class CommonDetailAdapter extends BaseExpandableListAdapter {
    private static final int STATE_IDLE = 0;
    private static final int STATE_EXPANDING = 1;
    private static final int STATE_COLLAPSING = 2;
    private static final int STATE_EXPANDED = 3;


    /** 展开时旋转角度 */
    private static final int EXPAND_ROTATE_ANGLE = 90;


    /**
     * Group控件的信息
     * 说明:因为分组视图存在复用的情况因此以最后的视图为准
     */

    private Map<Integer, ViewHolderGroup> groupInfo = new HashMap<Integer,

ViewHolderGroup>();


    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    @Override
    public View getGroupView(int groupPosition, final boolean isExpanded,

View convertView, ViewGroup parent) {
        ViewHolderGroup holder = null;
        if (convertView == null) {
            holder = new ViewHolderGroup();
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_common_layout, null);
            holder.title = (TextView) convertView.findViewById(R.id.common_item_title);
            holder.image = (SmartImageView) convertView.findViewById(R.id.common_item_image);
            holder.right = (TextView) convertView.findViewById(R.id.common_item_right);
            holder.status = (TextView) convertView.findViewById(R.id.common_item_status);
            holder.right.setTypeface(StringUtils.getTypeface());
            holder.right.setText(Html.fromHtml("&#xe608"));
            convertView.setTag(holder);
        } else {
            holder = (ViewHolderGroup) convertView.getTag();
        }
        holder.isExpanded = isExpanded;
        groupInfo.put(groupPosition, holder);


        try {
            int isFinish = 0;
            int total = beans.get(groupPosition).getPic_cate_list().size();
            for (int i = 0; i < total; i++) {
                if (beans.get(groupPosition).getPic_cate_list().get(i).getIs_finish() == 1) {
                    isFinish++;
                }
            }
            holder.title.setTypeface(StringUtils.getTypeface());
            holder.title.setText(Html.fromHtml(beans.get(groupPosition).getTitle()));
            holder.status.setText("" + isFinish + "/" + total);
            if (isFinish < total) {
                holder.status.setTextColor(mContext.getResources().getColor(R.color.main_blue));
            } else {
                holder.status.setTextColor(mContext.getResources().getColor(R.color.color_main));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //根据图片URL显示
        if (!TextUtils.isEmpty(beans.get(groupPosition).getIcon_url())) {
            holder.image.setVisibility(View.VISIBLE);
            holder.image.setImageUrl(beans.get(groupPosition).getIcon_url());
        } else {
            holder.image.setVisibility(View.VISIBLE);
            holder.image.setImageResource(R.drawable.common_default);
        }
        if(isExpanded && STATE_EXPANDED != holder.expandStatus) {
            //如果当前项需要展开
            ViewHelper.setRotation(holder.right, EXPAND_ROTATE_ANGLE);
            holder.expandStatus = STATE_EXPANDED;
        } else if(!isExpanded && STATE_IDLE != holder.expandStatus) {
            //如果当前项需要收起
            ViewHelper.setRotation(holder.right, 0);
            holder.expandStatus = STATE_IDLE;
        }

        return convertView;
    }


2)点击分组展开或者收缩动画,根据数据项找到对应的视图,进行动画播放。


    public void setSelectedGroup(int selectedGroup) {
        this.selectedGroup = selectedGroup;
        //获取对应的视图信息
        ViewHolderGroup holder = groupInfo.get(selectedGroup);
        if (null != holder) {
            if (holder.isExpanded) {
                //展开分组
                expandGroupAnimation(holder);
            } else {
                //收起分组
                collapseGroupAnimation(holder);
            }
        }
    }

    /**
     * 收起分组动画
     */

    private void collapseGroupAnimation(final ViewHolderGroup holder) {
        if(STATE_IDLE == holder.expandStatus
                || (holder.animating && STATE_COLLAPSING == holder.expandStatus)) {
            return;
        }
        ObjectAnimator animation = ObjectAnimator.ofFloat(holder.right, "rotation", 90, 0);
        holder.expandStatus = STATE_COLLAPSING;
        holder.animating = true;
        animation.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {


            }


            @Override
            public void onAnimationEnd(Animator animator) {
                selectedGroup = -1;
                holder.expandStatus = STATE_IDLE;
                holder.animating = false;
            }


            @Override
            public void onAnimationCancel(Animator animator) {


            }


            @Override
            public void onAnimationRepeat(Animator animator) {


            }
        });
        animation.setDuration(250);
        animation.start();
    }


    /**
     * 展开分组动画
     */
    private void expandGroupAnimation(final ViewHolderGroup holder) {
        if (STATE_EXPANDED == holder.expandStatus
                || (holder.animating && STATE_EXPANDING == holder.expandStatus)) {
            return;
        }
        LogUtils.d(TAG, "expandGroupAnimation start: ");
        ObjectAnimator animation = ObjectAnimator.ofFloat(holder.right, "rotation", 0, 90);
        animation.setDuration(250);
        holder.expandStatus = STATE_EXPANDING;
        holder.animating = true;
        LogUtils.d(TAG, "expandGroupAnimation : ");
        animation.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {


            }


            @Override
            public void onAnimationEnd(Animator animator) {
                selectedGroup = -1;
                holder.expandStatus = STATE_EXPANDED;
                holder.animating = false;
                LogUtils.d(TAG, "expandGroupAnimation End: ");
            }


            @Override
            public void onAnimationCancel(Animator animator) {


            }


            @Override
            public void onAnimationRepeat(Animator animator) {


            }
        });
        animation.start();
    }


    static class ViewHolderGroup {
        /**
         * 分组标题
         */

        TextView title;
        /**
         * 分组图片
         */

        SmartImageView image;
        /**
         * 分组右边的标记
         */

        TextView right;
        /**
         * 分组完成情况
         */

        TextView status;
        /**
         * 当前状态
         */

        int expandStatus = STATE_IDLE;
        /**
         * 当前分组是否展开
         */

        boolean isExpanded;
        /**
         * 是否正在播放动画
         */

        boolean animating;


    }
}


3)在列表初始化完成后,再进行动画播放。

mListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v,

final int groupPosition, long id) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
commonDetailAdapter.setSelectedGroup(groupPosition);
Log.d(CommonDetailAdapter.TAG, "onGroupClick groupPosition : " + groupPosition);
}
}, 100);


return false;
}
});


当然,这只是我的一种处理方法。最完美的方式当前是能够将动画处理完美集成到

ExpandableListView的固有方法和过程中。网络上还有其他一些的方法可参考。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值