自定义View仿iOS的UiSwitch控件

自定义View仿iOS的UiSwitch控件

本文原创,转载请注明出处。欢迎关注我的 简书
安利一波我写的开发框架:MyScFrame喜欢的话就给个Star

前言:

Android的Switch控件相信大家都用过,其实我觉得效果还好,不过公司要求UI上的统一,所以让我仿iOS效果,我就纳闷了,为什么一直要仿iOS,就不能iOS仿Android么?牢骚发完了,可以开工了。

附上效果图

效果如图,看起来还行吧

思路

绘制控件

整个控件在绘制的时候分2个部分:

  1. 底板,也就是那个椭圆形类似跑道的部分。
  2. 按钮。

这部分没什么需要特别说明的,如果有一点自定义View基础的朋友应该都能轻松搞定。

动效处理

动效我这里用的也是最基础的平移动效,同时加上底板颜色渐变效果

/**
     * 关闭开关
     */
    public void toggleOn() {
        //手柄槽颜色渐变和手柄滑动通过属性动画来实现
        ObjectAnimator animator = ObjectAnimator.ofFloat(this, "spotStartX", 0, mOffSpotX);
        animator.setDuration(300);
        animator.start();
        animator.setInterpolator(new DecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float fraction = animation.getAnimatedFraction();
                calculateColor(fraction, mOffSlotColor, mOpenSlotColor);
                invalidate();
            }
        });
    }

    /**
     * 打开开关
     */
    public void toggleOff() {
        //手柄槽颜色渐变和手柄滑动通过属性动画来实现
        ObjectAnimator animator = ObjectAnimator.ofFloat(this, "spotStartX", mOffSpotX, 0);
        animator.setDuration(300);
        animator.start();
        animator.setInterpolator(new DecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float fraction = animation.getAnimatedFraction();
                calculateColor(fraction, mOpenSlotColor, mOffSlotColor);
                invalidate();
            }
        });
    }

/**
     * 计算切换时的手柄槽的颜色
     *
     * @param fraction   动画播放进度
     * @param startColor 起始颜色
     * @param endColor   终止颜色
     */
    public void calculateColor(float fraction, int startColor, int endColor) {
        final int fb = Color.blue(startColor);
        final int fr = Color.red(startColor);
        final int fg = Color.green(startColor);

        final int tb = Color.blue(endColor);
        final int tr = Color.red(endColor);
        final int tg = Color.green(endColor);

        //RGB三通道线性渐变
        int sr = (int) (fr + fraction * (tr - fr));
        int sg = (int) (fg + fraction * (tg - fg));
        int sb = (int) (fb + fraction * (tb - fb));
        //范围限定
        sb = clamp(sb, 0, 255);
        sr = clamp(sr, 0, 255);
        sg = clamp(sg, 0, 255);

        mSlotColor = Color.rgb(sr, sg, sb);
    }

Touch事件与Onclick事件

这里我是自己做了一个手势工具类,专门处理Touch中的手势,没任何难度,只是懒得每个自定义控件里面都写一套重复的代码,所以就做了个工具类,方便今后的开发
这里也分享给大家(不要吐槽我的类名,我是百度翻译的)

/**
 * Created by caihan on 2017/2/10.
 * 手势判断工具类,
 */
public class GestureUtils {
    private static final String TAG = "GestureUtils";

    private float startX = 0f;
    private float endX = 0f;
    private float startY = 0f;
    private float endY = 0f;
    private float xDistance = 0f;
    private float yDistance = 0f;

    public enum Gesture {
        PullUp, PullDown, PullLeft, PullRight
    }

    public GestureUtils() {

    }

    /**
     * 当event.getAction() == MotionEvent.ACTION_DOWN 的时候调用
     * 设置初始X,Y坐标
     *
     * @param event
     */
    public void actionDown(MotionEvent event) {
        xDistance = yDistance = 0f;
        setStartX(event);
        setStartY(event);
    }

    /**
     * 当event.getAction() == MotionEvent.ACTION_MOVE 的时候调用
     * 设置移动的X,Y坐标
     *
     * @param event
     */
    public void actionMove(MotionEvent event) {
        setEndX(event);
        setEndY(event);
    }

