ゴリポシェブログ

プログラミングやゲームについて気ままに綴ります

SwiftUIでインタースティシャル広告を実装する方法

 

インタースティシャル用のクラスを用意

import GoogleMobileAds    

#if DEBUG

let adUnitID = ""

#else

let adUnitID = ""

#endif

 

final class Interstitial: NSObject, GADFullScreenContentDelegate {

    private var interstitial: GADInterstitialAd?

    

    override init() {

        super.init()

        loadInterstitial()

    }

    

    func loadInterstitial(){

        let request = GADRequest()

        GADInterstitialAd.load(withAdUnitID:adUnitID,

                                    request: request,

                          completionHandler: { [self] ad, error in

                            if let error = error {

                              print("Failed to load interstitial ad: \(error.localizedDescription)")

                              return

                            }

                            interstitial = ad

                            interstitial?.fullScreenContentDelegate = self

                          }

        )

    }

    

    /// Tells the delegate that the ad failed to present full screen content.

    func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {

        print("Ad did fail to present full screen content.")

    }

    

    /// Tells the delegate that the ad presented full screen content.

    func adDidPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {

        print("Ad did present full screen content.")

    }

    

    /// Tells the delegate that the ad dismissed full screen content.

    func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {

        print("Ad did dismiss full screen content.")

        loadInterstitial()

    }

    

    func showAd(){

        let root = UIApplication.shared.windows.first?.rootViewController

        interstitial?.present(fromRootViewController: root!)

    }

}

 

SWiftuiのボタン押下時に呼び出し

変数は用意してください

 

//保存ボタン

            Button(action:{

                self.showingAlert = true

            }){

                Image(systemName: "tray.and.arrow.down")

                Text("保存")

            }

            .padding(.trailing)

            .alert(isPresented: $showingAlert) {

                Alert(title: Text("保存しますか"),

                      primaryButton: .cancel(Text("キャンセル")),

                      secondaryButton: .default(Text("保存"),

                                                action: {

                                        interstitial.showAd()

                }))

            }

この度iosアプリをリリースしました。

ぜひダウンロードしてください。

 

ゴルフのオリンピックを計算してくれたり、保存してくれたりします。

 

①初期画面

まずは、ご自身の名前を入力してください。

あとで設定で変更できます。

f:id:GoliraPochette:20210510230458p:plain

 

名前や初期レートは設定画面で変更できます。

 

 

f:id:GoliraPochette:20210510230252p:plain

 

【Swift UI】配列を特定の文字で絞り込む方法

ちょっとだけ詰まったので載せておきます。

Textfieldに入力された文字でLISTの絞りこみをしたかったので実装しました。
こんな感じです。

f:id:GoliraPochette:20210212230243p:plain
f:id:GoliraPochette:20210212230257p:plain

リストは配列をループさせて表示しているので、Textfield入力された文字で配列を絞り込めば上記が実現できます。
nameがテキストフィールドの値でitemが配列です。
絞り込まれた配列はsearchArray の中に入ります。

ContentView一部抜粋

                    self.searchArray = item.filter{
                        if $0.localizedCaseInsensitiveContains(name){
                            return true
                        }
                        return false
                    }

ContentView.Swift

//
//  ContentView.swift
//  olnpickGolfer
//
//  Created by Yosuke Yoshida on 2021/02/09.
//

import SwiftUI

struct ContentView: View {
    
    @State private var name:String = ""
    @State private var item = getDataName()
    @State private var isShowingAlert = false
    @State private var showingAlert = false
    @State var text: String = ""
    @State private var selectionValue: Set<String>
        = []
    @State var searchArray = [String]()
    
