Swift下拉菜单实现


title: Swift下拉菜单实现

1.效果图

dropDown.gif

2.实现过程

整体思路就是创建一个View,两个tableView,一个背景bgView。实现一个代理协议和一个数据源协议,通过设置代理和数据源传值。

2.1 代理和数据源
private let SCREEN_WIDTH = UIScreen.main.bounds.size.width
private let SCREEN_HEIGHT = UIScreen.main.bounds.size.height

protocol DropMenuViewDelegate: NSObjectProtocol {
    func menu(_ menu: DropMenuView, didSelectRowAtIndexPath index: DropMenuView.Index)
}

protocol DropMenuViewDataSource: NSObjectProtocol {

func numberOfColumns(in menu: DropMenuView) -> Int

func menu(_ menu: DropMenuView, numberOfRowsInColumn column: Int) -> Int

func menu(_ menu: DropMenuView, titleForRowsInIndePath index: DropMenuView.Index) -> String

func menu(_ menu: DropMenuView, numberOfItemsInRow row: Int, inColumn: Int) -> Int

func menu(_ menu: DropMenuView, titleForItemInIndexPath indexPath: DropMenuView.Index) -> String
}

extension DropMenuViewDataSource {
func numberOfColumns(in menu: DropMenuView) -> Int {
    return 1
}

func menu(_ menu: DropMenuView, numberOfItemsInRow row: Int, inColumn: Int) -> Int {
    return 0
}

func menu(_ menu: DropMenuView, titleForItemInIndexPath indexPath: DropMenuView.Index) -> String {
    return ""
}
}
2.2 根据菜单列数创建button
private func createTitleButtons(columns: Int) {

    let btnW: CGFloat = SCREEN_WIDTH / CGFloat(columns)
    let btnH: CGFloat = self.menuHeight
    let btnY: CGFloat = 0
    var btnX: CGFloat = 0
    
    for i in 0..<columns {
        let btn = UIButton(type: .custom)
        btnX = CGFloat(i) * btnW
        btn.frame = CGRect(x: btnX, y: btnY, width: btnW, height: btnH)
        btn.setTitle(dataSource?.menu(self, titleForRowsInIndePath: Index(column: i, row: 0)), for: UIControlState.normal)
        btn.setTitleColor(titleColor, for: .normal)
        btn.titleLabel?.font = titleFont
        btn.addTarget(self, action: #selector(titleBtnDidClick(btn:)), for: .touchUpInside)
        btn.tag = i + 1000
        addSubview(btn)
        titleButtons.append(btn)
        
        let seperatorLine = UIView(frame: CGRect(x: btn.frame.maxX, y: 0, width: 1, height: btnH))
        seperatorLine.backgroundColor = seperatorLineColor
        addSubview(seperatorLine)
    }
}
2.3 button点击时候控制tableView的展示或者隐藏
@objc func titleBtnDidClick(btn: UIButton) {
    let column = btn.tag - 1000
    
    guard let dataSource = dataSource else {
        return
    }
    
    if selectedColumn == column && isShow {
        // 收回列表
        animationTableView(show: false)
        isShow = false
        
    } else {
        selectedColumn = column
        leftTableView.reloadData()
        
        // 刷新右边tableView
        if dataSource.menu(self, numberOfItemsInRow: selectedRows[selectedColumn], inColumn: selectedColumn) > 0 {
            rightTableView.reloadData()
        }
        
        // 展开列表
        animationTableView(show: true)
        isShow = true
    }
}
2.4 展示或者隐藏TableView
//MARK:- 展示或者隐藏TableView
func animationTableView(show: Bool) {
    var haveItems = false
    let rows = leftTableView.numberOfRows(inSection: 0)
    if let dataSource = dataSource {
        for i in 0..<rows {
            if dataSource.menu(self, numberOfItemsInRow: i, inColumn: selectedColumn) > 0 {
                haveItems = true
            }
        }
    }
    
    let tableViewHeight = CGFloat(rows) * cellHeight > maxTableViewHeight ? maxTableViewHeight : CGFloat(rows) * cellHeight
    
    if show {
        superview?.addSubview(backgroundView)
        superview?.addSubview(self)
        
        if haveItems {
            leftTableView.frame = CGRect(x: menuOrigin.x, y: menuOrigin.y + menuHeight, width: SCREEN_WIDTH * 0.5, height: 0)
            rightTableView.frame = CGRect(x: SCREEN_WIDTH * 0.5, y: menuOrigin.y + menuHeight, width: SCREEN_WIDTH * 0.5, height: 0)
            superview?.addSubview(leftTableView)
            superview?.addSubview(rightTableView)
        } else {
            rightTableView.removeFromSuperview()
            leftTableView.frame = CGRect(x: menuOrigin.x, y: menuOrigin.y + menuHeight, width: SCREEN_WIDTH, height: 0)
            superview?.addSubview(leftTableView)
        }

        UIView.animate(withDuration: animationDuration) {
            self.backgroundView.alpha = 1.0
            self.leftTableView.frame.size.height = tableViewHeight
            if haveItems {
                self.rightTableView.frame.size.height = tableViewHeight
            }
        }
    } else {
        UIView.animate(withDuration: animationDuration, animations: {
            self.backgroundView.alpha = 0
            self.leftTableView.frame.size.height = 0
            if haveItems {
                self.rightTableView.frame.size.height = 0
            }
        }) { (_) in
            self.backgroundView.removeFromSuperview()
            self.leftTableView.removeFromSuperview()
            if haveItems {
                self.rightTableView.removeFromSuperview()
            }
        }
    }
}
2.5 实现tableView的代理和数据源方法
extension DropMenuView: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if let dataSource = dataSource {
        if tableView == leftTableView {
            return dataSource.menu(self, numberOfRowsInColumn: selectedColumn)
        } else {
            return dataSource.menu(self, numberOfItemsInRow: selectedRows[selectedColumn], inColumn: selectedColumn)
        }
    }
    return 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: DropViewTableCellID)
    
    if let dataSource = dataSource {
        if tableView == leftTableView {
            cell?.textLabel?.text = dataSource.menu(self, titleForRowsInIndePath: Index(column: selectedColumn, row: indexPath.row))
            
            // 选中上次选中的那行
            if selectedRows[selectedColumn] == indexPath.row {
                tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
            }
            
        } else {
            cell?.textLabel?.text = dataSource.menu(self, titleForItemInIndexPath: Index(column: selectedColumn, row: selectedRows[selectedColumn], item: indexPath.row))
            
            //选中上次选中的行
            if cell?.textLabel?.text == titleButtons[selectedColumn].titleLabel?.text {
                leftTableView.selectRow(at: IndexPath(row: selectedRows[selectedColumn], section: 0), animated: true, scrollPosition: .none)
                tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
            }
        }
    }
    
    return cell!
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    guard let dataSource = dataSource else {
        return
    }
    
    if tableView == leftTableView {
        selectedRows[selectedColumn] = indexPath.row
        
        let haveItems = dataSource.menu(self, numberOfItemsInRow: indexPath.row, inColumn: selectedColumn) > 0
        if haveItems {
            rightTableView.reloadData()
        } else {
            //收回列表
            animationTableView(show: false)
            isShow = false
            
            //更新title
            titleButtons[selectedColumn].setTitle(dataSource.menu(self, titleForRowsInIndePath: Index(column: selectedColumn, row: indexPath.row)), for: .normal)
        }
        delegate?.menu(self, didSelectRowAtIndexPath: Index(column: selectedColumn, row: indexPath.row))
    } else {
        
        //收回列表
        animationTableView(show: false)
        isShow = false
        
        let index = Index(column: selectedColumn, row: selectedRows[selectedColumn], item: indexPath.row)
        
        //更新title
        titleButtons[selectedColumn].setTitle(dataSource.menu(self, titleForItemInIndexPath: index), for: .normal)
        
        delegate?.menu(self, didSelectRowAtIndexPath: index)
    }
    
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return cellHeight
}
}

