Android中實現(xiàn)滑動效果

預備知識

  1. Android屏幕區(qū)域劃分
    我們先看一副圖來了解一下Android屏幕的區(qū)域劃分实愚,如下:


    Android屏幕的區(qū)域劃分

    通過上圖我們可以很直觀的看到Android對于屏幕的劃分定義丰歌。下面我們就給出這些區(qū)域里常用區(qū)域的一些坐標或者度量方式梅肤。如下:

//獲取屏幕區(qū)域的寬高等尺寸獲取
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
//應用程序App區(qū)域?qū)捀叩瘸叽绔@取
Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
//獲取狀態(tài)欄高度
Rect rect= new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rectangle.top;
//View布局區(qū)域?qū)捀叩瘸叽绔@取
Rect rect = new Rect();  
getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(rect);

特別注意:上面這些方法最好在Activity的onWindowFocusChanged ()方法或者之后調(diào)運掩缓,因為只有這時候才是真正的顯示OK筛武。

  1. Android坐標系桨仿、View坐標系报腔、位置的獲取偎谁、距離的獲取和View寬度的獲取
    在Android中,將屏幕最左上角的頂點作為Android坐標系的原點俺驶,從這個點向右是X軸正方向幸逆,從這個點向下是Y軸正方向棍辕。
    在Android中,將View的左上角頂點作為View坐標系的原點还绘,從這個點向右是X軸正方向楚昭,從這個點向下是Y軸正方向。
    下面我們就來看看在上面兩種坐標系下位置的獲取拍顷、距離的獲取和View寬度的獲取 的方法抚太。
    1中我們分析了Android屏幕的劃分,可以發(fā)現(xiàn)我們平時開發(fā)的重點其實都在關注View布局區(qū)域昔案,那么下面我們就來細說一下View區(qū)域常用的位置和距離尿贫。先看下面這幅圖:

    通過上圖我們可以很直觀的給出View一些坐標相關的方法解釋,不過必須要明確的是上面這些方法必須要在layout之后才有效踏揣,如下:
View的靜態(tài)坐標方法 解釋
getLeft() 返回View自身左邊到父布局左邊的距離(返回值是mLeft)
getTop() 返回View自身頂邊到父布局頂邊的距離(返回值是mTop)
getRight() 返回View自身右邊到父布局左邊的距離(返回值是mRight)
getBottom() 返回View自身底邊到父布局頂邊的距離(返回值是mBottom)
getX() 返回值為getLeft()+getTranslationX()庆亡,當setTranslationX()時getLeft()不變,getX()變捞稿。
getY() 返回值為getTop()+getTranslationY()又谋,當setTranslationY()時getTop()不變,getY()變括享。

同時也可以看見上圖中給出了手指觸摸屏幕時MotionEvent提供的一些方法解釋搂根,如下:

MotionEvent坐標方法 解釋
getX() 當前觸摸事件距離當前View左邊的距離
getY() 當前觸摸事件距離當前View頂邊的距離
getRawX() 當前觸摸事件距離整個屏幕左邊的距離
getRawY() 當前觸摸事件距離整個屏幕頂邊的距離

下面我們來看看幾個和上面方法緊密相關的獲取View寬高的View方法。如下:

View寬高方法 解釋
getWidth() layout后有效铃辖,返回值是mRight-mLeft剩愧,一般會參考measure的寬度(measure可能沒用),但不是必須的娇斩。
getHeight() layout后有效仁卷,返回值是mBottom-mTop,一般會參考measure的高度(measure可能沒用)犬第,但不是必須的锦积。
getMeasuredWidth() 返回measure過程得到的mMeasuredWidth值,供layout參考歉嗓,或許沒用丰介。
getMeasuredHeight() 返回measure過程得到的mMeasuredHeight值,供layout參考鉴分,或許沒用哮幢。

上面解釋了自定義View時各種獲取寬高的一些方法,下面我們再來看看獲取View可見區(qū)域和頂點坐標的一些方法志珍,不過這些方法需要在Activity的onWindowFocusChanged ()方法之后才能使用橙垢。如下圖:



下面我們就給出上面這幅圖涉及的View的一些坐標方法的結(jié)果,如下所示:

