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

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

ただいまの
回答率

87.59%

Android ViewPager でFragmentのImageViewを切り替える

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,812

score 6

解決できない問題があり、至急質問させて頂きたいです。
Android StudioでECサイト型のアプリ開発を行なっています。 
その商品詳細画面で、商品の写真を3枚、クリック又はスワイプで切り替える動作を行いたいです。
viewpagerでFragmentを3つ用意して、Fragment毎にimageviewを、photo1 photo2 photo3 を用意しています。
imageのpngデータはURLから取ってくる予定です。
urlから画像を取得してimageにsetしたいのですが、fragmentの3つ目だけ、参照先のfragmentのphoto3がないとエラーが出ます。
void android.widget.ImageView.setImageBitmap(android.graphics.Bitmap)' on a null object reference  ....

以下ni
fragmewntを格納してadapterに繋いでいますが、この中で3つ目のfragmentだけがどうして null object になるのかわかりません。
val fragments = arrayListOf(Product_photo1Fragment(), Product_photo2Fragment(), Product_photo3Fragment())

お気付きのことなどありましたら、教えて頂けると幸いです。
よろしくお願いいたします。

以下にコードを記載いたします。

adapter はこちら

public class product_detail_adapter(fm: FragmentManager?, private  var fragments: ArrayList<Fragment>) : FragmentPagerAdapter(fm) {

    lateinit var fragment : Fragment

    init {
        getItem(0)
    }

    override fun getCount(): Int {


        return fragments.size
    }

    override fun getItem(position: Int): Fragment {

        return fragments[position]
    }

表示するActivity のviewpagerの部分 image_1,image_2, image_3が画像のurlがstringで格納されている

 //ここからviewpager処理
                    var current_page = 1

                    val pager = findViewById<ViewPager>(R.id.viewPager)
                    val fragments = arrayListOf(Product_photo1Fragment(), Product_photo2Fragment(), Product_photo3Fragment())

                    val adapter =  product_detail_adapter(supportFragmentManager, fragments)

                    pager.adapter = adapter



                    val url1 = URL("${image_1}")
                    val tlstream1 = url1.openStream()
                    val mbitmap1 =BitmapFactory.decodeStream(tlstream1)
                    photo1.setImageBitmap(mbitmap1)

                    val url2 = URL("${image_2}")
                    val tlstream2 = url2.openStream()
                    val mbitmap2 =BitmapFactory.decodeStream(tlstream2)
                    photo2.setImageBitmap(mbitmap2)

                    val url3 = URL("${image_3}")
                    val tlstream3 = url3.openStream()
                    val mbitmap3 =BitmapFactory.decodeStream(tlstream3)
                    photo3.setImageBitmap(mbitmap3)

Fragmentの1つ 3つあるが内容はそれぞれ変数名以外は同じ

// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Activities that contain this fragment must implement the
 * [Product_photo3Fragment.OnFragmentInteractionListener] interface
 * to handle interaction events.
 * Use the [Product_photo3Fragment.newInstance] factory method to
 * create an instance of this fragment.
 *
 */
class Product_photo3Fragment : Fragment() {
    private var param1: String? = null
    private var param2: String? = null
  //  private var listener: OnFragmentInteractionListener? = null

   // override fun onCreate(savedInstanceState: Bundle?) {
      //  super.onCreate(savedInstanceState)
      //  arguments?.let {
      //      param1 = it.getString(ARG_PARAM1)
      //      param2 = it.getString(ARG_PARAM2)
      //  }
   // }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_product_photo3, container, false)
    }

   // fun onButtonPressed(uri: Uri) {
    //    listener?.onFragmentInteraction(uri)
    //}

   // override fun onAttach(context: Context) {
    //    super.onAttach(context)
     //   if (context is OnFragmentInteractionListener) {
      //      listener = context
      //  } else {
      //      throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener")
      //  }
    //}

    //override fun onDetach() {
    //    super.onDetach()
     //   listener = null
    //}

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     *
     *
     * See the Android Training lesson [Communicating with Other Fragments]
     * (http://developer.android.com/training/basics/fragments/communicating.html)
     * for more information.
     */
  //  interface OnFragmentInteractionListener {
   //     fun onFragmentInteraction(uri: Uri)
   // }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment Product_photo3Fragment.
         */
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            Product_photo3Fragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}

fragmentのXML こちらもそれぞれ変数名以外は同じ

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".Product_photo3Fragment">


    <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent" android:id="@+id/photo3"
            android:scaleType="centerCrop" app:srcCompat="@drawable/pic_product_07"/>


</LinearLayout>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

ViewPagerが保持するView(Fragment)のキャッシュは、デフォルトでは「今表示しているView+左右のViewの計3つ」です。ですので最初のページを表示した段階では、右隣の2ページ目までしか読み込まれず3ページ目のViewはまだ生成されていません。

ですので、各ページのViewに関する処理は、各Fragment内で行うようにするのがベストです。Activity(Adapter)側からは画像のURLだけを渡して、Fragment側で表示される際に読み込んでImageViewに表示されるようにします。

  • Activity側
val fragments = arrayListOf(
    Product_photo1Fragment().apply { arguments = bundleOf("url" to image_1) }, 
    Product_photo2Fragment().apply { arguments = bundleOf("url" to image_2) }, 
    Product_photo3Fragment().apply { arguments = bundleOf("url" to image_3) }
)
  • Fragment側
override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    val url = requireArguments().getString("url")
    // urlから画像を読み込み...
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/14 15:07

    教えて頂いた通りの実装で期待の挙動が実現できました。
    各ページのViewの処理はそれぞれで行わないといけないということがわかってよかったです。
    ありがとうございました。

    キャンセル

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

  • ただいまの回答率 87.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る