表格视图中的iOS地图视图错误帧起源

时间:2022-03-09 08:41:21

I need to set the position of my map view in a table view cell. I simply set the frame in cellForRow method.

我需要在表格视图单元格中设置地图视图的位置。我只是在cellForRow方法中设置框架。

some of the map views are misplaced. When I scroll up the table and scroll down to let it reappear (to reuse the table cell), then it is fixed.

一些地图视图放错了地方。当我向上滚动表并向下滚动以重新出现(重用表格单元格)时,它就被修复了。

Note

  1. the y position is wrong but the x position is correct.

    y位置错误但x位置正确。

  2. I use the same way (simply set frame) to set the pictures position and they are always correct. So the problem is map view itself instead of how to position the frame.

    我使用相同的方式(只需设置框架)来设置图片位置,它们始终是正确的。所以问题是地图视图本身而不是如何定位框架。

The following screenshot shows 3 map views, the middle one has a wrong y position

以下屏幕截图显示了3个地图视图,中间的一个具有错误的y位置

表格视图中的iOS地图视图错误帧起源

EDIT:

The UI part is quite complicated. inside cellForRowAtIndexPath method, I dequeue a MessageCell and call its setupWithMessage:(Message *)message method and then I check if the message is of type location: (a location type message has an optional text view and a map view)

UI部分非常复杂。在cellForRowAtIndexPath方法中,我将MessageCell出列并调用其setupWithMessage:(Message *)消息方法,然后检查消息是否为类型位置:(位置类型消息具有可选的文本视图和地图视图)

        self.textView.hidden = NO;
        self.mapView.hidden = NO;

        self.textView.text = message.text;


        [Helper setupMapView:self.mapView posx:message.posx posy:message.posy];

        CGSize size1 = [UIHelper sizeWithText:message.text entity:message];
        CGSize size2 = [UIHelper sizeWithMapEntity:message];

        CGRect frame = [UIHelper adjustTextView:self.textView textViewSize:size1 extraView:self.mapView extraViewSize:size2 entity:message];








+ (CGRect)adjustTextView:(UITextView *)textView textViewSize:(CGSize)textViewSize extraView:(UIView *)extraView extraViewSize:(CGSize)extraViewSize entity:(id)entity {


    if (textView == nil || extraView == nil || CGSizeEqualToSize(textViewSize, CGSizeZero) || CGSizeEqualToSize(extraViewSize, CGSizeZero)) {
        CGSize targetSize;
        UIView *targetView;

        if (textView == nil || CGSizeEqualToSize(textViewSize, CGSizeZero)) {

            targetView = extraView;
            targetSize = extraViewSize;

        }
        else {
            targetView = textView;
            targetSize = textViewSize;
        }

        return [self adjustContentView:targetView size:targetSize entity:entity];

    }

    else {

        CGRect frame1 = [self adjustContentView:textView size:textViewSize entity:entity];
        CGRect frame2 = [self adjustContentView:extraView size:extraViewSize entity:entity];

        frame2.origin.y += frame1.size.height + OFFSET_BETWEEN_TEXTVIEW_EXTRAVIEW;
        extraView.frame = frame2;

        return CGRectMake(frame1.origin.x, frame1.origin.y, MAX(frame1.size.width, frame2.size.width), frame1.size.height + frame2.size.height + OFFSET_BETWEEN_TEXTVIEW_EXTRAVIEW);
    }

Note that the "extraView" above can refer to any view below a text view, such as an UIImageView

请注意,上面的“extraView”可以引用文本视图下方的任何视图,例如UIImageView

+ (CGRect)adjustContentView:(UIView *)contentView size:(CGSize) size entity:(id)entity {

    float photoSideOffset = 60;
    float topOffset = 30;

    CGRect frame;
    frame.origin.y = topOffset;
    frame.size = size;

    if ([DBHelper isMyEntity:entity]) {
        frame.origin.x = 320 - size.width - photoSideOffset;
    }
    else {
        frame.origin.x = photoSideOffset;
    }
    contentView.frame = frame;


    if ([contentView isKindOfClass:[UITextView class]]) {
        [(UITextView *)contentView sizeToFit];
    }

    return contentView.frame;
}

EDIT 2: i use the same UIHelper methods for photo messages and the coordinates are correct:

编辑2:我对照片消息使用相同的UIHelper方法,坐标是正确的:

表格视图中的iOS地图视图错误帧起源

EDIT 3: the value of size1 size2 and frame

编辑3:size1 size2和frame的值

表格视图中的iOS地图视图错误帧起源

4 个解决方案

#1


2  

the workaround i propose isnt really a "solution" but an "alternative"

我建议的解决方法不是真正的“解决方案”,而是“另类”

instead of putting the mkmapview to the cell, you can create a snapshot from the map view. And then you can create image cells for the map cell. My suggestion is that you trigger an action when user click on the image cell and push a new "MapViewController" modal.

您可以从地图视图创建快照,而不是将mkmapview放入单元格。然后,您可以为地图单元格创建图像单元格。我的建议是当用户点击图像单元格并推送一个新的“MapViewController”模式时触发一个动作。

        self.textView.hidden = NO;
        self.thumbnailButton.hidden = NO;

        self.textView.text = message.text;


        [Helper setupMapSnapshotThumbnailButton:self.thumbnailButton withPosx:message.posx posy:message.posy size:MESSAGE_SIZE_MAP];

        CGSize size1 = [UIHelper sizeWithText:message.text entity:message];
        CGSize size2 = MESSAGE_SIZE_MAP;

        CGRect frame = [UIHelper adjustTextView:self.textView textViewSize:size1 extraView:self.thumbnailButton extraViewSize:size2 entity:message];

        [self setupCommonOutletsWithContentFrame:frame];

and you can create the image by using

并且您可以使用创建图像

MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
options.scale = [UIScreen mainScreen].scale;
options.region = [self private_mapRegionWithPosx:posx posy:posy];
options.size = size;

MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
    [thumbnailButton setBackgroundImage:snapshot.image forState:UIControlStateNormal];
}];