    /**
     * 当event.getAction() == MotionEvent.ACTION_UP 的时候调用
     * 设置截止的X,Y坐标
     *
     * @param event
     */
    public void actionUp(MotionEvent event) {
        setEndX(event);
        setEndY(event);
    }

    /**
     * 手势判断接口
     *
     * @param gesture
     * @return
     */
    public boolean getGesture(Gesture gesture) {
        switch (gesture) {
            case PullUp:
                return isRealPullUp();
            case PullDown:
                return isRealPullDown();
            case PullLeft:
                return isRealPullLeft();
            case PullRight:
                return isRealPullRight();
            default:
                LogUtils.e(TAG, "getGesture error");
                return false;
        }
    }

    /**
     * 获取Touch点相对于屏幕原点的X坐标
     *
     * @param event
     * @return
     */
    private float gestureRawX(MotionEvent event) {
        return event.getRawX();
    }

    /**
     * 获取Touch点相对于屏幕原点的Y坐标
     *
     * @param event
     * @return
     */
    private float gestureRawY(MotionEvent event) {
        return event.getRawY();
    }

    /**
     * 获取X轴偏移量,取绝对值
     *
     * @param startX
     * @param endX
     * @return
     */
    private float gestureDistanceX(float startX, float endX) {
        setxDistance(Math.abs(endX - startX));
        return xDistance;
    }

    /**
     * 获取Y轴偏移量,取绝对值
     *
     * @param startY
     * @param endY
     * @return
     */
    private float gestureDistanceY(float startY, float endY) {
        setyDistance(Math.abs(endY - startY));
        return yDistance;
    }

    /**
     * endY坐标比startY小,相减负数表示手势上滑
     *
     * @param startY
     * @param endY
     * @return
     */
    private boolean isPullUp(float startY, float endY) {
        return (endY - startY) < 0;
    }

    /**
     * endY坐标比startY大,相减正数表示手势下滑
     *
     * @param startY
     * @param endY
     * @return
     */
    private boolean isPullDown(float startY, float endY) {
        return (endY - startY) > 0;
    }

    /**
     * endX坐标比startX大,相减正数表示手势右滑
     *
     * @param startX
     * @param endX
     * @return
     */
    private boolean isPullRight(float startX, float endX) {
        return (endX - startX) > 0;
    }

    /**
     * endX坐标比startX小,相减负数表示手势左滑
     *
     * @param startX
     * @param endX
     * @return
     */
    private boolean isPullLeft(float startX, float endX) {
        return (endX - startX) < 0;
    }

    /**
     * 判断用户真实操作是否是上滑
     *
     * @return
     */
    private boolean isRealPullUp() {
        if (gestureDistanceX(startX, endX) < gestureDistanceY(startY, endY)) {
            //Y轴偏移量大于X轴,表示用户真实目的是上下滑动
            return isPullUp(startY, endY);
        }
        return false;
    }

    /**
     * 判断用户真实操作是否是下滑
     *
     * @return
     */
    private boolean isRealPullDown() {
        if (gestureDistanceX(startX, endX) < gestureDistanceY(startY, endY)) {
            //Y轴偏移量大于X轴,表示用户真实目的是上下滑动
            return isPullDown(startY, endY);
        }
        return false;
    }

    /**
     * 判断用户真实操作是否是左滑
     *
     * @return
     */
    private boolean isRealPullLeft() {
        if (gestureDistanceX(startX, endX) > gestureDistanceY(startY, endY)) {
            //Y轴偏移量大于X轴,表示用户真实目的是上下滑动
            return isPullLeft(startX, endX);
        }
        return false;
    }

    /**
     * 判断用户真实操作是否是左滑
     *
     * @return
     */
    private boolean isRealPullRight() {
        if (gestureDistanceX(startX, endX) > gestureDistanceY(startY, endY)) {
            //Y轴偏移量大于X轴,表示用户真实目的是上下滑动
            return isPullRight(startX, endX);
        }
        return false;
    }


    private GestureUtils setStartX(MotionEvent event) {
        this.startX = gestureRawX(event);
        return this;
    }

    private GestureUtils setEndX(MotionEvent event) {
        this.endX = gestureRawX(event);
        return this;
    }

    private GestureUtils setStartY(MotionEvent event) {
        this.startY = gestureRawY(event);
        return this;
    }

    private GestureUtils setEndY(MotionEvent event) {
        this.endY = gestureRawY(event);
        return this;
    }

