Android仿IOS系統(tǒng)下發(fā)件人輸入框

分享一個(gè)Android自定義控件杈帐,仿照IOS短信添加聯(lián)系人輸入框,供發(fā)送信件時(shí)選擇聯(lián)系人使用悟泵。
ChipInputView.java

package cn.com.jfyuan.mail.widget;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.text.Editable;
import android.text.InputType;
import android.text.Spannable;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import cn.com.jfyuan.mail.R;

public class ChipInputView extends ScrollView {

    private static final String TAG = "ChipInputView";
    private static final int CHIP_HEIGHT = 25; // dp
    private static final int SPACING_LEFT = 4; // dp
    private static final int SPACING_TOP = 4; // dp
    private static final int SPACING_RIGHT = 4; // dp
    private static final int SPACING_BOTTOM = 4; // dp
    public static final int DEFAULT_VERTICAL_SPACING = 4; // dp
    private int mVerticalSpacing = DEFAULT_VERTICAL_SPACING;
    private int mChipsTextColor = Color.BLACK;
    private int mChipsTextColorClicked = Color.WHITE;
    private int mChipsTextColorErrorClicked = Color.RED;
    private float mDensity;
    private RelativeLayout mChipsContainer;
    private ChipsListener mChipsListener;
    private ChipsEditText mEditText;
    private ChipsVerticalLinearLayout mRootChipsLayout;
    private EditTextListener mEditTextListener;
    private List<Chip> mChipList = new ArrayList<>();
    private Object mCurrentEditTextSpan;
    private ChipValidator mChipsValidator;

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

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

