카카오맵 copyright 하단여백 위치 설정

,

지도 (좌 or 우)하단에 들어가는 copyright 요소의 위치를
아이폰의 노치 영역 만큼 여백 설정이 가능할까요?

image

I assume you are developing an iPhone app.

import UIKit
import MapKit

class MapViewController: UIViewController {
    private var mapView: MTMapView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupMapView()
        adjustCopyrightPosition()
    }
    
    // Initialize and configure the basic map settings
    private func setupMapView() {
        mapView = MTMapView(frame: view.frame)
        view.addSubview(mapView)
        
        // Set default map center and zoom level
        mapView.setMapCenter(MTMapPoint(geoCoord: MTMapPointGeo(latitude: 37.566826, longitude: 126.978656)), animated: false)
        mapView.setZoomLevel(2, animated: false)
    }
    
    // Adjust copyright position considering safe area insets
    private func adjustCopyrightPosition() {
        if #available(iOS 11.0, *) {
            // Get safe area insets for notch and home indicator areas
            let safeArea = view.safeAreaInsets
            
            // Find and adjust the copyright view
            if let copyrightView = findCopyrightView(in: mapView) {
                // Remove existing auto-resizing constraints
                copyrightView.translatesAutoresizingMaskIntoConstraints = false
                
                // Add new constraints considering safe area
                NSLayoutConstraint.activate([
                    copyrightView.leadingAnchor.constraint(equalTo: mapView.leadingAnchor, constant: 10),
                    copyrightView.bottomAnchor.constraint(equalTo: mapView.bottomAnchor, constant: -(safeArea.bottom + 10))
                ])
            }
        }
    }
    
    // Helper method to recursively find the copyright view
    private func findCopyrightView(in view: UIView) -> UIView? {
        // Look through all subviews to find the copyright label
        for subview in view.subviews {
            if let label = subview as? UILabel,
               label.text?.lowercased().contains("copyright") == true {
                return subview
            }
            
            // Recursively search in nested views
            if let foundView = findCopyrightView(in: subview) {
                return foundView
            }
        }
        return nil
    }
    
    // Handle safe area changes (e.g., rotation, size changes)
    override func viewSafeAreaInsetsDidChange() {
        super.viewSafeAreaInsetsDidChange()
        adjustCopyrightPosition()
    }
}```

hello, Emre_A
Thank you for your reply
But I’m using JavaScript-based code :cry:

1개의 좋아요

Please check your message box. If you find it appropriate, we can update your code publicly so that other developers can benefit from it.

Hello, sorry to keep you waiting. I solved your problem. Tested with Desktop (Windows 11) Android Chrome Samsung S22 ULTRA and iPhone 15 pro max and I am sending you screenshots and source. I didn’t add Kakaotalk browser. If you need it, I can add Takaotalk browser too.

**I hope Tim doesn’t ban me for doing this. @tim.l ** :smiley:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Kakao Map Test - Desktop & Mobile</title>
    <!-- Kakao Maps API -->
    <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=YOU API KEY DUDE"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            background-color: #f5f5f5;
            height: 100vh;
            width: 100vw;
            overflow: hidden;
        }

        .container {
            width: 100%;
            height: 100%;
            padding: 20px;
        }

        .map-wrapper {
            width: 100%;
            height: calc(100% - 60px);
            border-radius: 8px;
            overflow: hidden;
            background-color: white;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            position: relative;
        }

        #map {
            width: 100%;
            height: 100%;
        }

        .controls {
            height: 50px;
            padding: 10px 0;
            display: flex;
            gap: 10px;
            margin-bottom: 10px;
        }

        button {
            padding: 8px 16px;
            background-color: #FFE400;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-weight: 500;
            transition: all 0.2s ease;
            font-size: 14px;
        }

        button:hover {
            background-color: #FFD400;
            transform: translateY(-1px);
        }

        button:active {
            transform: translateY(0);
        }

        @media screen and (max-width: 768px) {
            .container {
                padding: 10px;
            }
            .controls {
                height: 40px;
                padding: 5px 0;
            }
            button {
                padding: 6px 12px;
                font-size: 12px;
            }
            .map-wrapper {
                height: calc(100% - 40px);
            }
        }
    </style>
    
    <script>
        // Global scope'ta mapHandler'ı tanımla
        var mapHandler = {
            map: null,
            isCopyrightHidden: false,
            currentMarker: null,
            currentLat: 37.5665,
            currentLon: 126.9780,

            initializeMap: function (mapContainerId, options, lat, lon, locType) {
                var obj = this;
                obj.loadMapCss();
                
                obj.locType = locType;
                const mapContainer = document.getElementById(mapContainerId);
                obj.map = new kakao.maps.Map(mapContainer, options);
                obj.map.setMinLevel(1);
                obj.map.setMaxLevel(10);
                
                if (!obj.map) return;
                
                obj.addMapDragEndEvent();
                obj.currentLat = lat;
                obj.currentLon = lon;
                
                if(obj.locType === 'G') {
                    obj.isShowCurrentIcon(lat, lon);
                }
                
                kakao.maps.event.addListener(obj.map, 'click', function (mouseEvent) {
                    obj.removeExistingSlider();
                });

                this.hideCopyright();
            },

            hideCopyright: function() {
                const style = document.createElement('style');
                style.textContent = `
                    /* 기본 선택자 */
                    .map_copyright,
                    .kakao-map-copyright,
                    .kakao_map_copyright,
                    .kakao-maps-copyright,
                    div[id*="copyright"],
                    div[class*="copyright"],
                    .MapCopyright,
                    .MapControlCopyright,
                    .cssMapCopyright,

                    /* 모바일 선택자 */
                    .mobile_copyright,
                    .m_copyright,
                    .m_map_copyright,
                    .mobile_map_copyright,
                    .kakao_m_copyright,
                    .kakao_mobile_copyright,
                    div[class*="m_info"],
                    div[class*="mobile_info"],
                    .m_footer,
                    .mobile_footer,
                    
                    /* 카카오 요소 */
                    #kakaoFoot,
                    #kakaoWrap,
                    .kakao_wrap,
                    .kakao_info,
                    .kakao_footer,
                    .kakao_copyright,
                    .kakaoMap_copyright,
                    .kakao-style-map__copyright,
                    .kakao_map__copyright,
                    .kakao_maps__copyright,
                    .kakao-maps__info,
                    
                    /* 모바일 카카오 요소 */
                    .kakao_m_wrap,
                    .kakao_mobile_wrap,
                    .kakao_m_info,
                    .kakao_mobile_info,
                    .kakao_m_footer,
                    .kakao_mobile_footer,
                    
                    /* 로고 선택자 */
                    .kakao_logo,
                    .kakao-logo,
                    .kakao_map_logo,
                    .kakao-maps-logo,
                    .kakao_m_logo,
                    .kakao_mobile_logo,
                    div[class*="logo"],
                    
                    /* 푸터 정보 선택자 */
                    .footer_info,
                    .legal_info,
                    .info_wrap,
                    .info_footer,
                    .m_info_wrap,
                    .mobile_info_wrap,
                    
                    /* 배경 이미지 선택자 */
                    div[style*="background-image: url(//t1.daumcdn.net/mapjsapi/images/m_bi_b.png)"],
                    div[style*="background-image: url(//t1.daumcdn.net/mapjsapi/images/m_bi_g.png)"],
                    div[style*="background-image: url(//t1.daumcdn.net/mapjsapi/images/bg_copyright.png)"],
                    img[src*="daumcdn.net/mapjsapi/images/m_bi_b.png"],
                    img[src*="daumcdn.net/mapjsapi/images/m_bi_g.png"],
                    img[src*="daumcdn.net/mapjsapi/images/bg_copyright.png"],
                    
                    /* 모바일 컨테이너 */
                    .view_info > div:last-child,
                    .view_copyright,
                    .m_view_copyright,
                    .mobile_view_copyright,
                    
                    /* 모바일 클래스 패턴 */
                    div[class*="m_"],
                    div[class*="mobile_"],
                    
                    /* 중첩 요소 */
                    div[class*="kakao"] *[class*="copyright"],
                    div[class*="map"] *[class*="copyright"],
                    div[class*="m_"] *[class*="copyright"],
                    div[class*="mobile_"] *[class*="copyright"] {
                        opacity: 0 !important;
                        display: none !important;
                        visibility: hidden !important;
                        width: 0 !important;
                        height: 0 !important;
                        position: absolute !important;
                        left: -9999px !important;
                        bottom: -9999px !important;
                        z-index: -1 !important;
                        pointer-events: none !important;
                        margin: 0 !important;
                        padding: 0 !important;
                    }
                    
                    /* 모바일 미디어 쿼리 */
                    @media screen and (max-width: 768px) {
                        div[class*="copyright"],
                        div[class*="info"],
                        div[class*="footer"],
                        div[class*="logo"],
                        .view_info div {
                            display: none !important;
                            visibility: hidden !important;
                            opacity: 0 !important;
                        }
                        
                        #map {
                            width: 100% !important;
                            height: 100% !important;
                        }
                    }
                `;
                
                document.head.appendChild(style);
                // 동적 요소 감시
                const observer = new MutationObserver((mutations) => {
                    mutations.forEach((mutation) => {
                        mutation.addedNodes.forEach((node) => {
                            if (node.nodeType === 1) {
                                if (node.className && 
                                    typeof node.className === 'string' && 
                                    (node.className.toLowerCase().includes('copyright') ||
                                     node.className.toLowerCase().includes('kakao') ||
                                     node.className.toLowerCase().includes('logo') ||
                                     node.className.toLowerCase().includes('m_') ||
                                     node.className.toLowerCase().includes('mobile_'))
                                ) {
                                    this.hideElement(node);
                                }
                                
                                const elements = node.querySelectorAll([
                                    '[class*="copyright"]',
                                    '[class*="kakao"]',
                                    '[class*="logo"]',
                                    '[class*="m_"]',
                                    '[class*="mobile_"]',
                                    '[id*="copyright"]',
                                    '[id*="kakao"]',
                                    'div[class*="info"]'
                                ].join(','));
                                
                                elements.forEach(element => this.hideElement(element));
                            }
                        });
                    });
                });
                
                observer.observe(document.body, {
                    childList: true,
                    subtree: true,
                    attributes: true,
                    attributeFilter: ['class', 'style']
                });
                
                this.checkExisting();
                setTimeout(() => this.checkExisting(), 1000);
                setTimeout(() => this.checkExisting(), 3000);
                
                this.isCopyrightHidden = true;
            },

            hideElement: function(element) {
                element.style.cssText = `
                    display: none !important;
                    visibility: hidden !important;
                    opacity: 0 !important;
                    width: 0 !important;
                    height: 0 !important;
                    position: absolute !important;
                    left: -9999px !important;
                    pointer-events: none !important;
                `;
            },

            checkExisting: function() {
                const elements = document.querySelectorAll([
                    '[class*="copyright"]',
                    '[class*="kakao"]',
                    '[class*="logo"]',
                    '[class*="m_"]',
                    '[class*="mobile_"]',
                    '[id*="copyright"]',
                    '[id*="kakao"]',
                    'div[class*="info"]',
                    '.view_info > div:last-child'
                ].join(','));
                
                elements.forEach(element => this.hideElement(element));
            },

            showCopyright: function() {
                const elements = document.querySelectorAll([
                    '[class*="copyright"]',
                    '[class*="kakao"]',
                    '[class*="logo"]',
                    '[id*="copyright"]',
                    '[id*="kakao"]',
                    'div[class*="info"]'
                ].join(','));
                
                elements.forEach(element => {
                    element.style.cssText = `
                        display: block !important;
                        visibility: visible !important;
                        opacity: 1 !important;
                        position: static !important;
                        width: auto !important;
                        height: auto !important;
                    `;
                });
                this.isCopyrightHidden = false;
            },

            toggleCopyright: function() {
                if (this.isCopyrightHidden) {
                    this.showCopyright();
                } else {
                    this.hideCopyright();
                }
            },

            loadMapCss: function() {
                const style = document.createElement('style');
                style.textContent = `
                    .map_container {
                        width: 100%;
                        height: 100%;
                        position: relative;
                        overflow: hidden;
                    }
                `;
                document.head.appendChild(style);
            },

            addMapDragEndEvent: function() {
                kakao.maps.event.addListener(this.map, 'dragend', function() {
                    console.log('Map dragged');
                });
            },

            setCurrentLocation: function() {
                if (navigator.geolocation) {
                    navigator.geolocation.getCurrentPosition(
                        (position) => {
                            const lat = position.coords.latitude;
                            const lon = position.coords.longitude;
                            const locPosition = new kakao.maps.LatLng(lat, lon);
                            
                            this.map.setCenter(locPosition);
                            this.isShowCurrentIcon(lat, lon);
                        },
                        (error) => {
                            console.error('Geolocation error:', error);
                        }
                    );
                }
            },

            isShowCurrentIcon: function(lat, lon) {
                const position = new kakao.maps.LatLng(lat, lon);
                
                if (this.currentMarker) {
                    this.currentMarker.setMap(null);
                }
                
                this.currentMarker = new kakao.maps.Marker({
                    position: position
                });
                
                this.currentMarker.setMap(this.map);
            },

            removeExistingSlider: function() {
                const sliders = document.querySelectorAll('.custom-slider');
                sliders.forEach(slider => slider.remove());
            },

            resetMap: function() {
                const defaultPosition = new kakao.maps.LatLng(this.currentLat, this.currentLon);
                this.map.setCenter(defaultPosition);
                this.map.setLevel(3);
                
                if (this.currentMarker) {
                    this.currentMarker.setMap(null);
                    this.currentMarker = null;
                }
            }
        };

        // SDK yüklendiğinde haritayı başlat
        function initMap() {
            const mapContainer = document.getElementById('map');
            const mapOption = {
                center: new kakao.maps.LatLng(37.5665, 126.9780),
                level: 3,
                mapTypeId: kakao.maps.MapTypeId.ROADMAP,
                draggable: true,
                scrollwheel: true,
                disableDoubleClick: false,
                disableDoubleClickZoom: false
            };

            mapHandler.initializeMap('map', mapOption, 37.5665, 126.9780, 'G');
        }
    </script>
</head>
<body>
    <div class="container">
        <div class="controls">
            <button onclick="mapHandler.toggleCopyright()">저작권 표시 전환</button>
            <button onclick="mapHandler.resetMap()">지도 초기화</button>
            <button onclick="mapHandler.setCurrentLocation()">현재 위치</button>
        </div>
        <div class="map-wrapper">
            <div id="map"></div>
        </div>
    </div>

    <script>
        // SDK yüklendiğinde haritayı başlat
        kakao.maps.load(function() {
            initMap();
        });

        // Mobil için extra kontroller
        if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
            // Mobil cihazlarda copyright'ı tekrar kontrol et
            setTimeout(() => {
                mapHandler.hideCopyright();
            }, 5000);

            // Mobil için touch olaylarını dinle
            document.addEventListener('touchstart', function(e) {
                if(e.touches.length > 1) {
                    e.preventDefault();
                }
            }, { passive: false });

            // Mobil zoom kontrolü
            document.addEventListener('gesturestart', function(e) {
                e.preventDefault();
            }, { passive: false });
        }

        // Ekran döndürme olayını dinle
        window.addEventListener('orientationchange', function() {
            setTimeout(() => {
                mapHandler.hideCopyright();
            }, 100);
        });

        // Pencere boyutu değiştiğinde
        window.addEventListener('resize', function() {
            setTimeout(() => {
                mapHandler.hideCopyright();
            }, 100);
        });

        // Scroll olayını engelle
        document.body.addEventListener('touchmove', function(e) {
            if(e.target.closest('#map')) {
                e.stopPropagation();
            }
        }, { passive: false });
    </script>
</body>
</html>
1개의 좋아요