View的方法 上圖View1結(jié)果 上圖View2結(jié)果 結(jié)論描述
getLocalVisibleRect() (0, 0, 410, 100) (0, 0, 410, 470) 獲取View自身可見的坐標區(qū)域伦糯,坐標以自己的左上角為原點(0,0)柜某,另一點為可見區(qū)域右下角相對自己(0,0)點的坐標嗽元,其實View2當前height為550,可見height為470喂击。
getGlobalVisibleRect() (30, 100, 440, 200) (30, 250, 440, 720) 獲取View在屏幕絕對坐標系中的可視區(qū)域剂癌,坐標以屏幕左上角為原點(0,0),另一個點為可見區(qū)域右下角相對屏幕原點(0,0)點的坐標惭等。
getLocationOnScreen() (30, 100) (30, 250) 坐標是相對整個屏幕而言珍手,Y坐標為View左上角到屏幕頂部的距離。
getLocationInWindow() (30, 100) (30, 250) 如果為普通Activity則Y坐標為View左上角到屏幕頂部(此時Window與屏幕一樣大)辞做;如果為對話框式的Activity則Y坐標為當前Dialog模式Activity的標題欄頂部到View左上角的距離。

通過layout方法實現(xiàn)滑動

我們知道寡具,在View進行繪制時秤茅,會調(diào)用onLayout方法來設置顯示的位置。同樣童叠,可以通過修改View的mLeft, mTop, mRight, mBottom四個屬性來控制View的位置框喳。實現(xiàn)代碼如下所示:

@Override
public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        // 記錄觸摸點坐標
        android.util.Log.i("chenyang", "onTouchEvent ACTION_DOWN x = " + x + ",  y = " + y);
        mLastX = x;
        mLastY = y;
        break;
    case MotionEvent.ACTION_MOVE:
        // 計算偏移量
        android.util.Log.i("chenyang", "onTouchEvent ACTION_HOVER_MOVE x = " + x + ",  y = " + y);
        int offsetX = x - mLastX;
        int offsetY = y - mLastY;
        // 在當前mLeft, mTop, mRight, mBottom的基礎上加上偏移量
        layout(getLeft() + offsetX, getTop() + offsetY, getRight()
                + offsetX, getBottom() + offsetY);
        break;

    default:
        break;
    }
    return true;
}

通過offsetLeftAndRight()與offsetTopAndBottom實現(xiàn)滑動

這兩個方法相當于系統(tǒng)提供了一個對左右、上下移動的API的封裝厦坛。與上面一樣五垮,也是通過修改View的mLeft, mTop, mRight, mBottom四個屬性來控制View的位置,實現(xiàn)代碼如下:

@Override
public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        // 記錄觸摸點坐標
        android.util.Log.i("chenyang", "onTouchEvent ACTION_DOWN x = " + x + ",  y = " + y);
        mLastX = x;
        mLastY = y;
        break;
    case MotionEvent.ACTION_MOVE:
        // 計算偏移量
        android.util.Log.i("chenyang", "onTouchEvent ACTION_HOVER_MOVE x = " + x + ",  y = " + y);
        int offsetX = x - mLastX;
        int offsetY = y - mLastY;
        offsetLeftAndRight(offsetX);
        offsetTopAndBottom(offsetY);
        break;

    default:
        break;
    }
    return true;
}

通過LayoutParams實現(xiàn)滑動

LayoutParams保存了一個View的布局參數(shù)杜秸,因此可以在程序中放仗,通過改變LayoutParams來動態(tài)地修改一個View的布局參數(shù),從而達到改變View位置的效果撬碟。我們可以很方便的在程序中使用getLayoutParams()來獲取一個View的LayoutParams(注意必須在layout之后才可以獲取到)诞挨。實現(xiàn)代碼如下:

@Override
public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        // 記錄觸摸點坐標
        android.util.Log.i("chenyang", "onTouchEvent ACTION_DOWN x = " + x + ",  y = " + y);
        mLastX = x;
        mLastY = y;
        break;
    case MotionEvent.ACTION_MOVE:
        // 計算偏移量
        android.util.Log.i("chenyang", "onTouchEvent ACTION_HOVER_MOVE x = " + x + ",  y = " + y);
        int offsetX = x - mLastX;
        int offsetY = y - mLastY;
        ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
        layoutParams.leftMargin = getLeft() + offsetX;
        layoutParams.topMargin = getTop() + offsetY;
        setLayoutParams(layoutParams);
        break;

    default:
        break;
    }
    return true;
}

