【X / Twitter】アップロードしようとした動画のフレームレートが高すぎます。

あれ?

こんなメッセージ。

「アップロードしようとした動画のフレームレートが高すぎます。」

60 fps でダメでした?

👉 メディアのベストプラクティス | Docs | Twitter Developer Platform

古いのか、何なのか。

以下が正しいのかな。

👉 Xで動画を共有および視聴する方法

ブラウザだけダメなのかも知れん。

30 fps に下げる。


ffmpeg -i input.mov -r 30 output.mov

以下、特に意味はありません。


👉【ffmpeg】VP9 コーデックから H.264 コーデックへの動画変換
👉 Twitter 動画をツイートできず - 公式「YUV 4:2:0 ピクセルフォーマット にのみ対応しています」


【SwiftUI】UIImage / NSImage の Image への抽象化

どちらが好きですか、以下2つのコード。

 

■ 1つ目


import SwiftUI

public extension Image {
    #if canImport(AppKit)
    init(image: NSImage) {
        self = Image(nsImage: image)
    }
    #endif

    #if canImport(UIKit)
    init(image: UIImage) {
        self = Image(uiImage: image)
    }
    #endif
}

特徴:
- 拡張機能 (extension) を使って、Imageに新しいinitイニシャライザを追加しています。
- プラットフォームごとに異なる型 (NSImageやUIImage) を直接引数に取ります。
- プラットフォーム依存の条件付きで、NSImage(macOS)またはUIImage(iOS)を使用してImageを初期化しています。

メリット:
- 各プラットフォームに対応したイニシャライザが個別に用意されており、Imageの初期化が直感的です。

デメリット
- プラットフォームごとにinitメソッドが別々に定義されているため、共通の型を扱うのが難しい。

 

■ 2つ目


#if canImport(AppKit)
import AppKit
public typealias PlatformImage = NSImage
#elseif canImport(UIKit)
import UIKit
public typealias PlatformImage = UIImage
#endif

import SwiftUI

extension Image {
    init(platformImage: PlatformImage) {
        #if canImport(UIKit)
        self = Image(uiImage: platformImage)
        #elseif canImport(AppKit)
        self = Image(nsImage: platformImage)
        #endif
    }
}

特徴:
- PlatformImageという型エイリアスを使って、macOSのNSImageとiOSのUIImageを抽象化しています。
- platformImageという共通の引数型を持つイニシャライザを追加しています。これにより、プラットフォームごとにImageを初期化しますが、型エイリアスによって共通化されています。

メリット:
- 抽象化されているため、呼び出し側のコードがプラットフォームに依存しません。つまり、共通のコードでPlatformImage型を使えば、iOSでもmacOSでも同じコードで動作します。
- 可読性が高く、メンテナンスが容易です。プラットフォームごとにメソッドを分ける必要がなく、1つのメソッドで対応しています。

デメリット:
- プラットフォームごとに異なる処理を追加する際に、多少複雑になる可能性があります。

 

■ まとめ

AIによると、

結論:どちらが良いか?

2つ目のコードの方が一般的に推奨されます。理由は、コードの抽象化によって、呼び出し側がプラットフォームに依存しない形でImageを扱うことができるためです。メンテナンス性が高く、同じコードベースで複数のプラットフォームをサポートしやすくなります。

ただし、プラットフォームごとに異なる処理が必要なケースでは、1つ目のコードの方が直感的に分かりやすい場合もあるので、状況に応じて選択が変わることがあります。

ということです。

私的には、どっちも勉強になります、としか。



【SwiftUI】Create Draggable Reorder ListView without List

👉 Drag and Drop List In SwiftUI. In this article, We will explore how to… | by Mobile Apps Academy | Medium

よくある UI の挙動を SwiftUI でどれだけシンプルに作れるのか。

やってみました。

import SwiftUI
struct Fruit: Identifiable, Equatable {
let id = UUID()
let name: String
let color: Color
}
struct DraggableList: View {
@State private var fruits: [Fruit] = [
Fruit(name: "APPLE", color: .red),
Fruit(name: "ORANGE", color: .orange),
Fruit(name: "BANANA", color: .yellow),
Fruit(name: "MELON", color: .green),
Fruit(name: "PEACH", color: .pink),
Fruit(name: "KIWI", color: .brown),
Fruit(name: "GRAPES", color: .purple),
Fruit(name: "LIME", color: .cyan),
Fruit(name: "TOMATO", color: .indigo)
]
@State private var dragging: Fruit?
var body: some View {
ScrollView {
LazyVStack(spacing: 16) {
ForEach(fruits) { fruit in
FruitItemView(fruit: fruit)
.onDrag {
print("onDrag: \(fruit)")
dragging = fruit
//return NSItemProvider() // iOS only
return NSItemProvider(object: NSString(string: "\(fruit.id)"))
} preview: {
//EmptyView() // crash on macOS
PreviewView()
}
.onDrop(
of: [.text], // *
delegate: DropViewDelegate(
fruit: fruit,
fruits: $fruits,
dragging: $dragging
)
)
}
}
}
.padding()
}
}
struct FruitItemView: View {
var fruit: Fruit
var body: some View {
HStack {
Spacer()
Text("\(fruit.name)")
Spacer()
}
.foregroundStyle(.background)
.padding(.vertical, 40)
.background(fruit.color, in: .rect(cornerRadius: 16))
}
}
struct PreviewView: View {
var body: some View {
EmptyView()
}
}
struct DropViewDelegate: DropDelegate {
let fruit: Fruit
@Binding var fruits: [Fruit]
@Binding var dragging: Fruit?
func dropEntered(info: DropInfo) {
print("\(dragging?.name ?? "") on \(fruit.name)")
if dragging != fruit {
let from = fruits.firstIndex(of: dragging!)!
let to = fruits.firstIndex(of: fruit)!
withAnimation {
fruits.move(
fromOffsets: IndexSet(integer: from),
toOffset: to > from ? to + 1 : to
)
}
}
}
func dropUpdated(info: DropInfo) -> DropProposal? {
return DropProposal(operation: .move) // icon on macOS
}
func performDrop(info: DropInfo) -> Bool {
print("performDrop: \(info)")
dragging = nil
return true
}
}
#Preview {
DraggableList()
}

本来は、何かを NSItemProvider() 経由で、

ドロップ先に渡すのが役目っぽいけども、

DropDelegate の便利さを利用して

配列を並び替えるイメージ。

並び替えのアニメーションは withAnimation デフォルトに頼る。

iOS と macOS、Preview と シュミレータ と 実機、OS バージョンなど、

互換しようとするといろいろありそう。

ここらのコンポーネントはまだ不安定な感じ ?