第2回 iOSとAndroidで端末サイズを求める。
古い奴だとお思いでしょうが、
座標をもとに色々やっていく「オジサン世代」には
端末サイズを求めていくのは必要条件でございます。
ということで、端末サイズを求めてみますね。
まずはiOS版
前回のNoStoryBoardから呼び出されるViewController.swiftに
サイズを求めるプログラムを書きこんだのがこちら。
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func viewDidAppear(_ animated: Bool) { // UIScreennクラスが端末サイズを持っている let width: CGFloat = UIScreen.main.bounds.size.width let height: CGFloat = UIScreen.main.bounds.size.height // UILabel を使って画面中央に表示。 let info = UILabel() info.text = "Width=\(width), Height=\(height)" info.sizeToFit() info.center = CGPoint(x: width/2, y: height/2) self.view.addSubview(info) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
そしてシュミレータで起動したのがこちらです。
背景は白だと見にくいので、
self.window?.backgroundColor = UIColor(red: 1, green: 1, blue: 0.6, alpha: 1)
としてあります。
ただし、このままでは重大な欠陥があります。
なぜなら、回転を加えた時、再読み込みをしないので、
おかしな表示になってしまいます。
右側が、縦で起動した後、横にしたものです。
左上隅からの相対位置が変更されず(上の図の左側と同じ位置)に、
内容も元のままで表示されます。
何らかの方法で、情報の更新をし、再描画すればよいのですが、
ひとまずで置いておいて、
次、Android版を作ります。
Androidでは、MainActyvity.javaが最初のファイルとなります。
初期状態はこんな感じです。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
setContentView(R.layout.activity_main); が
xmlファイルをセットするところですが、
ここを空のRelativeLayoutをセットして行きます。
まず、リラティブレイアウトの作成。
名前はMainLayout.javaとしました。
MainLayoutクラスをRelativeLayoutを継承して
作っています。
サイズを求めるのはここに記述します。
getSizeは外部からの呼び出されるようにします。
(実際にはMainActivity.javaからコールされる。)
import android.content.Context; import android.view.ViewGroup; import android.widget.RelativeLayout; import android.widget.TextView; public class MainLayout extends RelativeLayout { public MainLayout(Context context) { super(context); } public void getSize(Context context) { // 端末のサイズを取得 final int width = this.getWidth(); final int height = this.getMeasuredHeight(); final TextView info = new TextView(context); info.setText("Width=" + width + ", Height=" + height ); RelativeLayout.LayoutParams infoParams = new RelativeLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT ); infoParams.addRule(CENTER_IN_PARENT,CENTER_IN_PARENT); addView(info, infoParams); } }
そして、MainActivity.javaの変更。
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // レイアウトを作成。 MainLayout mainLayout = new MainLayout(this); setContentView(mainLayout); // 端末のサイズを求め表示する mainLayout.getSize(this); } } これで、エラーなく走るのですが、実行すると、 width=0 , height=0 が表示されます。 これはAndroidの仕様であって、 描画終了後、レイアウトが確定してからサイズを取る必要があるのです。 そこで、MainActivity.javaを次のように変更。 >|java| import android.content.Context; import android.os.Build; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.ViewTreeObserver; public class MainActivity extends AppCompatActivity { private ViewTreeObserver.OnGlobalLayoutListener mListener; private Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; // レイアウトを作成。 final MainLayout mainLayout = new MainLayout(this); setContentView(mainLayout); // リスナーを設置し、サイズを求める。 mListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { removeListener(mainLayout.getViewTreeObserver(),mListener); mainLayout.getSize(mContext); } }; mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(mListener); } private static void removeListener(ViewTreeObserver observer, ViewTreeObserver.OnGlobalLayoutListener listner) { if (observer == null) { return; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { observer.removeOnGlobalLayoutListener(listner); } else { observer.removeGlobalOnLayoutListener(listner); } } }
ViewTreeObserver.OnGlobalLayoutListener というものが必要。
レイアウトが完成したら知らせてね!ってことです。
レイアウトが完成した後実行されるプログラムで、getSizeを呼ぶ。
こうしておくと画面サイズが取れるのです。
しかも、回転してあげると、きちっと表示されているじゃないですか!
回転の対応はiOSよりずっと楽みたいですね。