DZNEmptyDataSetでbuttonTitleに合わせてBackgroundImageのsizeを調節する


今国際化に伴い、アプリを大幅改修しています。
こんな感じの画面を作ろうと思っていました。
ライブラリはDZNEmptyDataSetを使っています。


今まで

文言(画像のCreate New Streamの部分)を日本語で指定していた
=> 自ずと文言のサイズは一意的に決まる
=> そのLabelのサイズに合わせてpaddingを指定して、かつ、文言も含んだImageを用意していた

国際化

文言は国・地域によって変化する
=> 文言のサイズはもちろん動的に変化する
=> 背景画像だけ別で用意して、動的に変化するLabelのサイズに合わせて大きさを上手い感じに合わせる必要がある

というわけで流れとしては、

  • 背景画像の用意(Normal/Highlighted)
  • titleLabelのサイズを測って変数に格納しておく
  • backgroundImageの描画の際に、上記のサイズに合わせてimageのwidthを調節する

サクッと元のソースコードを見ながら自分でもサンプルを作ってみました。

DZNEmptyDataSetとは

TableView, collectionViewが空の時に代わりに表示するものを作成するためのライブラリ
参考

delegate method一覧

func titleForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
  // titleを指定する
}
func descriptionForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
  // 説明文を指定
 }
func imageForEmptyDataSet(scrollView: UIScrollView!) -> UIImage! {
  //  画像を指定
}
func buttonTitleForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> NSAttributedString! {
   // buttonのtitleを指定
}
func buttonImageForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> UIImage! {
   //  buttonに貼る画像を指定
}
func buttonBackgroundImageForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> UIImage! {
   // buttonの背景画像を指定
}
func backgroundColorForEmptyDataSet(scrollView: UIScrollView!) -> UIColor! {
    // 全体のviewの背景の色を指定
}
func verticalOffsetForEmptyDataSet(scrollView: UIScrollView!) -> CGFloat {
    // contentsの位置をviewの上端からどれくらいの距離離すかを指定
}
func spaceHeightForEmptyDataSet(scrollView: UIScrollView!) -> CGFloat {
    //  contentsが複数ある場合、それぞれの距離をどれくらい離すかを指定
}
func emptyDataSetShouldDisplay(scrollView: UIScrollView!) -> Bool {
    //  emptyDataSetのcontentsを表示するか否か
}
func emptyDataSetDidTapView(scrollView: UIScrollView!) {
     //  全体のviewをtapした時のアクションを指定
}
func emptyDataSetDidTapButton(scrollView: UIScrollView!) {
     //  作成したbuttonをtapした時のactionを指定
}

buttonBackgroundImageForEmptyDataSetでtitleに合わせてsizeを変える

これが面倒だったのでshareします。
やりたいことは最初に説明した通りです。

func buttonTitleForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> NSAttributedString! {
        let str = "Create New Stream"
        let font = UIFont.systemFontOfSize(14.0, weight: 2.0)


        // 文言のサイズを格納しておく
        titleSize = str.widthWithConstrainedHeight(44, font: font)

        return NSAttributedString(
            string: str,
            attributes: [
                NSFontAttributeName: font,
                NSForegroundColorAttributeName: ColorUtil.rgba(172, green: 175, blue: 189)
            ]
        )
    }


func buttonBackgroundImageForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> UIImage! {

        // 引き伸ばされたbackgroundImageとview.bounds.size.widthとの比率。
        // どの機種でもだいたい88%でした
        let ratioViewBoundsWidthAndButton: CGFloat = 0.88


        //  引き伸ばされたbackgroundImageのsize
        let defaultSize = view.bounds.size.width * ratioViewBoundsWidthAndButton


        //  titleLabelのpadding.お好みで
        let padding: CGFloat = 20


        // 背景画像を引き伸ばしてからtitleLabelに合わせてwidthを調節してUIImageを返す
        return UIImage.makeBackgroundImage(state).shrinkImageAdjustingObject(before: defaultSize, objectSize: messageSizeForEmptyDataSet, padding: padding)
    }



extension UIImage {

    // 引き延ばした画像を返すメソッド
    class func makeBackgroundImage(state: UIControlState) -> UIImage {

        let baseImage = (state == UIControlState.Highlighted) ? R.image.btn_highlight()! : R.image.btn()!

        // capInsetsは引き延ばす時に引き伸ばしたくない一部分を指定できる
        // ここでは四端5.0×5.0だけそのままのサイズで他を引き延ばすイメージ
        let capInsets = UIEdgeInsets(top: 5.0, left: 5.0, bottom: 5.0, right: 5.0)


       return baseImage.resizableImageWithCapInsets(capInsets, resizingMode: UIImageResizingMode.Stretch)
    }


    //  内部のobjectのサイズとpaddingを指定すれば、imageのwidthを拡大・縮小するメソッド
    func shrinkImageAdjustingObject(before imageSize: CGFloat, objectSize: CGFloat, padding: CGFloat) -> UIImage {

        var rectInsets = UIEdgeInsetsZero


        // imageの端と内部のオブジェクトの端までの距離(片方ずつ)
        let widthBetweenBackgroundAndLabel = (imageSize - objectSize)/2


        // paddingを考慮してimageをどれくらい拡大・縮小させるか、の指定
        let shrinkWidth = widthBetweenBackgroundAndLabel - padding
        rectInsets = UIEdgeInsets(top: 0, left: -shrinkWidth, bottom: 0, right: -shrinkWidth)


        return imageWithAlignmentRectInsets(rectInsets)
    }

}

参考