3.所有代码

private let SCREEN_WIDTH = UIScreen.main.bounds.size.width
private let SCREEN_HEIGHT = UIScreen.main.bounds.size.height

protocol DropMenuViewDelegate: NSObjectProtocol {
    func menu(_ menu: DropMenuView, didSelectRowAtIndexPath index: DropMenuView.Index)
}

protocol DropMenuViewDataSource: NSObjectProtocol {

func numberOfColumns(in menu: DropMenuView) -> Int

func menu(_ menu: DropMenuView, numberOfRowsInColumn column: Int) -> Int

func menu(_ menu: DropMenuView, titleForRowsInIndePath index: DropMenuView.Index) -> String

func menu(_ menu: DropMenuView, numberOfItemsInRow row: Int, inColumn: Int) -> Int

func menu(_ menu: DropMenuView, titleForItemInIndexPath indexPath: DropMenuView.Index) -> String
}

extension DropMenuViewDataSource {
    func numberOfColumns(in menu: DropMenuView) -> Int {
        return 1
}

func menu(_ menu: DropMenuView, numberOfItemsInRow row: Int, inColumn: Int) -> Int {
    return 0
}

func menu(_ menu: DropMenuView, titleForItemInIndexPath indexPath: DropMenuView.Index) -> String {
    return ""
}
}


