I am new to android application development. I have a fragment (layout of which contains one vertical linear layout). I am adding some views dynamically in the linear layout. When i change orientation to landscape from portrait the layout of fragment is recreated and all dynamically added views disappear. How can i prevent the fragment's layout from recreating?
EDIT: the code below is inside fragment. clicking on a button(say add button) dynamically adds a view in vertical linear layout but changing orientation these views disappear.
buttonAdd.setOnClickListener(new OnClickListener() {
#SuppressWarnings("unchecked")
#Override
public void onClick(View arg0) {
methodForCheckEmail(textIn);
if(textIn.getText().toString().length() == 0) {
Toast.makeText(getActivity(), "please enter valid email", Toast.LENGTH_LONG).show();
} else if (textIn.getText().toString().length() > 0 && checkEmail == false) {
Toast.makeText(getActivity(), "please enter valid email", Toast.LENGTH_LONG).show();
} else {
LayoutInflater layoutInflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View addView = layoutInflater.inflate(R.layout.row2, null);
final TextView textOut = (TextView) addView.findViewById(R.id.textout);
textOut.setText(textIn.getText().toString());
Button buttonRemove = (Button) addView.findViewById(R.id.remove);
arrayList.add(textIn.getText().toString());
buttonRemove.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
((LinearLayout) addView.getParent()).removeView(addView);
// textIn.setText("");
arrayList.remove(textOut.getText().toString());
}
});
textIn.setText("");
container.addView(addView);
}
//textIn.setText("");
}
});
If you change oriantation the activity will be recreated so you have to add the fragment again.
Please add code if you ask a question. You will get more help.
Use the activity lifecycle methods:
http://developer.android.com/training/basics/activity-lifecycle/index.html
Read this post:
Activity restart on rotation Android
Related
I want to render xamarin forms view control into android textview.
Below customrenderer renders Android TextView on Android device with initial default text.
Now, If I add more text into it, this control would not grow in height but instead becomes scrollable to see the text not visible on screen.
On other way around, if I reduce text content, this control would not reduce in height and occupy the same space and show reduced text content on scree.
Issue : In this case of text change, this label should increase or reduce height on screen for Android. It is working fine on IOS as expected.
BindingText is bindable property to set text for this control.
CopyableLabelRenderer is my custom renderer class for Xamarin Forms
view.
Here is a sample code.
class CopyableLabelRenderer : ViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
try
{
var label = new TextView(MainApplication.Context);
label.SetTextIsSelectable(true);
label.LinksClickable = true;
label.Text = (e.NewElement as CopyableLabel).BindingText; // this line sets text into this label
SetNativeControl(label);
}
catch (Exception ex)
{
var msg = ex.Message;
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName.Equals("BindingText"))
{
TextView textView = this.Control as TextView;
textView.Text = (Element as CopyableLabel).BindingText;
}
}
}
Here is a base class,
public class CustomLabel : View
{
public static readonly BindableProperty BindingTextProperty = BindableProperty.Create("BindingText", typeof(string),typeof(View),
string.Empty
);
public string BindingText
{
get
{
return (string)GetValue(BindingTextProperty);
}
set
{
SetValue(BindingTextProperty, value);
}
}
}
I have a custom DialogFragment as an inner class in my Activity. The custom DialogFragment contains 2 Buttons.
The first Button opens the Camera and the second one opens the Gallery.
Normally this DialogFragment is shown after an Image is pressed.
Until here everything is fine.
Now I want add a new functionality. When the Activityis opened the first time, I want to open the Camera automatically, that means I want to "press" the first Button of my DialogFragment.
In my Activity onCreate method I just show the DialogFragment and perform a click on the first Button. The problem is that the DialogFragment is not dismissed.
Here is my code:
public static class MyDialogFragment extends DialogFragment {
Button openCameraButton;
Button openGalleryButton;
boolean openCameraAutomatically;
public static MyDialogFragment newInstance(boolean openCameraAutomatically) {
MyDialogFragment f = new MyDialogFragment();
Bundle args = new Bundle();
args.putBoolean("open_camera", openCameraAutomatically);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
openCameraAutomatically = getArguments().getBoolean("open_camera");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.my_dialog, container, false);
getDialog().setTitle("title");
openCameraButton = (Button) rootView.findViewById(R.id.open_camera_button);
openCameraButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// launch Camera Intent...
getDialog().dismiss();
}
});
openGalleryButton = (Button) rootView.findViewById(R.id.open_gallery_button);
openGalleryButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Launch Gallery Picker Intent
getDialog().dismiss();
}
});
if(openCameraAutomatically) {
openCameraButton.performClick();
}
return rootView;
}
}
And here is how I call it:
FragmentManager fm = getSupportFragmentManager();
MyDialogFragment myDialogFragment = MyDialogFragment.newInstance();
myDialogFragment.show(fm, "");
The line getDialog().dismiss(); does not dismiss the DialogFragment, after the Camera callback (onActivityResult) the DialogFragment is still visible. If I press the Button manually (without using the method performClick) everything works fine.
Any ideas?
Thanks.
Try just dismiss() to dismiss the dialog and the fragment instead of getDialog().dismiss() which just dismisses the dialog and but not the fragment.
https://developer.android.com/reference/android/app/DialogFragment.html#dismiss()
void dismiss ()
Dismiss the fragment and its dialog. If the fragment was added to the back stack, all back stack state up to and including this entry will be popped. Otherwise, a new transaction will be committed to remove the fragment.
Update:
Here is another thought. You are trying to dismiss the dialog before the view for the DialogFragment is fully ready. This isn't a problem once the buttons are available for you to push, i.e., the layout is complete.
Try moving the automatic dismissal later in life cycle. I think that will work for you.
I am using an open source project(https://github.com/chrisbanes/cheesesquare) to develop my own application.
what I want is:
1.In the Home Fragment, there is a tablayout below to the toobar,and when the recycelview scroll, the Toolbar can hide, but the FloatingActionButton always stay;
2. In the Message Frgment, the is no Tab and on FloatingActionButton, only a simple blank Fragment with a Toolbar.
I try to do this in MainActivity:
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
menuItem.setChecked(true);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = null;
int id = menuItem.getItemId();
if (id == R.id.nav_home) {
fragment = new HomeFragment();
} else if (id == R.id.nav_message) {
fragment = new MessageFragment();
} else if (id == R.id.nav_friends) {
fragment = new FriendsFragment();
} else if (id == R.id.nav_discussion) {
fragment = new DiscussionFragment();
}
ft.replace(R.id.viewpager, fragment);
ft.commit();
mDrawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
}
but this not work, because the tablayout stay both in HomeFragment and MessageFragment.
When I try to do change the tablayout to the layout xml of HomeFragment, I also meet some problem because the below code should write in MainActivity
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
I feel puzzled, what should I do to achieve my goals?
I try to solve the problem like this, implement the basic functions.
I used grid component, and added row details..
However grid doesn't show details..
It's my code.
====
Grid grid = new Grid("Plain Grid");
grid.setDetailsGenerator(new DetailsGenerator() {
#Override
public Component getDetails(RowReference rowReference) {
// Find the bean to generate details for
final TrainingMemberVo bean = (TrainingMemberVo) rowReference.getItemId();
// A basic label with bean data
Label label = new Label("Extra data for " + bean.getMemberName());
// A button just for the sake of the example
Button button = new Button("Click me", new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
Notification.show("Button clicked for " + bean.getMemberName());
}
});
// Wrap up all the parts into a vertical layout
VerticalLayout layout = new VerticalLayout(label, button);
layout.setSpacing(true);
layout.setMargin(true);
return layout;
}
});
grid.addItemClickListener(new ItemClickListener() {
#Override
public void itemClick(ItemClickEvent event) {
if (event.isDoubleClick()) {
Object itemId = event.getItemId();
grid.setDetailsVisible(itemId, !grid.isDetailsVisible(itemId));
}
}
});
===
double clicked row, noting shows details..
Works for me without any issues. Have you checked if the event in the itemClick() is correctly fired? I. e. remove the boolean check for event.isDoubleClick() to see if it gets executed.
I'm using viewpager to display pictures. I just need three fragments basically: previous image to preview, current display image and next image to preview. I would like to just display a preview of previous and next image, it will change to full image when user actually swipe to it. So I'm thinking of just using 3 fragment to achieve this. Code is below:
private class ImagePagerAdapter extends FragmentStatePagerAdapter implements ViewPager.OnPageChangeListener {
private ImageFragment mImageFragment;
private ImagePreviewFragment mPreviousPreviewFragment;
private ImagePreviewFragment mNextPreviewFragment;
public ImagePagerAdapter(FragmentManager fm, ImageFragment image, ImagePreviewFragment previous, ImagePreviewFragment next) {
super(fm);
mImageFragment = image;
mPreviousPreviewFragment = previous;
mNextPreviewFragment = next;
}
#Override
public Fragment getItem(int position) {
if (position == mPager.getCurrentItem()) {
mImageFragment.display(position);
return mImageFragment;
}
if (position < mPager.getCurrentItem()) {
mPreviousPreviewFragment.display(position - 1);
return mPreviousPreviewFragment;
}
mNextPreviewFragment.display(position + 1);
return mNextPreviewFragment;
}
#Override
public int getCount() {
return 100;
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.d(TAG, "onPageScrolled");
}
#Override
public void onPageSelected(final int position) {
Log.d(TAG, "onPageSelected " + position);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
}, 500);
}
#Override
public void onPageScrollStateChanged(int state) {
Log.d(TAG, "onPageScrollStateChanged " + state);
}
#Override
public int getItemPosition(Object item) {
return POSITION_NONE;
//return POSITION_UNCHANGED;
}
}
So basically, I pre-created three fragments to display previous/next preview and current image and return them for getItem(). I also notifydatasetchange() in onpageselected() to make all three position to update the fragment when user swipe to new page.
But the problem is that it will throw out
Fragment already added IllegalStateException
when the fragments are added a second time. I think it's because it's been added before. I can create a new fragment every time but I think that's wasteful. So how can I reuse the already created fragment and just update them?
Thanks,
Simon
FragmentStatePagerAdapter design suggests creating a new Fragment for every page (see Google's example). And unfortunately you cannot readd a Fragment once it was added to a FragmentManager (what implicitly happens inside adapter), hence the exception you got. So the official Google-way is to create new fragments and let them be destroyed and recreated by the adapter.
But if you want to reuse pages and utilize an analogue of ViewHolder pattern, you should stick to views instead of fragments. Views could be removed from their parent and reused, unlike fragments. Extend PagerAdapter and implement instantiateItem() like this:
#Override
public Object instantiateItem(ViewGroup container, final int position) {
//determine the view type by position
View view = viewPager.findViewWithTag("your_view_type");
if (view == null) {
Context context = container.getContext();
view = LayoutInflater.from(context).inflate(R.layout.page, null);
view.setTag("your_view_type");
} else {
ViewGroup parent = (ViewGroup) item.getParent();
if (parent != null) {
parent.removeView(item);
}
}
processYourView(position, view);
container.addView(view, MATCH);
return view;
}
You should add some extra logic to determine the view type by position (since you have 3 types of views), I think you can figure that out.