    private GestureUtils setxDistance(float xDistance) {
        this.xDistance = xDistance;
        return this;
    }

    private GestureUtils setyDistance(float yDistance) {
        this.yDistance = yDistance;
        return this;
    }

    public float getStartX() {
        return startX;
    }

    public float getEndX() {
        return endX;
    }

    public float getStartY() {
        return startY;
    }

    public float getEndY() {
        return endY;
    }

    public float getxDistance() {
        return xDistance;
    }

    public float getyDistance() {
        return yDistance;
    }
}

大家都知道,Onclick事件是要在Touch的MotionEvent.ACTION_UP事件之后才触发的,也就是说,如果我们dispatchTouchEvent分发Touch事件的时候,当event.getAction() = MotionEvent.ACTION_UP时,返回true,那么Onclick就不会触发,这样的话,我们就能针对不同的事件做不同的处理,我这边就是这样设计的

    private boolean mIsToggleOn = false;//当前开关标记
    private boolean isTouchEvent = false;//是否由滑动事件消费掉
    private boolean isMoveing = false;//是否还在Touch相应中

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mGestureUtils.actionDown(event);
                isTouchEvent = false;
                isMoveing = false;
                break;
            case MotionEvent.ACTION_MOVE:
                mGestureUtils.actionMove(event);
                if (mGestureUtils.getGesture(GestureUtils.Gesture.PullLeft)) {
                    //左滑,关闭
                    isTouchEvent = true;
                    touchToggle(false);
                    return true;
                } else if (mGestureUtils.getGesture(GestureUtils.Gesture.PullRight)) {
                    //右滑,开启
                    isTouchEvent = true;
                    touchToggle(true);
                    return true;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            case MotionEvent.ACTION_UP:
                isMoveing = false;
                if (isTouchEvent) {
                    //不会触发Onclick事件了
                    return true;
                }
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }

    /**
     * Touch事件触发
     * mIsToggleOn是当前状态,当mIsToggleOn != open时做出相应
     *
     * @param open 是否打开
     */
    private void touchToggle(boolean open) {
        if (!isMoveing) {
            isMoveing = true;
            if (mIsToggleOn != open) {
                if (mIsToggleOn) {
                    toggleOff();
                } else {
                    toggleOn();
                }
                mIsToggleOn = !mIsToggleOn;
                if (mOnToggleListener != null) {
                    mOnToggleListener.onSwitchChangeListener(mIsToggleOn);
                }
            }
        }
    }

    /**
     * Onclick事件触发
     */
    private void onClickToggle() {
        if (mIsToggleOn) {
            toggleOff();
        } else {
            toggleOn();
        }
        mIsToggleOn = !mIsToggleOn;
        if (mOnToggleListener != null) {
            mOnToggleListener.onSwitchChangeListener(mIsToggleOn);
        }
    }

然后监听按钮状态

    public interface OnToggleListener {
        void onSwitchChangeListener(boolean switchState);
    }

    public void setOnToggleListener(OnToggleListener listener) {
        mOnToggleListener = listener;
    }

完了完了,就这么简单...什么?要完整代码?好吧

/**
 * Created by caihan on 2017/2/10.
 * 仿iOS的UiSwitch控件
 */
public class IosSwitch extends View implements View.OnClickListener {

    private static final String TAG = "IosSwitch";

    private final int BORDER_WIDTH = 2;//边框宽度

    private int mBasePlaneColor = Color.parseColor("#4ebb7f");//底盘颜色,布局描边颜色
    private int mOpenSlotColor = Color.parseColor("#4ebb7f");//开启时手柄滑动槽的颜色
    private int mOffSlotColor = Color.parseColor("#EEEEEE");//关闭时手柄滑动槽的颜色

    private int mSlotColor;

    private RectF mRect = new RectF();

    //绘制参数
    private float mBackPlaneRadius;//底板的圆形半径
    private float mSpotRadius;//手柄半径

    private float spotStartX;//手柄的起始X位置,切换时平移改变它
    private float mSpotY;//手柄的起始X位置,不变
    private float mOffSpotX;//关闭时,手柄的水平位置

    private Paint mPaint;//画笔

    private boolean mIsToggleOn = false;//当前开关标记
    private boolean isTouchEvent = false;//是否由滑动事件消费掉
    private boolean isMoveing = false;//是否还在Touch相应中