import UIKit

class DropMenuView: UIView {

public struct Index {
    // 列
    var column: Int
    //行
    var row: Int
    //item
    var item: Int
    
    init(column: Int, row: Int, item: Int = -1) {
        self.column = column
        self.row = row
        self.item = item
    }
}

//MARK:- 数据源
weak var dataSource: DropMenuViewDataSource? {
    didSet {
        if oldValue === dataSource {
            return
        }
        dataSourceDidSet(dataSource: dataSource!)
    }
}

weak var delegate: DropMenuViewDelegate?

private lazy var leftTableView: UITableView = {
    let tableView = UITableView(frame: CGRect(x: menuOrigin.x, y: menuOrigin.y + menuHeight, width: SCREEN_WIDTH, height: 0))
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: DropViewTableCellID)
    tableView.delegate = self
    tableView.dataSource = self
    return tableView
}()

private lazy var rightTableView: UITableView = {
    let tableView = UITableView(frame: CGRect(x: menuOrigin.x, y: menuOrigin.y + menuHeight, width: SCREEN_WIDTH, height: 0))
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: DropViewTableCellID)
    tableView.delegate = self
    tableView.dataSource = self
    return tableView
}()

private lazy var backgroundView: UIView = {
    let bgView = UIView(frame: CGRect(x: menuOrigin.x, y: menuOrigin.y, width: SCREEN_WIDTH, height: SCREEN_HEIGHT))
    bgView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
    bgView.alpha = 0
    return bgView
}()

// 菜单的原点坐标
private var menuOrigin: CGPoint = CGPoint.zero
// 菜单高度
private var menuHeight: CGFloat = 0
// tableView最大高度
private var maxTableViewHeight: CGFloat = SCREEN_HEIGHT - 200
// 当前选中的是哪一列
private var selectedColumn: Int = -1
// 每一列选中的row
private var selectedRows = Array<Int>()
// 列表是否正在展示
private var isShow: Bool = false
// 动画时长
private var animationDuration: TimeInterval = 0.25
// cell的高度
private let cellHeight: CGFloat = 50
// cell的标识
private let DropViewTableCellID = "DropViewTableCellID"
// titleButtons
private var titleButtons = [UIButton]()
// 背景颜色
private var bgColor: UIColor = UIColor.orange
// title字体颜色
private var titleColor: UIColor =  UIColor.white
// title 字体大小
private var titleFont: UIFont = UIFont.systemFont(ofSize: 15)
// 分割线颜色
private var seperatorLineColor: UIColor = UIColor.lightGray

init(menuOrigin: CGPoint, menuHeight: CGFloat) {
    self.menuOrigin = menuOrigin
    self.menuHeight = menuHeight
    
    super.init(frame: CGRect(x: menuOrigin.x, y: menuOrigin.y, width: SCREEN_WIDTH, height: menuHeight))
    
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapToDismiss))
    backgroundView.addGestureRecognizer(tapGesture)
    
    backgroundColor = bgColor
    
}

