ここ最近ググったりしたこと

NavigationDrawerの引っ張ったら出てくる奴の背景を白にした時


android - Navigation Drawer semi-transparent over status bar not working - Stack Overflow
StatusBarをtransparentなやつで今流行の
http://material-design.storage.googleapis.com/publish/v_2/material_ext_publish/0Bx4BSt6jniD7eDFoYlp1QzEwUDQ/layout_structure_sidenav1.png

http://material-design.storage.googleapis.com/publish/v_2/material_ext_publish/0Bx4BSt6jniD7SkR5bDYzaFFVVDQ/layout_structure_sidenav2.png
をやろうとした時に引っ張ったら出てくる奴の背景を白にした場合、うまく行かなかった。
他の色にしたりするとうまくいくけど、#ffffffだけは出来なくて...

解決策は上のリンクにあるやつですー。

Picassoのloadに空文字渡すと落ちる

if (!TextUtils.isEmpty(url)) {
        Picasso.with(getApplicationContext()).load(url).into((ImageView) findViewById(R.id.hoge));
}

しないといけない。
驚いたのがloadにnull渡しても落ちないけど、空文字渡すと落ちるっていうのがちょっと辛かった。

View#measureの引数

ViewGroupを拡張したViewで子のViewのmeasureを呼び出すときにdpを指定してた。
で、案の定うまく行かなくて、悩んで、ソース眺めたら引数が

measure(int widthMeasureSpec, int heightMeasureSpec)

MeasureSpecじゃねーか!って。

getChildAt(i).measure(MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));

これが多分widthが固定、heightがwrapなやつの指定がコレな気がします。

onMeasure内のViewのリサイズ処理

Modeによってリサイズできたり出来なかったりした。
the moon at dawn: カスタムビューを作る際に重要なonMeasure()とは?
参考になった。

Rippleなボタンのdrawable

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="?android:attr/colorControlHighlight">
    <item android:id="@android:id/mask">
        <color android:color="@android:color/white"/>
    </item>
    <item android:drawable="@drawable/hoge"/>
</ripple>

ListViewないのCardViewにデフォルトのRippleを当てる

無理だった。

<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:clickable="true"
    android:foreground="?android:attr/selectableItemBackground"
    android:elevation="10dp"
    card_view:cardCornerRadius="8dp">
...
</android.support.v7.widget.CardView>

こんな感じのレイアウトをトップに持ってきてもListViewの1行としてタッチイベントが取られてしまうと角を削った部分にも波が出てしまいダサくなった。
CardViewそのものにbackground付けるんだったら、そもそもCardView使うメリットが見えなくなった。

SimpleDateFormat と DateFormat

[Android]日付のフォーマットにはSimpleDateFormatを使うとよい| 手しごと
Y.A.M の 雑記帳: SimpleDateFormat ではなく android.text.format.DateFormat を使おう

これどっちが正しいのかな。
SimpleDateFormatで引数がStringのみの時にLintさんから黄色いやつ出るって書いてあるんですが、今は出ないし。
うーん。

ググるきっかけとなったのがこれ
f:id:amyu_dev:20150119182501p:plain
特定の端末で時間がHHと表示されてしまい...
これはDateFormatを使ってます。
まだ試してないですが、上の記事を読む限りSimpleDateFormatを使ったらうまくいくのかな?

最後に

まとめる気が...
今いろいろとViewを作ってるのでそのうち公開しますー

ではではー

ViewPagerの中にSwipeListViewを使うとき

タッチイベントが競合するので
SwipleListViewTouchListenerのonTouch内に
view.getParent().requestDisallowInterceptTouchEvent(true);
これ書けばいいらしい

Viewの階層やどっちが取るっていうの調べるいい機会になった。
DrawerLayoutはかなり高い層だからコレ書いても無駄無駄って言われた。
奥が深い。


android - Swipe ListView 47deg inside a fragment of ViewPager - Stack Overflow

新時代のToolBarへ

はじめに

この記事は「Android Advent Calendar 2014」の13日目の記事です。
ホントは「今さら聞けない英単語の読み方」を書きたかったんですが、非常にレベルの高い記事ばかりで...

ToolBarとは

AndroidのToolBar(新しいActionBar)メモ - Qiita
こちらの記事にもあるようにActionBarの代替品という認識でいます。

