Swift绘制雷达图(蛛网图、五方图)

前言

由于项目需求中用到了带有渐变色的能力雷达图,而我们常用的一些三方控件并不能满足我的项目需求。特此记录一下自己的实现此功能的过程。主要使用UIBezierPath路径相关、CAShapeLayer绘制相关、CAGradientLayer渐变色相关,通过对上述三个类的组合来实现此功能。先上一下效果图

雷达图.png

最终的实现效果会有一点出入,主要是背景颜色文字颜色可能会有点不同。如有需要大家可以自行修改一下颜色就可以了

绘制前需要知道的一些东西

  • 如何绘制正多边形
    绘制多边形主要是获取到对应的点的坐标,下面是获取点坐标的方法
/*
//.pi 、 M_PI  、 Double.pi   这三个值是一样的  只不过在OC和swift中的写法有点不同


***绘制顺序是逆时针顺序***获取横坐标***
index: 第几个点的坐标
ridus: 正多边形的半径值
count: 正几边形  如果传入5的话就代表是5边形
centerX:圆心的X坐标
*/
    private func pointX(index : Int , ridus : Double , count : Int , centerX : Double) -> Double{
        return centerX - cos(.pi / 180 * (90.0 - 360.0 / count * Double(index))) * ridus
    }
    
/*
***绘制顺序是逆时针顺序***获取纵坐标***
index: 第几个点的坐标
ridus: 正多边形的半径值
count: 正几边形  如果传入5的话就代表是5边形
centerY:圆心的Y坐标
*/
    private func pointY(index : Int , ridus : Double , count : Int , centerY : Double) -> Double{
        return centerY - sin(.pi / 180 * (90.0 - 360.0 / count * Double(index))) * ridus
    }
  • 如何绘制一个带边线的不规则渐变五边形(即本文章中最终实现的内容视图的样式)
  1. 边线的实现方法
    在开发过程中我们肯定或多或少的都用过CAShapeLayer进行一些绘制相关的操作,其中有一个设置画笔颜色的方法strokeColor而这个属性只能设置单颜色,所以在绘制渐变线条的时候这个方法是无法实现的,这时候就要用到CAGradientLayer这个与渐变有关的类来实现了。
    下面来具体说一下实现思路:
    第一步:设置CAGradientLayer的渐变色和对应的frame
    第二步:设置CAShapeLayerfillColorstrokeColor
    第三步:将设置好的CAShapeLayer添加到CAGradientLayermask属性上面
    第四步:将设置好的CAGradientLayer添加到viewlayer上面
    具体的关于fillColorstrokeColor
    如果设置fillColorclear则会只显示线条部分的渐变色。这个就是实现线条渐变的核心的地方
  2. 内容层渐变的实现方法
    关于内部层渐变的实现其实和边线的实现差不多。主要的区别还是在于fillColorstrokeColor的设置上做一些不同的设置就可以了

绘制最里面的小五边形

  1. 绘制路径
    private func setCenterCobWeb(){
        //设置五边形的五个顶点的位置
        let path = UIBezierPath.init()
        for index in 0...4 {
            let point = CGPoint.init(
                x: pointX(index : index , ridus : 10 , count : 5 , centerY : self.center.x),//此处我的圆心点是View的正中心
                y: pointY(index : index , ridus : 10 , count : 5 , centerY : self.center.x)
            )
            if index == 0 {
                path.move(to: point)
                continue
            }
            path.addLine(to: point)
        }
        
        //设置画笔的相关属性
        let centerCobWebLayer = CAShapeLayer.init()
        centerCobWebLayer.path = path.cgPath
        centerCobWebLayer.lineWidth = 0//因为我的内侧的五边形是带有填充色的且线的颜色和填充色一样所以此处设置0
        //如果这个位置边线和填充色不一样的话则需要这样设置
        /*
          centerCobWebLayer.fillColor = strokeColor.cgColor//自己替换颜色
          centerCobWebLayer.strokeColor = strokeColor.cgColor//自己替换颜色
        */
        centerCobWebLayer.fillColor = strokeColor.cgColor//此处修改成自己的填充色
        //添加到layer上去
        self.layer.addSublayer(centerCobWebLayer)
        
    }
     //获取X坐标
     private func pointX(index : Int , ridus : Double , count : Int , centerX : Double) -> Double{
        return centerX - cos(.pi / 180 * (90.0 - 360.0 / count * Double(index))) * ridus
    }
    //获取Y坐标
    private func pointY(index : Int , ridus : Double , count : Int , centerY : Double) -> Double{
        return centerY - sin(.pi / 180 * (90.0 - 360.0 / count * Double(index))) * ridus
    }

