Layout/View based navigation android - android

Is there some kind of View/Layout based navigation library out there. All the navigation libraries are based on activity/fragment. It make sense when Android phone has only 256M memory 10 years ago. Now adays, most Android phone has more than 4G, navigate between screen by show/hide view and save a lot of programming effort make a lot of sense, but I can not find such a library.
I mean something like
public class NavActivity extends AppCompatActivity {
ViewGroup viewRoot ;
Stack<ViewGroup> parentStack ;
ViewGroup activeView ;
public void NavigateTo (int layoutID)
{
viewRoot.removeView(activeView) ;
parentStack.push(activeView) ;
activeView = (ViewGroup) getLayoutInflater().inflate(layoutID, viewRoot, false);
viewRoot.addView(activeView) ;
}
public void NavigateBack ()
{
viewRoot.removeView(activeView) ;
if ( !parentStack.empty())
{
activeView = parentStack.pop() ;
viewRoot.addView(activeView) ;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewRoot = (ViewGroup) findViewById(R.id.viewHost);
activeView = (ViewGroup) viewRoot.getChildAt(0);
parentStack = new Stack<>() ;
}
public void onEdit (View v)
{
NavigateTo (R.layout.edit_view) ;
}
public void onDone (View v)
{
NavigateBack () ;
}
public void onDetail (View v)
{
NavigateTo (R.layout.detail_view) ;
}
}

Related

Update or switch BottomSheetDialogFragment inflated view when recyclerView dataset is changed

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

Android - RecyclerView multiplies itself every time device is rotated

I have a landscape configuration for one of my app's activities. This activity contains a fragment and this fragment contains one textview and one recyclerview. Everytime when i switch in between portrait and landscape modes, the recyclerview leaves the view of itself like however it was before i turned the device. It might be a little difficult to understand what i try to ask here, so i recorded a gif for that.
https://giphy.com/gifs/3Wv7NAtT8ezP1SQhDu
This is my activity
public class RecipeStepsActivity extends AppCompatActivity {
static Recipe recipe;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recipe_steps);
if (StepDetailActivity.SDA_TAG.equals(StepDetailActivity.NEGATIVE))
recipe = getIntent().getParcelableExtra("recipe");
Bundle b = new Bundle();
b.putParcelable("recipe", recipe);
ActionBar ab = getSupportActionBar();
if (ab != null)
ab.setTitle(recipe.getName());
RecipeStepsFragment recipeStepsFragment = new RecipeStepsFragment();
recipeStepsFragment.setArguments(b);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().add(R.id.frame_layout_steps, recipeStepsFragment).commit();
}
}
This is my fragment
public class RecipeStepsFragment extends Fragment {
#BindView(R.id.recipe_steps_rv)
RecyclerView recyclerView;
#BindView(R.id.ingredients_tv)
TextView tv_ingredients;
List<Step> steps;
public RecipeStepsFragment(){}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recipe_steps, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
List<Ingredients> ingredients;
Recipe recipe = getArguments().getParcelable("recipe");
steps = recipe.getSteps();
initRecyclerView();
ingredients = recipe.getIngredients();
String ingredientsAppended = "INGREDIENTS" + "\n\n";
if (ingredients == null){
ingredientsAppended = "Not Available";
} else {
for (int a = 0 ; a < ingredients.size() ; a++) {
Ingredients i = ingredients.get(a);
ingredientsAppended += String.valueOf(i.getQuantity()) + " " +
i.getMeasure() + " " +
i.getIngredient();
if (a+1 != ingredients.size()){
ingredientsAppended += '\n';
}
}
}
tv_ingredients.setText(ingredientsAppended);
if(savedInstanceState != null){
recyclerView.scrollToPosition(savedInstanceState.getInt("position"));
}
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
outState.putInt("position", recyclerView.getVerticalScrollbarPosition());
super.onSaveInstanceState(outState);
}
private void initRecyclerView(){
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
RecipeStepsRecyclerAdapter recipeStepsRecyclerAdapter =
new RecipeStepsRecyclerAdapter(steps, new RecipeStepsRecyclerAdapter.ClickListener() {
#Override
public void onItemClick(int clickedItemPosition) {
Intent intentToStepDetail = new Intent(getActivity(), StepDetailActivity.class);
Step step = steps.get(clickedItemPosition);
intentToStepDetail.putExtra("step", step);
startActivity(intentToStepDetail);
}
}, getContext());
recyclerView.setAdapter(recipeStepsRecyclerAdapter);
recipeStepsRecyclerAdapter.notifyDataSetChanged();
}
}
This is my adapter
public class RecipeStepsRecyclerAdapter extends RecyclerView.Adapter<RecipeStepsRecyclerAdapter.ViewHolder> {
private List<Step> stepList;
private LayoutInflater mInflater;
final private ClickListener clickListener;
public RecipeStepsRecyclerAdapter(List<Step> stepList, ClickListener clickListener, Context context){
this.stepList = stepList;
this.clickListener = clickListener;
mInflater = LayoutInflater.from(context);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recipe_steps_recyclerview_adapter, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Step step = stepList.get(position);
String stepContent = step.getShortDescription();
holder.listingNumber.setText(String.valueOf(position+1));
holder.stepContent.setText(stepContent);
}
#Override
public int getItemCount() {
return stepList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView listingNumber;
TextView stepContent;
private ViewHolder(View itemView) {
super(itemView);
listingNumber = itemView.findViewById(R.id.list_number_tv);
stepContent = itemView.findViewById(R.id.step_content_tv);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int clickedPosition = getAdapterPosition();
clickListener.onItemClick(clickedPosition);
}
}
public interface ClickListener{
void onItemClick(int clickedItemPosition);
}
}
Layout files are as I already explained above. I guess nothing special to post here.
Thanks in advance.
The problem is that you add a new fragment to the Activity every time it is created. Here's the end of your onCreate(...):
RecipeStepsFragment recipeStepsFragment = new RecipeStepsFragment();
recipeStepsFragment.setArguments(b);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().add(R.id.frame_layout_steps, recipeStepsFragment).commit();
The FragmentManager keeps a reference to the fragment you add to it even if the host Activity is destroyed. Thus, you keep adding new instances of the RecipeStepsFragment eventually overlaying each other and producing the seen behavior.
Don't worry, the fix is pretty simple: use replace(...) instead of add(...):
fm.beginTransaction().replace(R.id.frame_layout_steps, recipeStepsFragment).commit();
P.S.: Note, however, that replacing the current fragment with a new one every time the host activity is destroyed is not a good idea. You should check either if the savedInstanceState is null (which indicates that it's a non-recreated Activity) or if the given fragment is already added (define a tag when adding the fragment and try finding it in onCreate(...) before replacing the old one).
Every time you change the rotation of the screen your activity is destroyed and recreated. That is the reason why your list is populating with new items each time when you switch between your orientation.
So it's important you only instantiate your objects once, and not keep recreating them each time your app is recreated. Which then adds them to your list.
You can use onSaveInstanceState and onRestoreInstanceState.
If you want your app to allow orientation change, apply logic so your list don't get new items each time when activity is created.
Put configChanges attribute in your activity in menifest file
<activity android:name=".VideoActivity" android:configChanges="keyboardHidden|orientation|screenSize"/>

TextView SetTextSize not working inside fragment

I have a Activity with TabLayout and ViewPager. I have two fixed buttons floating on top of the activity at bottom right corner. These two buttons are Plus and Minus buttons for increasing/decreasing the font sizes of the text inside the fragment. I created an Interface inside Activity and implemented it inside the fragment where I am changing the textsize of TextView.
Problem is that it does not work at the time when I click the button. When I swipe the fragment then it shows with updated textsize. Am I missing something? Is this the correct way?
Inside Activity
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.post_single);
//....
onCoachMark();
//....
}
public void onCoachMark() {
final FrameLayout overlayFramelayout = new FrameLayout(getApplicationContext());
setContentView(overlayFramelayout);
View view = getLayoutInflater().inflate(R.layout.post_single, overlayFramelayout, false);
final View overlay_view = getLayoutInflater().inflate(R.layout.zoom_overlay, overlayFramelayout, false);
final ImageView ivPlus = (ImageView) overlay_view.findViewById(R.id.ivPlus);
final ImageView ivMinus = (ImageView) overlay_view.findViewById(R.id.ivMinus);
overlayFramelayout.addView(view);
overlayFramelayout.addView(overlay_view);
ivPlus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
CommonFunctions.FONT_SIZE += 3;
CommonFunctions.putMySharedPreferences(getApplicationContext(), "fontSize", String.valueOf(CommonFunctions.FONT_SIZE));
iCoachMark.onTextSizeChange();
}
});
ivMinus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
CommonFunctions.FONT_SIZE -= 3;
CommonFunctions.putMySharedPreferences(getApplicationContext(), "fontSize", String.valueOf(CommonFunctions.FONT_SIZE));
iCoachMark.onTextSizeChange();
}
});
}
public interface ICoachMark {
void onTextSizeChange();
}
public void setOnCoachMark(ICoachMark iCoachMark) {
this.iCoachMark = iCoachMark;
}
Inside Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.post_content, container, false);
tvTitle = (TextView) rootView.findViewById(R.id.tvTitle);
tvDescription = (TextView) rootView.findViewById(R.id.tvDescription);
svPost = (NestedScrollView) rootView.findViewById(R.id.svPost);
String fs = CommonFunctions.getMySharedPreferences(getActivity().getApplicationContext(), "fontSize");
if (fs.matches("")) {
CommonFunctions.putMySharedPreferences(getActivity().getApplicationContext(), "fontSize", String.valueOf(CommonFunctions.FONT_SIZE));
} else {
CommonFunctions.FONT_SIZE = Integer.valueOf(fs);
tvTitle.setTextSize(CommonFunctions.FONT_SIZE);
tvDescription.setTextSize(CommonFunctions.FONT_SIZE);
}
((PostActivity) getActivity()).onTextSizeChange(new PostActivity.ICoachMark() {
#Override
public void onTextSizeChange() {
tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, CommonFunctions.FONT_SIZE);
tvDescription.setTextSize(TypedValue.COMPLEX_UNIT_SP, CommonFunctions.FONT_SIZE);
}
});
}

