©️

【Roblox】コピー&スクロールできるテキストの作成

2024/11/13に公開

はじめに

今回は、自分が実装したコピー&スクロールができるテキストの作成について紹介します。

Robloxバージョン 0.650.0.6500743

準備

上記を実装するにあたり、エクスプローラーの配置は下記のようになります。

スクロールするために必要なScrollingFrameと表示用のTextBox、実際にコピーを行うTextBoxを用意します。

作成

テキストの表示

まずはテキストが表示されるように対応します。

-- インスタンス
local ScreenGui = script.Parent
local ScrollingFrame = ScreenGui:WaitForChild("ScrollingFrame")
local FocusTextBox = ScreenGui:WaitForChild("FocusTextBox")
local DisplayTextBox = ScrollingFrame:WaitForChild("DisplayTextBox")

DisplayTextBox.AutomaticSize = Enum.AutomaticSize.Y		-- Y座標のみ可変に
DisplayTextBox.ClearTextOnFocus = false		-- フォーカス時にテキストを消去しない
DisplayTextBox.TextEditable = false		-- テキストを編集できない
DisplayTextBox.RichText = true		-- リッチテキストに対応
DisplayTextBox.TextWrapped = true		-- テキストを折り返す

-- 長いテキストを設定
local sampleText = "サンプルテキスト"
for i = 1, 100 do
	DisplayTextBox.Text = DisplayTextBox.Text..sampleText
end

-- CanvasSizeをTextBoxで使用している高さに設定する
ScrollingFrame.CanvasSize =  UDim2.new(0, 0, 0, DisplayTextBox.AbsoluteSize.Y)

コードの解説

DisplayTextBox.AutomaticSize = Enum.AutomaticSize.Y		-- Y座標のみ可変に
DisplayTextBox.ClearTextOnFocus = false		-- フォーカス時にテキストを消去しない
DisplayTextBox.TextEditable = false		-- テキストを編集できない
DisplayTextBox.RichText = true		-- リッチテキストに対応
DisplayTextBox.TextWrapped = true		-- テキストを折り返す

-- CanvasSizeをTextBoxで使用している高さに設定する
ScrollingFrame.CanvasSize =  UDim2.new(0, 0, 0, DisplayTextBox.AbsoluteSize.Y)
  • AutomaticSizeをYに設定することでテキストの文字数に応じてTextBox.Sizeが変更します。
    これによりCanvasSizeを設定する際にAbsoluteSizeからTextBoxで使用しているサイズを設定することができます。横スクロールの場合はXを設定しましょう。
  • ClearTextOnFocusをオフにします。フォーカスした際にテキストが消えコピーができないためです。
  • TextEditableはオフにします。TextBoxはコピー用に用意しているので、入力はできないようにします。
  • RichTextはオンにします。TextBoxの場合TextWrappedが正しく動作するために必要です。(理由は調べてもよく分かりませんでした...。)
  • TextWrappedはオンにします。テキストが長文の場合は折り返してほしいためです。

これらはプロパティから直接設定しても大丈夫です。
今回は分かりやすいのでコードから指定しています。

上記コードにより下記のように表示されます。

PCで確認した際はコピーできる

スマホで確認


選択した際にテキストが消える...

スマホで確認をしたところ、選択した際にテキストが消えます。
ClearTextOnFocusはオフにしてあるはずです...。
スマホの場合はキーボードを表示して文字を選択してコピーするので、このままではコピーできません。
そこで下記を追加します。

+ DisplayTextBox.MultiLine = true		-- 複数行表示できるようにする
+ DisplayTextBox.ShowNativeInput = true		-- プラットフォーム固有の入力を表示する
  • MultiLineをオンにすることで、フォーカス時にテキストをTextBox内に複数行表示させることができます。
  • ShowNativeInputをオンにすることで、プラットフォーム固有のインプットを使用します。オフの場合はRobloxの組み込みキーボードを使用します。先ほどのテキストが消える問題はここが原因です。

