动态信息窗口大小iOS谷歌地图

3
我正在创建类似于以下方式的自定义信息窗口,用于谷歌地图:

我正在创建自定义信息窗口来显示谷歌地图上的信息,如下所示:

NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"InfoView" owner:self options:nil];
InfoView *mainView = [subviewArray objectAtIndex:0];
UIView *subview = mainView.subviews[0];
//setup content
return subview;

这样做是有效的,但我无法添加任何约束条件,因为这样会填满整个屏幕并变成空白。所以我决定不使用自动布局来完成这项工作。
我的内容是一些标签,一个接一个地排列。在某些情况下,文本不能适应单行,标签框架应该增加。同时,整个视图框架也必须增加,并且下面的视图必须正确偏移。我已经编写了一个方法来实现此功能,除了信息窗口视图框架本身外,所有东西都在发生变化。在日志中,我可以看到框架已更改,但在屏幕上,它仍然具有原始大小,并且文本在其外面。
我甚至尝试仅更改信息窗口框架,但仍然没有效果-根本不会改变。
我还尝试调用[subview layoutIfNeeded]和[subview layoutSubviews]。
那么,如何制作具有动态大小的信息窗口?
编辑:
如@Milan所要求的,整个代码如下:
- (UIView *_Nullable) mapView:(GMSMapView *)mapView markerInfoContents: (GMSMarker *)marker {
    NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"PortView" owner:self options:nil];
    PortView *mainView = [subviewArray objectAtIndex:0];
    UIView *subview = mainView.subviews[0];
    mainView.frame = CGRectMake(mainView.frame.origin.x, mainView.frame.origin.y, mainView.frame.size.width, mainView.frame.size.height + 40) //increase frame size doesn't work
    mainView.titleLabel.text = portSzukany.name;
    return subview;
}
3个回答

2
您需要实现GMSMapViewDelegate并从下面的方法中返回信息视图:
- (UIView *GMS_NULLABLE_PTR)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker;

根据所述方法的描述,“返回的UIView在任一维度上不能超过500个点的边界。”

我已经在使用这个了。问题是我必须使用严格的视图大小,如果内容较短或较长,则大小不会改变。 - Makalele
你能贴出代码吗?展示一下你是如何创建动态大小的视图的。 - Milan Agarwal
1
我正在从xib中加载视图并修改其框架以调整大小。问题是它没有改变任何东西。约束也无法与之配合使用。唯一实现这一点的方法是在代码中从头构建整个视图。 - Makalele
是的,我看过了,我的问题是你是如何通过代码实现的。这可能存在错误的风险。 - Milan Agarwal
好的,它起作用了!现在的问题是我失去了“气球”样式的背景,因为它只是一个简单的矩形。但我想我可以用自己的图像来解决这个问题。 - Makalele
显示剩余3条评论

0
当我面对这个问题时,我发现更新infoWindow框架的唯一方法是:像这样解除infoWindow并再次显示它:
let m = mapView?.selectedMarker
mapView?.selectedMarker = nil
mapView?.selectedMarker = m

或者您可以直接使用SMCalloutView,它与Google Maps兼容。

我认为Google Maps不使用系统布局进行渲染。它使用OpenGL或其他技术。

完整的源代码(这是Swift代码,希望这对您不是问题)

import GoogleMaps


class GMapsViewController: UIViewController {
    let CalloutYOffset:CGFloat = 50.0

    var mapView = GMSMapView.map(
        withFrame: CGRect.zero,
        camera: GMSCameraPosition.camera(withLatitude: -33.86, longitude: 151.20, zoom: 6)
    ),
    infoWindowWidth:CGFloat = 0


    override func viewDidLoad() {
        super.viewDidLoad()

        infoWindowWidth = UIApplication.shared.keyWindow?.frame.size.width ?? 0 - 30
        //maps
        mapView.isMyLocationEnabled = true
        mapView.delegate = self
        self.view = mapView
        //markers
        let marker1 = GMSMarker(position: CLLocationCoordinate2DMake(-33.86, 151.20))
        marker1.title = "Sydney"
        marker1.snippet = "Custom"
        marker1.map = mapView

        mapView.selectedMarker = marker1

        updateInfoWIndowText()
    }

    var infoWindowText = "tqweqweqweqweqwe"
    func updateInfoWIndowText(){
        DispatchQueue.main.asyncAfter(deadline:  (DispatchTime.now() + .milliseconds(2000)), execute: {
            print("UPDATE INFO WINDOW TEXT")
            self.infoWindowText = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

            weak var mapView = self.mapView
            //dismissing info window and showing it
            let m = mapView?.selectedMarker
            mapView?.selectedMarker = nil
            mapView?.selectedMarker = m
        })
    }

}

extension GMapsViewController:GMSMapViewDelegate {

    func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {

        let stackView = UIStackView(frame: CGRect(x: 0, y: 0, w: infoWindowWidth, h: 0))
        stackView.axis = .vertical
        for _ in 0...3 {
            let lab = UILabel()
            lab.numberOfLines = 0
            lab.text = infoWindowText
            lab.backgroundColor = UIColor.red
            stackView.addArrangedSubview(lab)
        }
        stackView.addConstraint(NSLayoutConstraint(
            item: stackView,
            attribute: .width,
            relatedBy: .equal,
            toItem: nil,
            attribute: .notAnAttribute,
            multiplier: 1.0,
            constant: infoWindowWidth))
        stackView.h = stackView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
        return stackView
    }

    func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
        mapView.selectedMarker = marker
        return true
    }
}

0
只要你不设置任何框架,它的高度应该能正确地缩放。我试了很多次才意识到这一点。
但是宽度将会是全宽。我还在进行实验,但是如果你想要根据设备宽度在infoWindow的两侧添加一些边距/填充,我认为边距必须直接来自nib文件,而不是试图直接设置主视图的框架宽度。
我认为一旦你调整了框架大小,一些视图将无法正确显示,比如某些视图可能会被截断,因为宽度的改变导致标签必须换行为两行。然后一旦视图返回,已经为谷歌地图的info window转换为图像,此时已经为时已晚。任何layoutsubview方法都不会再影响该info window。
所以要么你正确计算框架,这非常难做到,特别是因为你无法正确渲染和获取框架,要么你在.xib文件中提前设置好所有内容,并将其原样返回,而不改变其框架!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接