btw the snapshot code only works for ios 7. if you need ios6 or earlier support, you need to do a bit of cg coding

btw快照代码仅适用于ios 7.如果你需要ios6或更早版本的支持,你需要做一些cg编码

#2


3  

Approach 1: alloc init UITableViewCell inside your cellForRowAtIndexPath

方法1:在您的cellForRowAtIndexPath中分配init UITableViewCell

Simple solution is to cell = [[UITableViewCell alloc]init]; alloc init every time (it will make new cell each time instead caching/or reusing )

简单的解决方案是cell = [[UITableViewCell alloc] init];每次都分配init(每次都会创建新的单元格而不是缓存/或重用)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

        // Configure the cell...

       /*
        if (cell == nil) {

            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

        }

       */
      // Try below code

      cell = [[UITableViewCell alloc]init];


        ------

        -------

        return cell;

    }

Approach 2: removeFromSuperView

方法2:removeFromSuperView

  for (UIView *subview in self.view.subviews) {

        if ([subview isKindOfClass:[UIButton class]]) { // set kind as per your own requirement

            [subview removeFromSuperview];
        }


    }

#3


1  

Sample of code

代码示例

MultiMap.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface MultiMap : UIViewController
<UITableViewDelegate,UITableViewDataSource,MKMapViewDelegate>
{
    MKMapView *mapView;
}
@property (retain, nonatomic) IBOutlet UITableView *mainTableView;

@end

MultiMap.m

#import "MultiMap.h"

@interface MultiMap ()

@end

@implementation MultiMap

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:YES];
    self.title=@"Multi Map";
}

- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
    return nil;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 200;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 4;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"multi";
    UITableViewCell *cell=nil;

    cell = [tableView dequeueReusableHeaderFooterViewWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    mapView=[[MKMapView alloc]initWithFrame:CGRectMake(25, 25, 275, 150)];
    mapView.delegate=self;
    [mapView setBackgroundColor:[UIColor whiteColor]];
    [mapView setTintColor:[UIColor whiteColor]];

    [cell addSubview:mapView];

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

}

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{

}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@""];

    annotationView.canShowCallout = YES;

    return annotationView;
}

- (void)dealloc {
    [_mainTableView release];
    [super dealloc];
}
@end

May you get help..

愿你得到帮助..

#4


1  

Please make sure your textView frame is 0. for the case the mapView doesn't show at accurate place additionally you can try following.

请确保textView框架为0.对于mapView未在准确位置显示的情况,您可以尝试以下操作。