通過ViewDragHelper實現(xiàn)滑動

Google在其support庫中為我們提供了DrawerLayout和SlidingPaneLayout兩個布局來幫助開發(fā)者實現(xiàn)側(cè)邊欄滑動的效果。這兩個新的布局大大方便了我們創(chuàng)建自己的滑動布局界面呢蛤。然而惶傻,這兩個功能強大的布局背后隱藏著一個鮮為人知卻功能強大的類---ViewDragHelper。通過ViewDragHelper基本可以實現(xiàn)各種不同的滑動其障、拖放需求银室,因此此方法也是各種滑動解決方案中的終極絕招。

ViewDragHelper雖然功能強大励翼,但其使用方法也是最復雜的蜈敢。下面通過一個實例,來演示一下如何使用ViewDragHelper創(chuàng)建一個滑動布局抚笔,在這個例子中扶认,準備實現(xiàn)類似QQ滑動側(cè)邊欄的效果,初始時顯示內(nèi)容界面殊橙,當用戶手指滑動超過一定距離時辐宾,內(nèi)容界面?zhèn)然@示菜單界面狱从,整個過程下圖所示:


初始狀態(tài)

側(cè)滑展開菜單界面

實現(xiàn)代碼如下所示:

package com.cytmxk.test.scroll;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

/**
 * Created by chenyang on 16/6/26.
 */
public class DragViewGroup extends FrameLayout {

    private static final String TAG = DragViewGroup.class.getCanonicalName();

    private ViewDragHelper mViewDragHelper = null;
    private View mMenuView = null;
    private View mMainView = null;
    private int mMenuWidth;

    public DragViewGroup(Context context) {
        super(context);
        initView();
    }

    public DragViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        //初始化ViewDragHelper,第一個參數(shù)是要監(jiān)聽的View叠纹,通常需要是一個ViewGroup季研,
        //即parentView;第二個參數(shù)是一個Callback回調(diào)誉察,后面會做解釋与涡。
        mViewDragHelper = ViewDragHelper.create(this, callback);
    }

    //獲取菜單布局的寬度,之后可以根據(jù)菜單布局(mMenuView)的寬度處理滑動后的效果持偏。
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mMenuWidth = mMenuView.getMeasuredWidth();
        Log.d(TAG, "onSizeChanged mMenuWidth = " + mMenuWidth);
    }
    //初始化菜單布局(mMenuView)和主布局(mMainView)
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mMenuView = getChildAt(0);
        mMainView = getChildAt(1);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //將觸摸事件傳遞給ViewDragHelper,此操作必不可少
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        //將觸摸事件傳遞給ViewDragHelper,此操作必不可少
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        // 何時開始檢測觸摸事件驼卖,通過這個方法,我們可以指定在創(chuàng)建ViewDragHelper時鸿秆,
       //參數(shù)parentView中的哪一個View可以被移動酌畜。
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            //如果當前觸摸的child是mMainView時開始檢測,并且只有mMainView可以被移動
            return mMainView == child;
        }

        // 觸摸到View后回調(diào)
        @Override
        public void onViewCaptured(View capturedChild,
                                   int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
        }

        // 當拖拽狀態(tài)改變卿叽,比如idle桥胞,dragging
        @Override
        public void onViewDragStateChanged(int state) {
            super.onViewDragStateChanged(state);
        }

        // 當位置改變的時候調(diào)用,常用與滑動時更改scale等
        @Override
        public void onViewPositionChanged(View changedView,
                                          int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
        }

        // 處理水平滑動
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left;
        }

        // 處理垂直滑動
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return 0;
        }

        // 拖動結(jié)束后調(diào)用
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
            Log.d(TAG, "onViewReleased mMainView.getLeft() = " + mMainView.getLeft() + ", mMenuWidth = " + mMenuWidth);
            //手指抬起后緩慢移動到指定位置
            if (mMainView.getLeft() < mMenuWidth) {
                //關閉菜單
                //相當于Scroller的startScroll方法
                mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            } else {
                //打開菜單
                mViewDragHelper.smoothSlideViewTo(mMainView, mMenuWidth, 0);
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            }
        }

    };

    //由于ViewDragHelper內(nèi)部是利用Scroller實現(xiàn)滑動的,所以利用computeScroll方法實現(xiàn)平滑滑動
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }
}

