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

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

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

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

Q&A

解決済

2回答

2719閲覧

ListFragmentのアイテムを削除すると、一つ下のアイテムが重なって表示される

tarofess

総合スコア127

Android

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

0グッド

0クリップ

投稿2015/10/13 01:47

編集2015/10/13 08:56

ListFragmentの一番上のアイテムを削除すると、一つ下のアイテムが一番上のアイテムに重なって表示されてしまいます。現在リストのアイテム数は2つあり、2つ目のアイテムのみを削除するとアイテム同士が重なったりということはないのですが、2つ目のアイテムの表示が少し薄くなります。
動作を見る限り実際アイテムは消されているが、描画が残ったままのように思います。
ListView#invalidateViews()や、Adapter#clear、Adapter#addAllなどを試したのですがどれもうまくいきません。どうすれば指定したListFragmentのアイテムを削除することができるでしょうか?下記にソースコードを記します。

Java

1public class IPCartProductData { 2 private Bitmap mProductImage; 3 private String mProductName; 4 private int mProductPrice; 5 6 public Bitmap getProductImage() { 7 return mProductImage; 8 } 9 10 public String getProductName() { 11 return mProductName; 12 } 13 14 public int getProductPrice() { 15 return mProductPrice; 16 } 17 18 public void setProductImage(Bitmap mProductImage) { 19 this.mProductImage = mProductImage; 20 } 21 22 public void setProductName(String mProductName) { 23 this.mProductName = mProductName; 24 } 25 26 public void setProductPrice(int mProductPrice) { 27 this.mProductPrice = mProductPrice; 28 } 29} 30 31 32public class IPCartFragment extends ListFragment { 33 public static IPCartProductAdapter adapter; 34 35 @Override 36 public void onViewCreated(View view, Bundle savedInstanceState) { 37 super.onViewCreated(view, savedInstanceState); 38 39 ListView cartListView = (ListView)view.findViewById(android.R.id.list); { 40 List<IPCartProductData> itemList = new ArrayList<>(); 41 42 IPCartProductData customCartData1 = new IPCartProductData(); 43 customCartData1.setProductImage(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); 44 customCartData1.setProductName("ハンバーガー"); 45 customCartData1.setProductPrice(120); 46 47 IPCartProductData customCartData2 = new IPCartProductData(); 48 customCartData2.setProductImage(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); 49 customCartData2.setProductName("コーラ"); 50 customCartData2.setProductPrice(80); 51 52 itemList.add(customCartData1); 53 itemList.add(customCartData2); 54 55 adapter = new IPCartProductAdapter(getActivity(), android.R.layout.simple_expandable_list_item_1, itemList); 56 57 cartListView.setAdapter(adapter); 58 } 59 } 60} 61 62 63public class IPCartProductAdapter extends ArrayAdapter <IPCartProductData> { 64 private static List<IPCartProductData> productData; 65 private LayoutInflater mLayoutInflater; 66 67 public IPCartProductAdapter(Activity activity, int textViewResourceId, List<IPCartProductData> objects) { 68 super(activity, textViewResourceId, objects); 69 70 productData = objects; 71 mLayoutInflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 72 } 73 74 @Override 75 public View getView(final int position, View convertView, final ViewGroup parent) { 76 IPCartProductData item = getItem(position); 77 78 if (null == convertView) { 79 convertView = mLayoutInflater.inflate(R.layout.list_item_cart, null); 80 } 81 82 ImageView productImageView = (ImageView)convertView.findViewById(R.id.imageViewProductImageInCart); { 83 productImageView.setImageBitmap(item.getProductImage()); 84 } 85 86 TextView productNameTextView = (TextView)convertView.findViewById(R.id.textViewProductNameInCart); { 87 productNameTextView.setText(item.getProductName()); 88 } 89 90 TextView productAmountTextView = (TextView)convertView.findViewById(R.id.textViewProductAmount); { 91 productAmountTextView.setText(String.valueOf(item.getAmountOfProduct())); 92 } 93 94 TextView productPriceTextView = (TextView)convertView.findViewById(R.id.textViewProductPriceInCart); { 95 productPriceTextView.setText(String.valueOf(item.getProductPrice())); 96 } 97 98 Button productDeleteButton = (Button)convertView.findViewById(R.id.buttonDeleteProductInCart); { 99 productDeleteButton.setOnClickListener(new View.OnClickListener() { 100 @Override 101 public void onClick(View v) { 102 productData.remove(position); 103 IPCartFragment.adapter.notifyDataSetChanged(); 104 105 } 106 }); 107 } 108 109 return convertView; 110 } 111}