+ (CGRect)adjustTextView:(UITextView *)textView textViewSize:(CGSize)textViewSize extraView:(UIView *)extraView extraViewSize:(CGSize)extraViewSize entity:(id)entity {


    if (textView == nil || extraView == nil || CGSizeEqualToSize(textViewSize, CGSizeZero) || CGSizeEqualToSize(extraViewSize, CGSizeZero)) {
        CGSize targetSize;
        UIView *targetView;

        if (textView == nil || CGSizeEqualToSize(textViewSize, CGSizeZero)) {

            targetView = extraView;
            targetSize = extraViewSize;

        }
        else {
            targetView = textView;
            targetSize = textViewSize;
        }

        return [self adjustContentView:targetView size:targetSize entity:entity];

    }

    else {

        CGRect frame1 = [self adjustContentView:textView size:textViewSize entity:entity];
        CGRect frame2 = [self adjustContentView:extraView size:extraViewSize entity:entity];

        frame2.origin.y += frame1.size.height + OFFSET_BETWEEN_TEXTVIEW_EXTRAVIEW;
        extraView.frame = frame2;
        [[extraView superview] setNeedsLayout]; //Addition
        return CGRectMake(frame1.origin.x, frame1.origin.y, MAX(frame1.size.width, frame2.size.width), frame1.size.height + frame2.size.height + OFFSET_BETWEEN_TEXTVIEW_EXTRAVIEW);
    }

UPDATE: Or you can update the following

更新:或者您可以更新以下内容

+ (CGRect)adjustContentView:(UIView *)contentView size:(CGSize) size entity:(id)entity {

float photoSideOffset = 60;
float topOffset = 30;

CGRect frame;
frame.size = size;

if ([DBHelper isMyEntity:entity]) {
    frame.origin.x = 320 - size.width - photoSideOffset;
}
else
{
    frame.origin.x = photoSideOffset;
}

for (id view in [[contentView superview] subviews])
{
    if (view != contentView)
    {
        if ([view respondsToSelector:@selector(frame)])
        {
            topOffset = (([view frame].origin.y + [view frame].size.height)<topOffset)?([view frame].origin.y + [view frame].size.height):topOffset;
        }
    }
}
if ((int)topOffset != 30)
{
    topOffset += OFFSET_BETWEEN_TEXTVIEW_EXTRAVIEW;
}
frame.origin.y = topOffset;
contentView.frame = frame;


if ([contentView isKindOfClass:[UITextView class]]) {
    [(UITextView *)contentView sizeToFit];
}

return contentView.frame;
}

Also make sure you update the height of the cell accordingly using - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

还要确保使用 - (CGFloat)tableView更新单元格的高度:( UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

#1


2  

the workaround i propose isnt really a "solution" but an "alternative"

我建议的解决方法不是真正的“解决方案”,而是“另类”

instead of putting the mkmapview to the cell, you can create a snapshot from the map view. And then you can create image cells for the map cell. My suggestion is that you trigger an action when user click on the image cell and push a new "MapViewController" modal.

您可以从地图视图创建快照,而不是将mkmapview放入单元格。然后,您可以为地图单元格创建图像单元格。我的建议是当用户点击图像单元格并推送一个新的“MapViewController”模式时触发一个动作。

        self.textView.hidden = NO;
        self.thumbnailButton.hidden = NO;

        self.textView.text = message.text;


        [Helper setupMapSnapshotThumbnailButton:self.thumbnailButton withPosx:message.posx posy:message.posy size:MESSAGE_SIZE_MAP];

        CGSize size1 = [UIHelper sizeWithText:message.text entity:message];
        CGSize size2 = MESSAGE_SIZE_MAP;

        CGRect frame = [UIHelper adjustTextView:self.textView textViewSize:size1 extraView:self.thumbnailButton extraViewSize:size2 entity:message];

        [self setupCommonOutletsWithContentFrame:frame];

and you can create the image by using

并且您可以使用创建图像

MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
options.scale = [UIScreen mainScreen].scale;
options.region = [self private_mapRegionWithPosx:posx posy:posy];
options.size = size;

MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
    [thumbnailButton setBackgroundImage:snapshot.image forState:UIControlStateNormal];
}];

btw the snapshot code only works for ios 7. if you need ios6 or earlier support, you need to do a bit of cg coding

btw快照代码仅适用于ios 7.如果你需要ios6或更早版本的支持,你需要做一些cg编码

#2


3  

Approach 1: alloc init UITableViewCell inside your cellForRowAtIndexPath

方法1:在您的cellForRowAtIndexPath中分配init UITableViewCell

Simple solution is to cell = [[UITableViewCell alloc]init]; alloc init every time (it will make new cell each time instead caching/or reusing )

