たくさんの自由帳

iPhone Duo の大きさを Android の ARCore で置いて比べてみた

投稿日 : | 0 日前

文字数(だいたい) : 12043

どうもこんばんわ。
美容室に行ってみました。怖いのかなーって思ってましたが怖くなかったです。免許更新があったので切りに行ってみた。

なんか短い方が似合うって言われたけど短くしたことないから分からん :(
なんか髪の毛押し付けながらドライバーするとボリューム感へっておすすめらしいので試してみている

話はなんか髪を短くした方が似合いそう(?)とかの話とか、髪質が強い(?)から染めたりとかで柔らかくなるかも見たいな。陽キャすぎんか?

せっかくなので、なんかちょっと白髪混じってるの聞いてみた。
そしたら、ツヤがあるからそのままでいいんじゃないって言われたのでそのままにすることにした(?)

本題

ついにiPhoneから折り畳みスマホが出るようです。どれくらいのサイズ感なのかは気になりますよね!?
そういうのに向いてる機能があります(?)。AndroidのAR機能というかAPIであるARCoreですね!

というわけで今回はiPhone Duoと同じサイズの3D オブジェクトをBlenderで作ってARCoreで表示してみます。

Q 興味ないので APK ファイルだけくれませんか

はい

ボトムシートに表示される項目は以下の通りです。

  • google_pixel_11_profold_collapsed_same_size_obj.obj
    • Pixel 11 Pro Fold閉じた時のサイズ
  • google_pixel_11_profold_expanded_same_size_obj.obj
    • Pixel 11 Pro Fold開いた時のサイズ
  • iphone_duo_collapsed_same_size_obj.obj
    • iPhone Duo閉じた時のサイズ
  • iphone_duo_expanded_same_size_obj.obj
    • iPhone Duo開いた時のサイズ

Q 興味ないので比較した写真だけ見せてくれませんか

いろいろ置いてみた、けど、なかなかこれというのが見つからんかった。

閉じたときはポケットティッシュを一回り大きくしたくらいだと思います。
開いたときは小説の本(A6らしい)が近い気がします。

ポケットティッシュと並べた

小説の本と並べた

小説の本と並べた

ガリレオ、3つ目の映画まだ見てないな・・・

Macbook Air 13 インチ

閉じたらトラックパッドくらい

macbook_air_13_のトラックパッドに置いた

開いてキーボードの上に乗せた感じ

macbook_air_13_のキーボードに置いた

そのほか

AirDropのためになんか持ってるiPhone7(今ならPixelでAppleデバイスとAirDropできる)
こうしてみると思ったより小さい。

iPhone7と比較

はがき(と同じサイズです!)閉じるとはがきより一回りくらい小さかった。

はがきと比較_おりたたみ

ひらくとはがきちょい大きいくらい

はがきと比較_ひらいた

雑誌

雑誌

詳しい話は大昔に書いたのでそっちも見てください

ARCore とは

AndroidでARアプリを作るためのAPI。ゲームエンジンを使わなくてもJava/Kotlinで利用できます。
しかしその場合、代わりにOpenGL ESを使って描画しているので、ゲームエンジンを避けてもどのみち難しいです。

結構むかしの話ですが、かつてGoogleが作ったSceneformっていうライブラリがありました。
OpenGL ESの知識は一切不要、簡単なJava/Kotlinのコードを書くだけで現実世界にオブジェクトが置けたライブラリです。Googleのお家芸というかなんというかで、これはずっと前に廃止されました・・

ですが、Sceneformは今でも有志が引き継いでるはず!なのでそっちを使う方がいい気がします。
まあこんなことがあったのでAndroid XRもやる気があるのかは少し怪しいところです()

そうはいっても、今回やることはGoogleが書いてるサンプルコードを書き換えて、自分で作ったBlenderの3D オブジェクトを表示するように直すだけなので別に難しくないです。

環境

なまえあたい
AndroidPixel 11 Pro Fold
Blender5.2.2
ARCore1.56
Android StudioAndroid Studio Rabbit 1 2026.2.1

手順

  • いい感じに3D モデルを作る
  • GoogleのARCoreサンプルコードをクローンしてビルドが通るようになるまで直す
  • ソースコードを書き換えて、作った3D モデルを表示するように直す

3Dモデルを作る

Blenderを入れます。ポータブル版でもインストール版でもどっちでもいいと思います。
いっぱい使うならインストール版がいいのかな、私はポータブル版を入れました。

ポータブル版ならダウンロードしたzipを解凍しておいてください。

Blender を開く

blender-launcher.exeを開きます。日本語が選べるっぽいので選びました。どっちでもいいと思います。選んだらダイアログ?の外側を押して閉じました。
もうすでに正方形があるのでこれを使いますか!?

blender_起動画面

blender_正方形が出ている

正方形を調整する

マウス押し込みで視点変更が、スクロールで前後に動かせます。で、なんか正方形の下半分が埋まってますね。。。
Z軸の0地点に正方形が来てほしいです。

何が原因なのかというと、オブジェクトの原点が真ん中にあるせいらしい。
これを底面に移動させて、位置をZ軸の0地点に合わせれば、底面と0が一致し下に埋まることはなくなるはずです!

左上がオブジェクトモードになっているので、Tabキーを押して編集モードに切り替えます。左上がそうなると思います。
次に数字の3キーを押します。この状態で正方形の底面が見えるようにマウス押し込みで視点変更しつつ、底面をクリックします。選んだ面だけ色が変わるハズ!

blender_正方形の底面を選択している状態

つぎに、ShiftとSキーを押すとメニューが出るので、カーソル→選択物を選びます。

blender_カーソルを選択物に合わせる

最後にTabキーを押して元のモードに戻し、正方形を右クリックし、原点を調整→原点を3Dカーソルに移動を選びます。
これで、三次元に伸びてる矢印が正方形の底に表示されるはずです。矢印が出ない場合は左の縦にアイコンが並んでる部分から矢印のアイコンを選んでください(移動ってやつ)

blender_原点を3Dカーソルに移動を選ぶ

blender_原点が底面に移動した状態

単位をミリメートル

スマホの大きさとかはミリメートル表記なので、先に変えちゃいますか。
右のパネル?からシーンを選んで、単位を開き長さをミリメートルに変更します。

blender_単位をミリメートルに変更

サイズを位置を合わせる

これでもまだ下半分が埋まってます。これを調整するための画面を出します。Nキーを押してください。
するとなんか左から出てくると思います。

blender_左側から出てくる

まず埋まってるのはZ軸が0になってないせいですね。0にします。これで埋まらなくなります。
また、寸法のところはiPhone Duoの大きさに合わせます。大きさはAppleのサイトから見れます。

出来ました、とりあえず開いてる状態作りました。たぶんあってます。
数字を合わせるだけですね!

blender_サイズを合わせた状態

保存する

Blenderで編集する予定があれば、ツールバーからファイル→保存を選んで.blend形式で保存。
もう完成して3D モデルを書きだすなら、ファイル→エクスポート→wavefront (.obj)形式がARCoreのサンプルコードで使われている形式なので、objで書き出してください。
適当な名前を付けて保存してください。

blender_obj形式で書き出す

保存すると.obj形式ともう一つ何か生成されるのですが、.objしか使いません!

何パターンか作った

閉じたバージョンも作りました。また、Pixel 11 Pro Foldも同じように作りました。まあ私は手元にあるので作らなくてもいいのですが。(下取りに出したのにまだ高い!)

blender_pixelも作った

アプリを作る

ARCore のサンプルコードをクローンする

Kotlin + OpenGL ESのサンプルコードはこれです。
gitリポジトリの中に複数のサンプルコードがあるので、これだけが欲しくても多分全部クローンする必要があります。ファイルサイズが切りなる場合は--depth=1を付けてgit cloneするとよいかも?

git clone https://github.com/google-ar/arcore-android-sdk.git --depth=1

サンプルコードを開く

hello_ar_kotlinフォルダをAndroid Studioで開きます。
・・・・あ、Gradle周りが古すぎて一発ではビルドが通らないかも。

android_studio_gradle_jdk_version

このダイアログ通りにJDKのバージョン(Javaのバージョン)を変える方法もありますが、GradleやAGPのバージョンを新しくしてビルドを通す方法もあります。
今回は後者のバージョンをすべて新しくする方法で行きます。ダイアログはバツで閉じます。
(org.jetbrains.kotlin:kotlin-stdlibとか逆に今通るか・・?とっくのとうに不要になったので)

いうまでもなく、Gradle周りのバージョンを新しくするのはARCore関係ないです。

Gradle 周りを新しくする

2026年10月現在。多分もっと新しいバージョンが出てると思いますが、ここでは私が公開してるアプリで使っているバージョンを使うようにします(コピペしたいだけです)

まず最近の.gradleファイルは.gradle.ktsというKotlinを使った形式になるので、以下の3つのファイルを.ktsに変更してください
ビルドすら通ってないので名前変更で警告が出てもRefactorやOKを選んでください。

  • settings.gradle → settings.gradle.kts
  • build.gradle → build.gradle.kts
  • app/build.gradle → app/build.gradle.kts

中身を書き換える

コピペできない部分はコメントで!
また、今回はあとでJetpack Composeでボトムシートを作りたいため、Jetpack Compose込みのライブラリ設定になります。

settings.gradle.kts

pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.name = "iPhoneDuoSameSizeObjectARCore" // ここはプロジェクトの名前にしてください
include(":app")

build.gradle.kts

appフォルダの方じゃないbuild.gradle.kts

plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.compose.compiler) apply false
}