通過scrollTo和scrollBy實現(xiàn)滑動

  1. 在一個View中考婴,系統(tǒng)提供了scrollTo贩虾、scrollBy兩種方式來改變一個View中初始可見內(nèi)容的位置。這兩個方法的區(qū)別非常好理解沥阱,與英文中To和By的區(qū)別類似缎罢,scrollTo(x, y)表示讓View中初始可見內(nèi)容的在水平方向偏移到點(- x, - y)(x大于零表示向左偏移,否者向右偏移; y大于零表示向上偏移喳钟,否者向右偏移)屁使,scrollBy(dx, dy)表示讓View中初始可見內(nèi)容的在水平方向偏移dx(dx大于零表示向左偏移,否者向右偏移)奔则,在垂直方向偏移dy(dy大于零表示向上偏移蛮寂,否者向右偏移)如下是這兩個方法的代碼實現(xiàn):
    /**
     * The offset, in pixels, by which the content of this view is scrolled
     * horizontally.
     * {@hide}
     */
    @ViewDebug.ExportedProperty(category = "scrolling")
    protected int mScrollX;
    /**
     * The offset, in pixels, by which the content of this view is scrolled
     * vertically.
     * {@hide}
     */
    @ViewDebug.ExportedProperty(category = "scrolling")
    protected int mScrollY;
    /**
     * Set the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the x position to scroll to
     * @param y the y position to scroll to
     */
    public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
    }

    /**
     * Move the scrolled position of your view. This will cause a call to
     * {@link #onScrollChanged(int, int, int, int)} and the view will be
     * invalidated.
     * @param x the amount of pixels to scroll by horizontally
     * @param y the amount of pixels to scroll by vertically
     */
    public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }

有上面的代碼可以得知mScrollX,mScrollY是用來保存View初始可見內(nèi)容的偏移量易茬。理解了mScrollX和mScrollY的用法酬蹋,就不難理解getScrollX() 和getScrollY()。這兩個函數(shù)的源碼如下所示:

    /**
     * Return the scrolled left position of this view. This is the left edge of
     * the displayed part of your view. You do not need to draw any pixels
     * farther left, since those are outside of the frame of your view on
     * screen.
     *
     * @return The left edge of the displayed part of your view, in pixels.
     */
    public final int getScrollX() {
        return mScrollX;
    }

    /**
     * Return the scrolled top position of this view. This is the top edge of
     * the displayed part of your view. You do not need to draw any pixels above
     * it, since those are outside of the frame of your view on screen.
     *
     * @return The top edge of the displayed part of your view, in pixels.
     */
    public final int getScrollY() {
        return mScrollY;
    }
  1. 舉例說明抽莱,如下圖所示(注意范抓,圖中黃色矩形區(qū)域表示的是View,綠色虛線矩形為View中初始可見的內(nèi)容食铐。一般情況下兩者的大小一致匕垫,本文為了顯示方便,將虛線框畫小了一點虐呻。圖中的黃色區(qū)域的位置始終不變象泵,發(fā)生偏移的是初始可見的內(nèi)容寞秃。):



    scrollTo(0, 100)的效果如下圖所示:



    scrollTo(100, 100)的效果圖如下:

    若函數(shù)中參數(shù)為負值,則子View的移動方向?qū)⑾喾矗?/p>

通過Scroller實現(xiàn)滑動

上面舉例中通過scrollTo偏移View的初始可見內(nèi)容是在瞬間完成的偶惠,這樣的效果會讓人感覺非常突兀春寿。Google也想到了這一點,所以提供了Scroller類來模擬平滑滑動的效果忽孽。
Scroller類提供了startScroll方法來初始化一個模擬平滑滑動的過程绑改,然后調(diào)用invalidate()方法,這個方法會導致View重繪兄一,系統(tǒng)在繪制View的時候會在draw方法中調(diào)用computeScroll方法來實現(xiàn)模擬滑動厘线,在computeScroll方法中通過調(diào)用Scroller的computeScrollOffset方法判斷是否完成了整個滑動,同時Scroller也提供了getCurrX出革、getCurrY來獲取當前滑動過程中 View初始可見內(nèi)容 即將的偏移量皆的,然后利用srcollTo方法實現(xiàn)偏移即可,然后執(zhí)行invalidate方法實現(xiàn)循環(huán)調(diào)用computeScroll方法直到滑動結(jié)束蹋盆。

  1. Scroller中相關API簡介如下:
