android图片滚动选择器的实现

来源:互联网 发布:网络直播发展史 编辑:程序博客网 时间:2024/05/01 12:48

之前的一篇文章《Android自定义view——滚动选择器》(没看过的同学建议先去了解一下)介绍了滚动选择器的原理,并实现了字符串选择器。现在要讲讲图片选择器的实现,以及通过选择器实现老虎机效果。

01

这里写图片描述


图片选择器

跟字符串选择器(StringScrollPicker)一样,图片选择器继承了ScrollPickerView,并在drawItem()方法里面实现图片的绘制。这里边提供了三种图片绘制模式:填充、居中、指定大小。

public class BitmapScrollPicker extends ScrollPickerView<Bitmap> {    /**     * 图片绘制模式:填充     */    public final static int DRAW_MODE_FULL = 1;    /**     * 图片绘制模式:居中     */    public final static int DRAW_MODE_CENTER = 2;    /**     * 图片绘制模式:指定大小     */    public final static int DRAW_MODE_SPECIFIED_SIZE = 3;      ...    @Override    public void drawItem(Canvas canvas, List<Bitmap> data, int position, int relative, float moveLength, float top) {     ...    }    ...}

老虎机

其实老虎机就是三个图片滚动选择器的组合,另外加上自动滚动及控制每个滚动器的结果。下面是老虎机SlotMachine的简单布局,主要是把三个滚动选择器的长度设置得比父容器稍高大一点,使得最上面和最下面的奖励只显示一半。
03

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"             android:layout_width="match_parent"             android:layout_height="250dp"             android:layout_gravity="center_horizontal"             android:padding="24dp"    >    <LinearLayout        android:layout_width="match_parent"        android:layout_height="288dp"        android:layout_gravity="center_vertical"        android:layout_margin="6dp"        android:layout_weight="1"        android:orientation="horizontal">        <cn.forward.androids.views.BitmapScrollPicker            android:id="@+id/slot_view_01"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_weight="1"            />        <FrameLayout            android:layout_width="2dp"            android:layout_height="match_parent"            android:layout_gravity="center_vertical"            android:background="#bfbfbf"/>        <cn.forward.androids.views.BitmapScrollPicker            android:id="@+id/slot_view_02"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_weight="1"            />        <FrameLayout            android:layout_width="2dp"            android:layout_height="match_parent"            android:layout_gravity="center_vertical"            android:background="#bfbfbf"/>        <cn.forward.androids.views.BitmapScrollPicker            android:id="@+id/slot_view_03"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_weight="1"            />    </LinearLayout>    <FrameLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="@drawable/shape_slot_machine_border"        /></FrameLayout>

为了更接近老虎机的效果,当结果为没抽中时,使得其中两个选择器的奖励尽量相同,给玩家一种“差一点就中了”的感觉。同时,提供了回调接口给调用者来确定最终的结果,并采取相应的弥补措施。老虎机的关键代码如下:

/** * 老虎机 */public class SlotMachine extends FrameLayout implements ScrollPickerView.OnSelectedListener {    // 滚动的时间    private static int DURATION01 = 3000;    private static int DURATION02 = 3500;    private static int DURATION03 = 4000;    private final static ArrayList<Integer> mDurationList = new ArrayList<Integer>(Arrays.asList(DURATION01, DURATION02, DURATION03));...    @Override    public void onSelected(ScrollPickerView slotView, int position) {        if (mIsPlaying) {            mFinishedCounter++;            if (slotView == mSlot01) {                mSelectedArray[0] = position;            } else if (slotView == mSlot02) {                mSelectedArray[1] = position;            } else if (slotView == mSlot03) {                mSelectedArray[2] = position;            }            if (mFinishedCounter >= 3) {                mFinishedCounter = 0;                if (mSlotMachineListener != null) {                    boolean win = false;                    boolean makeup = false;                    if (mSelectedArray[0] == mSelectedArray[1] && mSelectedArray[0] == mSelectedArray[2]) { // win                        // 是否取消中奖,采用弥补动画,使之变成不中奖的结果                        win = mSlotMachineListener.acceptWinResult(mSelectedArray[0]);                        makeup = !win;                    }                    final boolean finalMakeup = makeup;                    Runnable task = new Runnable() {                        public void run() {                            if (finalMakeup) {                                mSelectedArray[2] = mSlot03.getSelectedPosition();                            }                            mSlotMachineListener.onFinish(mSelectedArray[0], mSelectedArray[1], mSelectedArray[2]);                            mIsPlaying = false;                        }                    };                    if (makeup) {                        makeUpPurchaseFailed(mSelectedArray[2]);                        // 等待弥补动画结束                        ThreadUtil.getInstance().runOnMainThread(task, 1200);                    } else {                        task.run();                    }                }            }        }    }    /**     * 开始滚动,     *     * @param prizePosition 奖品的索引,如果prizePosition<0或者 prizePosition>=总的奖品数,则表示不中奖     */    public boolean play(int prizePosition) {        if (!isClickable() || mIsPlaying) {            return false;        }        mFinishedCounter = 0;        mIsPlaying = true;        int slot01, slot02, slot03;        int duration01, duration02, duration03;//        Collections.shuffle(mDurationList);        duration01 = mDurationList.get(0);        duration02 = mDurationList.get(1);        duration03 = mDurationList.get(2);        if (prizePosition < 0 || prizePosition >= mPrizeList.size()) { // 不中奖,控制三个中有两个相同            // pos01表示时间最短的停留位置,pos03表示时间最长            int pos01, pos02, pos03;            pos01 = mRandom.nextInt(mPrizeList.size());            if (mRandom.nextInt(3) == 0) { // 01,02相同的概率为1/3                pos02 = pos01;                pos03 = mRandom.nextInt(mPrizeList.size());            } else {                pos02 = mRandom.nextInt(mPrizeList.size());                if (mRandom.nextInt(4) == 0) { // 01,03相同的概率为1/4                    pos03 = pos01;                } else {                    pos03 = mRandom.nextInt(mPrizeList.size());                }            }            if (pos01 == pos02 && pos01 == pos03) {                pos01 = (pos01 + 1) % mPrizeList.size();            }            // 按照时间排序老虎机的窗口,如[1,3,2]表示slot01的时间最短,接着是slot03,slot02            HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();            map.put(mDurationList.indexOf(DURATION01) + 1, pos01); // 时间最短的那个slot停留的位置            map.put(mDurationList.indexOf(DURATION02) + 1, pos02);            map.put(mDurationList.indexOf(DURATION03) + 1, pos03);            slot01 = map.get(1);            slot02 = map.get(2);            slot03 = map.get(3);        } else {            slot01 = slot02 = slot03 = prizePosition;        }        mSlot01.autoScrollFast(slot01, duration01);        mSlot02.autoScrollFast(slot02, duration02);        mSlot03.autoScrollFast(slot03, duration03);        return true;    }    /**     * 弥补购买失败,使其中一个往下滚动一列,造成未抽中的假象     *     * @param prizePosition     */    public void makeUpPurchaseFailed(int prizePosition) {        int moveY = mSlot03.getItemHeight();        mSlot03.autoScrollTo(moveY, 1200, new LinearInterpolator(), false);    }    public interface SlotMachineListener {        /**         * 滚动结束时回调         * @param pos01         * @param pos02         * @param pos03         */        void onFinish(int pos01, int pos02, int pos03);        /**         * 是否接受该次中奖结果         * @param position         * @return 返回true则表示确认该次赢得奖品,false则表示取消该次奖品         */        boolean acceptWinResult(int position);    }}

完整的代码放在了github上:https://github.com/1993hzw/Androids,谢谢大伙的支持!

0 0