例えば、ActionBarを真ん中に置きたいとき、

<RelativeLayout 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"
                tools:context=".MainActivity">

    <android.support.v7.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:minHeight="?attr/actionBarSize"
        android:background="@color/base_actionbar"
        android:id="@+id/main_tool_bar"/>

</RelativeLayout>

f:id:amyu_dev:20141210173654j:plain
ほら簡単!
Material DesignでActionBarもヌルヌル動かないといけない時代の必須アイテムですね!

今回のエントリではToolBarのソースをざっくり眺めて必要そうな情報を書き出してみました。
基本的にpublicで@hideではないメソッドを網羅してるはずです!

popupTheme

f:id:amyu_dev:20141210174332p:plain
このようにビロ~ンって出てくるpopupItemのthemeを結構簡単に変えることが出来ます。

style

<style name="PopupMenu" parent="Base.ThemeOverlay.AppCompat">
    <item name="android:background">@color/base_actionbar</item>
    <!-- <color name="base_actionbar">#e51c23</color> -->
</style>

xmlで指定するとき

<android.support.v7.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:minHeight="?attr/actionBarSize"
        android:background="@color/base_actionbar"
        app:popupTheme="@style/PopupMenu"
        android:id="@+id/tool_bar"/>

コードで指定するとき

Toolbar toolbar = (Toolbar) findViewById(R.id.main_tool_bar);
toolbar.setTitle("Action Bar");
toolbar.setPopupTheme(R.style.PopupMenu); 
//inflateMenuでViewの更新が入ってるっぽいのでinflateMenuより前で
toolbar.inflateMenu(R.menu.menu_main);

みたいな感じで指定すると、
f:id:amyu_dev:20141210180114p:plain
おぉ、すごい。
こんな感じで中の文字の色やその他いろいろを変えられます。

Logo

toolbar.setLogo(R.drawable.ic_launcher);

f:id:amyu_dev:20141210181049p:plain
ちょっとダサい感が否めない...

TitleとSubTitle

通常のTitleとSubTitleの表示はこんな感じ

toolbar.setTitle("Action Bar");
toolbar.setSubtitle("Sub Title");

f:id:amyu_dev:20141210182720p:plain

TitleやSubTitleにstyleを適用させて上げると

<style name="TextStyle">
    <item name="android:textColor">#00ff00</item>
    <item name="android:textStyle">bold</item>
</style>

toolbar.setSubtitleTextAppearance(getApplicationContext(),R.style.TextStyle);

f:id:amyu_dev:20141210183450p:plain

その他、setSubtitleTextColorsetTitleTextColorで色は簡単に変更することが出来ます。

NavigationIcon

NavigationIconの簡単なやつ

toolbar.setNavigationIcon(R.drawable.ic_launcher);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("log", "hogehoge");
    }
});

f:id:amyu_dev:20141210184136p:plain

Menu

Menuのinflate、ClickListener

toolbar.inflateMenu(R.menu.menu_main);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
    @Override
    public boolean onMenuItemClick(MenuItem menuItem) {
        return false;
    }
});

ContentInsetsAbsoluteとContentInsetsRelative

ToolBarタグのなかにViewを追加することが出来るのは知っていると思います。
例えばこんなレイアウトにした場合

<android.support.v7.widget.Toolbar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:minHeight="?attr/actionBarSize"
    android:background="@color/base_actionbar"
    android:id="@+id/main_tool_bar">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:textSize="30sp"
        android:background="@android:color/white"
        android:textColor="@android:color/black"
        android:gravity="center"
        android:text="hogeeeeee"/>

</android.support.v7.widget.Toolbar>

f:id:amyu_dev:20141210190232p:plain
デフォルトのToolBarではこのように左が空いてる状態になります。
レイアウトを見る限りでは、内部にあるTextViewのwidthはmatchにしているので、画面横いっぱいになることを想定しています。
ところが左に微妙なマージンが発生しています。

これの原因が
ToolBar#mContentInsetsの初期値です。

final int contentInsetStart = a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetStart,
                        RtlSpacingHelper.UNDEFINED);
mContentInsets.setRelative(contentInsetStart, contentInsetEnd);

R.styleable.Toolbar_contentInsetStartの値が16dpになっています。

そのため、きっちり左上にスタートにしたい場合は

toolbar.setContentInsetsRelative(0,画面横のサイズ);

または

<android.support.v7.widget.Toolbar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:minHeight="?attr/actionBarSize"
    android:background="@color/base_actionbar"
    app:contentInsetStart="0dp"
    android:id="@+id/main_tool_bar">
    <!-- app:contentInsetStart="0dp"これが大事 -->

    <TextView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:textSize="30sp"
        android:background="@android:color/white"
        android:textColor="@android:color/black"
        android:gravity="center"
        android:text="hogeeeeee"/>

</android.support.v7.widget.Toolbar>

にしてあげると
f:id:amyu_dev:20141210192039p:plain
このようにきっちり左上スタートになります。


今回のこの16dpというマージン、これMaterial Designのためなんですね。
Metrics & keylines - Layout - Google design guidelines
自分で16dpあけるとかしたほうが個人的にわかりやすいような気もするので、どっちがいいとは言えない感じ。

最後に

最初はタダのActionBarのラッパかなって思ってたんですけど、なんかいい感じな気がしてきました。
新規のプロジェクトからはToolBarを使っていきたいな!

あ、Twitterもよろしくお願いします...!


ではではー

ここ最近知った便利なViewまとめ

適当にまとめる気がない感じで、また!

ExpandableHeightGridView


これ何がしたいかというと、
ScrollViewの中にListViewやGridViewがあるとき、開発者的に望まれる挙動としてはScrollViewが優先されて、ListViewなどのデータは全部出ている状態かなって思います。
個人的に今までコレに似たようなことを実装しようとしていた時って、setAdapterをするタイミングで、LayoutParamを変更していました。
Items数 * (1行のViewの高さ + divider)
みたいな感じで。
それか、LinearLayoutを拡張してaddViewしまくったりとか。
ただ、今回のこれ

How to Make Android ListView or GridView Expandable inside ScrollView
非常に便利ですねー。
さすが、いちごたけさん。
あざっす。
これ、本物にマージして欲しいっす。

WrapContentHeightViewPager


Android: I am unable to have ViewPager WRAP_CONTENT - Stack Overflow
ViewPagerの特性的にheightがmatchになりますよね。
とくにScrollViewの中にViewPagerを入れたい時とか普通のまんまだと望んだレイアウトになってくれません。
で、登場するのがこのWrapContentHeightViewPager。
非常に便利っす。

NoSwipeViewPager


ただ、ViewPagerのSwipeを無効化しただけです。
なんとなく、必要に迫られて...

SwipeListView


47deg/android-swipelistview · GitHub
便利だけど、Android的なこと考えると実装はしたくない...!
デザインの住み分けをお願いしたいところです。

最後に

ViewPagerのTabとIndicatorを作っていたら片方が動かなくて超頭がはてなってました。
で、見るとOnPageChangeListenerを両方共にセットしてたという。
同じViewPagerに対してTab、Indicatorそれぞれにセットしてしまってて最後にセットした方にしか...な感じでした。
親を作らねばという。
はー

いろんなことを知りたいなー
ではではー

2行くらいのTips

あるアプリを作ってて、結構初めて知ったことが多かったのでそれをサクッと。
全部2行以内で終わるので。

Screen Captcha撮ろうとしたら自作Viewの文字が描画されなんだ

一番上のViewにsetDrawingCacheEnabledをTrueにしても自作Viewだけ表示されない部分があった。
自作Viewに対してもsetDrawingCacheEnabledをTrueにしたらうまく行った。

LINEにIntent投げてもうまく行かなかった。

UTF-8エンコーディングしないといけなかった。

FacebookのPermissionのReview待つのがダルい

アプリで権限の追加をしたほうが早かった。

TabWidgetで縦タブ、高さをwrapにしたい場合

addViewをOverrideしてLayoutParamを変えてsetOrientationをVERTICALにすればさくっと終わった。

リストに対して最後の行にある更に読み込むボタン

Footerに追加すれば良い感じで楽だった。

ListViewの描画タイミング

setAdapterしたときかな?

自作ActionBarの自作閉じるボタン

普通に閉じるViewの範囲だと小さすぎて操作性が悪いから大きいViewをかぶせた。

ListViewのdividerの高さ

1px

最後に

まとめる気も何も感じさせない…
ではではー

Disrupt SF 2014 - TechCrunch に参加してきた