    public ChipInputView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
        return true;
    }

    private void init() {
        mDensity = getResources().getDisplayMetrics().density;
        mChipsContainer = new RelativeLayout(getContext());
        addView(mChipsContainer);
        LinearLayout linearLayout = new LinearLayout(getContext());
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(0, 0);
        linearLayout.setLayoutParams(params);
        linearLayout.setFocusable(true);
        linearLayout.setFocusableInTouchMode(true);
        mChipsContainer.addView(linearLayout);
        mEditText = new ChipsEditText(getContext());
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        layoutParams.leftMargin = (int) (SPACING_LEFT * mDensity);
        layoutParams.topMargin = (int) (SPACING_TOP * mDensity);
        layoutParams.rightMargin = (int) (SPACING_RIGHT * mDensity);
        layoutParams.bottomMargin = (int) (SPACING_BOTTOM * mDensity);
        mEditText.setLayoutParams(layoutParams);
        mEditText.setMinHeight((int) (CHIP_HEIGHT * mDensity));
        mEditText.setPadding(0, 0, 0, 0);
        mEditText.setLineSpacing(mVerticalSpacing, (CHIP_HEIGHT * mDensity) / mEditText.getLineHeight());
        mEditText.setBackgroundColor(Color.argb(0, 0, 0, 0));
        mEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_UNSPECIFIED);
        mEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
        mChipsContainer.addView(mEditText);
        mRootChipsLayout = new ChipsVerticalLinearLayout(getContext(), mVerticalSpacing);
        mRootChipsLayout.setOrientation(LinearLayout.VERTICAL);
        mRootChipsLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        mRootChipsLayout.setPadding(0, (int) ((SPACING_TOP + mVerticalSpacing) * mDensity), 0, 0);
        mChipsContainer.addView(mRootChipsLayout);
        initListener();
    }

    private void initListener() {
        mChipsContainer.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mEditText.requestFocus();
                unSelectAllChips();
            }
        });

        mEditTextListener = new EditTextListener();
        mEditText.addTextChangedListener(mEditTextListener);
        mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    unSelectAllChips();
                }
            }
        });
    }

    public void addChip(String displayName, Contact contact) {
        addChip(displayName, contact, false, false);
        mEditText.setText("");
        addLeadingMarginSpan();
    }

    public void addChip(String displayName, Contact contact, boolean isIndelible, boolean isModifiable) {
        Chip chip = new Chip(displayName, contact, isIndelible, isModifiable);
        mChipList.add(chip);
        onChipsChanged(true);
        post(new Runnable() {
            @Override
            public void run() {
                fullScroll(View.FOCUS_DOWN);
            }
        });
    }

    public void addChips(List<Contact> contacts, boolean isIndelible, boolean isModifiable) {
        if (null != contacts) {
            for (Contact c : contacts) {
                Chip chip = new Chip(c.getDisplayName(), c, isIndelible, isModifiable);
                mChipList.add(chip);
            }
        }
        onChipsChanged(true);
        post(new Runnable() {
            @Override
            public void run() {
                fullScroll(View.FOCUS_DOWN);
            }
        });
    }

    public void clearAllChips() {
        mChipList.clear();
        onChipsChanged(false);
    }

    public boolean removeChipBy(Contact contact) {
        for (int i = 0; i < mChipList.size(); i++) {
            if (mChipList.get(i).mContact != null && mChipList.get(i).mContact.equals(contact)) {
                mChipList.remove(i);
                onChipsChanged(true);
                return true;
            }
        }
        return false;
    }

    public List<Chip> getChips() {
        return Collections.unmodifiableList(mChipList);
    }

    public boolean hasErrorChip() {
        List<Chip> chips = getChips();
        if (null != chips) {
            for (Chip chip : chips) {
                if (chip.isError) {
                    return true;
                }
            }
        }
        return false;
    }

    public void setChipsListener(ChipsListener chipsListener) {
        this.mChipsListener = chipsListener;
    }

    public void setChipsValidator(ChipValidator chipsValidator) {
        mChipsValidator = chipsValidator;
    }

    public EditText getEditText() {
        return mEditText;
    }

    private void onChipsChanged(final boolean moveCursor) {
        ChipsVerticalLinearLayout.TextLineParams textLineParams = mRootChipsLayout.onChipsChanged(mChipList);
        if (textLineParams == null) {
            post(new Runnable() {
                @Override
                public void run() {
                    onChipsChanged(moveCursor);
                }
            });
            return;
        }
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mEditText.getLayoutParams();
        params.topMargin = (int) ((SPACING_TOP + textLineParams.row * CHIP_HEIGHT) * mDensity) + textLineParams.row * mVerticalSpacing;
        mEditText.setLayoutParams(params);
        addLeadingMarginSpan(textLineParams.lineMargin);
        if (moveCursor) {
            mEditText.setSelection(mEditText.length());
        }
    }

    private void addLeadingMarginSpan(int margin) {
        Spannable spannable = mEditText.getText();
        if (mCurrentEditTextSpan != null) {
            spannable.removeSpan(mCurrentEditTextSpan);
        }
        mCurrentEditTextSpan = new android.text.style.LeadingMarginSpan.LeadingMarginSpan2.Standard(margin, 0);
        spannable.setSpan(mCurrentEditTextSpan, 0, 0, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

        mEditText.setText(spannable);
    }

    private void addLeadingMarginSpan() {
        Spannable spannable = mEditText.getText();
        if (mCurrentEditTextSpan != null) {
            spannable.removeSpan(mCurrentEditTextSpan);
        }
        spannable.setSpan(mCurrentEditTextSpan, 0, 0, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
        mEditText.setText(spannable);
    }

    private void onEnterPressed(String text) {
        if (text != null && text.length() > 0) {
            onEmailRecognized(text);
            mEditText.setSelection(0);
        }
    }

    private void onEmailRecognized(String email) {
        onEmailRecognized(new Contact(email, null, email));
    }

    private void onEmailRecognized(Contact contact) {
        Chip chip = new Chip(contact.getDisplayName(), contact, false, true);
        mChipList.add(chip);
        if (mChipsListener != null) {
            mChipsListener.onChipAdded(chip);
        }
        post(new Runnable() {
            @Override
            public void run() {
                onChipsChanged(true);
            }
        });
    }

    private void selectOrDeleteLastChip() {
        if (mChipList.size() > 0) {
            onChipInteraction(mChipList.size() - 1);
        }
    }

    private void onChipInteraction(int position) {
        try {
            Chip chip = mChipList.get(position);
            if (chip != null) {
                onChipInteraction(chip, true);
            }
        } catch (IndexOutOfBoundsException e) {
            Log.e(TAG, "Out of bounds", e);
        }
    }

    private void onChipInteraction(Chip chip, boolean nameClicked) {
        unSelectChipsExcept(chip);
        if (chip.isSelected()) {
            mChipList.remove(chip);
            if (mChipsListener != null) {
                mChipsListener.onChipDeleted(chip);
            }
            onChipsChanged(true);
            if (nameClicked && chip.isModifiable()) {
                mEditText.setText(chip.getContact().getEmailAddress());
                addLeadingMarginSpan();
                mEditText.requestFocus();
                mEditText.setSelection(mEditText.length());
            }
        } else {
            chip.setSelected(true);
            onChipsChanged(false);
        }
    }

    private void unSelectChipsExcept(Chip rootChip) {
        for (Chip chip : mChipList) {
            if (chip != rootChip) {
                chip.setSelected(false);
            }
        }
        onChipsChanged(false);
    }

    private void unSelectAllChips() {
        unSelectChipsExcept(null);
    }

    public InputConnection getInputConnection(InputConnection target) {
        return new KeyInterceptingInputConnection(target);
    }

    private class EditTextListener implements TextWatcher {
        private boolean mIsPasteTextChange = false;

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (count > 1) {
                mIsPasteTextChange = true;
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
            if (mIsPasteTextChange) {
                mIsPasteTextChange = false;
                // copy/paste
            } else {
                // no paste text change
                if (s.toString().contains("\n")) {
                    String text = s.toString();
                    text = text.replace("\n", "");
                    while (text.contains("  ")) {
                        text = text.replace("  ", " ");
                    }
                    s.clear();
                    if (text.length() > 1) {
                        onEnterPressed(text);
                    } else {
                        s.append(text);
                    }
                }
            }
        }
    }

    private class KeyInterceptingInputConnection extends InputConnectionWrapper {
        public KeyInterceptingInputConnection(InputConnection target) {
            super(target, true);
        }

        @Override
        public boolean commitText(CharSequence text, int newCursorPosition) {
            return super.commitText(text, newCursorPosition);
        }

        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            if (mEditText.length() == 0) {
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
                        selectOrDeleteLastChip();
                        return true;
                    }
                }
            }
            if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
                mEditText.append("\n");
                return true;
            }
            return super.sendKeyEvent(event);
        }

        @Override
        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
            if (mEditText.length() == 0 && beforeLength == 1 && afterLength == 0) {
                return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
                        && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
            }
            return super.deleteSurroundingText(beforeLength, afterLength);
        }
    }

    class ChipsEditText extends EditText {
        public ChipsEditText(Context context) {
            super(context);
        }

        @Override
        public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
            return getInputConnection(super.onCreateInputConnection(outAttrs));
        }
    }

    class ChipsVerticalLinearLayout extends LinearLayout {
        private List<LinearLayout> mLineLayouts = new ArrayList<>();
        private int mRowSpacing;

        public ChipsVerticalLinearLayout(Context context, int rowSpacing) {
            super(context);
            mRowSpacing = rowSpacing;
            init();
        }

        private void init() {
            setOrientation(VERTICAL);
        }

        private int getViewMeasuredWidth(View view) {
            if (null != view) {
                view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                return view.getMeasuredWidth();
            }
            return 0;
        }

        public TextLineParams onChipsChanged(List<ChipInputView.Chip> chips) {
            clearChipsViews();
            int width = getWidth();
            if (width == 0) {
                return null;
            }
            int widthSum = 0;//當(dāng)前行的寬度
            int rowCounter = 0;//行數(shù)
            LinearLayout ll = createHorizontalView();
            for (ChipInputView.Chip chip : chips) {
                View chipView = chip.getView();
                int chipViewWidth = getViewMeasuredWidth(chipView);
                if (widthSum + chipViewWidth > width) {//寬度總和大于當(dāng)前寬度杈笔,新起一行
                    rowCounter++;
                    widthSum = 0;
                    ll = createHorizontalView();
                }
                if (chipViewWidth > width) {//單個(gè)寬度大于當(dāng)前寬度,重置文本框?qū)挾确乐钩鼋缑?                    chip.resetLabelWidth((int) (width * 0.75));
                    chipViewWidth = getViewMeasuredWidth(chipView);
                }
                widthSum += chipViewWidth;
                ll.addView(chipView);
            }
            if (width - widthSum < width * 0.1f) {
                widthSum = 0;
                rowCounter++;
            }
            if (width == 0) {
                rowCounter = 0;
            }
            return new TextLineParams(rowCounter, widthSum);
        }

        private LinearLayout createHorizontalView() {
            LinearLayout ll = new LinearLayout(getContext());
            ll.setPadding(0, 0, 0, mRowSpacing);
            ll.setOrientation(HORIZONTAL);
            addView(ll);
            mLineLayouts.add(ll);
            return ll;
        }

        private void clearChipsViews() {
            for (LinearLayout linearLayout : mLineLayouts) {
                linearLayout.removeAllViews();
            }
            mLineLayouts.clear();
            removeAllViews();
        }

        class TextLineParams {
            public int row;
            public int lineMargin;

            public TextLineParams(int row, int lineMargin) {
                this.row = row;
                this.lineMargin = lineMargin;
            }
        }
    }

    public class Chip implements OnClickListener {
        private String mLabel;
        private final Contact mContact;
        private final boolean mIsIndelible;
        private final boolean mIsModifiable;
        private RelativeLayout mView;
        private View mIconWrapper;
        private TextView mTextView;
        private ImageView mCloseIcon;
        private ImageView mErrorIcon;
        private boolean isError = false;
        private boolean mIsSelected = false;

        public Chip(String label, Contact contact, boolean isIndelible, boolean isModifiable) {
            this.mLabel = label;
            this.mContact = contact;
            this.mIsIndelible = isIndelible;
            this.mIsModifiable = isModifiable;
            if (null == contact || (mChipsValidator != null && !mChipsValidator.isValid(mContact))) {
                isError = true;
            }
            if (mLabel == null) {
                mLabel = contact.getEmailAddress();
            }
        }

        public void resetLabelWidth(int width) {
            if (null != mTextView) {
                mTextView.setWidth(width);
            }
        }

        public View getView() {
            if (mView == null) {
                mView = (RelativeLayout) inflate(getContext(), R.layout.chips_view, null);
                mView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, (int) (CHIP_HEIGHT * mDensity)));
                mIconWrapper = mView.findViewById(R.id.layout_icon_wrapper);
                mTextView = (TextView) mView.findViewById(R.id.tv_ch_name);
                mCloseIcon = (ImageView) mView.findViewById(R.id.iv_ch_close);
                mErrorIcon = (ImageView) mView.findViewById(R.id.iv_ch_error);
                mTextView.setTextColor(mChipsTextColor);
                mView.setOnClickListener(this);
                mIconWrapper.setOnClickListener(this);
            }
            updateViews();
            return mView;
        }

        private void updateViews() {
            mTextView.setText(mLabel);
            if (isSelected()) {
                mIconWrapper.setVisibility(VISIBLE);
                if (isError) {
                    mView.setSelected(true);
                    mTextView.setTextColor(mChipsTextColorErrorClicked);
                } else {
                    mView.setSelected(true);
                    mTextView.setTextColor(mChipsTextColorClicked);
                }
            } else {
                mIconWrapper.setVisibility(GONE);
                if (isError) {
                    mErrorIcon.setVisibility(View.VISIBLE);
                } else {
                    mErrorIcon.setVisibility(View.GONE);
                }
                mView.setSelected(false);
                mTextView.setTextColor(mChipsTextColor);
            }
        }

        @Override
        public void onClick(View v) {
            mEditText.clearFocus();
            if (v.getId() == mView.getId()) {
                onChipInteraction(this, true);
            } else {
                onChipInteraction(this, false);
            }
        }

        public boolean isSelected() {
            return mIsSelected;
        }

        public void setSelected(boolean isSelected) {
            if (mIsIndelible) {
                return;
            }
            this.mIsSelected = isSelected;
        }

        public boolean isModifiable() {
            return mIsModifiable;
        }

        public Contact getContact() {
            return mContact;
        }

        @Override
        public boolean equals(Object o) {
            if (mContact != null && o instanceof Contact) {
                return mContact.equals(o);
            }
            return super.equals(o);
        }

    }

    public interface ChipsListener {
        void onChipAdded(Chip chip);

        void onChipDeleted(Chip chip);
    }

    public static abstract class ChipValidator {
        public abstract boolean isValid(Contact contact);
    }

    public static class Contact {
        private String mEmailAddress;
        private String mDisplayName;
        private String mId;

        @Override
        public boolean equals(final Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Contact contact = (Contact) o;
            if (null == mId) {
                if (null != contact.getId()) return false;
                if (null == mEmailAddress) {
                    if (null != contact.getEmailAddress()) return false;
                } else {
                    if (!mEmailAddress.equals(contact.mEmailAddress)) return false;
                }
            } else {
                if (!mId.equals(contact.mId)) return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            if (null == mEmailAddress) {
                if (null == mId) {
                    return 31;
                } else {
                    return mId.hashCode();
                }
            } else {
                return mEmailAddress.hashCode();
            }
        }

        public Contact(String displayName, String id, String emailAddress) {
            mEmailAddress = emailAddress;
            mId = id;
            if (!TextUtils.isEmpty(displayName)) {
                mDisplayName = displayName;
            } else if (!TextUtils.isEmpty(emailAddress)) {
                mDisplayName = mEmailAddress;
            } else {
                mDisplayName = "None";
            }
        }

        public String getEmailAddress() {
            return mEmailAddress;
        }

        public String getDisplayName() {
            return mDisplayName;
        }

        public String getId() {
            return mId;
        }
    }
}