mScroller.getCurrX() //獲取mScroller當前水平方向滑動過程中的位置  
mScroller.getCurrY() //獲取mScroller當前豎直方向滑動過程中的位置  
mScroller.getFinalX() //獲取mScroller最終停止滑動的水平位置  
mScroller.getFinalY() //獲取mScroller最終停止滑動的豎直位置  
mScroller.setFinalX(int newX) //設置mScroller最終停留的水平位置,沒有動畫效果硝全,直接跳到目標位置  
mScroller.setFinalY(int newY) //設置mScroller最終停留的豎直位置栖雾,沒有動畫效果,直接跳到目標位置  
mScroller.startScroll(int startX, int startY, int dx, int dy) //使用默認完成時間250ms  
mScroller.startScroll(int startX, int startY, int dx, int dy, int duration)  
//開始滑動伟众,startX, startY為 View初始可見內(nèi)容 開始滑動的位置(即mScrollX析藕,mScrollY的值),dx,dy分別為水平方向和垂直方向的偏移量(dx大于零表示向左偏移凳厢,否者向右偏移;dy大于零表示向上偏移账胧,否者向下偏移), duration為完成滾動的時間 。
mScroller.computeScrollOffset() //返回值為boolean先紫,true說明滑動尚未完成治泥,false說明滑動已經(jīng)完成。這是一個很重要的方法遮精,通常放在View.computeScroll()中居夹,用來判斷是否滑動是否結(jié)束。

2 舉例如下:

public void moveToDest(int index) {

    /*
     * 對 index 進行判斷 本冲,確保 是在合理的范圍
     * 即  index >=0  && index <=getChildCount()-1
     */
    //確保 index>=0
    index = index >= 0 ? index : 0;
    //確保 currIndex<=getChildCount()-1
    currIndex = index <= getChildCount() - 1 ? index : getChildCount() - 1;

    if (null != mOnPagerChangeListener) {
        mOnPagerChangeListener.OnPagerChange(currIndex);
    }
    myScroller.startScroll(getScrollX(), 0, currIndex * getWidth() - getScrollX(), 0, 500);
    invalidate();
}

@Override
public void computeScroll() {
    super.computeScroll();
    if (myScroller.computeScrollOffset()) {
        scrollTo(myScroller.getCurrX(), 0);
        invalidate();
    }
}

參考文檔

  1. Android應用坐標系統(tǒng)全面詳解
  2. Android群英傳
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末准脂,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子檬洞,更是在濱河造成了極大的恐慌狸膏,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件添怔,死亡現(xiàn)場離奇詭異湾戳,居然都是意外死亡贤旷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門院塞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遮晚,“玉大人,你說我怎么就攤上這事拦止∠厍玻” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵汹族,是天一觀的道長萧求。 經(jīng)常有香客問我,道長顶瞒,這世上最難降的妖魔是什么夸政? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮榴徐,結(jié)果婚禮上守问,老公的妹妹穿的比我還像新娘。我一直安慰自己坑资,他們只是感情好耗帕,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著袱贮,像睡著了一般仿便。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上攒巍,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天嗽仪,我揣著相機與錄音,去河邊找鬼柒莉。 笑死闻坚,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的常柄。 我是一名探鬼主播鲤氢,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼西潘!你這毒婦竟也來了卷玉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤喷市,失蹤者是張志新(化名)和其女友劉穎相种,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡寝并,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年箫措,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衬潦。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡斤蔓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镀岛,到底是詐尸還是另有隱情弦牡,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布漂羊,位于F島的核電站驾锰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏走越。R本人自食惡果不足惜椭豫,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望旨指。 院中可真熱鬧赏酥,春花似錦、人聲如沸谆构。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽低淡。三九已至,卻和暖如春瞬项,著一層夾襖步出監(jiān)牢的瞬間蔗蹋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工囱淋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留猪杭,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓妥衣,卻偏偏與公主長得像皂吮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子税手,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容