9月4日からサンフランシスコに行ってきました!
とりあえず、もろもろの報告は置いといて、ハッカソンのレポートでも!

Disrupt SF 2014 - TechCrunch

f:id:amyu_dev:20140906124318j:plain
f:id:amyu_dev:20140906165837j:plain
とりあえず、人がめっちゃ多かった!
いやーすごかったです。
場所は超大きな倉庫のような感じでした。
とりあえず、サイズがアメリカン!

正直どうだったか、かなり忘れかけててツイッターを見ながら思い出してる感じです。

ルールとしては24時間で何でもいいから作ると言った感じでした。
で、もしスポンサーのAPIを使ったりしてくれたら賞金上げるよ、みたいなノリでした。

チームで作ったよ

えーと、今回はいつもの一人開発ではなく、強力な助っ人が居てくれたおかげで作業が順調に進みました。
ODAさんには徹夜でWearのアプリ作ってもらったり、知見ためてもらったり、発表してもらったり超助かりました。
あ、どういった経緯で参加したかはまたあとで書きますー。

つくったやーつ


とりあえず、初期の方向性としてWearアプリを作ろうということでした。
で、素晴らしきODAさんによるアイデア

・電話かかってくる
・どうしてもスマホ出れない(なんか怒られてるとか超偉い人に合ってるとか)
・が、電話に出れない理由を教えたい
スマホを出さずに、腕をもじもじして返信しちゃおう

的な感じの動作をするアプリです。
ちょっと似たようなアプリを知っていましたが、ま、気にせずに。

お互い作業量がパないことになっており、時間内での完成にならなかったんです。
とりあえず、APIを叩く要因がもう一人…
今回はとくにお互いあまり知見のないWearアプリを作ったりで調べることが多かった気がします。
あと、デザインも自分たちで考えないといけなく、アプリ内のアイコンなど色んな所から切り抜いたものを使用しています。
やっぱり、今回の理想の形としては

・デザイナー
スマホアプリUI
スマホアプリBackground
・Wearアプリ

でしたねー。
来年はせめて3人で挑んでみたいなーって思ったり!

発表!

先に書いた通り、ODAさんに思いっきし頼ってしまいました。
英語できるし超すごいっす。
f:id:amyu_dev:20140907111756j:plain
f:id:amyu_dev:20140907135822j:plain

お礼

今回、インターンという形でサンフランシスコまでの旅費とかとかとかを払ってもらいました。
Miewさん、ありがとうございました!
で、そこのインターン生のODAさん(21)とチームを組んだわけです。
また一緒にコード書きたいですー。

最後に

適当にまた後でサンフランシスコの雑感を書きます。
とりあえず、時差ボケが辛い…

ではではー

真ん中を切り抜いたView

ネム。
6時とか超早起きで偉いっすね。
これから寝ますけど。

切り抜く

なんとなく、真ん中を切り抜くのって難しいなーって。
f:id:amyu_dev:20140903060324p:plain
こんな感じ!

で、コードがこんな感じ。

public static int alpha = 150;

public static Bitmap makeSquare(int x, int y, int width, int height, Bitmap bmp) {
        int w = DisplayUtil.width();
        int h = DisplayUtil.height();

        final Paint paint = new Paint();
        paint.setAntiAlias(true);

        Bitmap base;
        Canvas baseCanvas;
        if (bmp == null) {
            base = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            baseCanvas = new Canvas(base);
            baseCanvas.drawARGB(alpha, 0, 0, 0);
        } else {
            base = bmp;
            baseCanvas = new Canvas(base);
        }

        Bitmap rect = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas rectCanvas = new Canvas(rect);
        RectF rectF = new RectF(x, y, x + width, y + height);
        rectCanvas.drawRoundRect(rectF, 0, 0, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        baseCanvas.drawBitmap(rect, 0.0f, 0.0f, paint);

        rect.recycle();

        return base;
    }

いやー、実は今年の3月ちょうどこれとおんなじのつくろうとしてたんですよー。
ただ、自分の技術的にちょーっと足りなかったところとか、時間が足りなかったりで、画像を用意してたんですよね。
今作ってみるとかなりサクッと出来ちゃうあたり進化してますね!

最後に

多分次はアメリカからの更新になる気がしますー。

ではではー

ViewPagerのスクロール速度を変える

f:id:amyu_dev:20140612022524j:plain
溜まってるものを吐き出さねば。
ということで本日2本目

ViewPagerのスクロール速度

ViewPagerのsetCurrentItemを使うとき、引数は(int)か(int, boolean)です。
どちらも第1引数は何ページ目に行くか、第2引数がある方はsmoothScrollがtrue, false的な感じになっています。
で、実際に使ってみると…

まぁ、キモいんです。
キモいというか、早い。
ViewPagerをsetCurrentItemでページ移動した時、左右の移動が早すぎてめくれる感覚というより、Viewが入れ替わってるだけといったような印象を受けます。
そう、Scroll速度が早過ぎるんです。

ということで、タイトル回収。
ViewPagerのScroll速度を変えていきます。

とりあえず、ググる

"android ViewPager setCurrentItem scroll speed"

android - ViewPager setCurrentItem(pageId, true) does NOT smoothscroll - Stack Overflow

はい、こんな感じですね。

で、パk、参考にしながら作ったのがこんな感じですね。

public class CustomViewPager extends ViewPager {

    /**
     * @param context
     */
    public CustomViewPager(Context context) {
        super(context);
        init();
    }

    /**
     * @param context
     * @param attrs
     */
    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    /**
     * 初期化
     */
    private void init() {
        try {
            Field mScroller;
            mScroller = ViewPager.class.getDeclaredField("mScroller");
            mScroller.setAccessible(true);
            Interpolator sInterpolator = new AccelerateInterpolator();
            FixedSpeedScroller scroller = new FixedSpeedScroller(this.getContext(), sInterpolator);
            mScroller.set(this, scroller);
        } catch (NoSuchFieldException e) {
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        }
    }

    /**
     * Scrollの速度遅くする奴
     */
    private class FixedSpeedScroller extends Scroller {

        private static final int mDuration = 300; //ここ変えたい速度

        public FixedSpeedScroller(Context context) {
            super(context);
        }

        public FixedSpeedScroller(Context context, Interpolator interpolator) {
            super(context, interpolator);
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, mDuration);
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy) {
            super.startScroll(startX, startY, dx, dy, mDuration);
        }
    }

}

なんか、うん。
パクってゴメンナサイ。

まず、このコードのすごいというか、変なところ。

Field mScroller;
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);

いやー気持ち悪いですね。
本来のViewPagerクラスのprivateなmScrollerに直接アクセスして、変更をしているという。
それで、

mScroller.set(this, scroller);

setを行い新たなScrollerをセットしているんですね。

私、この書き方初めてだったので結構衝撃的だったり。
privateな所に直接アクセスするってところまではわかったんですが、

mScroller.setAccessible(true);

で、常にViewPagerのmScrollerに対してアクセスするってかなり気持ち悪いですよね。
とくにprivateな変数なので今後、変数名を変えられたら使えなくなっちゃったりするんですよね。
なんかあまり多用するものではないのかなとか思ったり。

最後に

zzz
おやすみなさい

ではではー

DrawerLayout内のWebView

f:id:amyu_dev:20140612000510p:plain
いい加減更新しないと忘れ去られる。
今回は短めに。

DrawerLayoutのGesture

みんな大好き、DrawerLayout。
いろんなGoogleの公式アプリでも使用されている、このレイアウト。
見た目も綺麗だし、どんどん使っていきたいところですね。

さて、DrawerLayoutって実は便利そうに見えてかなり不便だったりします。
例えば、横スクロール。
Googleで"DrawerLayout Horizontal Scroll"とググれば腐るほどStackOverFlowがヒットします。
しかし、どの解決法を読んでもあまり解決できないのが… なところ。
横スクロール自体がDrawerLayoutのGestureと被ってしまうため、DrawerLayout内の横スクロールを取ることが出来ないんです。
Oh... Shock

そう、WebViewも例外ではありません。
しかし、WebViewで表示されるコンテンツは2~3年前と比べ、圧倒的にスマホの画面対応が済んでおり、横移動することはほとんどありません。
だったら、DrawerLayoutで横スクロールがかぶること無いよね?って思うわけです。
そこが今回の軽い、軽いTips。

気持ち悪いWebView と DrawerLayout