gradle-wrapper.properties

gradle/wrapper/gradle-wrapper.propertiesにあります。

#Mon Aug 03 01:07:56 JST 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=553c78f50dafcd54d65b9a444649057857469edf836431389695608536d6b746
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

app/build.gradle.kts

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.compose.compiler) // もし Room や Hilt で ksp や databinding で kapt 使ってるならここに追加
}

android {
    namespace = "com.google.ar.core.examples.kotlin.helloar" // これもアプリケーションIDに合わせるのがセオリーか
    compileSdk {
        version = release(37)
    }
    defaultConfig {
        applicationId = "com.google.ar.core.examples.kotlin.helloar" // アプリケーションID

        // AR Optional apps must declare minSdkVersion >= 14.
        // AR Required apps must declare minSdkVersion >= 24.
        minSdk = 24 // SDK バージョンが違う場合はこの辺を変更してください
        targetSdk = 37
        versionCode = 1
        versionName = "1.0"
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    buildTypes {
        release {
            optimization {
                enable = true // ちな難読化のファイルは app/src/main/keepRules/rules.keep に移動になりました
            }
        }
    }
    buildFeatures {
        compose = true // viewbinding / databinding 使ってるなら
    }
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}

dependencies {
    // ARCore (Google Play Services for AR) library.
    implementation("com.google.ar:core:1.56.0")

    // Obj - a simple Wavefront OBJ file loader
    // https://github.com/javagl/Obj
    implementation("de.javagl:obj:0.4.0")

    implementation("androidx.appcompat:appcompat:1.1.0")
    implementation("androidx.lifecycle:lifecycle-common-java8:2.2.0")

    implementation("com.google.android.material:material:1.1.0")

    // --- ここまで ARCore のサンプルコードで使っている依存 ---

    // jetpack compose
    implementation(libs.androidx.activity.compose)
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.ui)
    implementation(libs.androidx.ui.graphics)
    implementation(libs.androidx.ui.tooling.preview)
    implementation(libs.androidx.material3)
    implementation(libs.androidx.navigation3.ui)
    implementation(libs.androidx.navigation3.runtime)
}