これでスマホでもフォーカス時にテキストが表示されるはずです。


さらに余力があれば...
テキストのサイズを画面比率が変わっても調整するようなスクリプトを入れるとテキストが崩壊するのを防ぐことができます。
今回は下記記事で紹介された処理を追加します。
詳細な処理や説明は今回関係ないので省きます。
気になる方はぜひご覧ください!!
https://zenn.dev/landho_roblox/articles/8342c97966cadd


上記までの処理を追加してスマホで確認してみます。


フォーカスした際に上の方に片寄る...

テキストは表示されましたが、フォーカスした際に上に片寄る現象が発生します。


RobloxStudioの画面

上記は実際のRobloxStudioの画面です。
スマホで確認したテキストが片寄った際のTextBox.Sizeと、RobloxStudioで実際に設定したTexBox.Sizeが同じことが分かります。
つまりサイズ調整として設定したAutomaticSizeがフォーカスした際にオフになることが原因だと推測できます。

AutomaticSizeの設定を削除し、TextBox.TextBoundsからText.Sizeを設定するようにコードを修正します。


- DisplayTextBox.AutomaticSize = Enum.AutomaticSize.Y		-- Y座標のみ可変に
DisplayTextBox.ClearTextOnFocus = false		-- フォーカス時にテキストを消去しない
DisplayTextBox.TextEditable = false		-- テキストを編集できない
DisplayTextBox.TextWrapped = true		-- テキストを折り返す
DisplayTextBox.MultiLine = true		-- 複数行表示できるようにする
DisplayTextBox.ShowNativeInput = true		-- プラットフォーム固有の入力を表示する

+ -- TextBoxのサイズ調整
+ DisplayTextBox.Size = UDim2.fromOffset(DisplayTextBox.TextBounds.X, DisplayTextBox.TextBounds.Y)

これでスマホで確認してみます。

フォーカスしていない時はきちんと見えている!


フォーカスするとテキストがはみ出る...


フォーカスした際のスクロールバーの位置に応じて画面が上にずれる...

このようにフォーカスした際の問題が多く出てきます。
このあたりの対処方法は調べてもなかなか出てこず...。

表示用のTextBoxとコピー用のTextBoxを分ける

これらはScrollingFrameとTextBoxの相性が悪いことが原因です。
TextBoxはフォーカスしたとき、解除された時に呼ばれるイベントを設定で来ます。
またTextBoxにはフォーカスを当てる、解除させる関数も用意されています。
これらを利用して、タッチ操作の場合はフォーカス用のTextBoxに切り替える手法を採用しました。

最終的なコードは下記になります。

-- Service
local UserInputService = game:GetService("UserInputService")

-- Module
local AutoTextScaled = require(script:WaitForChild("AutoTextScaled"))

-- インスタンス
local ScreenGui = script.Parent
local ScrollingFrame = ScreenGui:WaitForChild("ScrollingFrame")
local FocusTextBox = ScreenGui:WaitForChild("FocusTextBox")
local DisplayTextBox = ScrollingFrame:WaitForChild("DisplayTextBox")

DisplayTextBox.ClearTextOnFocus = false		-- フォーカス時にテキストを消去しない
DisplayTextBox.TextEditable = false		-- テキストを編集できない
DisplayTextBox.RichText = true		-- リッチテキストに対応
DisplayTextBox.TextWrapped = true		-- テキストを折り返す
DisplayTextBox.MultiLine = true		-- 複数行表示できるようにする
DisplayTextBox.ShowNativeInput = true		-- プラットフォーム固有の入力を表示する

FocusTextBox.ClearTextOnFocus = false
FocusTextBox.TextEditable = false
FocusTextBox.TextWrapped = true
FocusTextBox.MultiLine = true
FocusTextBox.ShowNativeInput = true
FocusTextBox.Visible = false