@objc func tapToDismiss() {
    animationTableView(show: false)
    isShow = false
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


func dataSourceDidSet(dataSource: DropMenuViewDataSource) {
    let columns = dataSource.numberOfColumns(in: self)
    createTitleButtons(columns: columns)
    
    selectedRows = Array<Int>(repeating: 0, count: columns)
}

private func createTitleButtons(columns: Int) {

    let btnW: CGFloat = SCREEN_WIDTH / CGFloat(columns)
    let btnH: CGFloat = self.menuHeight
    let btnY: CGFloat = 0
    var btnX: CGFloat = 0
    
    for i in 0..<columns {
        let btn = UIButton(type: .custom)
        btnX = CGFloat(i) * btnW
        btn.frame = CGRect(x: btnX, y: btnY, width: btnW, height: btnH)
        btn.setTitle(dataSource?.menu(self, titleForRowsInIndePath: Index(column: i, row: 0)), for: UIControlState.normal)
        btn.setTitleColor(titleColor, for: .normal)
        btn.titleLabel?.font = titleFont
        btn.addTarget(self, action: #selector(titleBtnDidClick(btn:)), for: .touchUpInside)
        btn.tag = i + 1000
        addSubview(btn)
        titleButtons.append(btn)
        
        let seperatorLine = UIView(frame: CGRect(x: btn.frame.maxX, y: 0, width: 1, height: btnH))
        seperatorLine.backgroundColor = seperatorLineColor
        addSubview(seperatorLine)
    }
}

@objc func titleBtnDidClick(btn: UIButton) {
    let column = btn.tag - 1000
    
    guard let dataSource = dataSource else {
        return
    }
    
    if selectedColumn == column && isShow {
        // 收回列表
        animationTableView(show: false)
        isShow = false
        
    } else {
        selectedColumn = column
        leftTableView.reloadData()
        
        // 刷新右边tableView
        if dataSource.menu(self, numberOfItemsInRow: selectedRows[selectedColumn], inColumn: selectedColumn) > 0 {
            rightTableView.reloadData()
        }
        
        // 展开列表
        animationTableView(show: true)
        isShow = true
    }
}

//MARK:- 展示或者隐藏TableView
func animationTableView(show: Bool) {
    var haveItems = false
    let rows = leftTableView.numberOfRows(inSection: 0)
    if let dataSource = dataSource {
        for i in 0..<rows {
            if dataSource.menu(self, numberOfItemsInRow: i, inColumn: selectedColumn) > 0 {
                haveItems = true
            }
        }
    }
    
    let tableViewHeight = CGFloat(rows) * cellHeight > maxTableViewHeight ? maxTableViewHeight : CGFloat(rows) * cellHeight
    
    if show {
        superview?.addSubview(backgroundView)
        superview?.addSubview(self)
        
        if haveItems {
            leftTableView.frame = CGRect(x: menuOrigin.x, y: menuOrigin.y + menuHeight, width: SCREEN_WIDTH * 0.5, height: 0)
            rightTableView.frame = CGRect(x: SCREEN_WIDTH * 0.5, y: menuOrigin.y + menuHeight, width: SCREEN_WIDTH * 0.5, height: 0)
            superview?.addSubview(leftTableView)
            superview?.addSubview(rightTableView)
        } else {
            rightTableView.removeFromSuperview()
            leftTableView.frame = CGRect(x: menuOrigin.x, y: menuOrigin.y + menuHeight, width: SCREEN_WIDTH, height: 0)
            superview?.addSubview(leftTableView)
        }

        UIView.animate(withDuration: animationDuration) {
            self.backgroundView.alpha = 1.0
            self.leftTableView.frame.size.height = tableViewHeight
            if haveItems {
                self.rightTableView.frame.size.height = tableViewHeight
            }
        }
    } else {
        UIView.animate(withDuration: animationDuration, animations: {
            self.backgroundView.alpha = 0
            self.leftTableView.frame.size.height = 0
            if haveItems {
                self.rightTableView.frame.size.height = 0
            }
        }) { (_) in
            self.backgroundView.removeFromSuperview()
            self.leftTableView.removeFromSuperview()
            if haveItems {
                self.rightTableView.removeFromSuperview()
            }
        }
    }
}

}

extension DropMenuView: UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if let dataSource = dataSource {
        if tableView == leftTableView {
            return dataSource.menu(self, numberOfRowsInColumn: selectedColumn)
        } else {
            return dataSource.menu(self, numberOfItemsInRow: selectedRows[selectedColumn], inColumn: selectedColumn)
        }
    }
    return 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: DropViewTableCellID)
    
    if let dataSource = dataSource {
        if tableView == leftTableView {
            cell?.textLabel?.text = dataSource.menu(self, titleForRowsInIndePath: Index(column: selectedColumn, row: indexPath.row))
            
            // 选中上次选中的那行
            if selectedRows[selectedColumn] == indexPath.row {
                tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
            }
            
        } else {
            cell?.textLabel?.text = dataSource.menu(self, titleForItemInIndexPath: Index(column: selectedColumn, row: selectedRows[selectedColumn], item: indexPath.row))
            
            //选中上次选中的行
            if cell?.textLabel?.text == titleButtons[selectedColumn].titleLabel?.text {
                leftTableView.selectRow(at: IndexPath(row: selectedRows[selectedColumn], section: 0), animated: true, scrollPosition: .none)
                tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
            }
        }
    }
    
    return cell!
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    guard let dataSource = dataSource else {
        return
    }
    
    if tableView == leftTableView {
        selectedRows[selectedColumn] = indexPath.row
        
        let haveItems = dataSource.menu(self, numberOfItemsInRow: indexPath.row, inColumn: selectedColumn) > 0
        if haveItems {
            rightTableView.reloadData()
        } else {
            //收回列表
            animationTableView(show: false)
            isShow = false
            
            //更新title
            titleButtons[selectedColumn].setTitle(dataSource.menu(self, titleForRowsInIndePath: Index(column: selectedColumn, row: indexPath.row)), for: .normal)
        }
        delegate?.menu(self, didSelectRowAtIndexPath: Index(column: selectedColumn, row: indexPath.row))
    } else {
        
        //收回列表
        animationTableView(show: false)
        isShow = false
        
        let index = Index(column: selectedColumn, row: selectedRows[selectedColumn], item: indexPath.row)
        
        //更新title
        titleButtons[selectedColumn].setTitle(dataSource.menu(self, titleForItemInIndexPath: index), for: .normal)
        
        delegate?.menu(self, didSelectRowAtIndexPath: index)
    }
    
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return cellHeight
}
}