gradle/libs.versions.toml

とりあえず上記のbuild.gradle.ktsで使っているライブラリのみ。
既存の書き方をバージョンカタログにするとかはお任せします。

[versions]
agp = "9.3.1"
kotlin = "2.4.10"
activityCompose = "1.13.0"
composeBom = "2026.08.00"
nav3Core = "1.1.7"

[libraries]
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" }
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }

ここまでやるとビルドが通るハズなのですが、まあうまくいかないかと。Gradle エラーは我々が直せるレベルの話か怪しいときがよくあるから困るよな~

最低限ビルドが通るまでのコミット

ちなみに起動すると

なんかピンみたいなのが置ける

サンプルアプリの画面

オブジェクトを取り込む

app/src/main/assets/modelsに.objを置いてください。
ちなみに↑のオブジェクトはpawn.objです。

android_studio_ここにobjを置く

environmental_hdr 修正

テクスチャを作ってない(3Dモデルの画像を作ってない)ので、テクスチャから色を取らずに単色にする処理を書く必要があります。
でその処理はたぶんここです。

albedoは白色(1.0, 1.0, 1.0)として、その下のroughnessMetallicAmbientOcclusionの値の出所は忘れてしまいました。(え?)

void Pbr_CreateMaterialParameters(const in vec2 texCoord,
                                  const in sampler2D albedoTexture,
                                  const in sampler2D pbrTexture,
                                  const in sampler2D dfgTexture,
                                  const in ShadingParameters shading,
                                  out MaterialParameters material) {
  // Read the material parameters from the textures
  // vec3 albedo = texture(albedoTexture, texCoord).rgb;
  // vec3 roughnessMetallicAmbientOcclusion = texture(pbrTexture, texCoord).rgb;
  // テクスチャを作ってないので
  vec3 albedo = vec3(1.0, 1.0, 1.0);
  vec3 roughnessMetallicAmbientOcclusion = vec3(0.5, 0.0, 1.0);
  // Roughness inputs are perceptually linear; convert them to regular roughness
  // values. Roughness levels approaching 0 will make specular reflections
  // completely invisible, so cap the lower bound. This value was chosen such
  // that (kMinPerceptualRoughness^4) > 0 in fp16 (i.e. 2^(-14/4), rounded up).
  // https://github.com/google/filament/blob/main/shaders/src/common_material.fs#L2

  // 以下省略...

HelloArActivity

ここで、3Dモデルを切り替えるUIを作るためにJetpack Composeを用意して切り替えUIも作ります。
Jetpack ComposeのActivityではComponentActivity()を継承してるっぽいのでそうします。

class HelloArActivity : ComponentActivity() { // ComponentActivity に直す

次に、setContentView()をJetpack Composeで描画するのでsetContentに置き換えます。
ただ、setContentView()にはARを描画していたSurfaceViewがあるため、AndroidViewで埋め込む必要があります。

onCreate()のsetContentView()をこんな感じに治します。ボトムシートで切り替えもできる!
また、onCreate()関数にOptIn ExperimentalMaterial3Apiを付けろって言われると思うので付けてください。
あとHelloArRendererのクラスも書き換わってるので次直します。

// Set up Hello AR UI.
view = HelloArView(this)
lifecycle.addObserver(view)
setContent {
    // 既にある view は使いまわす + 自作部分だけ compose
    Box {
        AndroidView(factory = { view.root })

        val isShowObjSelectBottomSheet = remember { mutableStateOf(false) }
        if (isShowObjSelectBottomSheet.value) {
            ModalBottomSheet(onDismissRequest = { isShowObjSelectBottomSheet.value = false }) {
                LazyColumn {
                    items(HelloArRenderer.OBJECT_LIST) { obj ->
                        Text(
                            text = obj,
                            modifier = Modifier
                                .clickable {
                                    renderer.nextTapAddMeshObjName = obj
                                    isShowObjSelectBottomSheet.value = false
                                }
                                .padding(10.dp)
                                .align(Alignment.CenterHorizontally)
                        )
                        HorizontalDivider()
                    }
                }
            }
        }
        Button(
            modifier = Modifier.align(Alignment.BottomCenter),
            onClick = { isShowObjSelectBottomSheet.value = true }
        ) {
            Text(text = "オブジェクト選択")
        }
    }
}

HelloArRenderer

まずはobjのファイル名をcompanion objectで定数として定義しておきましょう。↑のActivityで使うのと、このRendererで使うのでここで定義しておきます。

companion object {
    // 以下省略...

    val OBJECT_LIST = listOf(
        "google_pixel_11_profold_collapsed_same_size_obj.obj",
        "google_pixel_11_profold_expanded_same_size_obj.obj",
        "iphone_duo_collapsed_same_size_obj.obj",
        "iphone_duo_expanded_same_size_obj.obj"
    )
}

つぎに、オブジェクトを複数変数に保持できるように配列、正しくはオブジェクトのファイル名とオブジェクトの連想配列にします。
なのでlateinit var virtualObjectMesh: Meshを連想配列に直します。

// Virtual object key:OBJECT_LIST value:Mesh
private val virtualObjectMeshHashMap = hashMapOf<String, Mesh>()
lateinit var virtualObjectShader: Shader
lateinit var virtualObjectAlbedoTexture: Texture
lateinit var virtualObjectAlbedoInstantPlacementTexture: Texture

つぎに、一番最後に変数を一つ。これは、次画面を押してオブジェクトをARに追加する際に、OBJECT_LISTのどのオブジェクトを追加するかを保持するための変数です。
HelloArActivityからこの変数を操作して切り替えできるように。nextTapAddMeshObjName

val session
    get() = activity.arCoreSessionHelper.session

val displayRotationHelper = DisplayRotationHelper(activity)
val trackingStateHelper = TrackingStateHelper(activity)

// 次追加するオブジェクト
var nextTapAddMeshObjName = OBJECT_LIST[0]

つぎに、virtualObjectMeshをロードしていた箇所で、代わりに連想配列にロードしたものを格納するようにします。
そういえばフラグメントシェーダーで結局テクスチャを使わずに固定の色を表示するようになった。で、たぶんGPUは賢いので使われないUniform変数(今回はテクスチャ)は削除され、渡しても渡す宛がなくなるのでコメントアウトします。

// assets にある obj をまとめて読み込む
virtualObjectMeshHashMap += OBJECT_LIST.associateWith { Mesh.createFromAsset(render, "models/$it") }
virtualObjectShader =
    Shader.createFromAssets(
        render,
        "shaders/environmental_hdr.vert",
        "shaders/environmental_hdr.frag",
        mapOf("NUMBER_OF_MIPMAP_LEVELS" to cubemapFilter.numberOfMipmapLevels.toString())
    )
        // .setTexture("u_AlbedoTexture", virtualObjectAlbedoTexture)
        // .setTexture("u_RoughnessMetallicAmbientOcclusionTexture", virtualObjectPbrTexture)
        .setTexture("u_Cubemap", cubemapFilter.filteredCubemapTexture)
        .setTexture("u_DfgTexture", dfgTexture)

つぎに、onDrawFrameまで移動します。
画面更新のために何度も呼ばれ、ここでOpenGL ESを使って描画しているわけですね。

render.draw(virtualObjectMesh, virtualObjectShader, virtualSceneFramebuffer)に渡しているvirtualObjectMeshが描画したい3Dオブジェクトになります。
ここを連想配列から取り出す。。ではまだダメで。

というのも、ここは画面更新のたびに呼び出されるため、追加したオブジェクトを渡してあげる必要があります。
ここでrender.draw(virtualObjectMeshHashMap[nextTapAddMeshObjName] ...)で渡すと、追加したオブジェクトのすべてがnextTapAddMeshObjNameのオブジェクトになってしまいます。

そうならないためには、追加したオブジェクトが何なのかを保持しておけばよさそうですね。
オブジェクトを決めるのは画面を押したとき。何を追加したかを保持してrender.draw()ではその保持しているオブジェクトを描画するようにします。

ここではオブジェクトの位置?とかが入ってるdata classがあるので、これに何のオブジェクト化を追加で保持させます。
wrappedAnchorsがAR内に追加した(表示する)3Dオブジェクトのリストになります。

for ((anchor, trackable, mesh) in wrappedAnchors.filter { it.anchor.trackingState == TrackingState.TRACKING }) {
    // Get the current pose of an Anchor in world space. The Anchor pose is updated
    // during calls to session.update() as ARCore refines its estimate of the world.
    anchor.pose.toMatrix(modelMatrix, 0)

    // Calculate model/view/projection matrices
    Matrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, modelMatrix, 0)
    Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0)

    // Update shader properties and draw
    virtualObjectShader.setMat4("u_ModelView", modelViewMatrix)
    virtualObjectShader.setMat4("u_ModelViewProjection", modelViewProjectionMatrix)
    val texture =
        if ((trackable as? InstantPlacementPoint)?.trackingMethod ==
            InstantPlacementPoint.TrackingMethod.SCREENSPACE_WITH_APPROXIMATE_DISTANCE
        ) {
            virtualObjectAlbedoInstantPlacementTexture
        } else {
            virtualObjectAlbedoTexture
        }
    virtualObjectShader.setTexture("u_AlbedoTexture", texture)
    render.draw(mesh, virtualObjectShader, virtualSceneFramebuffer)
}