    var body: some View {
        
        VStack {
            TextField("検索", text: $name,onCommit: {
            
                item = getDataName()
            
                if self.name == "" {
                    item = getDataName()
                } else {
                    self.searchArray = item.filter{
                        if $0.localizedCaseInsensitiveContains(name){
                            return true
                        }
                        return false
                    }
                    item = searchArray
                }
            })
            .padding()
            
            // 入力域のまわりを枠で囲む
            .textFieldStyle(RoundedBorderTextFieldStyle())
            
            List (selection: $selectionValue) {
                ForEach(item, id: \.self) { item in
                    Text(item)
                }
            }
            .environment(\.editMode, .constant(.active))
            
            Spacer()
            
            HStack {
                Button("追加") { isShowingAlert = true }
                    .padding()
                
                if !item.isEmpty {
                    Button("削除") {
                        rowRemove(delList: selectionValue)
                        selectionValue = []
                    }
                    .padding()
                }
                
                Spacer()
                
                TextFieldAlertView(
                    text: $text,
                    isShowingAlert: $isShowingAlert,
                    placeholder: "",
                    isSecureTextEntry: false,
                    title: "名前登録",
                    message: "名前を入力してください",
                    leftButtonTitle: "キャンセル",
                    rightButtonTitle: "登録",
                    leftButtonAction: nil,
                    rightButtonAction: {
                        if item.contains(text) {
                            alertD()
                        } else {
                            registDataName(name: text)
                            item = getDataName()
                        }
                    }
                )
                .frame(width: 0, height: 0, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
            }
        }
    }
    
    func rowRemove(delList:Set<String>) {
        var counter:Int = 0
        var isDel = false
        var tmpItem = getDataName()
        
        while counter < tmpItem.count {
            
            for data in delList {
                if tmpItem[counter] == data {
                    tmpItem.remove(at: counter)
                    isDel = true
                }
            }
            if isDel {
                counter = 0
                isDel = false
            } else {
                counter+=1
            }
        }
        
        reWriteDataName(nameList: tmpItem)
        item = getDataName()
        self.name = ""
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

【Swift UI】初期起動画面を変更する方法

SceneDelegate.swift

let contentView = SwiftUIView()ここの値を起動したいViewの名前に変更してください。

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

        // Create the SwiftUI view that provides the window contents.
        let contentView = SwiftUIView()//ここの値を起動したいViewの名前に変更する。

        // Use a UIHostingController as window root view controller.
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }

【Swift UI】LISTが複数選択と削除が同居できない

Swift UIのリストについての記事です。

UserDefaultに保存されているデータをLISTに表示させ、選択できるような画面を作成しました。
ついでに削除までできたら便利だなぁと考えて調べてみましが、両立させることができませんでした。

最終的にはかなりの力技で実装しました。誰か知ってたら教えて欲しいものです。

①複数選択を可能にする。
→できる。
f:id:GoliraPochette:20210212212611p:plain

ContentView.swiftの一部

 List (selection: $selectionValue) {
  ForEach(item, id: \.self) { item in
                    Text(item)
       }
    }
   <u> .environment(\.editMode, .constant(.active))</u>

②削除可能
→できる。
 左にスワイプしたら削除ボタンが出てきます。
f:id:GoliraPochette:20210212214922p:plain

List (selection: $selectionValue) {
                ForEach(item, id: \.self) { item in
                    Text(item)
                }
                /// 行削除操作時に呼び出す処理の指定
                .onDelete(perform: rowRemove)
            }

③両立
→色々調べたが、できない。
 選択はできるが、スライドしても削除ボタンが出てこない。。
 

            List (selection: $selectionValue) {
                ForEach(item, id: \.self) { item in
                    Text(item)
                }
                /// 行削除操作時に呼び出す処理の指定
                .onDelete(perform: rowRemove)
            }
            .environment(\.editMode, .constant(.active))

解決策としては、削除ボタンとリストから削除する処理を自前で実装して、乗り越えました。

//
//  ContentView.swift
//  olnpickGolfer
//
//  Created by Yosuke Yoshida on 2021/02/09.
//

import SwiftUI

struct ContentView: View {
    
    @State private var name = ""
    @State private var item = getDataName()
    @State private var isShowingAlert = false
    @State private var showingAlert = false
    @State var text: String = ""
    @State private var selectionValue: Set<String>
        = []
    
    
    var body: some View {
        
        VStack {
            TextField("検索", text: $name)
                .padding()
                // 入力域のまわりを枠で囲む
                .textFieldStyle(RoundedBorderTextFieldStyle())
            
            List (selection: $selectionValue) {
                ForEach(item, id: \.self) { item in
                    Text(item)
                }
            }
            .environment(\.editMode, .constant(.active))
            
            Spacer()
            
            HStack {
                Button("追加") { isShowingAlert = true }
                    .padding()
                
                if !item.isEmpty {
                    Button("削除") {
                        rowRemove(delList: selectionValue)
                        selectionValue = []
                    }
                        .padding()
                }
                    
                Spacer()
                
                TextFieldAlertView(
                    text: $text,
                    isShowingAlert: $isShowingAlert,
                    placeholder: "",
                    isSecureTextEntry: false,
                    title: "名前登録",
                    message: "名前を入力してください",
                    leftButtonTitle: "キャンセル",
                    rightButtonTitle: "登録",
                    leftButtonAction: nil,
                    rightButtonAction: {
                        if item.contains(text) {
                            alertD()
                        } else {
                            registDataName(name: text)
                            item = getDataName()
                        }
                    }
                )
                .frame(width: 0, height: 0, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
            }
        }
    }
    
    func rowRemove(delList:Set<String>) {
        var counter:Int = 0
        var isDel = false
        
        
        while counter < item.count {

            for data in delList {
                if item[counter] == data {
                    item.remove(at: counter)
                    isDel = true
                }
            }
            if isDel {
                counter = 0
                isDel = false
            } else {
                counter+=1
            }
        }
        
        reWriteDataName(nameList: item)
        item = getDataName()
    }
}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

SwiftUIでは入力ダイアログはサポートされない件

2019年6月から開始されたSwiftUIですが、触ってみた感じ、かゆいところに手が届かないなぁと思いました。

 

発端は、入力ダイアログを使おうと思って、調べてみたらSwift UIではAlert表示はできるが、ユーザーから入力させるよなテキストフィールドは追加できないとのこと。

うーん。

 

SwiftUIで完結できると記載されている記事をありましたが、エラーになってしまいうまく動きませんでした。

面倒なので、エラー内容を追うことはしませんでした。m(__)m↓↓

alert — SwiftUIでTextFieldをAlertに追加する方法は?

 

解決策としては、

UIViewControllerRepresentable プロトコルを継承して、UKit の UIAlertController をラップしたViewを作成することで実装すれば良いとのこと。

下記サイトに記載されているコードを完コピで動きました。

【SwiftUI】TextField付きAlertを表示する – .NET ゆる〜りワーク

 

ただし、TextFieldAlertViewが要素の一部として認識されてしまい、レイアウトが崩れてしまうので、サイズを0にすることで解決しました。

 

                TextFieldAlertView(

                    text: $text,

                    isShowingAlert: $isShowingAlert,

                    placeholder: "",

                    isSecureTextEntry: false,

                    title: "名前登録",

                    message: "名前を入力してください",

                    leftButtonTitle: "キャンセル",

                    rightButtonTitle: "登録",

                    leftButtonAction: nil,

                    rightButtonAction: {

                        if item.contains(text) {

                            alertD()

                        } else {

                            registDataName(name: text)

                            item = getDataName()

                        }

                    }

                )

                .frame(width: 0, height: 0, alignment: .center)

 

早いとこアプデで追加されるといいなぁー