绘制最里面的小五边形对应的五条虚线的边

    //此方法可以直接在绘制小五边形的时候在获取坐标点的for循环里面直接调用就可以了
    private func setLinelayer(index : Int){
        let lineLayer = CAShapeLayer.init()
        lineLayer.bounds = self.bounds
        //此处一定要设置,不然的话绘制的位置会出现变化
        lineLayer.position = CGPoint.init(x: centerX, y: centerX)  //定到你的圆心点的位置就可以了
        lineLayer.fillColor = UIColor.clear.cgColor
        lineLayer.strokeColor = strokeColor.cgColor
        lineLayer.lineWidth = 1
        lineLayer.lineDashPattern = [5,10]//虚线相关的属性  【虚线长度,虚线间隔】
        //开始点的坐标-> 虚线离着最里面的小五边形有一点点的距离。小五边形的半径是10  此处设置15,
        //如果不需要也可以设置成和小五边形一样的半径
        let startPoint = CGPoint.init(
            x: pointX(index : index , ridus : 15 , count : 5 , centerY : self.center.x),
            y: pointY(index : index , ridus : 15 , count : 5 , centerY : self.center.x)
        )
        //结束点的坐标->最外层的大的五边形的坐标
        let endPoint = CGPoint.init(
            x: pointX(index : index , ridus : 大五边形的半径 - 大五边形的线的宽度 * 2 , count : 5 , centerY : self.center.x),
            y: pointY(index : index , ridus : 大五边形的半径 - 大五边形的线的宽度 * 2 , count : 5 , centerY : self.center.x)
            //说明一下:大五边形的线的宽度 * 2  这个是因为不减去这个宽度的话
            //最终绘制出来的虚线和大五边形的边出现重叠的情况。如果没有这个要求的话可以直接去掉这个
        )
        
        let path = CGMutablePath.init()
        path.move(to: startPoint)
        path.addLine(to: endPoint)
        lineLayer.path = path
        self.layer.addSublayer(lineLayer)
    }

绘制大五边形

    private func setCobwebLineLayer(){
        let path = UIBezierPath.init()
        var endPoint = CGPoint.init(x: 0, y: 0)
        for index in 0...4 {//绘制几边形就到几
            let point = CGPoint.init(
                
                x: pointX(index : index , ridus : 大五边形半径 , count : 5 , centerY : self.center.x),
                y: pointY(index : index , ridus : 大五边形半径 , count : 5 , centerY : self.center.x)
            )
            if index == 0 {
                path.move(to: point)
                endPoint = point
                continue
            }
            path.addLine(to: point)
        }
        //也可以最终不添加这个endPoind 直接调用 path.close()
        //如果直接使用path.close() 呢在设置线条的圆角的话就会出现问题,
        //如果线条的交点不需要圆角可以直接使用path.close()
        path.addLine(to: endPoint)
        
        let cobWebLayer = CAShapeLayer.init()
        cobWebLayer.path = path.cgPath
        cobWebLayer.lineWidth = CGFloat(cobwebLineWidth)//画笔的宽度 自行修改
        cobWebLayer.lineCap = .round//线条圆角相关
        cobWebLayer.lineJoin = .round//线条圆角相关
        cobWebLayer.strokeColor = strokeColor.cgColor//自行修改画笔颜色
        cobWebLayer.fillColor = Color.clear.cgColor//填充色要设置成透明的
        self.layer.addSublayer(cobWebLayer)
    }

绘制数据的填充层和线条