简单的解决方案是cell = [[UITableViewCell alloc] init];每次都分配init(每次都会创建新的单元格而不是缓存/或重用)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

        // Configure the cell...

       /*
        if (cell == nil) {

            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

        }

       */
      // Try below code

      cell = [[UITableViewCell alloc]init];


        ------

        -------

        return cell;

    }

Approach 2: removeFromSuperView

方法2:removeFromSuperView

  for (UIView *subview in self.view.subviews) {

        if ([subview isKindOfClass:[UIButton class]]) { // set kind as per your own requirement

            [subview removeFromSuperview];
        }


    }

#3


1  

Sample of code

代码示例

MultiMap.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface MultiMap : UIViewController
<UITableViewDelegate,UITableViewDataSource,MKMapViewDelegate>
{
    MKMapView *mapView;
}
@property (retain, nonatomic) IBOutlet UITableView *mainTableView;

@end

MultiMap.m

#import "MultiMap.h"

@interface MultiMap ()

@end

@implementation MultiMap

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:YES];
    self.title=@"Multi Map";
}

- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
    return nil;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 200;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 4;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"multi";
    UITableViewCell *cell=nil;

    cell = [tableView dequeueReusableHeaderFooterViewWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    mapView=[[MKMapView alloc]initWithFrame:CGRectMake(25, 25, 275, 150)];
    mapView.delegate=self;
    [mapView setBackgroundColor:[UIColor whiteColor]];
    [mapView setTintColor:[UIColor whiteColor]];

    [cell addSubview:mapView];

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

}

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{

}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@""];

    annotationView.canShowCallout = YES;

    return annotationView;
}

- (void)dealloc {
    [_mainTableView release];
    [super dealloc];
}
@end

May you get help..

愿你得到帮助..

#4


1  

Please make sure your textView frame is 0. for the case the mapView doesn't show at accurate place additionally you can try following.

请确保textView框架为0.对于mapView未在准确位置显示的情况,您可以尝试以下操作。

+ (CGRect)adjustTextView:(UITextView *)textView textViewSize:(CGSize)textViewSize extraView:(UIView *)extraView extraViewSize:(CGSize)extraViewSize entity:(id)entity {


    if (textView == nil || extraView == nil || CGSizeEqualToSize(textViewSize, CGSizeZero) || CGSizeEqualToSize(extraViewSize, CGSizeZero)) {
        CGSize targetSize;
        UIView *targetView;

        if (textView == nil || CGSizeEqualToSize(textViewSize, CGSizeZero)) {

            targetView = extraView;
            targetSize = extraViewSize;

        }
        else {
            targetView = textView;
            targetSize = textViewSize;
        }

        return [self adjustContentView:targetView size:targetSize entity:entity];

    }

    else {

        CGRect frame1 = [self adjustContentView:textView size:textViewSize entity:entity];
        CGRect frame2 = [self adjustContentView:extraView size:extraViewSize entity:entity];

        frame2.origin.y += frame1.size.height + OFFSET_BETWEEN_TEXTVIEW_EXTRAVIEW;
        extraView.frame = frame2;
        [[extraView superview] setNeedsLayout]; //Addition
        return CGRectMake(frame1.origin.x, frame1.origin.y, MAX(frame1.size.width, frame2.size.width), frame1.size.height + frame2.size.height + OFFSET_BETWEEN_TEXTVIEW_EXTRAVIEW);
    }

UPDATE: Or you can update the following

更新:或者您可以更新以下内容

+ (CGRect)adjustContentView:(UIView *)contentView size:(CGSize) size entity:(id)entity {

float photoSideOffset = 60;
float topOffset = 30;

CGRect frame;
frame.size = size;

if ([DBHelper isMyEntity:entity]) {
    frame.origin.x = 320 - size.width - photoSideOffset;
}
else
{
    frame.origin.x = photoSideOffset;
}

for (id view in [[contentView superview] subviews])
{
    if (view != contentView)
    {
        if ([view respondsToSelector:@selector(frame)])
        {
            topOffset = (([view frame].origin.y + [view frame].size.height)<topOffset)?([view frame].origin.y + [view frame].size.height):topOffset;
        }
    }
}
if ((int)topOffset != 30)
{
    topOffset += OFFSET_BETWEEN_TEXTVIEW_EXTRAVIEW;
}
frame.origin.y = topOffset;
contentView.frame = frame;


if ([contentView isKindOfClass:[UITextView class]]) {
    [(UITextView *)contentView sizeToFit];
}

return contentView.frame;
}

Also make sure you update the height of the cell accordingly using - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

还要确保使用 - (CGFloat)tableView更新单元格的高度:( UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath