I have only recently learned about JAVA and Android programming, so bear with me.
Context: I made a tabbed Activity (using ViewPager and SectionsPagerAdapter) with one XML layout. I have used a standard Activity with Fragment from Android Studio for this. Only the values of some TextViews are different for the different pages (swipes). I have set this up using an onViewCreated override. This works fine on initialization, but now I want to update and hide TextViews on user interactions (onClick). This requires to keep track of the View of a Page in the PlaceholderFragment, which I have done by the setTag and findViewWithTag method I read on this forum, i.e. I made this override:
Within PlaceholderFragment:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
//added to keep reference to View
int position = getArguments().getInt(ARG_SECTION_NUMBER);
rootView.setTag(position);
return rootView;
}
Now I try to update three TextViews, including the one clicked on, when the TextView textViewStart is clicked:
Within main class:
public void onClick (View clickview) {
Log.i("onClick called: ", Integer.toString(clickview.getId())); // this gives a valid number. probably different from TextView ID in mView defined below
// get the current View from the ViewPager, stored using setTag
final View mView = mViewPager.findViewWithTag(currentTab); //currentTab is a variable with the current selected Page in the ViewPager, made using an override in onTabSelected
//Need to findIDs (for current tab page in ViewPager)
final TextView tvStart = (TextView)mView.findViewById(R.id.textViewStart);
final TextView tvPause = (TextView)mView.findViewById(R.id.textViewPause);
final TextView tvStop = (TextView)mView.findViewById(R.id.textViewStop);
//TextView tvStart = (TextView)findViewById(R.id.textViewStart); // this refers to another tab ! clickview.findViewById ONLY works for the actual object clicked
switch (clickview.getId()) {
case R.id.textViewStart: // START
runOnUiThread(new Runnable() {
@Override
public void run() {
//update controls
tvStart.setClickable(false);
tvStart.setVisibility(View.INVISIBLE);
tvStart.setTextColor(Color.parseColor("#888888"));//#RRGGBB // = grey
tvPause.setClickable(true);
tvPause.setVisibility(View.VISIBLE);
tvStop.setClickable(true);
tvStop.setVisibility(View.VISIBLE);
//NOTE this invalidates the textViews, BUT does not redraw the View, which only happens after onClick thread is finished, so what to do??
}
});
// mViewPager.setCurrentItem(currentTab-1); //also does not update View
//start timer
timerStatus = 1;
startTimer(currentTab); //this is another method, which starts a timer in the same View, this updates a ProgressBar which works.
}
}
Just in case, the TextViews are defined in the XML as follows:
fragment_main.xml:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/Start"
android:id="@+id/textViewStart"
android:textSize="30dp"
android:textColor="#fff"
android:onClick="onClick"
android:clickable="true"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/Pause"
android:id="@+id/textViewPause"
android:textSize="30dp"
android:textColor="#fff"
android:onClick="onClick"
android:clickable="false"
android:layout_below="@+id/view"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:visibility="invisible" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/Stop"
android:id="@+id/textViewStop"
android:textSize="30dp"
android:textColor="#fff"
android:onClick="onClick"
android:clickable="false"
android:layout_below="@+id/view"
android:layout_alignRight="@+id/tvTimerTotal"
android:layout_alignEnd="@+id/tvTimerTotal"
android:visibility="invisible" />
Problem: I simply cannot get the TextViews to appear or disappear, or get them (un)clickable. What happens now is that the TextViewStart (tvStart) gets grey as expected, but it does not go invisible and is still clickable (I can start another instance of startTimer). Also, the other TextViews tvPause and tvStop do not appear. The timer (started with startTimer(), a method of the main class) works fine, and also updates a ProgressBar on the same Page, using the same findViewWithTag method.
So the strange thing is, the IDs of the TextViews must be correct, as setText and setTextColor are working, but setVisibililty and setClickable on exactly the same objects are not working!
I first tried it without runOnUiThread, which works similarly. I also tried to put everything in a synchronized Thread, but that has similar results too. I also tried to put the startTimer in a tvStop.post() { ... }, but that did not even start the timer..
I really do not get it anymore, what do I overlook here?
Edit:
Here is my complete Activity (at least, the part of the Framents setup):
public class SomeActivity extends ActionBarActivity implements ActionBar.TabListener {
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
//Peter: need access to current tab throughout activity
int currentTab;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_whatever);
// Set up the action bar.
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
actionBar.addTab(
actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_whatever, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
// store current position in global variable
currentTab = tab.getPosition()+1; // +1 (!)
Log.i("TEST onTabSelected currentTab", Integer.toString(currentTab));
}
@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
@Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return PlaceholderFragment.newInstance(position + 1);
}
@Override
public int getCount() {
// Show 3 total pages.
// DEFAULT: return 3;
return getResources().getStringArray(R.array.whatever_sections).length;
}
@Override
//PETER: this is the names of the pages
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
// DEFAULT OVERRIDE
String[] menuItems = getResources().getStringArray(R.array.whatever_sections);
return menuItems[position];
}
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_whatever, container, false);
//Peter added to keep reference to View (THIS WORKS)
int position = getArguments().getInt(ARG_SECTION_NUMBER);
rootView.setTag(position);
//Log.i("TEST onCreateView ARGS position: ",Integer.toString(position));
return rootView;
}
//PETER: added, this is apparently the default for setup of the items View components
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
//default code:
super.onViewCreated(view, savedInstanceState);
TextView tvWork = (TextView)view.findViewById(R.id.tvWork);
TextView tvPause = (TextView)view.findViewById(R.id.tvPause);
tvWork.setText("0:10");
tvPause.setText("4:00"); // 4 minutes
}