-- ScrollingFrameのサイズに合わせる
FocusTextBox.Size = UDim2.fromOffset(ScrollingFrame.AbsoluteWindowSize.X, ScrollingFrame.AbsoluteWindowSize.Y)

-- 長いテキストを設定
local sampleText = "サンプルテキスト"
for i = 1, 100 do
	DisplayTextBox.Text = DisplayTextBox.Text..sampleText
end

-- 独自のテキストサイズ調整
AutoTextScaled:AddAutoScaleText(DisplayTextBox)
AutoTextScaled:AddAutoScaleText(FocusTextBox)

-- TextBoxのサイズ調整
DisplayTextBox.Size = UDim2.fromOffset(DisplayTextBox.TextBounds.X, DisplayTextBox.TextBounds.Y)

-- CanvasSizeをTextBoxで使用している高さに設定する
ScrollingFrame.CanvasSize =  UDim2.new(0, 0, 0, DisplayTextBox.AbsoluteSize.Y)

if UserInputService.TouchEnabled then
	-- タッチ操作の場合はフォーカスでTextBoxを切り替える
	
	DisplayTextBox.Focused:Connect(function()
		FocusTextBox.Text = DisplayTextBox.Text

		DisplayTextBox.Visible = false
		DisplayTextBox:ReleaseFocus()

		FocusTextBox.Visible = true
		FocusTextBox:CaptureFocus()
	end)

	FocusTextBox.FocusLost:Connect(function()
		FocusTextBox.Visible = false
		DisplayTextBox.Visible = true
		FocusTextBox.Text = ""
	end)
end

コードの解説

DisplayTextBox.Focused:Connect(function()
		FocusTextBox.Text = DisplayTextBox.Text

		DisplayTextBox.Visible = false
		DisplayTextBox:ReleaseFocus()

		FocusTextBox.Visible = true
		FocusTextBox:CaptureFocus()
	end)

	FocusTextBox.FocusLost:Connect(function()
		FocusTextBox.Visible = false
		DisplayTextBox.Visible = true
		FocusTextBox.Text = ""
	end)
  • TextBox:CaptureFocus()でそのTextBoxにフォーカスを当てることができます。
  • TextBox:ReleaseFocus()でそのTextBoxのフォーカスを解除することができます。
  • TextBox.Focusedはフォーカスされた際に呼ばれる関数を設定できます。
  • TextBox.FocusLostはフォーカスが解除された際に呼ばれる関数を設定できます。

スマホで確認


スクロールもコピーもできる!

これで通常時はスクロールができ、コピーもできるテキストが完成しました。
TextBoxを2つ使用することで少し無理やりのように感じますが、スマホの挙動を考えるとこれで妥当な気がします。

紹介

今回紹介したコピーできるテキストは、”Outfits Romance Town”というゲーム内で、アバターアイテムの説明文にて使用しています。
アバターアイテムの説明文内にあるURLをコピーできるようにするためです。
実際にゲームは下記から遊ぶことができます。
ぜひ、遊んでみてください!!!


実際に使用している画面

Outfits Romance Town
https://www.roblox.com/games/117927146209905/Outfits-Romance-Town

▼ 紹介動画
https://www.youtube.com/watch?v=W4o2yscdcbE

まとめ

  • スクロール&コピーできるテキストを作成するには、ScrollingFrameとTextBoxを使用する。
  • スマホでコピーできるようにするため、表示用のTextBoxとコピー用のTextBox2つを切り替えて対応する。

対応デバイス毎に挙動が違うことはRobloxではよくあり、特にUIでは注意を払わなければなりません。
今回はTextBoxを切り替えることで対応できましたが、他によい方法があればぜひ教えていただけると助かります!!

参考

https://create.roblox.com/docs/reference/engine/classes/TextBox
https://create.roblox.com/docs/reference/engine/classes/ScrollingFrame
https://zenn.dev/landho_roblox/articles/8342c97966cadd

ランド・ホー Roblox開発チーム

Discussion