ちなみに上記のコードのようにListFragmentを継承したIPCartFragmentのフィールドにstaticなカスタムアダプターの変数を置き、他のクラスでListViewのデータを変更した時にIPCartFragmentのstaticなカスタムアダプターの変数を参照して更新をかけるというやり方は正しいやり方でしょうか?(IPCartProductAdapterクラスのproductDeleteButtonのOnClickListener内で行っています)
色々と質問が多くて申し訳ないのですが、どなたか分かる方がいれば教えていただきたいです。
すみませんが、宜しくお願いします。

イメージ説明

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

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

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

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

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

guest

回答2

0

どうすれば指定したListFragmentのアイテムを削除することができるでしょうか?

ソースコードを拝見しましたが,superクラス(ArrayAdapter)のメソッド,自分のクラス(IPCartProductAdapter)のメソッドを使い分けられていないようです.
superクラスの要素を参照するのか,IPCartProductAdapterの要素を参照するのか明確にしましょう.

ちなみに上記のコードのようにListFragmentを継承したIPCartFragmentのフィールドにstaticなカスタムアダプターの変数を置き、他のクラスでListViewのデータを変更した時にIPCartFragmentのstaticなカスタムアダプターの変数を参照して更新をかけるというやり方は正しいやり方でしょうか?

正しくありません.今回のように Adapter 内のクラス View.OnClickListener などから,notifyDataSetChanged() を呼ぶときには,親を参照するために IPCartProductAdapter.this を使って参照します.

superクラスの要素を参照する形で書き直したものを載せます.

Java

