在Pdf中绘制表格?

时间:2013-07-24 08:18:51

标签: ios objective-c pdf core-graphics core-text

我创建了一个带有表格的PDF。该表不会继续到下一页,而是在下一页中创建一个新表,其y位置与第一页的位置相同。如何在下一页继续绘制表格?

- (IBAction)pdfPressed:(id)sender {
  // create some sample data. In a real application, this would come from the database or an API.
  NSString* path = [[NSBundle mainBundle] pathForResource:@"sampleData" ofType:@"plist"];
  NSDictionary* data = [NSDictionary dictionaryWithContentsOfFile:path];
  NSArray* students = [data objectForKey:@"Students"];

  // get a temprorary filename for this PDF
  path = NSTemporaryDirectory();
  self.pdfFilePath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"%d.pdf", [[NSDate date] timeIntervalSince1970] ]];

  // Create the PDF context using the default page size of 612 x 792.
  // This default is spelled out in the iOS documentation for UIGraphicsBeginPDFContextToFile
  UIGraphicsBeginPDFContextToFile(self.pdfFilePath, CGRectZero, nil);

  // get the context reference so we can render to it.
  CGContextRef context = UIGraphicsGetCurrentContext();

  int currentPage = 0;

  // maximum height and width of the content on the page, byt taking margins into account.
  CGFloat maxWidth = kDefaultPageWidth - kMargin * 2;
  CGFloat maxHeight = kDefaultPageHeight - kMargin * 2;

  // we're going to cap the name of the class to using half of the horizontal page, which is why we're dividing by 2
  CGFloat classNameMaxWidth = maxWidth / 2;

  // the max width of the grade is also half, minus the margin
  CGFloat gradeMaxWidth = (maxWidth / 2) - kColumnMargin;

  // only create the fonts once since it is a somewhat expensive operation
  UIFont* studentNameFont = [UIFont boldSystemFontOfSize:17];
  UIFont* classFont = [UIFont systemFontOfSize:15];

  CGFloat currentPageY = 0;

  // iterate through out students, adding to the pdf each time.
  for (NSDictionary* student in students)
  {
    // every student gets their own page
    // Mark the beginning of a new page.
    UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
    currentPageY = kMargin;

    // draw the student's name at the top of the page.
    NSString* name = [NSString stringWithFormat:@"%@ %@",
                          [student objectForKey:@"FirstName"],
                          [student objectForKey:@"LastName"]];

    CGSize size = [name sizeWithFont:studentNameFont forWidth:maxWidth lineBreakMode:UILineBreakModeWordWrap];
    [name drawAtPoint:CGPointMake(kMargin, currentPageY) forWidth:maxWidth withFont:studentNameFont lineBreakMode:UILineBreakModeWordWrap];
    currentPageY += size.height;

    // draw a one pixel line under the student's name
    CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]);
    CGContextMoveToPoint(context, kMargin, currentPageY);
    CGContextAddLineToPoint(context, kDefaultPageWidth - kMargin, currentPageY);
    CGContextStrokePath(context);
    int xOrigin = 50;
    int yOrigin = 300;

    int rowHeight = 50;
    int columnWidth = 120;

    int numberOfRows = 3;
    int numberOfColumns = 4;


    // iterate through the list of classes and add these to the PDF.
    NSArray* classes = [student objectForKey:@"Classes"];
    for (NSDictionary* class in classes)
    {
      NSString* className = [class objectForKey:@"Name"];
      NSString* grade = [class objectForKey:@"Grade"];

      // before we render any text to the PDF, we need to measure it, so we'll know where to render the
      // next line.
      size = [className sizeWithFont:classFont constrainedToSize:CGSizeMake(classNameMaxWidth, MAXFLOAT) lineBreakMode:UILineBreakModeWordWrap];

      // if the current text would render beyond the bounds of the page,
      // start a new page and render it there instead
      if (size.height + currentPageY > maxHeight) {
        // create a new page and reset the current page's Y value
        UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
        currentPageY = kMargin;
      }

      // render the text
      [className drawInRect:CGRectMake(kMargin, currentPageY, classNameMaxWidth, maxHeight) withFont:classFont lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft];

      // print the grade to the right of the class name
      [grade drawInRect:CGRectMake(kMargin + classNameMaxWidth + kColumnMargin, currentPageY, gradeMaxWidth, maxHeight) withFont:classFont lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft];

      currentPageY += size.height;

      [self drawTableAt:CGPointMake(xOrigin, yOrigin) withRowHeight:rowHeight andColumnWidth:columnWidth andRowCount:numberOfRows andColumnCount:numberOfColumns];
    }

    // increment the page number.
    currentPage++;
  }

  // end and save the PDF.
  UIGraphicsEndPDFContext();

  // Ask the user if they'd like to see the file or email it.
  UIActionSheet* actionSheet = [[[UIActionSheet alloc] initWithTitle:@"Would you like to preview or email this PDF?"
                                                            delegate:self
                                                   cancelButtonTitle:@"Cancel"
                                              destructiveButtonTitle:nil
                                                   otherButtonTitles:@"Preview", @"Email", nil] autorelease];
  [actionSheet showInView:self.view];
}

-(void)drawTableAt:(CGPoint)origin
     withRowHeight:(int)rowHeight
    andColumnWidth:(int)columnWidth
       andRowCount:(int)numberOfRows
    andColumnCount:(int)numberOfColumns
{
  for (int i = 0; i <= numberOfRows; i++) {
    int newOrigin = origin.y + (rowHeight*i);
    CGPoint from = CGPointMake(origin.x, newOrigin);
    CGPoint to = CGPointMake(origin.x + (numberOfColumns*columnWidth), newOrigin);
    [self drawLineFromPoint:from toPoint:to];
  }

  for (int i = 0; i <= numberOfColumns; i++) {
    int newOrigin = origin.x + (columnWidth*i);
    CGPoint from = CGPointMake(newOrigin, origin.y);
    CGPoint to = CGPointMake(newOrigin, origin.y +(numberOfRows*rowHeight));
    [self drawLineFromPoint:from toPoint:to];
  }
}

-(void)drawLineFromPoint:(CGPoint)from toPoint:(CGPoint)to
{
  CGContextRef context = UIGraphicsGetCurrentContext();
  CGContextSetLineWidth(context, 2.0);
  CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
  CGFloat components[] = {0.2, 0.2, 0.2, 0.3};
  CGColorRef color = CGColorCreate(colorspace, components);

  CGContextSetStrokeColorWithColor(context, color);
  CGContextMoveToPoint(context, from.x, from.y);
  CGContextAddLineToPoint(context, to.x, to.y);

  CGContextStrokePath(context);
  CGColorSpaceRelease(colorspace);
  CGColorRelease(color);
}

1 个答案:

答案 0 :(得分:0)

PDF绘图是“以页面为中心的”。当你开始绘制第二页时,你已经有效地获得了一个全新的上下文等等。除非你专门编写代码,否则不会有任何从一个页面到另一个页面的流血的概念。

我看到你已经通过检查className的大小是否会将其放在maxHeight之上,已经在“类”循环中解决了这个分页问题。你需要为表做同样的事情。

在较高级别,您可以一次一行地渲染您的表格,在每行之后以相同的方式检查,以查看下一行是否将表格放在maxHeight上,然后是否会,做你在类循环中已经做过的事情 - 开始一个新页面,重置currentPageY并继续绘制行直到表完成等等。

简而言之:没有办法让这个“免费”。