布局文件
chips_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="25dp"
    android:background="@drawable/chip_background"
    android:paddingRight="@dimen/padding_small">

    <RelativeLayout
        android:id="@+id/layout_icon_wrapper"
        android:layout_width="25dp"
        android:layout_height="25dp">

        <ImageView
            android:id="@+id/iv_ch_close"
            android:layout_width="18dp"
            android:layout_height="18dp"
            android:layout_centerInParent="true"
            android:background="@drawable/right_ad_close"
            android:gravity="center" />
    </RelativeLayout>

    <TextView
        android:id="@+id/tv_ch_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="@dimen/padding_small"
        android:layout_toRightOf="@id/layout_icon_wrapper"
        android:singleLine="true"
        android:textSize="@dimen/font_h5" />

    <ImageView
        android:id="@+id/iv_ch_error"
        android:layout_width="18dp"
        android:layout_height="18dp"
        android:layout_centerVertical="true"
        android:layout_marginLeft="@dimen/padding_small"
        android:layout_toRightOf="@id/tv_ch_name"
        android:src="@drawable/send_fail_nor"
        android:visibility="gone" />
</RelativeLayout>

最后附上gitHub飛機(jī)票

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末糕非,一起剝皮案震驚了整個(gè)濱河市蒙具,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌朽肥,老刑警劉巖禁筏,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異衡招,居然都是意外死亡篱昔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)蚁吝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)旱爆,“玉大人,你說(shuō)我怎么就攤上這事窘茁』陈祝” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵山林,是天一觀的道長(zhǎng)房待。 經(jīng)常有香客問(wèn)我邢羔,道長(zhǎng),這世上最難降的妖魔是什么桑孩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任拜鹤,我火速辦了婚禮,結(jié)果婚禮上流椒,老公的妹妹穿的比我還像新娘敏簿。我一直安慰自己,他們只是感情好宣虾,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布惯裕。 她就那樣靜靜地躺著,像睡著了一般绣硝。 火紅的嫁衣襯著肌膚如雪蜻势。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天鹉胖,我揣著相機(jī)與錄音握玛,去河邊找鬼。 笑死甫菠,一個(gè)胖子當(dāng)著我的面吹牛挠铲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播寂诱,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼市殷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了刹衫?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤搞挣,失蹤者是張志新(化名)和其女友劉穎带迟,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體囱桨,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仓犬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了舍肠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搀继。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖翠语,靈堂內(nèi)的尸體忽然破棺而出叽躯,到底是詐尸還是另有隱情,我是刑警寧澤肌括,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布点骑,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏黑滴。R本人自食惡果不足惜憨募,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望袁辈。 院中可真熱鬧菜谣,春花似錦、人聲如沸晚缩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)橡羞。三九已至眯停,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間卿泽,已是汗流浹背莺债。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留签夭,地道東北人齐邦。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像第租,于是被迫代替她去往敵國(guó)和親措拇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • 你知道慎宾,故事的結(jié)尾并不重要丐吓,生活唯一確保我們的就是死亡。所以我們最好不要讓那結(jié)尾趟据,奪走了故事的光芒券犁。 但是不努力,...
    留住時(shí)間閱讀 230評(píng)論 0 0
  • 孩子睡了汹碱。 終于有時(shí)間可以做些自己的事情粘衬。 老公嘆口氣,周末真累咳促!說(shuō)完轉(zhuǎn)身去看他的學(xué)習(xí)視頻了稚新。 我輕輕地給孩子翻身...
    干嘛非要起名字閱讀 254評(píng)論 0 2
  • 熊孩子的爆棚能量冒掌,不管正負(fù),我相信大家都曾經(jīng)見(jiàn)識(shí)過(guò)蹲盘。不管你是熊孩子的父母股毫,小姑,還是路人甲召衔。 有的時(shí)候熊孩子在公眾...
    澳洲紅豆豆閱讀 713評(píng)論 2 2
  • 陌上铃诬,四季更迭。熙熙攘攘的人群苍凛,依舊熙熙攘攘趣席。漂泊的人,依舊漂泊著醇蝴。一此經(jīng)過(guò)生命的人和事宣肚,漸次遁入流年深處。被我們...
    鉑翰閱讀 491評(píng)論 1 1