一定是要先绘制填充层
**关于代码中pointXArraypointYArray的说明:

  1. 在设置gradientLayerframe的时候设置多大呢么渐变的内容层就是多大。所以正常的渐变应该是内容层呢一部分进行渐变就可以了。如果设置的frame是当前view的大小呢么内容层的渐变只能是一部分。所以此处用两个数组保存x坐标y坐标用来回去最大值和最小值
  2. 设置了gradientLayerframe以后现在的数据层的坐标的计算就类似于在一个View上添加一个ImagView的坐标和你现在把这个ImageView添加到了一个新的View上面然后把新的View添加到当前的view上面此时ImageView的坐标性质差不多。只要保证还是现实在原来的位置就可以了
    private func setValueLayer(){
        self.valueArray = [0.5,0.4,0.9,0.7,0.2]//五条边对应的占比
        let path = UIBezierPath.init()
        var pointXArray = [CGFloat]()
        var pointYArray = [CGFloat]()
        for (index , value) in self.valueArray!.enumerated() {
            let point = CGPoint.init(
                x: pointX(index : index , ridus : 15 + (ridus - 15) * value , count : 5 , centerY : self.center.x),
                y: pointY(index : index , ridus : 15 + (ridus - 15) * value , count : 5 , centerY : self.center.x)
            )
            pointXArray.append(point.x)
            pointYArray.append(point.y)
        }
        for (index , value) in pointXArray.enumerated() {
            if index == 0 {
                path.move(to: CGPoint.init(x: value - pointXArray.min()!, y: pointYArray[index] - pointYArray.min()!))
            }else{
                path.addLine(to: CGPoint.init(x: value - pointXArray.min()!, y: pointYArray[index] - pointYArray.min()!))
            }
        }
        let shapeLayer = CAShapeLayer.init()
        shapeLayer.path = path.cgPath
        shapeLayer.strokeColor = UIColor.white.cgColor
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.lineWidth = 0//此处做填充层 所以没有线 画笔宽度为0就可以了
        
        let gradientLayer = CAGradientLayer.init()
        gradientLayer.frame = CGRect(x: pointXArray.min()!, y: pointYArray.min()!, width: pointXArray.max()! - pointXArray.min()!, height: pointYArray.max()! - pointYArray.min()!)
        gradientLayer.startPoint = CGPoint.init(x: 0.5, y: 0)
        gradientLayer.endPoint = CGPoint.init(x: 0.5, y: 1)
        let gradientLayerColors = infoFillColors
        gradientLayer.colors = gradientLayerColors
        gradientLayer.mask = shapeLayer
        self.layer.addSublayer(gradientLayer)
    }

绘制渐变的线条

private func setValueLineLayer(){
        let path = UIBezierPath.init()
        var pointXArray = [CGFloat]()
        var pointYArray = [CGFloat]()
        for (index , value) in self.valueArray!.enumerated() {
            let point = CGPoint.init(
                 x: pointX(index : index , ridus : 15 + (ridus - 15) * value , count : 5 , centerY : self.center.x),
                y: pointY(index : index , ridus : 15 + (ridus - 15) * value , count : 5 , centerY : self.center.x)
            )
            pointXArray.append(point.x)
            pointYArray.append(point.y)
        }
        
        for (index , value) in pointXArray.enumerated() {
            if index == 0 {
                path.move(to: CGPoint.init(x: value - pointXArray.min()!, y: pointYArray[index] - pointYArray.min()!))
            }else{
                path.addLine(to: CGPoint.init(x: value - pointXArray.min()!, y: pointYArray[index] - pointYArray.min()!))
            }
        }
        
        path.close()
        let lineChartLayer = CAShapeLayer.init()
        lineChartLayer.path = path.cgPath
        lineChartLayer.strokeColor = UIColor.white.cgColor
        lineChartLayer.fillColor = UIColor.clear.cgColor//设置填充色为clear 则只会显示线条部分的渐变色
        lineChartLayer.lineWidth = 2//此处一定要设置线条的宽度
        let gradientLayer =  CAGradientLayer.init()
        gradientLayer.frame = CGRect(x: pointXArray.min()!, y: pointYArray.min()!, width:pointXArray.max()! - pointXArray.min()!, height: pointYArray.max()! - pointYArray.min()!)
        gradientLayer.colors = infoLineColors
        gradientLayer.startPoint = CGPoint.init(x:0.5, y:0);
        gradientLayer.endPoint = CGPoint.init(x:0.5,y: 1);
        gradientLayer.mask = lineChartLayer
        self.layer.addSublayer(gradientLayer)
    }

大的五边形的文字信息

关于大五边形文字信息的设置这里就不上代码了。简单的说一下实现方法就可以了:

  • 在我们绘制大五边形的点的时候会获取到五个点,然后根据五个点的信息我们就可以拿到labelframe的一些关键信息了。
  • 根据获取到的五个点正常的创建Label然后添加到view上面就可以了

项目中我写的完整的代码

import UIKit

class CobwebChartView: UIView {
    
