2013年1月14日月曜日

[Android TIPS] キーワード履歴に使えそうなボタン配置

キーワード履歴に使えそうなボタン配置を作ってみました。
こういう配置を自動的にやってくれるレイアウトとかはないですよね。たぶん(汗)





サンプル野良apkはこちらからどうぞ。

レイアウトはこんな感じ。

<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:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/editInput"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <Button
            android:id="@+id/btnAdd"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Add" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/layoutTag1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <LinearLayout
        android:id="@+id/layoutTag2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <LinearLayout
        android:id="@+id/layoutTag3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

コードはこんな感じ。

package com.sample.sampleapp;

import java.util.ArrayList;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.app.Activity;
import android.graphics.Paint;

public class TagActivity extends Activity {

 /** WRAP_CONTENT */
 private final int WC = ViewGroup.LayoutParams.WRAP_CONTENT;

 /** タグのラベル最大長 */
 private final int MAX_LABEL_LEN = 8;

 /** ボタンのパディング */
 private final int BTN_PADDING = 8;

 /** 横幅に占めるボタンに必要な最低幅の割合 */
 private final float RATIO_BUTTONS = 0.8f;

 /** タグを表示するリニアレイアウト */
 private final int[] mListTagLayout = { R.id.layoutTag1, R.id.layoutTag2, R.id.layoutTag3 };

 /** タグボタンのリスト */
 private final ArrayList<Button> mListTagButton = new ArrayList<Button>();

 /** 画面幅 */
 private int mScreenWidth = 0;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_tag);

  // 画面幅の取得
  WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
  mScreenWidth = wm.getDefaultDisplay().getWidth();

  // ウィジェットの初期化
  initWidget();
 }

 /**
  * ウィジェットの初期化
  */
 private void initWidget() {
  // 「add」ボタンを非活性化
  final Button btnAdd = (Button) findViewById(R.id.btnAdd);
  btnAdd.setEnabled(false);

  // 文字が入力されている場合に「add」ボタンを活性化
  final EditText editInput = (EditText) findViewById(R.id.editInput);
  editInput.addTextChangedListener(new TextWatcher() {
   @Override
   public void onTextChanged(CharSequence s, int start, int count, int after) {
   }

   @Override
   public void beforeTextChanged(CharSequence s, int start, int before, int count) {
   }

   @Override
   public void afterTextChanged(Editable s) {
    btnAdd.setEnabled(0 < s.length());
   }
  });

  // 「add」ボタン押下時に入力された文字列を元にタグを生成
  btnAdd.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    // ボタンを生成
    final Button btn = new Button(TagActivity.this);
    btn.setText(getInputText());
    btn.setPadding(BTN_PADDING, BTN_PADDING, BTN_PADDING, BTN_PADDING);
    btn.setOnClickListener(new OnClickListener() {
     @Override
     public void onClick(View v) {
      editInput.setText(btn.getText());
     }
    });
    // 同一の内容があれば削除
    for (int i = mListTagButton.size() - 1; 0 <= i; i--) {
     if (mListTagButton.get(i).getText().equals(btn.getText())) {
      mListTagButton.remove(i);
     }
    }
    mListTagButton.add(btn);

    // ボタンを配置
    int index = mListTagButton.size() - 1;
    for (int id : mListTagLayout) {
     LinearLayout targetLayout = (LinearLayout) findViewById(id);
     targetLayout.removeAllViews();

     // リストの末尾 (直近に生成されたボタン) から配置
     while (0 <= index) {
      Button target = mListTagButton.get(index);

      // 同一行のボタンに必要なボタン幅を算出
      int totalWidth = 0;
      for (int i = 0; i < targetLayout.getChildCount(); i++) {
       Button child = (Button) targetLayout.getChildAt(i);
       totalWidth += getVirtualButtonWidth(child);
      }
      // 同一行のボタン幅と次に追加するボタンの幅が規定値より大きければ次の行へ
      if (mScreenWidth * RATIO_BUTTONS < totalWidth + getVirtualButtonWidth(target)) {
       break;
      }

      // 対象行へボタンを配置
      LayoutParams params = new LinearLayout.LayoutParams(0, WC);
      params.weight = getVirtualButtonWidth(target);
      targetLayout.addView(target, params);

      index--;
     }
    }

    editInput.setText("");
   }
  });
 }

 /**
  * 入力文字列の取得 (規定文字数以上は省略)
  * 
  * @return
  */
 private String getInputText() {
  final EditText editInput = (EditText) findViewById(R.id.editInput);
  String input = editInput.getText().toString();

  if (MAX_LABEL_LEN < input.length()) {
   input = input.substring(0, MAX_LABEL_LEN) + "...";
  }

  return input;
 }

 /**
  * ボタンの仮想幅を取得
  * 
  * @param button
  * @return
  */
 private int getVirtualButtonWidth(Button button) {
  Paint p = new Paint();
  p.setTextSize(button.getTextSize());
  int labelWidth = (int) p.measureText(button.getText().toString());
  return (labelWidth + button.getTotalPaddingLeft() + button.getTotalPaddingRight());
 }
}

「ボタンの仮想幅」はそのボタンを表示した時にラベルがきちんと見える最小の幅を算出したかったので書いてみましたが、これでよいかしらん。でも「i」とか表示した際に潰れることはないから、これでもよいかしらん。

0 件のコメント:

コメントを投稿