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

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

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

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

Android

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

Q&A

解決済

1回答

699閲覧

ボタンが機能するタブをつける(Empty Activity)

syosinsya109

総合スコア41

Java

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

Android

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

0グッド

0クリップ

投稿2022/12/10 11:51

前提

androidのタブレイアウトについて質問します。
タブをレイアウトして、そこにボタンを1つずつ配置しました。このボタン一つ一つにクリックイベントをつけたいと思っています。しかし、ボタンをクリックしたときにどこにクリックイベントを書けばいいのか分かりません。mainに書けないのは、タブでmainも切り替えたいためです。

実現したいこと

ボタンが機能するタブをつける

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

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference

該当のソースコード

java(main.java)

1import androidx.appcompat.app.AppCompatActivity; 2import androidx.viewpager2.widget.ViewPager2; 3 4import android.os.Bundle; 5import android.view.View; 6import android.widget.Button; 7 8import com.google.android.material.tabs.TabLayout; 9import com.google.android.material.tabs.TabLayoutMediator; 10 11public class MainActivity extends AppCompatActivity { 12 @Override 13 protected void onCreate(Bundle savedInstanceState) { 14 super.onCreate(savedInstanceState); 15 setContentView(R.layout.activity_main); 16 17 String[] hposition = {"てすと1","てすと2"}; 18 ViewPager2 pager = (ViewPager2)findViewById(R.id.pager); 19 PageAdapter adapter = new PageAdapter(this); 20 pager.setAdapter(adapter); 21 TabLayout tabs = (TabLayout)findViewById(R.id.tab); 22 new TabLayoutMediator(tabs, pager, 23 (tab, position) -> tab.setText(hposition[position]) 24 ).attach(); 25 26// Button button1 = findViewById(R.id.button1); 27// button1.setOnClickListener((View v) -> { 28// System.out.println("aaaa"); 29// }); 30// Button button2 = findViewById(R.id.button2); 31// button2.setOnClickListener((View v) -> { 32// System.out.println("aaaa"); 33// }); 34 } 35}

java(PageAdapter.java)

1import androidx.annotation.NonNull; 2import androidx.fragment.app.Fragment; 3import androidx.viewpager2.adapter.FragmentStateAdapter; 4 5public class PageAdapter extends FragmentStateAdapter { 6 //アカウント用のタブ 7 8 public PageAdapter(MainActivity fragment) { 9 super(fragment); 10 } 11 /** 12 * 指定されたタブの位置(position) に対応するタブページ(Fragment)を作成する 13 */ 14 @NonNull 15 @Override 16 public Fragment createFragment(int position) { 17 Fragment fragment = null; 18 if (position == 0) { 19 fragment = new TestPager(); 20 } else if (position == 1) { 21 fragment = new Test1Pager(); 22 } 23 return fragment; 24 } 25 /** 26 * タブの数を返す 27 */ 28 @Override 29 public int getItemCount() { 30 return 2; 31 } 32}

java(test.java)

1import androidx.fragment.app.Fragment; 2 3import android.os.Bundle; 4import android.view.LayoutInflater; 5import android.view.View; 6import android.view.ViewGroup; 7 8public class TestPager extends Fragment { 9 10 public TestPager() { 11 } 12 public static TestPager newInstance() { 13 TestPager fragment = new TestPager(); 14 return fragment; 15 } 16 @Override 17 public void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 } 20 @Override 21 public View onCreateView(LayoutInflater inflater, ViewGroup container, 22 Bundle savedInstanceState) { 23 // Inflate the layout for this fragment 24 return inflater.inflate(R.layout.activity_test_pager, container, false); 25 } 26}

java(test1.java)

1import androidx.fragment.app.Fragment; 2 3import android.os.Bundle; 4import android.view.LayoutInflater; 5import android.view.View; 6import android.view.ViewGroup; 7 8public class Test1Pager extends Fragment { 9 10 public Test1Pager() { 11 } 12 public static Test1Pager newInstance() { 13 Test1Pager fragment = new Test1Pager(); 14 return fragment; 15 } 16 @Override 17 public void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 } 20 @Override 21 public View onCreateView(LayoutInflater inflater, ViewGroup container, 22 Bundle savedInstanceState) { 23 // Inflate the layout for this fragment 24 return inflater.inflate(R.layout.activity_test1_pager, container, false); 25 } 26}

xml(activity_main.xml)

1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 xmlns:app="http://schemas.android.com/apk/res-auto" 5 xmlns:tools="http://schemas.android.com/tools" 6 android:layout_width="match_parent" 7 android:layout_height="match_parent" 8 android:gravity="center" 9 android:orientation="vertical" 10 android:padding="20dp" 11 tools:context=".MainActivity"> 12 13 <androidx.viewpager2.widget.ViewPager2 14 android:id="@+id/pager" 15 android:layout_width="0dp" 16 android:layout_height="0dp" 17 android:layout_weight="1" 18 app:layout_constraintBottom_toTopOf="@+id/tab" 19 app:layout_constraintEnd_toEndOf="parent" 20 app:layout_constraintStart_toStartOf="parent" 21 app:layout_constraintTop_toTopOf="parent" /> 22 23 <com.google.android.material.tabs.TabLayout 24 android:id="@+id/tab" 25 android:layout_width="match_parent" 26 android:layout_height="0dp" 27 app:layout_constraintBottom_toBottomOf="parent" 28 app:layout_constraintEnd_toEndOf="parent" 29 app:layout_constraintStart_toStartOf="parent" 30 app:tabSelectedTextColor="@color/teal_200" /> 31</androidx.constraintlayout.widget.ConstraintLayout>

xml(activity_test_pager.xml)

1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".TestPager"> 8 9 <Button 10 android:id="@+id/button1" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="ボタン1" 14 app:layout_constraintBottom_toBottomOf="parent" 15 app:layout_constraintEnd_toEndOf="parent" 16 app:layout_constraintStart_toStartOf="parent" 17 app:layout_constraintTop_toTopOf="parent" /> 18</androidx.constraintlayout.widget.ConstraintLayout>

xml(activity_test1_pager.xml)

1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".Test1Pager"> 8 9 <Button 10 android:id="@+id/button2" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="ボタン2" 14 app:layout_constraintBottom_toBottomOf="parent" 15 app:layout_constraintEnd_toEndOf="parent" 16 app:layout_constraintStart_toStartOf="parent" 17 app:layout_constraintTop_toTopOf="parent" /> 18</androidx.constraintlayout.widget.ConstraintLayout>

試したこと

ボタンを押したときにどこのactivityに行くのかを調べたけれど、どこにも入りませんでした。AppCompatActivityを継承しないとクリックイベントを追加できないと思うのでmain.javaしかないと思うのですが、そこに記述してしまうと、エラーが起こり、エラーを解消しても、メインのボタンが切り替えられなくなります。

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

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

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

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

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

jimbe

2022/12/10 21:31

> AppCompatActivityを継承しないとクリックイベントを追加できないと思う ボタンとアクティビティは全く関係ありません。 ボタンはフラグメントのレイアウトにあるのですから、ボタンの処理はフラグメントに書くしかありません。 フラグメントはアクティビティとは独立した部品として動作する為のもので、なるべく特定のアクティビティや他のフラグメントの存在を意識しないように設計するのが良いものです。 『リストのフラグメント』とその要素の『詳細を表示するフラグメント』があったとして、ListView 等のクリックのリスナーとして直接『詳細のフラグメント』の何かを書くのでは無く、リスナとして一旦『リストのフラグメント』磁針が受け取り、それを(フラグメントの唯一の入出力先として) ViewModel の LiveData に setValue します。『詳細のフラグメント』は予めそれを observe しておけばそのライブデータのリスナが(設定値をパラメータとして)呼び出されるので、処理としてその値を表示するようにしていれば、お互いがお互いの存在を知らなくても ViewModel が仲介して動作してくれます。
syosinsya109

2022/12/11 02:12

回答ありがとうございます。初心者過ぎて仰っていることが難しくてよく分かりません。簡単なサンプルとかありますでしょうか。
jimbe

2022/12/11 03:33

コメントに詰め込み過ぎました、すいません。質問のコードからサンプル作ってみます。
syosinsya109

2022/12/11 03:50

ありがとうございます。すごく助かります
guest

回答1

0

ベストアンサー

質問へのコメントにも書きましたが、ボタンとアクティビティは全く関係ありません。
ボタンはフラグメントのレイアウトにあるのですから、ボタンの処理はフラグメントに書くしかありませんし、そうなるためのフラグメントと言っても良いくらいです。
(ViewModel うんぬんはとりあえず無しにしました。)

質問自体とは関係ありませんが、クラス名や変数名等をテキトウにし過ぎです。
コードを理解する際に足がかりになるのは、動作に関係ない(間違っているかも知れない)コメントでは無く実際に動作するクラス名や変数名ですので、もう少し気を使われたほうが良いと思います。

MainActivity.java (PageAdapter クラスを内包)

java

1import androidx.annotation.NonNull; 2import androidx.appcompat.app.AppCompatActivity; 3import androidx.fragment.app.*; 4import androidx.viewpager2.adapter.FragmentStateAdapter; 5import androidx.viewpager2.widget.ViewPager2; 6 7import android.os.Bundle; 8 9import com.google.android.material.tabs.TabLayout; 10import com.google.android.material.tabs.TabLayoutMediator; 11 12public class MainActivity extends AppCompatActivity { 13 @Override 14 protected void onCreate(Bundle savedInstanceState) { 15 super.onCreate(savedInstanceState); 16 setContentView(R.layout.activity_main); 17 18 ViewPager2 pager = findViewById(R.id.pager); // "(ViewPager2)" とかは要りません 19 TabLayout tabs = findViewById(R.id.tab); 20 21 String[] hposition = {"てすと1","てすと2"}; 22 pager.setAdapter(new PageAdapter(this)); 23 new TabLayoutMediator(tabs, pager, (tab, position) -> tab.setText(hposition[position])).attach(); 24 } 25 26 //MainActivity でしか使わず public でなければならない理由も無いので、なるべく範囲を狭くするため 内部 static クラスに. 27 private static class PageAdapter extends FragmentStateAdapter { 28 //super() のパラメータは "fragment" ではありませんし、 MainActivity である必要もありません. 29 public PageAdapter(FragmentActivity activity) { 30 super(activity); 31 } 32 33 @NonNull 34 @Override 35 public Fragment createFragment(int position) { 36 Fragment fragment = null; 37 if (position == 0) { 38 fragment = new Page1Fragment(); 39 } else if (position == 1) { 40 fragment = new Page2Fragment(); 41 } 42 return fragment; 43 } 44 45 @Override 46 public int getItemCount() { 47 return 2; 48 } 49 } 50}

Page1Fragment.java ( 元 TestPager.java )
このクラスは (Pager では無く ) Fragment なので, クラス名を変更。
newInstance メソッドは、アダプタで直接 new しているので存在意味がありません。
onCreate や onCreateView は使わず、コンストラクタで super にレイアウトを渡し onViewCreated を使うのがお勧めです。 ( 今の Fragment#onCreateView はコンストラクタで指定したレイアウトを inflate して返すようになっています。)

Fragment#onCreateView()

デフォルトの View は、Fragmentコンストラクターを呼び出すことで返すことができます。それ以外の場合、このメソッドは null を返します。
このメソッドでレイアウトをインフレートするだけで、返されたビューで動作するロジックを onViewCreated に移動することをお勧めします。

(google 翻訳)

java

1import android.os.Bundle; 2import android.view.View; 3import android.widget.Button; 4 5import androidx.annotation.*; 6import androidx.fragment.app.Fragment; 7 8public class Page1Fragment extends Fragment { 9 10 public Page1Fragment() { 11 super(R.layout.fragment_page1); 12 } 13 14 @Override 15 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 16 super.onViewCreated(view, savedInstanceState); 17 18 Button button1 = view.findViewById(R.id.button1); 19 button1.setOnClickListener(v -> { 20 System.out.println("aaaa"); 21 }); 22 } 23}

Page2Fragment.java ( 元 Test1Pager.java )

java

1import android.os.Bundle; 2import android.view.View; 3import android.widget.Button; 4 5import androidx.annotation.*; 6import androidx.fragment.app.Fragment; 7 8public class Page2Fragment extends Fragment { 9 public Page2Fragment() { 10 super(R.layout.fragment_page2); 11 } 12 13 @Override 14 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 15 super.onViewCreated(view, savedInstanceState); 16 17 Button button2 = view.findViewById(R.id.button2); 18 button2.setOnClickListener(v -> { 19 System.out.println("bbbb"); 20 }); 21 } 22}

※ activity_main.xml は変更無しのため省略

fragment_page1.xml ( 元 activity_test_pager.xml)
アクティビティのレイアウトでも無いので、使うクラス名に合わせて変名。
(基本同じですが tools:context は変えています)

xml

1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".Page1Fragment"> 8 9 <Button 10 android:id="@+id/button1" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="ボタン1" 14 app:layout_constraintBottom_toBottomOf="parent" 15 app:layout_constraintEnd_toEndOf="parent" 16 app:layout_constraintStart_toStartOf="parent" 17 app:layout_constraintTop_toTopOf="parent" /> 18</androidx.constraintlayout.widget.ConstraintLayout>

fragment_page2.xml ( 元 activity_test1_pager.xml)

xml

1<?xml version="1.0" encoding="utf-8"?> 2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".Page2Fragment"> 8 9 <Button 10 android:id="@+id/button2" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:text="ボタン2" 14 app:layout_constraintBottom_toBottomOf="parent" 15 app:layout_constraintEnd_toEndOf="parent" 16 app:layout_constraintStart_toStartOf="parent" 17 app:layout_constraintTop_toTopOf="parent" /> 18</androidx.constraintlayout.widget.ConstraintLayout>

投稿2022/12/11 04:38

編集2022/12/11 07:01
jimbe

総合スコア12603

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

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

syosinsya109

2022/12/11 05:26 編集

ありがとうございます。無事に動きました。 もう一つ質問させてください。 savedInstanceStateやdbを使いたいとき、ボタンを押された時に画面遷移をしたいときは、Page1FragmentやPage2Fragmentでどのようにすればいいのでしょうか。mainactivityでした時と同様にしたらエラーが出てしまいます。
jimbe

2022/12/11 05:50 編集

> savedInstanceStateやdbを使いたいとき、ボタンを押された時に画面遷移をしたいときは、Page1FragmentやPage2Fragmentでどのようにすればいいのでしょうか それは状況に依ることで、一概に簡単にこうだとは言えません。 「savedInstanceStateやdbを使いたいとき」とはどういうことなのか、「ボタンを押された時に画面遷移をしたいとき」とはどこへどう遷移したいのか(タブの移動? 別のアクティビティの起動? …)、そして最終的にどうなるつもりなのかまでを考えるような"大きな"話です。 >mainactivityでした時と同様にしたらエラー フラグメントを使うということはアクティビティだけの時とは違ってくるのは当然です。 最初の内はトライ&エラーをすることになるでしょう。 ボタンを押したらそのフラグメントだけでは処理しきれないことを起こすのであれば、私なら質問へのコメントで書きましたように ViewModel を経由して処理なり通知なりを行うようにするでしょう。
syosinsya109

2022/12/11 06:47

分かりました。 貴重なアドバイスありがとうございます! 挑戦してみてダメそうであれば再度質問しようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問