あとすこし、handleTap()関数まで移動してください。
wrappedAnchors.add()している箇所があると思います。まだdata classを書き換えてないので赤くなると思いますが、第三引数を追加します。
描画したい3Dオブジェクトですね。先述の通り、画面に表示されるオブジェクトがすべて同じにならないよう、このタイミングで記憶するようにします。

wrappedAnchors.add(WrappedAnchor(firstHitResult.createAnchor(), firstHitResult.trackable, virtualObjectMeshHashMap[nextTapAddMeshObjName]!!))

さいご。WrappedAnchorに描画したい3Dオブジェクトを保持するための引数を追加するだけ。

/**
 * Associates an Anchor with the trackable it was attached to. This is used to be able to check
 * whether or not an Anchor originally was attached to an {@link InstantPlacementPoint}.
 */
private data class WrappedAnchor(
    val anchor: Anchor,
    val trackable: Trackable,
    val mesh: Mesh
)

動かす

これで起動すると、下にボタンが表示されて、3Dオブジェクトを選択できるようになり、画面を押すと選択した3DオブジェクトがAR内に設置されるはずです!

ARアプリ_オブジェクトを配置してみた

ARアプリ_ボトムシート

ちなみに20個までしか表示できないはずです。wrappedAnchorsに追加する前に超えていたら最後から消すみたいなのが入っているためです。
なんで20なのかは知りません、負荷的な話ですかね?

