2013年6月18日火曜日

[Android] TextViewの複数行Ellipsize

TextViewの複数行末尾Ellipsizeの記事を見て前に同じのでハマったことを思い出したので、その時の方法を書きます。
    /**
     * @param view TextView
     * @param maxLines 最大行数
     * @param where 省略する箇所
     */
    public static void setMultilineEllipsize(TextView view, int maxLines, TruncateAt where) {
        if (maxLines >= view.getLineCount()) {
            // ellipsizeする必要無し
            return;
        }
        float avail = 0.0f;
        for (int i = 0; i < maxLines; i++) {
            avail += view.getLayout().getLineMax(i);
        }
        CharSequence ellipsizedText = TextUtils.ellipsize(
                view.getText(), view.getPaint(), avail, where);
        view.setText(ellipsizedText);
    }
TextUtils#ellipsize()はavailで指定された範囲に文字列をいい具合にカットしてくれるAPIです。
availはLayout#getLineMax()で指定行の描画範囲が取得できるので、それを最大行(maxLines)までの範囲を足してもとめます。

使用例

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

        final TextView tv = (TextView) findViewById(android.R.id.text1);
        tv.setText(R.string.attack_on_titan);
        tv.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                tv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                setMultilineEllipsize(tv, 3, TruncateAt.END);
            }
        });
    }
TextView#getLayout()などは描画後じゃないと取得できないので、OnGlobalLayoutListenerを使います。

activity_main.xml
    <TextView
        android:id="@android:id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
TextViewにellipsize,maxLinesは設定しないでください。

実行

  • Ellipsize=START, MaxLines=1

  • Ellipsize=MIDDLE, MaxLines=3

  • Ellipsize=END, MaxLines=5

  • Ellipsize=END, MaxLines=20

まとめ

このTextViewのバグでウォール・休日が破壊された。

2013年6月11日火曜日

[Android] Navigation Drawerを画面上側から表示させる

Support Package revision 13でNavigation Drawerを作るためのクラス(DrawerLayoutとかActionBarDrawerToggleとか)が追加されました。

しかし、Navigation Drawerは左側固定で変更することができません。
それを右側から表示するように変更する!...にしようと思いましたが、ActionBarDrawerToggleのGravity.LEFTをGravity.RIGHTに変更したらできてしまったので、今回は上側から表示させるようにしました。

※Navigation Drawerのデザインガイドに準拠してないので使用する場合は自己責任でお願いします。

作成したのは以下のクラスです。それぞれDrawerLayout、ActionBarDrawerToggleの左右の処理を上下の処理に変更しました。

  • VerticalDrawerLayout.java
  • ActionBarVerticalDrawerToggle.java

使用例

MainActivity.java
public class MainActivity extends Activity {
    private VerticalDrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarVerticalDrawerToggle mDrawerToggle;

    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    private String[] mPlanetTitles;

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

        mTitle = mDrawerTitle = getTitle();
        mPlanetTitles = getResources().getStringArray(R.array.planets_array);
        mDrawerLayout = (VerticalDrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.top_drawer);

        // set a custom shadow that overlays the main content when the drawer opens
        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.TOP);
        // set up the drawer's list view with items and click listener
        mDrawerList.setAdapter(new ArrayAdapter<string>(this,
                R.layout.drawer_list_item, mPlanetTitles));
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

        // enable ActionBar app icon to behave as action to toggle nav drawer
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        // ActionBarDrawerToggle ties together the the proper interactions
        // between the sliding drawer and the action bar app icon
        mDrawerToggle = new ActionBarVerticalDrawerToggle(
                this,                  /* host Activity */
                mDrawerLayout,         /* DrawerLayout object */
                R.drawable.ic_drawer,  /* nav drawer image to replace 'Up' caret */
                R.string.drawer_open,  /* "open drawer" description for accessibility */
                R.string.drawer_close  /* "close drawer" description for accessibility */
                ) {
            public void onDrawerClosed(View view) {
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            public void onDrawerOpened(View drawerView) {
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        if (savedInstanceState == null) {
            selectItem(0);
        }
    }

    ...

}
Navigation Drawerのサンプルを使用しました。DrawerLayoutをVerticalDrawerLayoutに、ActionBarDrawerToggleをActionBarVerticalDrawerToggleに置き換えました。

activity_main.xml
<android.support.v4.widget.VerticalDrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ListView
        android:id="@+id/top_drawer"
        android:layout_width="match_parent"
        android:layout_height="240dp"
        android:layout_gravity="top"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>
</android.support.v4.widget.VerticalDrawerLayout>
DrawerLayoutをVerticalDrawerLayoutに、android:layout_gravityを"top"に変更します。

実行


上からスワイプまたは左上の画像をタップで、Navigation Drawerが上側から表示されました∩( ´∀` )∩
android:layout_gravityを"bottom"、ActionBarVerticalDrawerToggle#setGravity()にGravity.BOTTOMを設定することで下側からも表示できます。


まとめ
Navigation Drawerの上下表示はまだしも、右側表示はできるようにしないと右手だけで操作する人(私です)は左からスワイプするという操作が難しいので不便。。。

ソース
https://github.com/lilylight/VerticalNavigationDrawer