実際に実装してみるとわかると思いますが、実はあまりうまくいかないんです。
画面対応が済んで、"横移動することがほとんどない"と言っても横移動のGesture、横移動というのは取れてしまうんです。
ということは、横移動が入った瞬間そのGestureはWebViewからDrawerLayoutのGestureになってしまいます。

例えば、横に1pxも動かさないで完璧な縦スクロールを行うことが出来るのなら、今回の問題はおきません。
ただ、自動テストやBOT出ない限り、人間は絶対に横移動を入れてしまします。
すると、その途端縦スクロールができなくなり、DrawerLayoutがキモい動作をしてしまうんです。

あまり引き伸ばすのも面倒なので解決編へ。

解決編

縦スクロールだけ強制的に行わせればいいんです。
そこで考えたのが、

       <RelativeLayout
                android:layout_width="300dp"
                android:layout_height="match_parent"
                android:layout_gravity="end">

            <ScrollView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="#00000000">

                <WebView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        />

            </ScrollView>
        </RelativeLayout>

WebView自体をScrollViewに囲ませることです。

すると、なんと!期待する動作になるんですよーーー!
そう、解決策は、ScrollViewでかこ…

では、ないんです。
実はこれ機種単位で期待通りに動かないものがあるらしんです。
Androidマスターに教えてもらいました。

実は過去に全く同じことをやったと。
その時の解決策が…

「ListViewの1列目にWebViewを入れたんだよねー」


え?
いや、確かに動くと思います…
なんというか、予想の斜め上を行くというか…
さすが、Androidマスターはものしりでした…

最後に

というのが数カ月前の出来事だったりします。
いつかまとめようと思い、普通に忘れてました。
なんというか、こういう裏ワザまだあるので適当にまとめていきます。

ではではー

ListViewでYUBIが浮いた後の座標の取り方。

なんか久しぶりに更新する気がする。

ListViewで指が浮いた後の座標

ちょっと意味がわからないとか言われたら嫌なので、説明を。
ListViewとかScrollViewはビヨ~ンって出来ますよね?
そのビヨ~ンの時の座標、指が浮いてから加速の分で動くView達の座標を取りたかったんです。
ただ、これが探しても探しても見当たらないんですよー。
onTouchEvent系はTouchした時のListenerしか無いし、onScrollはそれぞれのpositionしか取れなかったりで。
「加速分の座標ってどこ!」って半ギレしながらやっつけコードを書いてたりしました。

事態が急変したのは今日の朝。
日課にしているAndroid Weeklyを読んでいるとこんなレポジトリが。
kmshack/Android-ParallaxHeaderViewPager · GitHub
これにやりたいことがある気がする、と思い立ってずっと今日一日コードを読んだり、Twitterをしてたりしました。
で、見つけたわけです。
素晴らしい、素晴らしい解決策が!

getScrollY()

まぁまぁ、焦らずこのコードを見て下さいよ。

public int getScrollY() {
        View c = mListView.getChildAt(0);
        if (c == null) {
            return 0;
        }

        int firstVisiblePosition = mListView.getFirstVisiblePosition();
        int top = c.getTop();

        int headerHeight = 0;
        if (firstVisiblePosition >= 1) {
            headerHeight = mPlaceHolderView.getHeight();
        }

        return -top + firstVisiblePosition * c.getHeight() + headerHeight;
    }

コレを見た瞬間、10歳ぐらい脳が若返りました。
ListViewのgetCheildAt(0)で1カラム分のViewをcに入れてるんですね。
ココがキモですね。
その後topにc.getTop()をしており、1カラム分の座標を取っていこうとしているんです。
"topには常に1カラム分の座標が取れる"というのが激アツですね。

returnには現在の1カラムの座標、カラム数 * 1カラムの長さ、ヘッダーの長さをそれぞれ足して上げて、現在の座標を返しているんです。

で、onScrollが呼ばれた時にgetScrollY()を呼ぶと指が浮いてる時の座標が取れるんですね!!

最後に

思い付かなかったので、すっごい勉強になりました。
他にも

public static float clamp(float value, float max, float min) {
        return Math.max(Math.min(value, min), max);
    }

これとか、私はif文2つ使って書いてしまう気がします。
だけど、ネストを深くしたifよりも断然、↑のコードのほうが見やすいですよね。

流石っすねー。

またブログもボチボチ更新していきます。
Androidのしょうもない小ネタ、Tipsも溜まってきてるので。

ではではー