4.在控制器中使用

import UIKit

class ViewController: UIViewController {

struct DropMenuData {
    static var TitleDatas = ["出售", "区域", "来源"]
    
    // 房屋类型
    static var HouseType = ["出租", "出售"]
    // 区域
    static var HouseArea = ["东城区": ["安定门", "交道口", "王府井", "和平里", "北新桥", "东直门外", "东直门", "雍和宫"], "西城区": ["新街口", "阜成门", "金融街", "长椿街", "西单"], "朝阳区": ["双井", "国贸", "北苑", "大望路", "四惠", "十里堡", "花家池"], "丰台区": ["方庄", "角门", "草桥", "木樨园", "宋家庄", "东大街", "南苑", "大红门"]]
    //来源
    static var HouseSource = ["全部来源", "房天下", "便民网", "列表网", "城际分类", "58同城", "赶集", "安居客"]
}

private var menuView: DropMenuView!

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.white
    
    menuView = DropMenuView(menuOrigin: CGPoint(x: 0, y: 30), menuHeight: 50)
    menuView.dataSource = self
    menuView.delegate = self
    view.addSubview(menuView)
}
}

extension ViewController: DropMenuViewDelegate {
    func menu(_ menu: DropMenuView, didSelectRowAtIndexPath index: DropMenuView.Index) {
        print(index.column, index.row, index.item)
    }
}

extension ViewController: DropMenuViewDataSource {
    func numberOfColumns(in menu: DropMenuView) -> Int {
        return DropMenuData.TitleDatas.count
    }

func menu(_ menu: DropMenuView, numberOfRowsInColumn column: Int) -> Int {
    if column == 0 {
        return DropMenuData.HouseType.count
    } else if column == 1 {
        return DropMenuData.HouseArea.count
    } else if column == 2 {
        return DropMenuData.HouseSource.count
    }
    return 0
}

func menu(_ menu: DropMenuView, titleForRowsInIndePath index: DropMenuView.Index) -> String {
    switch index.column {
    case 0:
        return DropMenuData.TitleDatas[index.row]
    case 1:
        return Array(DropMenuData.HouseArea.keys)[index.row]
    case 2:
        return DropMenuData.HouseSource[index.row]
    default:
        return ""
    }
}

func menu(_ menu: DropMenuView, numberOfItemsInRow row: Int, inColumn: Int) -> Int {
    if inColumn == 1 {
        return Array(DropMenuData.HouseArea.values)[row].count
    }
    return 0
}

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

推荐阅读更多精彩内容