    var centerX : Double = 0
    var centerY : Double = 0
    var ridus : Double = 0
    let cobwebLineWidth : Double = 2
    let strokeColor = UIColor.init(red: 30 / 255.0, green: 174 / 255.0, blue: 197 / 255.0, alpha: 1)
    let infoFillColors = [UIColor.init(red: 248 / 255.0, green: 24 / 255.0, blue: 101 / 255.0, alpha: 0.16).cgColor,
                          UIColor.init(red: 157 / 255.0, green:109 / 255.0, blue: 211 / 255.0, alpha: 0.16).cgColor]
    //let infoFillColors = [UIColor.red.cgColor,UIColor.blue.cgColor]
    let infoLineColors = [UIColor.init(red: 248 / 255.0, green: 24 / 255.0, blue: 101 / 255.0, alpha: 1).cgColor,
                          UIColor.init(red: 157 / 255.0, green:109 / 255.0, blue: 211 / 255.0, alpha: 1).cgColor]
    
    var valueArray : [Double]?{
        didSet{
            self.setCenterCobWeb()
            self.setCobwebLineLayer()
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = Color.viewBgColor
        self.centerX = Double(self.height / 2.0)
        self.centerY = Double(self.height / 2.0)
        self.ridus = centerX - 50
        self.setCenterCobWeb()
        self.setCobwebLineLayer()
        self.setValueLayer()
        self.setValueLineLayer()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

extension CobwebChartView{
    //MARK:设置最内侧的正五边形
    private func setCenterCobWeb(){
        let path = UIBezierPath.init()
        for index in 0...4 {
            let point = CGPoint.init(
                x: pointX(index: index, ridus: 10),
                y: pointY(index: index, ridus: 10)
            )
            setLinelayer(index: index)
            if index == 0 {
                path.move(to: point)
                continue
            }
            path.addLine(to: point)
        }
        
        let centerCobWebLayer = CAShapeLayer.init()
        centerCobWebLayer.path = path.cgPath
        centerCobWebLayer.lineWidth = 0
        centerCobWebLayer.fillColor = strokeColor.cgColor
        self.layer.addSublayer(centerCobWebLayer)
        
    }
    
    private func setLinelayer(index : Int){
        let lineLayer = CAShapeLayer.init()
        lineLayer.bounds = self.bounds
        lineLayer.position = CGPoint.init(x: centerX, y: centerX)
        lineLayer.fillColor = UIColor.clear.cgColor
        lineLayer.strokeColor = strokeColor.cgColor
        lineLayer.lineWidth = 1
        lineLayer.lineDashPattern = [5,10]
        let startPoint = CGPoint.init(
            x: pointX(index: index, ridus: 15),
            y: pointY(index: index, ridus: 15)
        )
        
        let endPoint = CGPoint.init(
            x: pointX(index: index, ridus: ridus - cobwebLineWidth * 2),
            y: pointY(index: index, ridus: ridus - cobwebLineWidth * 2)
        )
        
        let path = CGMutablePath.init()
        path.move(to: startPoint)
        path.addLine(to: endPoint)
        lineLayer.path = path
        self.layer.addSublayer(lineLayer)
    }
    
    private func setCobwebLineLayer(){
        let path = UIBezierPath.init()
        var endPoint = CGPoint.init(x: 0, y: 0)
        let titleArray = ["力量","恢复","耐力","柔韧性","平衡"]
        for index in 0...4 {
            let point = CGPoint.init(
                x: pointX(index: index, ridus: ridus),
                y: pointY(index: index, ridus: ridus)
            )
            
            if index == 0 {
                path.move(to: point)
                endPoint = point
                setTitleLabel(position: .top, point: point, title: titleArray[index])
                continue
            }
            if index == 1 {
                setTitleLabel(position: .left, point: point, title: titleArray[index])
            }
            
            if index == 2 || index == 3 {
                setTitleLabel(position: .bottom, point: point, title: titleArray[index])
            }
            if index == 4 {
                setTitleLabel(position: .right, point: point, title: titleArray[index])
            }
            path.addLine(to: point)
        }
        path.addLine(to: endPoint)
        
        let cobWebLayer = CAShapeLayer.init()
        cobWebLayer.path = path.cgPath
        cobWebLayer.lineWidth = CGFloat(cobwebLineWidth)
        cobWebLayer.lineCap = .round
        cobWebLayer.lineJoin = .round
        cobWebLayer.strokeColor = strokeColor.cgColor
        cobWebLayer.fillColor = Color.clear.cgColor
        self.layer.addSublayer(cobWebLayer)
    }
    
    private func setValueLayer(){
        self.valueArray = [0.5,0.4,0.9,0.7,0.2]
        let path = UIBezierPath.init()
        var pointXArray = [CGFloat]()
        var pointYArray = [CGFloat]()
        for (index , value) in self.valueArray!.enumerated() {
            let point = CGPoint.init(
                x: pointX(index: index, ridus: 15 + (ridus - 15) * value),
                y: pointY(index: index, ridus: 15 + (ridus - 15) * value)
            )
            pointXArray.append(point.x)
            pointYArray.append(point.y)
        }
        for (index , value) in pointXArray.enumerated() {
            if index == 0 {
                path.move(to: CGPoint.init(x: value - pointXArray.min()!, y: pointYArray[index] - pointYArray.min()!))
            }else{
                path.addLine(to: CGPoint.init(x: value - pointXArray.min()!, y: pointYArray[index] - pointYArray.min()!))
            }
        }
        let shapeLayer = CAShapeLayer.init()
        shapeLayer.path = path.cgPath
        shapeLayer.strokeColor = UIColor.white.cgColor
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.lineWidth = 0
        
        let gradientLayer = CAGradientLayer.init()
        gradientLayer.frame = CGRect(x: pointXArray.min()!, y: pointYArray.min()!, width: pointXArray.max()! - pointXArray.min()!, height: pointYArray.max()! - pointYArray.min()!)
        gradientLayer.startPoint = CGPoint.init(x: 0.5, y: 0)
        gradientLayer.endPoint = CGPoint.init(x: 0.5, y: 1)
        let gradientLayerColors = infoFillColors
        gradientLayer.colors = gradientLayerColors
        gradientLayer.mask = shapeLayer
        self.layer.addSublayer(gradientLayer)
        
        
        
    }
    
    private func setValueLineLayer(){
        let path = UIBezierPath.init()
        var pointXArray = [CGFloat]()
        var pointYArray = [CGFloat]()
        for (index , value) in self.valueArray!.enumerated() {
            let point = CGPoint.init(
                x: pointX(index: index, ridus: 15 + (ridus - 15) * value),
                y: pointY(index: index, ridus: 15 + (ridus - 15) * value)
            )
            pointXArray.append(point.x)
            pointYArray.append(point.y)
        }
        
        for (index , value) in pointXArray.enumerated() {
            if index == 0 {
                path.move(to: CGPoint.init(x: value - pointXArray.min()!, y: pointYArray[index] - pointYArray.min()!))
            }else{
                path.addLine(to: CGPoint.init(x: value - pointXArray.min()!, y: pointYArray[index] - pointYArray.min()!))
            }
        }
        
        path.close()
        let lineChartLayer = CAShapeLayer.init()
        lineChartLayer.path = path.cgPath
        lineChartLayer.strokeColor = UIColor.white.cgColor
        lineChartLayer.fillColor = UIColor.clear.cgColor
        lineChartLayer.lineWidth = 2
        let gradientLayer =  CAGradientLayer.init()
        gradientLayer.frame = CGRect(x: pointXArray.min()!, y: pointYArray.min()!, width:pointXArray.max()! - pointXArray.min()!, height: pointYArray.max()! - pointYArray.min()!)
        gradientLayer.colors = infoLineColors
        gradientLayer.startPoint = CGPoint.init(x:0.5, y:0);
        gradientLayer.endPoint = CGPoint.init(x:0.5,y: 1);
        gradientLayer.mask = lineChartLayer
        self.layer.addSublayer(gradientLayer)
    }
    
    private func setTitleLabel(position : LabelPosition , point : CGPoint , title : String){
        let titleLabel = UILabel.init()
        titleLabel.text = title
        titleLabel.font = UIFont.systemFont(ofSize: 14)
        titleLabel.sizeToFit()
        if position == .left {
            titleLabel.frame = CGRect(x: point.x - 10 - titleLabel.frame.size.width, y: point.y - titleLabel.frame.size.height / 2.0, width: titleLabel.frame.size.width, height: titleLabel.frame.size.height)
        }
        if position == .top {
            titleLabel.frame = CGRect(x: point.x - titleLabel.frame.size.width / 2.0, y: point.y - titleLabel.frame.size.height - 10, width: titleLabel.frame.size.width, height: titleLabel.frame.size.height)
        }
        
        if position == .right {
            titleLabel.frame = CGRect(x: point.x + 10, y: point.y - titleLabel.frame.size.height / 2.0, width: titleLabel.frame.size.width, height: titleLabel.frame.size.height)
        }
        if position == .bottom {
            titleLabel.frame = CGRect(x: point.x - titleLabel.frame.size.width / 2.0, y: point.y + 10, width: titleLabel.frame.size.width, height: titleLabel.frame.size.height)
        }
        self.addSubview(titleLabel)
    }
    
    enum LabelPosition {
        case left
        case right
        case top
        case bottom
    }
}

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

推荐阅读更多精彩内容