    private OnToggleListener mOnToggleListener;//toggle事件监听

    private GestureUtils mGestureUtils;//手势工具类

    public interface OnToggleListener {
        void onSwitchChangeListener(boolean switchState);
    }

    public IosSwitch(Context context) {
        super(context);
        init(context);
    }

    public IosSwitch(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        setOnClickListener(this);
        setEnabled(true);
        mGestureUtils = new GestureUtils();
    }

    @Override
    public void onClick(View v) {
        onClickToggle();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mGestureUtils.actionDown(event);
                isTouchEvent = false;
                isMoveing = false;
                break;
            case MotionEvent.ACTION_MOVE:
                mGestureUtils.actionMove(event);
                if (mGestureUtils.getGesture(GestureUtils.Gesture.PullLeft)) {
                    //左滑,关闭
                    isTouchEvent = true;
                    touchToggle(false);
                    return true;
                } else if (mGestureUtils.getGesture(GestureUtils.Gesture.PullRight)) {
                    //右滑,开启
                    isTouchEvent = true;
                    touchToggle(true);
                    return true;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            case MotionEvent.ACTION_UP:
                isMoveing = false;
                if (isTouchEvent) {
                    //不会触发Onclick事件了
                    return true;
                }
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int wMode = MeasureSpec.getMode(widthMeasureSpec);
        int hMode = MeasureSpec.getMode(heightMeasureSpec);
        int wSize = MeasureSpec.getSize(widthMeasureSpec);
        int hSize = MeasureSpec.getSize(heightMeasureSpec);
        int resultWidth = wSize;
        int resultHeight = hSize;
        Resources r = Resources.getSystem();
        //lp = wrapcontent时 指定默认值
        if (wMode == MeasureSpec.AT_MOST) {
            resultWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, r.getDisplayMetrics());
        }
        if (hMode == MeasureSpec.AT_MOST) {
            resultHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, r.getDisplayMetrics());
        }
        setMeasuredDimension(resultWidth, resultHeight);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        mBackPlaneRadius = Math.min(getWidth(), getHeight()) * 0.5f;
        mSpotRadius = mBackPlaneRadius - BORDER_WIDTH;
        spotStartX = 0;
        mSpotY = 0;
        mOffSpotX = getMeasuredWidth() - mBackPlaneRadius * 2;
        mSlotColor = mOffSlotColor;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //画底板
        mRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
        mPaint.setColor(mBasePlaneColor);
        canvas.drawRoundRect(mRect, mBackPlaneRadius, mBackPlaneRadius, mPaint);

        //画手柄的槽
        mRect.set(BORDER_WIDTH,
                BORDER_WIDTH,
                getMeasuredWidth() - BORDER_WIDTH,
                getMeasuredHeight() - BORDER_WIDTH);

        mPaint.setColor(mSlotColor);
        canvas.drawRoundRect(mRect, mSpotRadius, mSpotRadius, mPaint);

        //手柄包括包括两部分,深色底板和白板,这样做的目的是使圆盘具有边框
        //手柄的底盘
        mRect.set(spotStartX,
                mSpotY,
                spotStartX + mBackPlaneRadius * 2,
                mSpotY + mBackPlaneRadius * 2);

        mPaint.setColor(mBasePlaneColor);
        canvas.drawRoundRect(mRect, mBackPlaneRadius, mBackPlaneRadius, mPaint);

        //手柄的圆板
        mRect.set(spotStartX + BORDER_WIDTH,
                mSpotY + BORDER_WIDTH,
                mSpotRadius * 2 + spotStartX + BORDER_WIDTH,
                mSpotRadius * 2 + mSpotY + BORDER_WIDTH);