Unable to disable and enable LayoutTransition

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...
..............................
}

Refresh a TextView from inside a fragment

I'm quite new in android and i have a problem trying to develop an app.
I want to make a countdown timer in my activity but i need to do it within a fragment, so i need to put a for loop that count from 0 - 10 and refresh a TextView inside that fragment.
I need the fragment to do it independently from the activity.
thanks for your collaboration
public class fragmento_3 extends Fragment {
int count= 10;
TextView texto_count;
View v;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragmento_3, container, false);
texto_count = (TextView)v.findViewById(R.id.texto_count);
return v;
}
}
and I want to put this inside
for(int x = count; x >= 0 ; x--){
texto_count.setText(String.valueOf(x));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
thanks,
It is better to use Timer for periodic tasks rather than using Thread.sleep.
Try this code
public class fragmento_3 extends Fragment{
int count= 10;
TextView texto_count;
Timer t;
View v;
TimerTask timer= new TimerTask(){
#Override
public void run() {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
count--;
if(count >= 0) {
texto_count.setText(Integer.toString(count));
}
}
});
if (count <= 0) {
t.cancel();
}
}
};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragmento_3, container, false);
texto_count = (TextView)v.findViewById(R.id.texto_count);
t = new Timer();
t.scheduleAtFixedRate(timer , 0 , 2000);
return v;
}
}
Its probably because you are using the wrong variable texto_conteo. You have declared texto_count as the instance variable so you probably want to use that.

Categories

Resources