1 2public class IPCartFragment extends ListFragment { 3 // static にすべきではありません 4 // 参照されないなら不要です 5 // public IPCartProductAdapter adapter; 6 7 // 明確な理由がなければ onCreate() で setAdapter() してよいでしょう 8/* 9 @Override 10 public void onViewCreated(View view, Bundle savedInstanceState) { 11 super.onViewCreated(view, savedInstanceState); 12 13 ListView cartListView = (ListView)view.findViewById(android.R.id.list); { 14 List<IPCartProductData> itemList = new ArrayList<>(); 15 16 IPCartProductData customCartData1 = new IPCartProductData(); 17 customCartData1.setProductImage(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); 18 customCartData1.setProductName("ハンバーガー"); 19 customCartData1.setProductPrice(120); 20 21 IPCartProductData customCartData2 = new IPCartProductData(); 22 customCartData2.setProductImage(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); 23 customCartData2.setProductName("コーラ"); 24 customCartData2.setProductPrice(80); 25 26 itemList.add(customCartData1); 27 itemList.add(customCartData2); 28 29 adapter = new IPCartProductAdapter(getActivity(), android.R.layout.simple_expandable_list_item_1, itemList); 30 31 cartListView.setAdapter(adapter); 32 } 33*/ 34 35 @Override 36 public void onCreate(Bundle savedInstanceState) { 37 super.onCreate(savedInstanceState); 38 39 List<IPCartProductData> itemList = new ArrayList<>(); 40 41 IPCartProductData customCartData1 = new IPCartProductData(); 42 customCartData1.setProductImage(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); 43 44 customCartData1.setProductName("ハンバーガー"); 45 customCartData1.setProductPrice(120); 46 47 IPCartProductData customCartData2 = new IPCartProductData(); 48 customCartData2.setProductImage(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); 49 customCartData2.setProductName("コーラ"); 50 customCartData2.setProductPrice(80); 51 52 itemList.add(customCartData1); 53 itemList.add(customCartData2); 54 55 // adapter = new IPCartProductAdapter(getActivity(), android.R.layout.simple_expandable_list_item_1, itemList); 56 57 // cartListView.setAdapter(adapter); 58 59 // ListFragment を使うのであれば 便利なメソッドがあります 60 // 外部から参照しないのであればこれで十分でしょう 61 setListAdapter(new IPCartProductAdapter(getContext(), R.layout.list_item_cart, itemList)); 62 } 63} 64 65 66class IPCartProductAdapter extends ArrayAdapter<IPCartProductData> { 67 // static にすべきではありません 68 // private static List<IPCartProductData> productData; 69 70 // -> 書くならこう書くべきです 71 // private List<IPCartProductData> productData; 72 73 // 今回は ArrayAdapter を継承しているため スーパークラスのメソッドを上手く使ってあげると 74 // メンバ変数を用意せずとも きれいに書くことができます 75 76 private LayoutInflater mLayoutInflater; 77 78 // ArrayAdapter クラスは Context を 要求しているので Activity を渡す必要もないです 79/* 80 public IPCartProductAdapter(Activity activity, int textViewResourceId, List<IPCartProductData> objects) { 81 super(activity, textViewResourceId, objects); 82 83 // productData = objects; 84 mLayoutInflater = LayoutInflater.from(context); 85 } 86*/ 87 // こちらが適切でしょう 88 public IPCartProductAdapter(Context context, int textViewResourceId, List<IPCartProductData> objects) { 89 super(context, textViewResourceId, objects); 90 91 // productData = objects; 92 mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 93 } 94 95 @Override 96 public View getView(final int position, View convertView, final ViewGroup parent) { 97 // このメソッドは ArrayAdapter が持っているメソッドです 98 // あなたの productData から消しても ArrayAdapter のリストからは上手く消えてくれません 99 // もちろん ArrayAdapter の中のリストを適切に管理すればこれで十分です 100 IPCartProductData item = getItem(position); 101 102 // もしメンバ変数として productData を利用するなら 上のgetItem()の代わりに こう書きます 103 // IPCartProductData item =productData.get(position); 104 105 106 107 if (null == convertView) { 108 convertView = mLayoutInflater.inflate(R.layout.list_item_cart, null); 109 } 110 111 ImageView productImageView = (ImageView) convertView.findViewById(R.id.imageViewProductImageInCart); 112 //{ 113 productImageView.setImageBitmap(item.getProductImage()); 114 // } 115 116 117 // わざわざ {} でブロック分けする必要もなさそうです 118 119 TextView productNameTextView = (TextView) convertView.findViewById(R.id.textViewProductNameInCart); 120 //{ 121 productNameTextView.setText(item.getProductName()); 122 //} 123 124 TextView productAmountTextView = (TextView) convertView.findViewById(R.id.textViewProductAmount); 125 //{ 126 // 今回のソースコードではこのメソッドが呼べないので コメントアウト 127 // productAmountTextView.setText(String.valueOf(item.getAmountOfProduct())); 128 //} 129 130 TextView productPriceTextView = (TextView) convertView.findViewById(R.id.textViewProductPriceInCart); 131 //{ 132 productPriceTextView.setText(String.valueOf(item.getProductPrice())); 133 //} 134 135 Button productDeleteButton = (Button) convertView.findViewById(R.id.buttonDeleteProductInCart); 136 //{ 137 productDeleteButton.setOnClickListener(new View.OnClickListener() { 138 @Override 139 public void onClick(View v) { 140 // これでは IPCartProductAdapter の productData からは消去されますが 141 // ArrayAdapter に渡してあるリストからは消えません 142 // productData.remove(position); 143 144 // 素直に親のメソッドを呼んであげましょう 145 IPCartProductAdapter.this.remove(IPCartProductAdapter.this.getItem(position)); 146 147 // IPCartFragment.adapter.notifyDataSetChanged(); 148 // notifyDataSetChanged() を呼ぶのは正しいです 149 IPCartProductAdapter.this.notifyDataSetChanged(); 150 } 151 }); 152 //} 153 154 return convertView; 155 } 156} 157 158class IPCartProductData { 159 private Bitmap mProductImage; 160 private String mProductName; 161 private int mProductPrice; 162 163 public Bitmap getProductImage() { 164 return mProductImage; 165 } 166 167 public String getProductName() { 168 return mProductName; 169 } 170 171 public int getProductPrice() { 172 return mProductPrice; 173 } 174 175 public void setProductImage(Bitmap mProductImage) { 176 this.mProductImage = mProductImage; 177 } 178 179 public void setProductName(String mProductName) { 180 this.mProductName = mProductName; 181 } 182 183 public void setProductPrice(int mProductPrice) { 184 this.mProductPrice = mProductPrice; 185 } 186}

投稿2015/10/13 16:50

編集2015/10/14 05:28
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

tarofess

2015/10/14 02:56

ご回答ありがとうございます。 一つ一つの丁寧なご指導誠に感謝しています。 ソースコードがかなり綺麗になり見通しが良くなりました。 しかし削除ボタンを押してみるとアイテム同士が重なってしまいました。 ここで質問なのですが、IPCartProductAdapterクラスのコンストラクタの mLayoutInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); のactivityはどこから来たのでしょうか?(contextでいいでしょうか?) また、「親を参照するために IPCartProductAdapter.this を使って参照します」とありますが、 親を参照するには IPCartProductAdapter.super ではないということに少しモヤモヤしています。ちょっとした疑問なのですが、他の例えばArrayAdapter以外の何らかのクラスを継承したクラスの親を参照するにも .this を使って参照するというのが一般的な手法なのでしょうか? 今回のこの削除したアイテムが重なってしまうのはプロジェクトでFragmentTabHostを使っているのが関係しているのかな?と個人的に少し思ったりしています......。
退会済みユーザー

退会済みユーザー

2015/10/14 05:39 編集