ソースコード

はい

おわりに

まじで全然関係ない話になるわけですが、Android搭載メガネXREAL AURAがついに買えるらしい。10年以上前にYouTubeで見たGoogle Glassがついに実現するのか?!。
完全にスルーしてたわけですが、予約時点で1500ドルは超えない値段で発売するって言っててちょっと高いなあ~って

だったのが、発売すると1279ドルスタートで思ったよりかは安かった。ハイエンドスマホの値段とあんまり変わらない、もっとべらぼうに高いと思ってた。
(まあ普通に全然高いんですけど!!)

もっと高くなるもんだと思ってたから下取りにしてPixel 11 Pro Foldに変えたけど、10 Pro Foldをそのまま続けてこっち買うか考えてたかもしれない・・・

おわりに2

よくある?iPhone 対 Androidスマホのクリックベイト記事にならないように書きましたが、もしそう感じてしまったらすいません。
まじでもういいよiPhoneとAndroidの比較というか。煽りすぎ。

機嫌悪いときに見つけた日には、Google Discover(ホーム画面の一番左にあるやつ、Chromeにあるやつ)からWeb サイトごとまるまる非表示にしてる。

おわりに3

もしおりたたみスマホ気になってる人がいれば。

わたし的には、折り目はマジで気にならない。触ればわかるし光の当たり方によっては折り目はちゃんと見える。
でもそれだけ。普通に使えるし。こんなもんだよ。

それこそおりたたみスマホ黎明期は分からないけど今時そんなひどいことある?

折り目はもう仕方ない気がします。今でもスマホの電池は繰り返し使うほど使える時間が短くなってくるし。
最近はあんまり聞かなくなりましたが、iPhone X (2017)で有機EL (OLED)が採用されたとき、人々は画面が焼き付くのではないかの話題で持ちきりになってた時と同じように見えます。
(電池マークとかアンテナマークの部分が常に表示されるから残像が残るのではないか)

折り目なんかよりもハイエンド以上の値段を払ってもなお、望遠カメラが無いのが不満・・・難しいのかな

おわりに4

ぼーっとYouTubeみてたんですけど

YouTube

NeoとDuoって名前の組み合わせ、言われるまで気付かなかった。
Macbook Neoの時点で規則性に気付いていれば、UltraでもFoldでもなくDuoだって予想できた可能性がある?