I am building a quiz app with three questions and therefore I have 6 Fragments but I would like to disable the default transition from one fragment to another, how can I achieve this? I already disabled that you can swipe between the fragments, you have to click a button to get to the next fragment, but there is still somehow a swiping transition after clicking the button. I searched for this but there was never an answer that would fit my problem. Here is one fragment example:
public class FragmentQuestion1 extends Fragment {
private Button btnNavFrag1;
private EditText editText;
private ProgressBar m_bar;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_question_1, container, false);
btnNavFrag1 = view.findViewById(R.id.btn_question1);
editText = view.findViewById(R.id.edit_text_question_1);
editText.addTextChangedListener(new NumberTextWatcher(editText));
m_bar = view.findViewById(R.id.progress_bar_question_1);
btnNavFrag1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
((GameActivity)getActivity()).setViewPager(2);
}
});
return view;
}
// Method that is used so the countdown starts when the user gets to this fragment
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
startCountdownTimer();
}
}
// Countdown 17 seconds
int i = 0;
private void startCountdownTimer() {
m_bar.setProgress(i);
final int totalMsecs = 17 * 1000; // 17 seconds in milli seconds
int callInterval = 100;
/** CountDownTimer */
new CountDownTimer(totalMsecs, callInterval) {
public void onTick(long millisUntilFinished) {
int secondsRemaining = (int) millisUntilFinished / 1000;
float fraction = millisUntilFinished / (float) totalMsecs;
// progress bar is based on scale of 1 to 100;
m_bar.setProgress((int) (fraction * 100));
}
public void onFinish() {
}
}.start();
}
Because you are using a viewPager, you could use a library like this which lets you add a transformer (some sort of effect) to the viewPager when going to the next fragment. I'd recommend the ZoomOutTranformer for your use-case. If the transition is not what you expect you can always extend from that class and override the transition so it's more to your liking.
ViewPagerTransformers are native, so you don't need to use a library. Just create a class, implement the PageTransformer interface and override the method transformPage.
In your layout xml define a tablayout and a FrameLayout like this:
..................your xml code...............
.............................................................
<com.google.android.material.tabs.TabLayout
android:id="#+id/simpleTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="#color/colorPrimary"
app:tabIndicatorColor="#0080FF"
app:tabSelectedTextColor="#050505"
app:tabTextColor="#color/colorAccent">
<com.google.android.material.tabs.TabItem
android:id="#+id/abcd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Item 1" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="item 2" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="item 3" />
</com.google.android.material.tabs.TabLayout>
<FrameLayout
android:id="#+id/simpleFrameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
This layout is defined for three tabs. You can make it for more tabs by adding more tabs if you like.
Then define the fragments for each tab. In this case:
item_one_fragment:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="your.activity.context">
......................................
............................................
fragments xml
.............................
,.....................................
</RelativeLayout>
Similarly item 2 and item 3 fragment layouts.
Then define the fragments in java:
public class FirstItemFragment extends Fragment {
public ListView CallListView;
public FirstFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.item_one_fragment, container, false);
// Inflate the layout for this fragment
return view;
}
}
Simiarly second and third fragment.
Then in your Main Activity:
FrameLayout simpleFrameLayout = (FrameLayout) findViewById(R.id.simpleFrameLayout);
TabLayout tabLayout = (TabLayout) findViewById(R.id.simpleTabLayout);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.simpleFrameLayout, new FirstItemFragment());
ft.commit();
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
// get the current selected tab's position and replace the fragment accordingly
Fragment fragment = null;
switch (tab.getPosition()) {
case 0:
fragment = new FirstItemFragment();
break;
case 1:
fragment = new SecondItemFragment();
break;
case 2:
fragment = new ThirdItemFragment();
break;
}
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.simpleFrameLayout, fragment)
.addToBackStack(null)
//Commit the transaction.
.commit();
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
Now when you run your activity you will have three tabs and when you click on any one you will go to the respective fragment without any swipe
Related
I have an app that has 1 Main Activity and 5 main fragments. When the MainActivity is created I create a List containing each of the 5 fragments. The user is presented with a tab bar on the bottom of the screen which he/she can use to navigate between fragments. How do I set this up so as when the user selects a tab, the corresponding fragment is shown without creating a new instance of it? Just want to change the view on the screen to the already created fragment.
I am using a BottomBar from https://github.com/roughike/BottomBar which calls a "onTabSelected" interface method when a tab is pressed.
You can use 5 Fragments with the library you specified like this. The layout file should look like this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- This could be your fragment container, or something -->
<FrameLayout
android:id="#+id/contentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/bottomBar" />
<com.roughike.bottombar.BottomBar
android:id="#+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
app:bb_tabXmlResource="#xml/bottombar_tabs" />
</RelativeLayout>
The containing Activity class will replace the Framelayout with Fragment depending on the Fragment selected from the BottomBar View. A simple example
public class Main3Activity extends AppCompatActivity {
private Fragment fragment;
private FragmentManager fragmentManager;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_three_tabs);
BottomBar bottomBar = (BottomBar) findViewById(R.id.bottomBar);
bottomBar.setOnTabSelectListener(new OnTabSelectListener() {
#Override
public void onTabSelected(#IdRes int tabId) {
if(tabId == R.id.tab_home){
fragment = new HomeFragment();
}
if(tabId == R.id.tab_favorite){
fragment = new FavoriteFragment();
}
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.contentContainer, fragment).commit();
});
bottomBar.setOnTabReselectListener(new OnTabReselectListener() {
#Override
public void onTabReSelected(#IdRes int tabId) {
Toast.makeText(getApplicationContext(), TabMessage.get(tabId, true), Toast.LENGTH_LONG).show();
}
});
}
}
Then you can create individual Fragment with their content like below
public class FavoriteFragment extends Fragment {
public FavoriteFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_favorite, container, false
);
}
}
I have an app that I desperately need to convert from using the old ActivityGroup class to Fragments. I'm not sure how to go about it though. Below is a sample of the code I use now. Could anyone provide some insight into what steps I should take to start switching it over to use Fragments / FragmentManager instead?
Main.java
public class Main extends TabActivity implements OnTabChangeListener {
public static TextView txtViewHeading;
public static Button btnBack;
public static ImageButton btnShare;
public static Main mainActivity;
public static Boolean isVisible = false;
private GoogleCloudMessaging gcm;
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mainActivity = this;
NotificationsManager.handleNotifications(this, NotificationSettings.SenderId, PushHandler.class);
registerWithNotificationHubs();
//reference headings text & button for access from child activities
txtViewHeading = (TextView) findViewById(R.id.txtViewHeading);
btnBack = (Button) findViewById(R.id.btnBack);
btnShare = (ImageButton) findViewById(R.id.btnShare);
// Update the font for the heading and back button
Typeface arialTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/arial.ttf");
Typeface myriadTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/myriad.ttf");
txtViewHeading.setTypeface(myriadTypeface);
btnBack.setTypeface(arialTypeface);
Resources res = getResources();
TabHost tabsNavigation = getTabHost();
// Set up the views for each tab - custom view used for Badge icon
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Set up my tabs...each one looks similar to this
View statusTabView = inflater.inflate(R.layout.tab, null);
ImageView statusTabIcon = (ImageView) statusTabView.findViewById(R.id.tabIcon);
statusTabIcon.setImageResource(R.drawable.tab_first);
TextView statusTabText = (TextView) statusTabView.findViewById(R.id.tabText);
statusTabText.setText("Status");
statusTabText.setTypeface(arialTypeface);
statusTabBadge = (TextView) statusTabView.findViewById(R.id.tabBadge);
statusTabBadge.setTypeface(arialTypeface);
tabsNavigation.addTab(tabsNavigation.newTabSpec(getResources().getString(R.string.main_tab_status))
.setIndicator(statusTabView)
.setContent(new Intent(this, StatusGroupActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)));
//Set default tab to Status
tabsNavigation.setCurrentTab(0);
tabsNavigation.setOnTabChangedListener(this);
}
/* Set txtViewHeading text to selected tab text */
#Override
public void onTabChanged(String tabId) {
// TODO Auto-generated method stub
txtViewHeading.setText(tabId);
}
/* Set code to execute when onDestroy method is called */
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
/* Set code to execute when onPause method is called */
#Override
protected void onPause() {
super.onPause();
isVisible = false;
}
/* Set code to execute when onResume method is called */
#Override
protected void onResume() {
super.onResume();
isVisible = true;
}
/* Set code to execute when onStop method is called */
#Override
protected void onStop() {
super.onStop();
isVisible = false;
}
/**
* Check the device to make sure it has the Google Play Services APK. If
* it doesn't, display a dialog that allows users to download the APK from
* the Google Play Store or enable it in the device's system settings.
*/
private boolean checkPlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
.show();
} else {
ToastNotify("This device is not supported by Google Play Services.");
finish();
}
return false;
}
return true;
}
public void ToastNotify(final String notificationMessage) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(Main.this, notificationMessage, Toast.LENGTH_LONG).show();
}
});
}
public void registerWithNotificationHubs()
{
if (checkPlayServices()) {
// Start IntentService to register this application with GCM.
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
}
TabGroupActivity.java
public class TabGroupActivity extends ActivityGroup
{
private ArrayList<String> mIdList;
Button btnBack;
ImageButton btnShare;
TextView txtViewHeading;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
btnBack = Main.btnBack;
btnShare = Main.btnShare;
txtViewHeading = Main.txtViewHeading;
btnBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
if (mIdList == null) mIdList = new ArrayList<String>();
}
/**
* This is called when a child activity of this one calls its finish method.
* This implementation calls {#link LocalActivityManager#destroyActivity} on the child activity
* and starts the previous activity.
* If the last child activity just called finish(),this activity (the parent),
* calls finish to finish the entire group.
*/
#Override
public void finishFromChild(Activity child)
{
try
{
btnShare.setVisibility(View.GONE);
LocalActivityManager manager = getLocalActivityManager();
int index = mIdList.size()-1;
if (index < 1)
{
finish();
return;
}
manager.destroyActivity(mIdList.get(index), true);
mIdList.remove(index);
index--;
String lastId = mIdList.get(index);
Intent lastIntent = manager.getActivity(lastId).getIntent();
Window newWindow = manager.startActivity(lastId, lastIntent);
setContentView(newWindow.getDecorView());
//Set Heading text to current Id
txtViewHeading.setText(getActivityHeading(lastId));
//Set Back button text to previous Id if applicable
btnBack.setVisibility(View.VISIBLE);
//Back button
String backId = "";
if(mIdList.size() > 1)
{
backId = mIdList.get(mIdList.size()-2);
btnBack.setVisibility(View.VISIBLE);
btnBack.setText(getActivityHeading(backId));
txtViewHeading.setPadding(10,0,0,0);
}
else
{
btnBack.setVisibility(View.GONE);
txtViewHeading.setPadding(0,0,0,0);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* Starts an Activity as a child Activity to this.
* #param Id Unique identifier of the activity to be started.
* #param intent The Intent describing the activity to be started.
*/
public void startChildActivity(String Id, Intent intent)
{
try
{
btnShare.setVisibility(View.GONE);
Window window = getLocalActivityManager().startActivity(Id,intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
if (window != null)
{
mIdList.add(Id);
setContentView(window.getDecorView());
txtViewHeading.setText(getActivityHeading(Id));
//Back button
String backId = "";
if(mIdList.size() > 1)
{
backId = mIdList.get(mIdList.size()-2);
btnBack.setVisibility(View.VISIBLE);
btnBack.setText(backId);
txtViewHeading.setPadding(5,0,0,0);
}
else
{
btnBack.setVisibility(View.GONE);
txtViewHeading.setPadding(0,0,0,0);
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* The primary purpose is to prevent systems before android.os.Build.VERSION_CODES.ECLAIR
* from calling their default KeyEvent.KEYCODE_BACK during onKeyDown.
*/
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
//preventing default
return true;
}
return super.onKeyDown(keyCode, event);
}
/**
* Overrides the default implementation for KeyEvent.KEYCODE_BACK
* so that all systems call onBackPressed().
*/
#Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
onBackPressed();
return true;
}
return super.onKeyUp(keyCode, event);
}
/**
* If a Child Activity handles KeyEvent.KEYCODE_BACK.
* Simply override and add this method.
*/
#Override
public void onBackPressed ()
{
try
{
btnShare.setVisibility(View.GONE);
int length = mIdList.size();
if ( length > 1)
{
Activity current = getLocalActivityManager().getActivity(mIdList.get(length-1));
current.finish();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* Get the correct heading text and language based on activity id
*/
public String getActivityHeading(String id)
{
// method that returns the TEXT for my main heading TextView based on the activity we're on...
}
}
StatusGroupActivity
public class StatusGroupActivity extends TabGroupActivity
{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startChildActivity("Status", new Intent(this,Status.class));
}
}
... so basically when my app loads, I get my tabs at the bottom, my header at the top, and the "tab content" in the middle. In my Status activity, I can load another activity from it by using ...
Intent intent = new Intent(getParent(), SomeOtherActivity.class)
TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.startChildActivity("Some Other Activity", intent);
... and it loads the SomeOtherActivity activity into the content area. Hitting back takes me back to the Status screen.
Any pointers, examples and assistance with converting this over to use Fragments is so greatly appreciated. I will gladly donate 500 of my rep. points for a full example.
main.xml (Main Activity Layout file)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.app.FragmentTabHost xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:ignore="ContentDescription,HardcodedText" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/imageSuccess"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:adjustViewBounds="true"
android:scaleType="matrix"
android:src="#drawable/bg_navbar_blank" />
<com.myproject.android.BgButtonStyle
android:id="#+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="0dp"
android:background="#drawable/back_button"
android:text=""
android:textColor="#color/White"
android:textSize="12sp"
android:visibility="visible"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:padding="5dp"/>
<ImageButton
android:id="#+id/btnShare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:background="#null"
android:src="#drawable/icon_share"
android:visibility="visible"
android:adjustViewBounds="false"
android:scaleType="fitXY"/>
<com.myproject.android.AutoResizeTextView
android:id="#+id/txtViewHeading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingLeft="5dp"
android:text="Status"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="28sp"
android:textStyle="bold"
android:paddingRight="5dp"
android:layout_toEndOf="#id/btnBack"
android:layout_toStartOf="#id/btnShare"
android:layout_centerVertical="true"
android:lines="1"/>
</RelativeLayout>
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
</FrameLayout>
<TabWidget
android:id="#android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="-4dp"
android:layout_weight="0"
android:background="#drawable/bg_tabs">
</TabWidget>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
In my current TabGroupActivity class, in the finishFromChild and startChildActivity methods, I am able to call setText on the txtViewHeading TextView element in my main activity layout. Which is the current activities "title". If there is more than 1 activity in the group, the back button shows the previous title. How can I duplicate this in the examples below? The main activity layout there is much different than mine.
First you need to add Design Support Library and AppCompatLibrary into your Project
Add this code into your app gradle
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.android.support:design:24.0.0'
layout for activity_main.xml (like main.xml in your code)
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/appbar_padding_top"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/AppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
In above layout ViewPager will provides horizontal layout to display tabs. You can display more screens in a single screen using tabs. You can swipe the tabs quickly as you can.
Root Fragment
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/root_frame" >
View for First Fragment
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="#ff0"
android:layout_height="match_parent" >
<TextView
android:id="#+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:text="#string/first_fragment" />
<Button
android:id="#+id/btn"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:text="#string/to_second_fragment"/>
</RelativeLayout>
View for Second and Individual(s) Fragment.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin">
<TextView
android:id="#+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
Now add a MainActivity(like Main Activity in yours code) under which all this thing will handle.
public class MainActivity extends AppCompatActivity {
private TabGroupAdapter mTabGroupAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ArrayList<Fragment> fragmentList = new ArrayList<Fragment>();
fragmentList.add(new RootFragment());
fragmentList.add(new IndividualFragment1());
fragmentList.add(new IndividualFragment2());
ArrayList<String> name = new ArrayList<String>() {
{
add("Root Tab");
add("Second Tab");
add("Third Tab");
}
};
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mTabGroupAdapter = new TabGroupAdapter(getSupportFragmentManager(),name, fragmentList,);
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mTabGroupAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
}
}
There is one FragmentPagerAdapter defined as mTabGroupAdapter inside MainActivity that will add a different tabs inside a single Layout.
First we bind the mTabGroupAdapter to mViewPager.
TabLayout will act like a TabHost under which Tab will be added by FragmentPagerAdapter.
mViewPager is bind to the Tablayout.
Under MainActivity TabLayout will display the name of Tabs.
TabGroupAdapter
public class TabGroupAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> fragmentList = new ArrayList<Fragment>();
private ArrayList<String> fragment_name;
public TabGroupAdapter(FragmentManager fm, ArrayList<String> name, ArrayList<Fragment> list) {
super(fm);
this.fragmentList = list;
this.fragment_name = name;
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentList.size();
}
#Override
public CharSequence getPageTitle(int position) {
return fragment_name.get(position);
}
}
In TabGroupAdapter you would pass a List of fragments(or single fragment) and list of fragments name(or single name) as arguments in the Constructor.
IndividualFragment(s) will act like a individual Tab instead of Activity.
RootFragment will be acting as a container for other fragments( First Fragment and Second Fragment)
Root Fragment
public class RootFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.root_fragment, container, false);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.root_frame, new FirstFragment());
fragmentTransaction.commit();
return view;
}
}
First Fragment
public class FirstFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.first_fragment, container, false);
Button btn = (Button) view.findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
//use the "root frame" defined in
//"root_fragment.xml" as the reference to replace fragment
fragmentTransaction.replace(R.id.root_frame, new SecondFragment());
/*
* allow to add the fragment
* to the stack and return to it later, by pressing back
*/
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
}
}
Second Fragment
public class SecondFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
Individual(s) Fragment
public class IndividualFragment1 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
public class IndividualFragment2 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
In OnCreateView method you would set a layout of a Tab .
You won't have to use the getTabHost() method.
Let me know if you persist any problem.
Whenever you want to dynamically change or update the Tabs in View Pager just add or remove item from fragmentList and call this method mTabGroupAdapter.notifyDataSetChanged(); inside MainActivity.
Add these dependencies to your project:
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
First change your Main activity must be extended from AppCompatActivity.
Than change your main activity's layout like below:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:id="#+id/coordinatorlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".Main">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<include
layout="#layout/toolbar_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:tabGravity="fill"
app:tabMaxWidth="0dp"
app:tabIndicatorHeight="4dp"
app:tabMode="fixed"
app:tabIndicatorColor="#android:color/white"
android:background="#color/AppPrimary"/>
</android.support.design.widget.AppBarLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".dashboard.DashboardActivity"
tools:showIn="#layout/activity_dashboard">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager_main"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
And here's a toolbar layout example. You can customize however you want.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar_main"
style="#style/Widget.MyApp.Toolbar.Solid"
android:layout_width="match_parent"
android:layout_height="#dimen/abc_action_bar_default_height_material"
android:background="#color/AppPrimary"
app:contentInsetEnd="16dp"
app:contentInsetStart="16dp" />
Than you need to create fragments which you'll use in your tabs instead of activities which you use for tabs. In this case this'll your Status Activity if i'm not wrong.
Define a StatusFragment like below:
public class StatusFragment extends Fragment
{
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// this is your Status fragment. You can do stuff which you did in Status activity
}
}
Than you need to define a tabs adapter which you'll bind with your tabs and convert your TabHost to Fragment/Fragment manager type. Titles string array contains strings which you'll show in your tabs indicator. Such as "Status, My Assume Tab, My awesome tab 2
public class DashboardTabsAdapter extends FragmentPagerAdapter {
private String[] mTitles;
public DashboardTabsAdapter(FragmentManager fm, String[] titles) {
super(fm);
this.mTitles = titles;
}
#Override
public Fragment getItem(int position) {
return new StatusFragment();
// You can define some other fragments if you want to do different types of operations in your tabs and switch this position and return that kind of fragment.
}
#Override
public int getCount() {
return mTitles.length;
}
#Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
}
And finally in your Main activity find your view pager, tabs create a new adapter and bind them.
final TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
final DashboardTabsAdapter dashboardTabsAdapter = new DashboardTabsAdapter(getSupportFragmentManager(), getResources().getStringArray(R.array.tab_titles));
mViewPagerMain = (ViewPager) findViewById(R.id.viewpager_main);
mViewPagerMain.setOffscreenPageLimit(3);
mViewPagerMain.setAdapter(dashboardTabsAdapter);
tabLayout.setupWithViewPager(mViewPagerMain);
Edit: You'll no longer need TabHost and TabActivity any more. Your tab grup activity will be your ViewPager which handles screen changes and lifecycle of fragments inside. If you need to get this activity from fragments you can use getActivity() method and cast it to your activity and use it's public methods.
I have a ViewPager in my MainActivity. Every page in it is a Fragment. So, everytime I swipe right or left, a new instance of the fragment is created and the fragment view is updated accordingly.
I also have two buttons: LEFT and RIGHT for navigation. These buttons are inside the Fragment, not in the Activity. A user can either swipe or alternatively press the relevant button to navigate between the pages.
Here's the problem: Since I'm changing the views through my MainActivity, how do I detect the onClick events of those buttons in the Activity in order to update the fragment?
Here's the PagerAdapter class (Removed all the irrelevant code from everywhere):
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// logic part for the views.
return PlaceholderFragment.newInstance(sectionNumber, questionStatus, questionOrder, showNext, showPrevious);
}
And here's the PlaceHolderFragment class:
public class PlaceholderFragment extends Fragment{
//some global variables
public static PlaceholderFragment newInstance(int sectionNumber, int questionStatus, String questionOrder, boolean showNext, boolean showPrevious) {
PlaceholderFragment fragment = new PlaceholderFragment();
//setting up the arguments
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.explanation_fragment, container, false);
//code for filling up all the views
RightButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//can I do something here?
}
});
return rootView;
}
}
MORE INFO:
I have to keep the navigation buttons in the fragment itself and not in the activity.
In your fragment write one interface like:
public class PlaceholderFragment extends Fragment{
private OnButtonClickListener mOnButtonClickListener;
interface OnButtonClickListener{
void onButtonClicked(View view);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mOnButtonClickListener = (OnButtonClickListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(((Activity) context).getLocalClassName()
+ " must implement OnButtonClickListener");
}
}
yourButtons.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mOnButtonClickListener.onButtonClicked(v);
}
});
}
And in your mainactivity:
class MainActivity extends AppCompatActivity implements OnButtonClickListener{
#Override
void onButtonClicked(View view){
int currPos=yourPager.getCurrentItem();
switch(view.getId()){
case R.id.leftNavigation:
//handle currPos is zero
yourPager.setCurrentItem(currPos-1);
break;
case R.id.rightNavigation:
//handle currPos is reached last item
yourPager.setCurrentItem(currPos+1);
break;
}
}
}
For Kotlin and ViewPager2
previous page:
val currPos: Int = xyzViewPager.currentItem
if (currPos != 0) {
xyzViewPager.currentItem = currPos - 1
}
next page:
val currPos: Int = xyzViewPager.currentItem
if ((currPos + 1) != xyzViewPager.adapter?.count) {
xyzViewPager.currentItem = currPos + 1
}
Use kotlin extension functions:
fun ViewPager2.nextPage(smoothScroll: Boolean = true): Boolean {
if ((currentItem + 1) < adapter?.itemCount ?: 0) {
setCurrentItem(currentItem + 1, smoothScroll)
return true
}
//can't move to next page, maybe current page is last or adapter not set.
return false
}
fun ViewPager2.previousPage(smoothScroll: Boolean = true): Boolean {
if ((currentItem - 1) >= 0) {
setCurrentItem(currentItem - 1, smoothScroll)
return true
}
//can't move to previous page, maybe current page is first or adapter not set.
return false
}
Make a public method in your activity
public void swipeRight(int x){
if(x < totalNumberOfFragment){
viewPager.setCurrentItem(x + 1);
}
}
public void swipeLeft(int x){
if(x > 0){
viewPager.setCurrentItem(x - 1);
}
}
You can call these method from your fragment button's click action
RightButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Yes
((YourActivityClassName)getActivity()).swipeRight(position);
}
});
And do same for LeftButton
YourActivityClassName - Activity which is holding this viewPager fragment.
position - position of your current fragment.
You can add button in your activities xml as follows
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
</LinearLayout>
<ImageView
android:id="#+id/leftNavigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:padding="10dp"
android:src="#drawable/ic_chevron_left_black_24dp"
android:visibility="gone" />
<ImageView
android:id="#+id/rightNavigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:layout_weight="0"
android:gravity="center"
android:padding="10dp"
android:src="#drawable/ic_chevron_right_black_24dp" />
</FrameLayout>
You can create special method in your parent Activity like following:
public class PagerActiviy extends Activity {
...
public void onFragmentNavigationButtonClick(View button) {
// Do your stuff here
}
...
}
Then in your fragments you can get your parent Activity with getActivity() method, cast it to the actual type and call the method:
public class PlaceholderFragment extends Fragment{
...
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.explanation_fragment, container, false);
//code for filling up all the views
RightButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((PagerActvity) getActivity()).onFragmentNavigationButtonClick(v);
}
});
return rootView;
}
}
As a side note I should add that from your example it's not clear why do you need to keep your navigation buttons in the fragments and can't move them to the Activity and manage them there.
You can send a broadcast upon button click inside the fragment like below:
Intent intent = new Intent();
intent.setAction(NUMBER_OF_RECEIVER_NEXT);
getActivity().sendBroadcast(intent);
Then in your main activity you catch the Intent and you set the current position of the pager to the desired number
private class broadcastReceived extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String actionGet = intent.getAction();
if(actionGet.equals(NUMBER_OF_RECEIVER_NEXT)){
mPager.setCurrentItem(1);
Log.e("IntentNextPage","Received");
}
}
}
Do not forget to set a
private static final String NUMBER_OF_RECEIVER_NEXT = "nextPage";
in both main activity and fragment and of course to register,unregister receiver to onResume and onPause methods.
Also add an intent filter to the receiver in onCreate methd with the action specified as NUMBER_OF_RECEIVER_NEXT
I am currently using the following code to transition a block on the right side of the screen to a shared element on the left:
FragmentDetail newFragment = FragmentDetail.newInstance(id);
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.trans_move));
setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));
View block = view.findViewById(R.id.blocks);
block.setTransitionName("block");
newFragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.trans_move));
newFragment.setEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));
newFragment.setTransitionId(block.getTransitionName());
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.replace(R.id.container, newFragment);
trans.addToBackStack(null);
trans.addSharedElement(block, block.getTransitionName());
trans.commit();
This works exactly how I want, but I would like to reverse the effect upon pressing the back button, animating the item back in. As is, the explode animation plays, but the transition does not.
Any help is greatly appreciated.
Thanks
Josh
KOTLIN with Android Navigation Component
For anyone who's here looking for the answer to this question when you're using the Android Navigation component, you can make the reverse transition animation work by adding these lines to the onViewCreated function of the starting fragment:
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
You would generally use this if you are opening the second fragment by clicking on a RecyclerView item.
Let's say you have two fragments, A and B, and A commits a fragment transaction to start fragment B.
Then that means the exit and reenter transitions should be set on A and the enter and return transitions should be set on B.
It looks like you are calling setSharedElementReturnTransition on the calling fragment instead of the called fragment (newFragment, in this case), which might be causing the problem.
BTW, you should consider calling the set*****Transition() and setSharedElement*****Transition() methods in your fragment's onCreate() method instead of immediately before a fragment transaction is committed. If a fragment is destroyed and recreated, these transitions will be forgotten... so setting them in onCreate() is much safer.
switch from
trans.replace(R.id.container, newFragment);
to
trans.hide(oldFragment).add(R.id.container, newFragment).show(newFragment)
and it should work (as in my case).
reverting a shared fragment transition seems to only work if you hide the old one, instead of replacing it.
I have met the same problem with you.Buy I have found the solution.
You know, there are many causes for this problem. I just show my way.
Hope that can help you.
there are two fragments.
one have a RecyclerView widget:
ListFragment.java
public class ListFragment extends Fragment implements RecyclerItemInter {
#Bind(R.id.recycler_view)
RecyclerView recyclerView;
private OnListItemClickListener onListItemClickListener;
public void setOnListItemClickListener(ListFragment.OnListItemClickListener onListItemClickListener) {
this.onListItemClickListener = onListItemClickListener;
}
public ListFragment() {
}
public static ListFragment newInstance() {
ListFragment fragment = new ListFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_list, container, false);
ButterKnife.bind(this, view);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2));
RecyclerAdapter2 adapter = new RecyclerAdapter2(BEAUTY_BEANS);
recyclerView.setAdapter(adapter);
adapter.setItemInter(this);
return view;
}
private static final BeautyBean[] BEAUTY_BEANS = {
new BeautyBean("Avril Lavigne1", "Avril was born in Canada, the Canadian singer, songwriter creators, actors."),
new BeautyBean("Avril Lavigne2", "Avril was born in Canada, the Canadian singer, songwriter creators, actors."),
new BeautyBean("Avril Lavigne3", "Avril was born in Canada, the Canadian singer, songwriter creators, actors."),
new BeautyBean("Avril Lavigne4", "Avril was born in Canada, the Canadian singer, songwriter creators, actors."),
new BeautyBean("Avril Lavigne5", "Avril was born in Canada, the Canadian singer, songwriter creators, actors.")
};
#Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
}
#Override
public void onItemClick(View view, int position) {
}
#Override
public void onIvClick(RecyclerAdapter2.ViewHolder holder, int position) {
OtherFragment otherFragment = OtherFragment.newInstance();
otherFragment.setSharedElementEnterTransition(new CustomTransition());
otherFragment.setSharedElementReturnTransition(new CustomTransition());
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
otherFragment.setEnterTransition(new Fade());
setExitTransition(new Fade());
}*/
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frame_layout, otherFragment)
.addToBackStack(null)
.addSharedElement(holder.getPicIv(), getString(R.string.transition_img))
.commit();
}
then you should set the TransitionName to every ImageView in the RecyclerView:
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
if (items[position].getImageId() != 0) {
holder.getPicIv().setImageResource(items[position].getImageId());
}
ViewCompat.setTransitionName(holder.getPicIv(), String.valueOf(position) + "_beauty");
holder.getTitleTv().setText(items[position].getName());
holder.getDescTv().setText(items[position].getDesc());
holder.getLinearLayout().setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (null != itemInter) {
itemInter.onItemClick(holder.itemView, position);
}
}
});
holder.getPicIv().setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (null != itemInter) {
itemInter.onIvClick(holder, position);
}
}
});
}
click the list jump to the OtherFragment.
OtherFragment.java
public class OtherFragment extends Fragment {
public OtherFragment() {
}
public static OtherFragment newInstance() {
OtherFragment fragment = new OtherFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_other, container, false);
}
}
fragment_other.xml
<FrameLayout 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"
tools:context="com.jacksen.supportlibrarydemo.fragment.OtherFragment">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/bg_detail_header"
android:transitionName="#string/transition_img" />
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/ic_backup_white_36dp"
android:transitionName="#string/transition_fab"
app:borderWidth="0dp"
app:elevation="5dp"
app:pressedTranslationZ="10dp"
app:rippleColor="#color/color_gray" />
the crux of the problem is in this xml.
at the beginning, i set the attribute "transitionName" on and its father layout.
Actually we don't need to add the attribute on father Layout.
Just add transitionName to what you want to transform.
OK, that is my solution.
The Joe Muller answer is correct, I wrote it for Java
#Override
public void onViewCreated(#NonNull final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
postponeEnterTransition();
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
startPostponedEnterTransition();
view.getViewTreeObserver().removeOnPreDrawListener(this);
return false;
}
});
}
This resolve issue if the start transition is inside an adapter
I am using fragments,I have an edittext in fragment and I want to get value in main activity.
This is my fragment layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#878787" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="dfgdfgdf"
android:textSize="20dp"
android:layout_centerInParent="true"
android:id="#+id/user_name"/>
<EditText
android:id="#+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:text="Gönder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="getFromUser"
android:layout_marginTop="40dp"
/>
</RelativeLayout>
I am loading fragment with this function:
public void startChat(JsonObject user) {
FrameLayout layout = (FrameLayout)findViewById(R.id.container);
layout.setVisibility(View.VISIBLE);
Bundle bundle = new Bundle();
bundle.putString("name", user.get("name").getAsString());
sendTo=user.get("username").getAsString();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ConversationFragment conv = new ConversationFragment();
conv.setArguments(bundle);
fragmentTransaction.add(R.id.container, conv);
fragmentTransaction.commit();
viewPager.setVisibility(View.GONE);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayHomeAsUpEnabled(true);
}
And this is my fragment class
public class ConversationFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String name = getArguments().getString("name");
View rootView = inflater.inflate(R.layout.fragment_conversation, container, false);
TextView username=(TextView)rootView.findViewById(R.id.user_name);
username.setText(name);
return rootView;
}
}
As you can see when press the button main activity runs "getFromUser" function.I want to get edittext value in this function.How can I do this ?
It's always the same procedure for these things. You can't access a fragment's views just like that. You need a callback method.
Add this code to ConversationFragment:
private OnGetFromUserClickListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnGetFromUserClickListener ) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnGetFromUserClickListener");
}
}
public void getFromUser(View v) {
if (mListener != null) {
EditText edit = (EditText)findViewById(R.id.message);
mListener.getFromUser(edit.getText().toString());
}
}
public interface OnGetFromUserClickListener {
void getFromUser(String message);
}
Make your MainActivity implement this interface. Replace getFromUser() inside MainActivity with:
public void getFromUser(String message) {
sendMessage(message);
}
Done.
Edit:
Actually, using the XML-onClick attribute is currently bugged (see onClick inside fragment called on Activity): It links to the activity instead of the fragment. You have to set the click listener programmatically to make sure the code won't break at some point in the future. So give the button an ID inside the XML (e.g. get_from_user) and add this code to onCreateView inside ConversationFragment:
v.findViewById(R.id.get_from_user).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getId() == R.id.get_from_user) {
getFromUser(v);
}
}
});
Using this code vastly decouples the activity and the fragment from each other.
I resolved this problem.
public void getFromUser(View view) {
ConversationFragment fragment1 = (ConversationFragment)getSupportFragmentManager().findFragmentById(R.id.container);
View frag=fragment1.getView();
EditText editText1 =(EditText) frag.findViewById(R.id.message);
String message=editText1.getText().toString();
sendMessage(message);
}
Now I can get edittext value from fragment.