Sketchで背景をテキストでマスクする&背景の中のテキスト部分を透過させる方法
Sketchを使って画像やシェイプを文字の形に切り抜くやり方と、
画像やシェイプの中のテキストの部分を透明にするやり方のメモです。
次の画像のようなものを作ります。
公式サイト
参考サイト様
①シェイプの中のテキスト部分を透明にする
Rectangleのシェイプのレイヤーの上にテキストのレイヤーを重ねます。
テキストはそのままでもいいし、Convert to Outlines
でパスにしてもいいです。
テキストレイヤーとシェイプのレイヤーを同時に選択します。
メニューからLayer
→ Combine
→ Subtract
又は Difference
を選択します。
するとCombined Shape
というレイヤーになりテキスト部分が透過されます。
②画像の中のテキスト部分を透明にする
画像で行う場合は、画像レイヤーの上にテキストのレイヤーを重ねてCombined Shape
を作ってもうまくいきません。
シェイプの背景を画像にした後にCombined Shape
を作ります。
まずRectangleのシェイプを作ります。(説明のためRectangleのシェイプにしていますが、Ovalなどの形でも大丈夫です)
右側のスタイル設定の中の Fills
から Pattern Fill
をクリックし、
IMAGES
をクリックして画像を読み込み、Display
はFill
にします。
上の説明画像とは違う背景ですが、シェイプの背景が設定されました。
後は ①シェイプの中のテキスト部分を透明にすると同じように、
テキストレイヤーを作成し、 テキストレイヤーとシェイプのレイヤーを同時に選択した状態で
メニューからLayer
→ Combine
→ Subtract
又は Difference
を選択すれば Combined Shape
というレイヤーになりテキスト部分が透過されます。
③背景画像をテキストでマスクして画像を文字の形に切り抜く
参考サイト様がとても詳しく説明してくださっているので、そちらを読むのが一番よいと思いますが、
私の手元で試したものを軽く説明させていただきます。
Advanced Text Mask In Sketch - Design + Sketch - Medium
③-1 Combined Shapeによるマスク
まず、②画像の中のテキスト部分を透明にする と同様に
シェイプを作成し、背景画像を設定します。
テキストレイヤーも作成します。
テキストレイヤーとシェイプのレイヤーを同時に選択した状態で
メニューからLayer
→ Combine
→ Intersect
を選択すれば Combined Shape
というレイヤーになり背景がテキストの形にくり抜かれたようになります。
この方法だと、テキストレイヤーを背景の上の方や下の方に配置しても背景の中央にテキストがあるかのように
背景の中央部分が切り抜かれるようです。
切り抜きの位置を柔軟に変えたければ、次に説明するやり方のほうがよいと思います。
③-2 Combined Shapeレイヤーの上に画像を重ねてマスクする
今までのやり方と違い、テキストをマスク用のシェイプにして、その上に画像を重ねてマスクします。
例えば画像を丸くくり抜くような普通のマスク方法と似たような感じです。
テキスト部分と画像が結合していないので、マスク位置を柔軟に変更することが出来ます。
まずはテキストの形をした透明のシェイプレイヤーを作ります。
Rectangleのシェイプとテキストのレイヤーを作ります。
テキストの色はなんでもいいので、目立つ色にしてます。
Rectangleのシェイプを非表示にします。
テキストレイヤーとシェイプのレイヤーを同時に選択した状態で
メニューからLayer
→ Combine
→ Union
を選択します。
これでMaskもできるテキストの形のレイヤーになりました。
このレイヤーの上に画像を重ねて、テキストのレイヤーの右クリックメニューからMask
を選択すると
テキストの形に画像がマスクされます。
画像を動かすとマスクされる位置も変えられます。
以上です。
【Android開発】xmlファイルでアプリ全体にオリジナルのフォントを適用する(Android4.1 API level 16以降)
- 公式サイト
- この記事の内容を試したサンプルの環境
- フォントファイルをリソースとして認識させる
- フォントリソースにアクセスする
- アプリ全体にフォントを適用する
- 個別のViewにフォントを適用する
- アプリ全体+個別のViewにそれぞれフォントを指定した場合
カスタムフォントの記事です。
※2019/06/03時点での情報です。
公式サイト
Font resources | Android Developers
Fonts in XML | Android Developers
Android 8.0 の機能と API | Android Developers
この記事の内容を試したサンプルの環境
- Android Studio 3.4.1
- Gradle 3.4.1
- AndroidX appcompat:1.0.2を使用
- minSdkVersion 16
- targetSdkVersion 28
- 実行結果はエミュレータでAndroid4.1, Android6.0, Android9.0で確認
フォントファイルをリソースとして認識させる
Android 8.0 (API level 26) で、追加された機能を使ってフォントを適用します。
以下の公式サイトの引用にもあるように、サポートライブラリ26以上(当然AndroidXもOK)を導入していて
Android 4.1 (API level 16) 以降で実行すれば使えるので
(下記の引用ではAPIバージョン14以降とありますが、こちらでは16以降となっています)、
大抵の環境で使えると思います。
Android 8.0 には、フォントをリソースとして利用できる XML フォント機能が新しく導入されています。
この機能を使うと、フォントをアセットにバンドルする必要はなくなります。
フォントは R ファイルでコンパイルされ、システムで自動的にリソースとして利用できるようになります。
これらのフォントには、新しいリソースタイプ font を使ってアクセスします。
Support Library 26 は、API バージョン 14 以降が実行されている端末で、この機能に対するフルサポートを提供します。
引用元:Android 8.0 の機能と API | Android Developers
フォルダを追加する
res
フォルダの下にfont
フォルダを追加します。
Android Studioでres
フォルダの上で右クリックメニューを表示して
New
-> Folder
-> Font Resources Folder
を選択します。
フォントファイルを追加する
font
フォルダ配下に.ttf, .ttc, .otf, .xml などのファイルを設置すると、ファイル名がリソースIDとして認識されます。
注意点として
font
というフォルダ名である必要があります。- ファイル名はAndroidの規則に従い、小文字a-z, 0-9, _で構成されている必要があります。
フォントリソースにアクセスする
フォントにアクセスするには@font/customfont
や R.font.customfont
のように指定します。
プログラム内でアクセスする場合はgetFont(int)メソッドにリソースのidを渡してフォントを取得します。
Typeface typeface = getResources().getFont(R.font.myfont); textView.setTypeface(typeface);
アプリ全体にフォントを適用する
アプリのベースとなるスタイルにandroid:fontFamily
を記述します。
AndroidManifest.xmlのApplicationタグの中のthemeのやつです。
新規でプロジェクトを作るとandroid:theme="@style/AppTheme"
となっていると思います。
res/values/styles.xml
<!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <!-- Font style for a whole application project --> <item name="android:fontFamily">@font/sawarabimincho_regular</item> </style>
個別のViewにフォントを適用する
レイアウトの編集画面からTextViewなどのfontFamilyをフォントファイル名にします。
<TextView android:id="@+id/textView5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:fontFamily="@font/mplus_rounded1c_bold" android:text="5.この文章はダミーです。この文章はダミーです。この文章はダミーです。"/>
アプリ全体+個別のViewにそれぞれフォントを指定した場合
プロジェクト全体のフォントを指定している場合は、Viewに指定している方が優先されます。
例として、5つのTextViewがあるレイアウトで最初の2つはフォント指定無し、残りの3つは指定ありの場合
最初の2つはプロジェクト全体へのフォント指定が適用され、
残りの3つはそれぞれのViewに指定したフォントが適用されます。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:text="1.この文章はダミーです。この文章はダミーです。この文章はダミーです。"/> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:text="2.この文章はダミーです。この文章はダミーです。この文章はダミーです。"/> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:fontFamily="@font/mplus_rounded1c_regular" android:text="3.この文章はダミーです。この文章はダミーです。この文章はダミーです。"/> <TextView android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:fontFamily="@font/mplus_rounded1c_thin" android:text="4.この文章はダミーです。この文章はダミーです。この文章はダミーです。"/> <TextView android:id="@+id/textView5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/activity_vertical_margin" android:fontFamily="@font/mplus_rounded1c_bold" android:text="5.この文章はダミーです。この文章はダミーです。この文章はダミーです。"/> </LinearLayout>
"Type mismatch: inferred type is MainActivity but LifecycleOwner was expected"コンパイルエラー対応(AndroidX, support libraly, gradleのtranstive推移的依存関係の解決)
- 実行した環境
- 参考サイト様
- 発生した現象
- 原因
- gradleの推移的依存関係の解決
- 解決方法
- Material Components For Android にはRecyclerViewが最初から入っていた
※2019/05/10時点の状況です。
Googleの CodeLabsのAndroid Room with a View - Kotlinを写経した時に遭遇したエラーの覚書です。
実行した環境
- Android Studio version 3.4
- Gradle version 3.4
- Kotlin version 1.3.21
参考サイト様
参考にさせていただきました。本当にありがとうございました!
- gradle - 第51章 依存関係の管理
- AndroidX Overview | Android Developers
- 気をつけたいGradleの推移的依存関係とその解決 - Qiita
- GradleのResolutionStrategy – Kenji Abe – Medium
発生した現象
AppCompatActivityを継承したクラス内でデータの変更をobserveするために下記のようなコードを書くとコンパイルエラーが発生しました。 observeメソッドのowner引数にthisを渡している箇所です。
書いたコード(Kotlin)
wordViewModel.allWords.observe(this, Observer { words -> words?.let { adapter.setWords(it) } })
エラーメッセージ
Type mismatch: inferred type is MainActivity but LifecycleOwner was expected
エラー発生時のbuild.gradle(Project)
buildscript { ext.kotlin_version = '1.3.21' repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.4.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } allprojects { repositories { google() jcenter() } } task clean(type: Delete) { delete rootProject.buildDir } ext { roomVersion = '2.1.0-alpha07' archLifecycleVersion = '2.1.0-alpha04' androidxArchVersion = '2.1.0-alpha02' coroutines = '1.2.1' }
エラー発生時のbuild.gradle(Module:app)
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' android { compileSdkVersion 28 defaultConfig { applicationId "exam.com.sakurafish.room.roomwordsample" minSdkVersion 19 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // Room components implementation "androidx.room:room-runtime:$rootProject.roomVersion" implementation "androidx.room:room-ktx:$rootProject.roomVersion" kapt "androidx.room:room-compiler:$rootProject.roomVersion" androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion" // Lifecycle components implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.archLifecycleVersion" kapt "androidx.lifecycle:lifecycle-compiler:$rootProject.archLifecycleVersion" androidTestImplementation "androidx.arch.core:core-testing:$rootProject.androidxArchVersion" // ViewModel Kotlin support implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.archLifecycleVersion" // Coroutines api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$rootProject.coroutines" api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$rootProject.coroutines" implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha05' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'com.google.android.material:material:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' }
原因
原因:LifecycleOwnerを実装していないクラスを継承していたため(推移的依存関係が絡むので結構やっかい)
エラーメッセージにあるLifecycleOwner
を実装しているのは、実際にはAppCompatActivity
の上流のComponentActivity
になります。
このComponentActivity
の含まれるライブラリのバージョンによってはLifecycleOwnerを実装していないため、このようなエラーメッセージが発生しました。
androidx.appcompat:appcompat:1.0.2
となっている箇所のバージョンアップをするか、recyclerview:1.1.0-alpha05
をimplementationしている箇所を削除すればコンパイルエラーは解決するのですが、原因がわかるまでややこしかったのでもう少し詳しく説明します。
androidx.core:core1.1.0-beta01がクセモノ?
エラーが発生した時のbuild.gradleのdependenciesではrecyclerview:1.1.0-alpha05
をインストールするようにしている箇所があります。
implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha05'
これはandroidx.core:core1.1.0-beta01@aar
を依存するライブラリにしています。
androidx.core:core
は他のところからも依存されていますが、recyclerviewが依存しているのが最新のため、gradleの推移的依存関係の管理により全てに適用してしまいます。
(gradleの推移的依存関係の解決)
このバージョンのソースコードを見ると、androidx.core.app.ComponentActivity
内ではLifecycleOwner
はimplementsされていません。
とてもややこしいことに、androidx.appcompat:appcompat:1.0.2
が参照している古いバージョンであるandroidx.core:core1.0.1
ではLifecycleOwner
が実装されています。
実装していたりしていなかったりしてるのは何故なのかと疑問に思いました。
ComponentActivityが2つになっていた
ソースコードを眺めてみると、
appcompatのversion 1.0.0-alpha01からandroidx.core.app.ComponentActivity
に新しいサブクラス、androidx.activity.ComponentActivity
が出来たようです。
パッケージが変わっていますね。
FragmentActivity
が新クラスを継承するようになったことから、androidx.core.app.ComponentActivity
からLifecycleOwner
の実装が削除されました。
さらにandroidx.activity:activity1.0.0-alpha01@aar
のようなライブラリが新しく作られて、新クラスはandroidx.core:core
からは分離されたようです。
appcompatが古かった
図であらわすとこのような感じです。
androidx.appcompat:appcompat:1.0.2
が古いため、androidx.activity.ComponentActivity
を継承していないのにもかかわらず参照先ライブラリが新しくなっており既にLifecycleOwner
の実装が削除されていたというわけです。
本来androidx.appcompat:appcompat:1.0.2
はandroidx.core:core:1.0.1
に依存していたのがgradleの推移的依存関係の解決により、recyclerview:1.1.0-alpha05
が依存するより新しいライブラリで上書きされてしまったのですね。
当エントリはサンプルコードを書いていましたので、バージョンに-alphaとか付いている安定バージョンではないものを使っています。
安定バージョンを使い、依存ライブラリ同士のバージョンをなるべく揃えるようにすれば、AndroidXでもこの状況はそんなに発生しないかなと思っています。
gradleの推移的依存関係の解決
ライブラリが依存しているライブラリが別のライブラリからも依存されていてさらに依存してしまう関係のことを推移的な依存関係といいます。
gradleでは競合してしまうライブラリはその中で一番最新のバージョンのものを強制的に適用することで推移的依存関係の解決を行っています。
参考サイト様がとてもわかりやすく説明してくださっています。
依存関係は以下のコマンドで表示できます。
./gradlew :app:dependencies
androidx.appcompat:appcompat:1.0.2
が依存するandroidx.core:core:1.0.1
が上書きされているのがわかります。
自分で推移的依存関係の解決を行いたい時はこちらの参考サイト様が参考になりました。
GradleのResolutionStrategy – Kenji Abe – Medium
解決方法
方法1. appcompatを新しくする
implementation 'androidx.appcompat:appcompat:1.1.0-alpha05'
recyclerviewに合わせてアップグレードします。
AndroidXのライブラリ同士のバージョンをなるべく揃えるようにします。
方法2. recyclerviewを削除する
implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha05'
の箇所を削除します。ついでに↓のappcompat
も削除しても大丈夫です。
implementation 'androidx.appcompat:appcompat:1.0.2'
削除しても大丈夫な理由はMaterial Components For Android にはRecyclerViewが最初から入っていたです。
新しいバージョンのライブラリを使いたいというときなどは、バージョンを指定して導入すればよいと思います。
Material Components For Android にはRecyclerViewが最初から入っていた
本エントリの主題からは外れますが、Material Componentsだけで色んなライブラリを含んでいるという話です。
'com.android.support:design'
及び'com.google.android.material:material'
のMVN Repository を見てみました。
2019/05/10時点の最新バージョンです。
Maven Repository: com.android.support » design » 28.0.0
https://mvnrepository.com/artifact/com.android.support/design/28.0.0
Maven Repository: com.google.android.material » material » 1.1.0-alpha06
https://mvnrepository.com/artifact/com.google.android.material/material/1.1.0-alpha06
recyclerview入っていますね。他にも
annotation, appcompat, cardview, coordinatorlayout, core, fragment, legacy-support-core-ui, legacy-support-core-utils, transition, vectordrawable, viewpager2が入っています。
以上です。