UIViewのサブクラスはCALayerクラスをもっています。そんなCALayerのmasksToBoundsのプロパティの初期値がUIViewのサブクラスによって異なっていたので共有したいと思います。
masksToBounds
まず、masksToBoundsプロパティの説明ですが、CALayer Class Referenceによると下記のように記述してあります。
When the value of this property is true, Core Animation creates an implicit clipping mask that matches the bounds of the layer and includes any corner radius effects. If a value for the mask property is also specified, the two masks are multiplied to get the final mask value.
The default value of this property is false.
つまりmasksToBoundsがtrueの場合はコンテンツのサブレイヤの境界矩形外に描画処理はされないようですね。CALayer Class Referenceによると初期値はfalseとされています。
使用例
let view = UIView(frame: CGRectMake(0, 0, 200, 50))
view.backgroundColor = UIColor.lightGrayColor()
view.layer.masksToBounds = false
self.view.addSubview(view)
let label = UILabel(frame: CGRectMake(0, 0, 300, 50))
label.text = "masksToBounds Test by Shohei"
self.view.addSubview(label)
masksToBoundsがfalseの状態だとUILabelがUIViewをはみだしてもしっかり描画されていますね。
この状態でmasksToBoundsをtrueにしてあげると、下の図のようにUIViewの境界矩形外は描画されなくなります。
つまりmasksToBoundsをtrueの状態だと影の描画などもされなくなるんですね。
masksToBoundsの初期値の違いについて
CALayer Class ReferenceではmasksToBoundsの初期値はfalseとされていましたが、UIViewのサブクラスによって初期値は異なるようです。
ウィンドウ系
let window = UIWindow()//デバイスの画面上の最下層のビュー
print(window.layer.masksToBounds)// ->false
コンテンツ表示系
let label = UILabel()//テキスト表示
print(label.layer.masksToBounds)// ->false
let textView = UITextView()//テキストの表示・編集
print(textView.layer.masksToBounds)// ->true
let imageView = UIImageView()//画像表示
print(imageView.layer.masksToBounds)// ->false
let scrollView = UIScrollView()//スクロール可能なビュー
print(scrollView.layer.masksToBounds)// ->true
let webView = UIWebView()//ウェブコンテンツ表示
print(webView.layer.masksToBounds)// ->false
let progressView = UIProgressView()//進捗の表示
print(progressView.layer.masksToBounds)// ->false
let activityIndicatorView = UIActivityIndicatorView()//処理中を示すビュー
print(activityIndicatorView.layer.masksToBounds)// ->false
let actionSheet = UIActionSheet()//アクション表示(iOS8.3からはUIAlertController推奨)
print(actionSheet.layer.masksToBounds)// ->false
let alertView = UIAlertView()//アラート表示のためのポップアップ
print(alertView.layer.masksToBounds)// ->false
let pickerView = UIPickerView()//選択肢の表示と選択
print(pickerView.layer.masksToBounds)// ->true
データコレクション表示系
let tableView = UITableView()//縦方向にセルを表示
print(tableView.layer.masksToBounds)// ->true
let collectionView = UICollectionView()//任意のレイアウトでセル表示
print(collectionView.layer.masksToBounds)// ->true
UIコントロール系
let control = UIControl()//UIコントロール共通のスーパークラス
print(control.layer.masksToBounds)// ->false
let button = UIButton()//ボタン
print(button.layer.masksToBounds)// ->false
let textField = UITextField()//テキストの表示・編集
print(textField.layer.masksToBounds)// ->true
let switch = UISwitch()//オン・オフスイッチ
print(switch.layer.masksToBounds)// ->false
let segmentedControl = UISegmentedControl()//セグメントによる選択肢表示
print(segmentedControl.layer.masksToBounds)// ->false
let stepper = UIStepper()//段階式値の加算・減算
print(stepper.layer.masksToBounds)// ->false
let slider = UISlider()//スライダー
print(slider.layer.masksToBounds)// ->false
let datePicker = UIDatePicker()//日付・時刻のピッカー
print(datePicker.layer.masksToBounds)// ->false
let refreshControl = UIRefreshControl()//更新コントロール
print(refreshControl.layer.masksToBounds)// ->false
let pageControl = UIPageControl()//ページ表示
print(pageControl.layer.masksToBounds)// ->false
タブバー系
let tabBar = UITabBar()//タブバー
print(tabBar.layer.masksToBounds)// ->false
let navigationBar = UINavigationBar()//ナビゲーションバー
print(navigationBar.layer.masksToBounds)// ->false
let toolbar = UIToolbar()//ツールバー
print(toolbar.layer.masksToBounds)// ->false
let searchBar = UISearchBar()//検索バー
print(searchBar.layer.masksToBounds)// ->false
masksToBoundsの初期値が異なるUIViewサブクラス
- UITextView
- UIScrollView
- UIPickerView
- UITableView
- UICollectionView
- UITextField
これらのクラスはmasksToBoundsの初期値がtrueになっていますね。
よってサブビューのコンテンツをはみだして表示したい場合や影の描画をする場合はmasksToBoundsをfalseにする必要があります
最後に
masksToBoundsの初期値がtrueになってるということは、境界矩形外の描画は推奨されていないと思いますが、クラスによる初期値の違いは理解しておく必要があると思います。
他にもプロパティの初期値がクラスによって異なる場合はあると思いますので、知っておくとバグの早期発見などにも役立つと思います。