On my ListView I have setup LayoutTransition via onCreate(). However after transition end I want to disable the transition effect so I set it to null in endTransition(). So, the problem is after I set it to null I can't event let in enable again when I want to refresh the ListView (I want to disable animation change effect via on scroll, click, drag, expandable)
Here is my code
MainActivity.class
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupListViewAnimation();
}
void setupListViewAnimation() {
if (lt == null) {
lt = new LayoutTransition();
lt.enableTransitionType(LayoutTransition.CHANGING);
lt.addTransitionListener(new LayoutTransition.TransitionListener() {
#Override
public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
}
#Override
public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
list.setLayoutTransition(null);
}
});
}
list.setLayoutTransition(lt);
}
void onClick() {
//before start to refresh listview
setupListViewAnimation();
//refresh listview
..............................
ListView Refresh Logic Here...
..............................
}
ANSWER MY OWN QUESTION
I found my own answer. If I want to disable my LayoutTransition Animation instaed of set value to null I can disable it in endTransition under LayoutTransition.TransitionListener() like below fixed from question
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupListViewAnimation();
}
void setupListViewAnimation() {
if (lt == null) {
lt = new LayoutTransition();
lt.enableTransitionType(LayoutTransition.CHANGING);
lt.addTransitionListener(new LayoutTransition.TransitionListener() {
#Override
public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
}
#Override
public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
//Change this line of code to below one
transition.disableTransitionType(LayoutTransition.CHANGING);
}
});
}
list.setLayoutTransition(lt);
}
void onClick() {
//before start to refresh listview
setupListViewAnimation();
//refresh listview
..............................
ListView Refresh Logic Here...
..............................
}
Related
I have a BottomSheetDialogFragment and inside onCreateView i am inflating 2 different views based on a condition. Now my 1st view contains a recyclerView and the condition on which i want to switch my views is that if the list is empty then inflate view 1 else inflate view 2. Now my problem is when my list data count becomes 0 i want to call the onCreateView again so that based on the condition my 2nd view would be inflated. But i don't know how am i supposed to do it or rather is this the right way to do it.
My Code -
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
if (this.documentCount > 0) {
View v = inflater.inflate(R.layout.bottom_sheet_layout_document_attachments_added, container, false);
documentArrayList = dataToRender.get(fieldPosition).getAttachments();
Button attachMore = (Button) v.findViewById(R.id.btn_attachMore);
if(documentCount == 5){
attachMore.getBackground().setAlpha(128);
}else{
attachMore.getBackground().setAlpha(255);
}
attachMore.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try{
if(documentCount == 5){
PageLoader.showToast(getResources().getString(R.string.document_limit_message));
}else{
pickDocuments();
}
}
catch (Exception e){
Sentry.captureException(e);
}
}
});
Button btnCloseDrawer = (Button) v.findViewById(R.id.btn_closeDrawer);
btnCloseDrawer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dismiss();
}
});
recyclerview_documents = v.findViewById(R.id.recyclerview_documents);
adapter_documents = new DocumentAdapter(this, documentArrayList, fieldPosition);
recyclerview_documents.setAdapter(adapter_documents);
recyclerview_documents.setLayoutManager(new LinearLayoutManager(mContext));
return v;
} else {
View v = inflater.inflate(R.layout.bottom_sheet_layout_document, container, false);
TextView txtview_attach = (TextView) v.findViewById(R.id.txtview_attach);
txtview_attach.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try{
permissionManager.checkPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE, new PermissionManager.PermissionAskListener() {
#Override
public void onNeedPermission() {
ActivityCompat.requestPermissions(getActivity(), new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE
}, REQUEST_EXTERNAL_STORAGE);
}
#Override
public void onPermissionPreviouslyDenied() {
showDocumentRational();
}
#Override
public void onPermissionPreviouslyDeniedWithNeverAskAgain() {
dialogForSettings(getResources().getString(R.string.permission_denied), getResources().getString(R.string.permission_denied_document_access_message));
}
#Override
public void onPermissionGranted() {
pickDocuments();
}
});
}
catch (Exception e){
Sentry.captureException(e);
}
}
});
return v;
}
}```
Can't use more then one views for one fragment, but you can create a fragment wrapper that depends on the conditions, will show or create the fragment you need with the view you need.
for example WrapperFragment checking list size and creating Fragment1, when list size changed Wrapper fragment removung from fragment manager Fragment1 and add Fragment2
fab antimation only work on first time I click. after that when I click on the button, on click listener works and fab show but without animation. I am creating it on fragment. mAddFab is the main button to show other fab's and mRequestFab, mDonateFab are the buttons which shows after mAddFab button clicked. Tell me if animation file needed
public class NameFragment extends Fragment {
private FloatingActionButton mAddFab, mRequestFab, mDonateFab;
private Animation mFabOpenAnim, mFabCloseAnim, rotateOpen, rotateClose;
private boolean isOpen;
private Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
context = getContext();
super.onCreate(savedInstanceState);
mFabOpenAnim = AnimationUtils.loadAnimation(context, R.anim.fab_open_anim);
mFabCloseAnim = AnimationUtils.loadAnimation(context, R.anim.fab_close_anim);
rotateOpen = AnimationUtils.loadAnimation(context, R.anim.rotate_open_anim);
rotateClose = AnimationUtils.loadAnimation(context, R.anim.rotate_close_anim);
isOpen = false;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_plasma, container, false);
RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
RecyclerViewAdapter adapter = new RecyclerViewAdapter();
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
mAddFab = view.findViewById(R.id.addbtn);
mRequestFab = view.findViewById(R.id.requestbtn);
mDonateFab = view.findViewById(R.id.donatebtn);
mAddFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isOpen){
mAddFab.setAnimation(rotateClose);
mRequestFab.setAnimation(mFabCloseAnim);
mDonateFab.setAnimation(mFabCloseAnim);
mRequestFab.setVisibility(View.INVISIBLE);
mDonateFab.setVisibility(View.INVISIBLE);
isOpen = false;
} else {
mAddFab.setAnimation(rotateOpen);
mDonateFab.setAnimation(mFabOpenAnim);
mRequestFab.setAnimation(mFabOpenAnim);
mDonateFab.setVisibility(View.VISIBLE);
mRequestFab.setVisibility(View.VISIBLE);
isOpen = true;
}
}
});
return view;
}
}
I found the solution. the problem was with the function that I have used to do the animation which is setAnimation() and I have changed it with startAnimation().Main differences between both the functions are-
SetAnimation-
when the view is added to the viewGroup, animation will be called and when the view has been added, the animation will not be called
StartAnimation-
animation will be called all the time even though the view has been added.
I am having the "child already has a parent" error close to what a lot of people have been getting, however, I am getting it doing something different (as far as my searches have shown me). I am assuming that the way I am adding the fragment is not necessarily wrong, but I cannot for the life of me figure out how the fragment I am adding already has a parent.
I am launching from my main activity using a fragment to be loaded into a FrameLayout. Here is the onCreate from my main activity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
realm = Realm.getDefaultInstance();
if (savedInstanceState == null) {
}
tripsFragment = new CarTripsOverview();
getSupportFragmentManager().beginTransaction().add(R.id.content_container, tripsFragment).commit();
}
And here are the methods which run for CarTripsOverview (which is a Fragment):
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
}
setUpRealm();
}
void setUpRealm() {
realm = Realm.getDefaultInstance();
RealmQuery<Car> carQuery = realm.where(Car.class);
RealmResults<Car> carResults = carQuery.findAll();
carAdapter = new CarArrayAdapter(getActivity(),0, carResults, true);
RealmQuery<Trip> tripQuery = realm.where(Trip.class);
RealmResults<Trip> tripResults = tripQuery.findAll();
tripAdapter = new TripAdapterRealm(getActivity(), 0, tripResults, true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_car_trips_overview, container, true);
// Bind all of the views with Butter Knife
ButterKnife.bind(this, view);
setUpSwipeMenu();
// Add my event listeners
tripListView.setAdapter(tripAdapter);
carSpinner.setAdapter(carAdapter);
return view;
}
void setUpSwipeMenu() {
SwipeMenuCreator creator = new SwipeMenuCreator() {
#Override
public void create(SwipeMenu menu) {
SwipeMenuItem deleteItem = new SwipeMenuItem(getContext());
deleteItem.setBackground(new ColorDrawable(Color.RED));
deleteItem.setWidth(MathHelper.dipToPixels(getContext(), 90));
deleteItem.setTitle("Delete");
deleteItem.setTitleColor(Color.WHITE);
deleteItem.setTitleSize(18);
menu.addMenuItem(deleteItem);
}
};
tripListView.setMenuCreator(creator);
tripListView.setOnMenuItemClickListener(new SwipeMenuListView.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(int position, SwipeMenu menu, int index) {
Trip trip = tripAdapter.getItem(position);
switch (index) {
case 0:
delete(trip);
tripAdapter.notifyDataSetChanged();
break;
}
return false;
}
});
}
My biggest problem is that I just don't understand quite where I am adding the child to the parent where it would already have a parent.
All of my source code can be found here.
Instead of:
View view = inflater.inflate(R.layout.fragment_car_trips_overview, container, true);
use:
View view = inflater.inflate(R.layout.fragment_car_trips_overview, container, false);
Notice the last parameter is false now. If you use true, the view you just created will be automatically added to the container (second parameter of inflate). With fragments, always use false in onCreateView(...).
I'm trying to create a viewpager where the user can tap a photo and the photo will take a 'highlighted' state.
I achieve the 'highlighted' state by setting a FrameLayout overlay above the image. The problem is when i swipe trough the pages the state is not only lost but it appears on non selected images.
This is my viewpager adapter:
public class ImageSliderAdapter extends FragmentPagerAdapter {
//Image ids from constants
private int[] Images = Constants.Images;
private int mCount = Images.length;
public ImageSliderAdapter$Adapter(FragmentManager fm) {
super(fm);
}
// The displayed fragment for each position
#Override
public FragmentImageSlider getItem(int position) {
return FragmentImageSlider.newInstance(Images[position];
}
#Override
public int getCount() {
return mCount;
}
}
And this is the fragment that the viewpager returns:
public class FragmentImageSlider extends Fragment {
//Image resource id to show
int imageResourceId;
//Image view of the pic displayed
ImageView image;
// View to indicate highlighted images
View highliteView;
public static FragmentImageSlider newInstance(int imageResourceId){
FragmentImageSlider f = new FragmentImageSlider();
Bundle b = new Bundle();
b.putInt("image", imageResourceId);
f.setArguments(b);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (getArguments() !=null) {
//get image resource id from extras
imageResourceId = getArguments().getInt("image");
}
View root = inflater.inflate(R.layout.displayLayout, null);
image = (ImageView) root.findViewById(R.id.imageView);
highliteView = root.findViewById(R.id.highliteView);
image.setImageResource(imageResourceId);
//When the image is clicked, toggle the highlighted state
image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//toggle state
//this view has a selector and changes when selected
highliteView.setSelected(!highliteView.isSelected());
}
});
return root;
}
}
So my question is, how can i keep the highlighted state?
You can change the visibility of your highlight view instead of selected state.
By default set the visibility of highlight view as GONE and when the image is selected change it to visible.
highliteView.setVisibility(View.GONE);
// when the image is clicked show the highlighted view
image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
highliteView.setVisibility(View.VISIBLE);
}
});
According to the [FragmentPagerAdapter document](view hierarchy may be destroyed when not visible),
The fragment of each page the user visits will be kept in memory, though its view hierarchy may be destroyed when not visible
The view maybe reloaded from default layout when it go out of the view, that's why the highlight state is lost.
You should keep the highlight state in your Fragment:
public MyFragment extends Fragment{
//variable to keep the state
private boolean highlight;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//rest of your other code
image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
highliteView.setSelected(!highliteView.isSelected());
//set the highlight state when clicked
highlight = !highliteView.isSelected();
}
});
return root;
}
//set the view state to the image view
public void onViewCreated(View view, Bundle savedInstanceState){
highliteView.setSelected(highlight);
}
}
I have a list fragment on the left of another fragment and is essentially the standard click an item and update the right fragment pattern. When they click an item in the list fragment they are choosing the news article category and I need to keep whatever one is selected when they rotate the device. How do I do that? My current code doesn't work.
My code is as follows:
public class SideMenuFragment extends ListFragment {
ArrayList<SideItem> sideItems;
SideAdapter sideAdapter;
public SideMenuFragment() {
this.setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.list, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
sideItems = new ArrayList<SideItem>();
...add bunch of items
sideAdapter = new SideAdapter(getActivity(), sideItems);
getListView().setVerticalScrollBarEnabled(false);
setListAdapter(sideAdapter);
if (savedInstanceState != null) {
sideAdapter.setSelectedItem(savedInstanceState.getInt("sidePosition"));
sideAdapter.notifyDataSetChanged();
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("sidePosition", sideAdapter.getSelectedItem());
}
#Override
public void onListItemClick(ListView lv, View v, int position, long id) {
if (sideAdapter.getSelectedItem() != position) {
sideAdapter.setSelectedItem(position);
sideAdapter.notifyDataSetChanged();
}
switch (position) {
...switch the fragment depending on position.
}
}
// the meat of switching the above fragment
private void switchFragment(Fragment fragment, String title) {
if (getActivity() == null)
return;
if (getActivity() instanceof HomeActivity) {
HomeActivity a = (HomeActivity) getActivity();
a.switchContent(fragment, title);
}
}
}
First, add your Fragment in xml if the Activity layout.
In Activity onCreate
getFragmentManager().findFragmentById(R.id.youtfragmentid).setRetainInstance(true)
This means that the fragment will not be recreated on activity recreate.
Don't change your ListView in onActivityCreated - because it will be rebuilt every time orientation changes. If you set a new adapter - the states of children will be reseted.
Add checking for null or a boolean flag that the view already was created.
Next time onActivityCreated gets called, your list adapter should not change
if (sideAdapter == null) {
sideAdapter = new SideAdapter(getActivity(), sideItems);
getListView().setVerticalScrollBarEnabled(false);
setListAdapter(sideAdapter);
}
Also, don't create new view in onCreateView instead use previously created one.
private View v;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (v == null) {
v = inflater.inflate(R.layout.list, null);
} else {
// detatch from container and return the same view
((ViewGroup) getListView().getParent()).removeAllViews();
}
return v;
}