        mPaint.setColor(Color.WHITE);
        canvas.drawRoundRect(mRect, mSpotRadius, mSpotRadius, mPaint);
    }

    public float getSpotStartX() {
        return spotStartX;
    }

    public void setSpotStartX(float spotStartX) {
        this.spotStartX = spotStartX;
    }

    /**
     * 计算切换时的手柄槽的颜色
     *
     * @param fraction   动画播放进度
     * @param startColor 起始颜色
     * @param endColor   终止颜色
     */
    public void calculateColor(float fraction, int startColor, int endColor) {
        final int fb = Color.blue(startColor);
        final int fr = Color.red(startColor);
        final int fg = Color.green(startColor);

        final int tb = Color.blue(endColor);
        final int tr = Color.red(endColor);
        final int tg = Color.green(endColor);

        //RGB三通道线性渐变
        int sr = (int) (fr + fraction * (tr - fr));
        int sg = (int) (fg + fraction * (tg - fg));
        int sb = (int) (fb + fraction * (tb - fb));
        //范围限定
        sb = clamp(sb, 0, 255);
        sr = clamp(sr, 0, 255);
        sg = clamp(sg, 0, 255);

        mSlotColor = Color.rgb(sr, sg, sb);
    }

    private int clamp(int value, int low, int high) {
        return Math.min(Math.max(value, low), high);
    }

    /**
     * 关闭开关
     */
    public void toggleOn() {
        //手柄槽颜色渐变和手柄滑动通过属性动画来实现
        ObjectAnimator animator = ObjectAnimator.ofFloat(this, "spotStartX", 0, mOffSpotX);
        animator.setDuration(300);
        animator.start();
        animator.setInterpolator(new DecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float fraction = animation.getAnimatedFraction();
                calculateColor(fraction, mOffSlotColor, mOpenSlotColor);
                invalidate();
            }
        });
    }

    /**
     * 打开开关
     */
    public void toggleOff() {
        //手柄槽颜色渐变和手柄滑动通过属性动画来实现
        ObjectAnimator animator = ObjectAnimator.ofFloat(this, "spotStartX", mOffSpotX, 0);
        animator.setDuration(300);
        animator.start();
        animator.setInterpolator(new DecelerateInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float fraction = animation.getAnimatedFraction();
                calculateColor(fraction, mOpenSlotColor, mOffSlotColor);
                invalidate();
            }
        });
    }

    public boolean getSwitchState() {
        return mIsToggleOn;
    }

    /**
     * Touch事件触发
     * mIsToggleOn是当前状态,当mIsToggleOn != open时做出相应
     *
     * @param open 是否打开
     */
    private void touchToggle(boolean open) {
        if (!isMoveing) {
            isMoveing = true;
            if (mIsToggleOn != open) {
                if (mIsToggleOn) {
                    toggleOff();
                } else {
                    toggleOn();
                }
                mIsToggleOn = !mIsToggleOn;
                if (mOnToggleListener != null) {
                    mOnToggleListener.onSwitchChangeListener(mIsToggleOn);
                }
            }
        }
    }

    /**
     * Onclick事件触发
     */
    private void onClickToggle() {
        if (mIsToggleOn) {
            toggleOff();
        } else {
            toggleOn();
        }
        mIsToggleOn = !mIsToggleOn;
        if (mOnToggleListener != null) {
            mOnToggleListener.onSwitchChangeListener(mIsToggleOn);
        }
    }

    public void setOnToggleListener(OnToggleListener listener) {
        mOnToggleListener = listener;
    }

    /**
     * 界面上设置开关初始状态
     * @param open
     */
    public void setChecked(final boolean open) {
        this.postDelayed(new Runnable() {
            @Override
            public void run() {
                touchToggle(open);
            }
        }, 300);
    }
}

感谢

感谢kakacxicm提供的绘制思路与动效处理
这边再分享几个其他的版本给大家参考:
SwitchButton
自定义控件(三步搞定switch)
Swift-自定义switch控件

搞定,收工

欢迎大家留言指出我的不足。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 从现在开始,做一个简单的人, 早起跑步,看朝阳漫漫聚集成型, 感受第一缕强光照射身上的融融暖意。 从现在开始,做一...
    6班三期12组组长孙荣亮阅读 488评论 6 6
  • 世界上有两种人,一种是中心人,一种是边缘人。中心人的世界我不懂,这个物质社会他们能混得如鱼得水。边缘人的生活...
    康文阅读 1,986评论 0 5
  • 我总希望自己能够把烟戒掉,也因此痛下了很多次决心,可想来决心这东西的唯一用处是拿到安慰深夜睡不着的自己,而让失眠变...
    笔名苏式阅读 151评论 0 0
  • 不知不觉发现明天又到了新的一年上班的时候了,感觉完全没有准备好 开始又一年的时间~暂且写个目标清单这里 1.代码篇...
    四顾sel阅读 128评论 0 0