質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Q&A

解決済

1回答

1536閲覧

LinearLayoutManager継承クラスで、前のビューを再表示しようとすると描画が切れたり、タップイベントが取れなくなる

退会済みユーザー

退会済みユーザー

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

0グッド

0クリップ

投稿2018/09/22 16:50

前提・実現したいこと

ビューの動きを自分で制御する必要があるため、LinearLayoutManagerを継承したクラスを作成し、scrollVerticallyBy()内でビューの作成・削除を制御しています。
画面を上から下へスクロールし、上にあるビューを再表示しようとすると、上部しか表示されない・タップイベントも表示領域分しか取れないといった現象が起きています。
下から上へスクロールし、下からビューを表示する場合には起きません。
何故描画が切れるのか?が聞きたいことになります。

発生している問題・エラーメッセージ

上からスクロールするとき、再生成されるビューの表示が途切れる
イメージ説明

該当のソースコード

Java

1package com.example.myapplication; 2 3import android.content.Context; 4import android.support.v7.widget.LinearLayoutManager; 5import android.support.v7.widget.RecyclerView; 6import android.view.View; 7 8/** 9 * カスタムレイアウトマネージャ 10 */ 11public class CustomLinearLayoutManager extends LinearLayoutManager { 12 /** 13 * コンストラクタ 14 */ 15 public CustomLinearLayoutManager(Context context) { 16 super(context); 17 } 18 19 /** 20 * コンストラクタ 21 */ 22 public CustomLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { 23 super(context, orientation, reverseLayout); 24 } 25 26 /** 27 * {@inheritDoc} 28 */ 29 @Override 30 public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { 31 final int count = getChildCount(); 32 if (count == 0) { 33 return 0; 34 } 35 36 // 表示されているビューのうち、最初のビューと最後のビュー 37 View firstView = getChildAt(0); 38 View lastView = getChildAt(getChildCount() - 1); 39 40 if (firstView == null || lastView == null) { 41 return 0; 42 } 43 44 int firstPosition = getPosition(firstView); 45 int lastPosition = getPosition(lastView); 46 47 // 最初の項目が下へ行かないようにする 48 if (firstPosition == 0) { 49 final int viewTop = firstView.getTop(); 50 if (viewTop - dy > getPaddingTop()) { 51 dy = viewTop - getPaddingTop(); 52 } 53 } 54 // 最後の項目が上へ行かないようにする 55 if (lastPosition == getItemCount() - 1) { 56 final int viewBottom = lastView.getTop() + lastView.getMeasuredHeight(); 57 if (viewBottom - dy < getHeight()) { 58 dy = viewBottom - getHeight(); 59 } 60 } 61 62 // ビューの座標を確定する 63 for (int i = 0; i < count; ++i) { 64 View view = getChildAt(i); 65 if (view == null) { 66 continue; 67 } 68 69 view.setTop(view.getTop() - dy); 70 } 71 72 if (dy > 0) { 73 // 上へスクロール(通常) 74 removeFirstView(recycler); 75 76 addLastView(recycler); 77 } else { 78 // 下へスクロール(逆) 79 removeLastView(recycler); 80 81 addFirstView(recycler); 82 } 83 84 return dy; 85 } 86 87 /** 88 * 最初のビューを削除する 89 * 90 * @param recycler Recycler 91 */ 92 private void removeFirstView(RecyclerView.Recycler recycler) { 93 final int count = getChildCount(); 94 if (count == 0) { 95 return; 96 } 97 98 final View firstView = getChildAt(0); 99 if (firstView == null) { 100 return; 101 } 102 103 if (firstView.getTop() + firstView.getMeasuredHeight() < 0) { 104 removeAndRecycleView(firstView, recycler); 105 } 106 } 107 108 /** 109 * 最後のビューを削除する 110 * 111 * @param recycler Recycler 112 */ 113 private void removeLastView(RecyclerView.Recycler recycler) { 114 final int count = getChildCount(); 115 if (count == 0) { 116 return; 117 } 118 119 final View lastView = getChildAt(count - 1); 120 if (lastView == null) { 121 return; 122 } 123 124 if (lastView.getTop() > getHeight()) { 125 removeAndRecycleView(lastView, recycler); 126 } 127 } 128 129 /** 130 * 最初にビューを追加する 131 * 132 * @param recycler Recycler 133 */ 134 private void addFirstView(RecyclerView.Recycler recycler) { 135 final int count = getChildCount(); 136 if (count == 0) { 137 return; 138 } 139 140 final View firstView = getChildAt(0); 141 if (firstView == null) { 142 return; 143 } 144 145 final int firstIndex = findFirstVisibleItemPosition(); 146 if (firstIndex > 0 && firstView.getTop() > 0) { 147 View view = recycler.getViewForPosition(firstIndex - 1); 148 addView(view, 0); 149 150 measureChildWithMargins(view, 0, 0); 151 152 final int left = getPaddingLeft(); 153 final int right = getWidth() - getPaddingRight(); 154 final int bottom = firstView.getTop(); 155 final int top = bottom - view.getMeasuredHeight(); 156 layoutDecorated(view, left, top, right, bottom); 157 158 view.setLayoutParams(view.getLayoutParams()); 159 } 160 } 161 162 /** 163 * 最後にビューを追加する 164 * 165 * @param recycler Recycler 166 */ 167 private void addLastView(RecyclerView.Recycler recycler) { 168 final int count = getChildCount(); 169 if (count == 0) { 170 return; 171 } 172 173 final View lastView = getChildAt(count - 1); 174 if (lastView == null) { 175 return; 176 } 177 178 final int lastIndex = findLastVisibleItemPosition(); 179 if (lastIndex < getItemCount() - 1 && lastView.getTop() + lastView.getMeasuredHeight() < getHeight()) { 180 View view = recycler.getViewForPosition(lastIndex + 1); 181 addView(view); 182 183 measureChildWithMargins(view, 0, 0); 184 185 final int left = getPaddingLeft(); 186 final int right = getWidth() - getPaddingRight(); 187 final int top = (lastView.getTop() + lastView.getMeasuredHeight()); 188 final int bottom = top + view.getMeasuredHeight(); 189 layoutDecorated(view, left, top, right, bottom); 190 } 191 } 192}

試したこと

別途setLayoutParamなどしてみたが意味なし

補足情報(FW/ツールのバージョンなど)

Android Studio 3.1.4
Android 8.0 (Xperia XZ, HUAWEI P10 Lite)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

子Viewのtopを変更するときに、同時にbottomの変更も行っていないのが原因ですね。 offsetTopAndBottom メソッドを使えば両方の位置をずらすことができるので、問題が解決すると思います。

なお、LayoutManagerクラスには offsetChildrenVertical というメソッドも用意されていて、こちらを使えば

java

1// ビューの座標を確定する 2for (int i = 0; i < count; ++i) { 3 View view = getChildAt(i); 4 if (view == null) { 5 continue; 6 } 7 8 view.offsetTopAndBottom(-dy); 9}

このコードは次のように1行で置き換えられます。

java

1offsetChildrenVertical(-dy);

投稿2018/09/23 00:02

kakajika

総合スコア3131

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/09/23 00:38

できました!ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問