書いた時点で問題が解決したことを読んでませんでした.とりあえず書いたものは残しておきます. > 今回のこの削除したアイテムが重なってしまうのはプロジェクトでFragmentTabHostを使っているのが関係しているのかな?と個人的に少し思ったりしています......。 こちらの環境では正常動作しますので,他の要因(外部クラスから内容をいじったりが上手くいっていないなど)が考えられます.まったくその通りだと思われます.FragmentTabHostを使うことで,Fragment in Fragmentというパターンが出来上がります.このパターンは管理が難しく,問題がどこに潜んでいるのか見つけにくいです. たとえば,http://y-anz-m.blogspot.fi/2013/04/fragment-in-fragment.htmlなどは,再利用しないことで,問題が解決したと書いてありますね. 可能であればTabも含めた,あなたの完全なソースコードを上げてください. > activityはどこから来たのでしょうか? 修正し忘れました.context.getSystemService()で良いです.ラップメソッドである mLayoutInflater = LayoutInflater.from(context) を使うとより美しいでしょう(個人的な感覚ですが.) > 親を参照するには IPCartProductAdapter.super ではないということに少しモヤモヤしています。「親を参照するために IPCartProductAdapter.this を使って参照します」 親というのは不適切ですね.親ではありませんね.「外部クラスを参照するために」ですね.私の説明が不明瞭でした.すみません.修正しておきます. IPCartProductAdapterからIPCartProductAdapterを参照するときには,"this.---" を使います.このthisはしばしば省略されます. IPCartProductAdapterからArrayAdapterを参照するときには,"super.---"を使います. 内部クラス(今回のOnClickListener)から外部クラス(IPCartProductAdapter)を参照するには,"IPCartProductAdapter.this.---"を使います. 今回の,getItem()ではIPCartProductAdapterのメソッドを呼んでいます.IPCartProductAdapterのgetItem()なんてソースコードに書いていませんが,存在しています.特にOverrideしていないときは,extendsされた子供(IPCartProductAdapter)は親(ArrayList)の同じメソッド(getItem())を呼ぶだけのメソッドになっています. 私の説明ミスで疑問が浮かんでしまったようですが,これでちょっとした疑問の方は解決したでしょうか.
tarofess

2015/10/14 06:17

はい、無事FragmentTabHost周りを修正して問題が解決できました。 IPCartProductAdapter.thisは外部クラスを参照するという意味合いだったのですね。理解することができました。 自分のコードではstaticを多用していたり無駄な書き方をしているので、設計についても見直したいと思います。この度は誠にありがとうございました。
退会済みユーザー

退会済みユーザー

2015/10/14 07:12

解決してよかったです.ViewHolderについて調べるともっと考慮のよいAdapterが作れます.ぜひ改良を加えていってください.
tarofess

2015/10/14 08:43

ViewHolder、調べてみます。色々と教えてくださりありがとうございます。
guest

0

ベストアンサー

リストをあえてフィールドで保持する必要ないと思います。
ArrayAdapter#removeを使うことで対象データは削除はされます。

投稿2015/10/13 02:14

yona

総合スコア18155

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

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

tarofess

2015/10/13 03:15

ご回答ありがとうございます。確かに、IPCartProductAdapterクラスはArrayAdapterを継承しているのでわざわざ他のフィールドのクラスでそのArrayAdapterを保持する必要はなかったですね。しかしsetOnClickListener内で remove(productData.get(position)); notifyDataSetChanged(); としても依然アイテム同士が重複してしまいます。。。
yona

2015/10/13 04:06

notifyDataSetChanged();をコメントアウトしてみてはいかがでしょうか。 重なっている状態のスクリーンショット等はいただけないでしょうか。
tarofess

2015/10/13 08:59

notifyDataSetChanged(); をコメントアウトしても重なったままでした。 スクリーンショット貼りました。 この画像はハンバーガーのアイテムを削除した後の状態です。削除したハンバーガーがうっすらと残り、削除のため上にずれたコーラと重なってしまっています。 TabやListでFragmentを使っていることが原因でしょうか......?
yona

2015/10/13 11:21

ありがとうございます。 private static List<IPCartProductData> productData;を削除することはできますか?
tarofess

2015/10/14 02:57

はい、private static List<IPCartProductData> productData; を削除しました。
yona

2015/10/14 03:21

問題の切り分けをします。 ・タブホストで使われているフラグメントをカートだけにしてください。
tarofess

2015/10/14 04:31

カートだけにすると正常に削除することができました! やはりTabHostが問題だったのですね。 しかしタブは使いたいので、自分でも少し調べてみます。
yona

2015/10/14 04:48

最初に考えるべきでした。申し訳ない フラグメントをセットしているところが怪しいです。二重になっていないかを確認するといいでしょう。
tarofess

2015/10/14 04:57

いえいえ、お力添え頂き感謝しています。 ご指摘の通りFragmentをセットしているところが原因でした。 FragmentTabHostをセットする前にFragmentTransaction#addでタブに表示される最初の画面を追加していました。addしなくても最初にセットしたタブをFragmentTabHostでは表示してくれるのですね。 無事解決することができて大変うれしいです。誠にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問