I have implemented a ViewPager which connects multiple Fragments together to give off that 'scrolling view' experience as you might already know. Anyhow I have a button on my first fragment that needs to scroll the user to the second fragment. How do I get this done folks? Here's my code:
ViewPager XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
</LinearLayout>
Fragment 1:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#3498db" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="left"
android:layout_marginLeft="15dp"
android:layout_marginTop="25dp"
android:text="Step 1"
android:textColor="#ffffff"
android:textSize="50dp" />
<Button
android:id="#+id/step1Btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:layout_marginBottom="5sp"
android:background="#drawable/buttonshape"
android:shadowColor="#A8A8A8"
android:shadowDx="0"
android:shadowDy="0"
android:shadowRadius="5"
android:text="Next Step"
android:textColor="#FFFFFF"
android:textSize="30sp" />
</LinearLayout>
</RelativeLayout>
In order to make this post short, let's say the second fragment has the same XML.
So we have TWO fragments. Here's the fragment java class:
public class RegisterPageOne extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.registration_page1, container, false);
Button nextStep = (Button) v.findViewById(R.id.step1Btn);
nextStep.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
//Where I want to call the SECOND FRAG
}
});
return v;
}
public static RegisterPageOne newInstance(String text) {
RegisterPageOne f = new RegisterPageOne();
Bundle b = new Bundle();
b.putString("msg", text);
f.setArguments(b);
return f;
}
}
help me out please :)
You can use the setCurrentItem(int item,boolean smoothScroll) method of your viewPager object to achieve this. Here is the documentation.
Saw your followup question about how to refer to the ViewPager, from your Fragment. It's pretty convoluted, for a relative newbie like me, but, I think I can get all of it... I'll give you what I did in my code. Set up a listener in the ViewPager:
public class PageViewActivity extends FragmentActivity
implements PageDisplayPortFrag.OnLinkExpectedListener {
...
}
This gets referenced in your Fragment:
private OnLinkExpectedListener mListenerLink;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListenerLink = (OnLinkExpectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnLinkExpectedListener");
}
}
#Override
public void onDetach() {
mListenerLink = null;
super.onDetach();
}
// THIS IS THE METHOD CALLED BY THE BUTTON CLICK !!!
public void linkExpected(String ticker) {
if (mListenerLink != null) {
mListenerLink.onLinkActivity(ticker);
}
}
public interface OnLinkExpectedListener {
public void onLinkActivity(String ticker);
}
And, then, a method gets called in the ViewPager:
#Override
public void onLinkActivity(String ticker) {
// receive ticker from port click; user wants to view page in webview, for this security
//Toast.makeText(this, "Ticker item clicked: " + ticker, Toast.LENGTH_SHORT).show();
// NEHARA, YOU MAY OR MAY NOT NEED TO DO STUFF HERE
// THIS IS WHAT I NEEDED TO DO; LEAVING IT FOR THE
// getFragmentTag() EXAMPLE -- WHICH CAME FROM Stack Overflow POSTERS
// get all-important fragment tag
String frag_Tag = getFragmentTag(pager.getId(),1);
// use tag to get the webview fragment
PageXYZWebviewFrag xyzWeb = (PageXYZWebviewFrag)
getSupportFragmentManager().findFragmentByTag(frag_Tag);
// send request to the webview fragment
xyzWeb.loadPageForSelectedSecurity(ticker);
// SET THE DESIRED FRAGMENT, assumes I know the fragment number
// from when I set up the ViewPager
// switch to the webview fragment
pager.setCurrentItem(1);
}
// fragment tag getter -- very important, yet has been elusive
private String getFragmentTag(int viewPagerId, int fragmentPosition) {
return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
}
Related
I am working on android studio. I am using fragments to make the app workflow. The app is basically for order taking. One customer can have more than one order. So for it, I have used RecyclerView. Below is my GUI
What do I want to do?
I want to update my Total Qty and Order Value in such a way that whenever the user enters the quantity both edittexts should be updated. For example, in the above image, I searched for one product, its rate is 287.30 and when I entered the quantity 5 then Total Qty: 5 and Order Value: 287.30. After that, I select another product and enter its quantity 8 then both edit text should be updated like Total Qty: 13 and Order Value: 509.15, and when I remove any product then it should subtract the total quantity and order value.
The Total Qty: and Order Value: is in my main fragment. Below is my code
Fragment Layout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/products"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:focusable="true" />
</LinearLayout>
<LinearLayout
android:id="#+id/product_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10sp"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_product">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Total Qty:" />
<EditText
android:id="#+id/total_qty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_horizontal"
android:hint=""
android:inputType="number" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Order Value :" />
<EditText
android:id="#+id/order_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_horizontal"
android:hint=""
android:inputType="none" />
</LinearLayout>
</LinearLayout>
Fragment Code
// created getter setters
public EditText totalQty,totalOrder;
public EditText getTotalQty(){
return totalQty;
}
public void setTotalQty(EditText et){
this.totalQty = et;
}
public EditText getTotalOrder(){return totalOrder;}
public void setTotalOrder(EditText ett){this.totalOrder=ett;}
addProduct.setOnClickListener(v -> {
mProducts.add(new ProductDetail());
mProductsAdapter.setProducts(mProducts);
productsRecyclerView.smoothScrollToPosition(mProducts.size() - 1);
});
Product Layout
<AutoCompleteTextView
android:id="#+id/tv_product"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10sp"
android:gravity="start"
android:hint="Enter Product"
android:inputType="text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="#+id/product_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10sp"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_product">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="vertical">
<EditText
android:id="#+id/prod_qty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="left"
android:hint="Enter Quantity"
android:inputType="number" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="vertical">
<EditText
android:id="#+id/prod_price"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="left"
android:hint="Prod Price"
android:inputType="numberDecimal" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".5"
android:orientation="vertical">
<EditText
android:id="#+id/prod_specs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="left"
android:hint="Prod Specs"
android:inputType="none" />
</LinearLayout>
</LinearLayout>
<Button
android:id="#+id/btn_rmv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:layout_marginBottom="1dp"
android:text="Remove Product"
android:textColor="#color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/product_infos" />
Product Adapter
View productView = inflater.inflate(R.layout.product_layout, parent, false);
ProductViewHolder viewHolder = new ProductViewHolder(productView);
viewHolder.tvProduct.setAdapter(prodAdapter);
viewHolder.tvProduct.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
#Override
public void afterTextChanged(Editable s) {
mProductManager = new ProductManager(context);
int position = viewHolder.getAdapterPosition();
if (position != -1) {
ProductDetail productDetail = mProductManager.getProductByPrdName(s.toString());
mProducts.get(position).setProductNameFull(s.toString());
viewHolder.price.setText(productDetail.getPrice());
viewHolder.spec.setText(productDetail.getProductSpec());
viewHolder.pgrp.setText(productDetail.getProductGroup());
viewHolder.ccode.setText(productDetail.getCompanyCode());
viewHolder.cname.setText(productDetail.getCompanyName());
viewHolder.pcode.setText(productDetail.getProductCode());
}
}
});
viewHolder.quantity.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
int position = viewHolder.getAdapterPosition();
if (position != -1) {
Integer val = null;
try {
val = Integer.valueOf(s.toString());
} catch (Exception e) {
}
mProducts.get(position).setQuantity(val);
}
}
});
viewHolder.removeBtn.setOnClickListener(v -> {
int position = viewHolder.getAdapterPosition();
if (position != -1) {
mProducts.remove(position);
notifyItemRemoved(position);
}
});
return viewHolder;
Update 1
Below is my Fragment Class
public class SurveyFormFragment extends Fragment {
.
.
.
.
private final LiveData<Integer> mQuantity = new MutableLiveData<>(0);
private final LiveData<Integer> mOrderValue = new MutableLiveData<>(0);
private ViewModel mViewModel;
private FragmentBinding mBinding;
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d("myfragment", "onCreateView");
getActivity().setTitle(getString(R.string.title_new_survey));
mContext = getActivity();
if (view == null) {
view = inflater.inflate(R.layout.new_survey_form_layout, container, false);
mLinearLayout = view.findViewById(R.id.ll_prod);
this.initElements(view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.initListeners(getActivity());
}
Bundle arguments = getArguments();
if (arguments != null && arguments.containsKey("booking_id")) {
isNewSurvey = false;
initSurveyData(arguments.getString("booking_id"));
this.updatingSurveyId = arguments.getString("booking_id");
}
}
Log.d("package", getActivity().getPackageName());
Log.d(TAG, Common.getCarrierName(getActivity()));
return view;
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d("myfragment", "onActivityCreated");
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
Log.d("myfragment", "onCreate");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("myfragment", "onDestroy");
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
//save now
savedInstanceState.putString("faisal_qayyum", consumerNameEditText.getText().toString());
super.onSaveInstanceState(savedInstanceState);
Log.d("myfragment", "onSaveInstanceState saving " + consumerNameEditText.getText().toString());
}
#Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
//restore now
Log.d("myfragment", "onViewStateRestored");
}
.
.
.
.
}
Error
How can I add and then update the values?
Any help would be highly appreciated.
I will disappoint you by not sharing code. I will share you a simple graphic of what you need to do.
[Fragment]: displays your list of orders. When an event is triggered (user tapped something or changed something), forwards this event to a ViewModel. Also Observes for the ViewModel data state.
[ViewModel]: exposes a series of functions to listen for user events (e.g. the user tapped this order, or the user changed the quantity of this order to NN, etc.). Also offers a LiveData (or Flow) with the State and Data your Fragment needs. Maybe even talks to the repository where this data originates from (where you save your Orders in your persistent or backend).
Interactions:
When the UI modified something, you tell the viewModel: "This data changed, the order X, now has a quantity of Y".
The ViewModel will process this, update the State of the screen, and send the new data via your Livedata/Flow that the Fragment observes.
When the Fragment receives this new data, it will update the UI accordingly, as that's its most important job.
This whole thing has been greatly documented in the official Android recommended architecture guides. I suggest you start from there instead of trying to fight the framework and making your life more complicated.
implement interface between adapter and fragment like this (it is just sodu to tell how you have to implement things also you have to check it out how to implement interfaces
===============================================================
public frgment extends Fragment implements GetValueInterface{
in onCreate function{
int totalquantity;
call this after adapter initialization
adapter.registergetValueInterface(this)
}
#Override Void setQuantity(Int _gotquantity){
_gotquantity+=_gotquantity;
totalquantityedittext.setText(_gotquantity,TextView.BufferType.EDITABLE)
}
}
and in adapter class
Adapter class
{
public GetValueInterface instance;
function registergetValueInterface(GetValueInterface obj){
instance=obj;
}
//and in quantity edittext text watcher
call instance.setQuantity(quanity)
}
like this you can minus the quantity as well on removal of item
Actually it's releated with Interactions like LiveData.
But rather than write a looot of code, simply I'm passing runnable to childs for call it when somethink changed :)
For example:
class Root{
...
public void addItem(){
ItemController cont = new ItemController(() -> updateSums());
...
}
public void updateSums(){
//TODO
}
}
class ItemController{
Runnable updater;
public ItemController(Runnable updater){
this.updater = updater;
}
public void onSomethingChanged(){
updater.run();
}
}
You should work with LiveData and DataBinding
In order to do so you activate it in your build.gradle file:
android {
...
buildFeatures {
dataBinding true
}
}
Then add the following code.
Add a ViewModel class:
public class ViewModel extends AndroidViewModel
{
private final MediatorLiveData<Integer> mTotalQuantity = new MediatorLiveData<>();
private final MediatorLiveData<Integer> mTotalOrder = new MediatorLiveData<>();
private final List<LiveData<Integer>> mOrders = new ArrayList<>();
private final List<LiveData<Integer>> mQuantities = new ArrayList<>();
public ViewModel(#NonNull Application application)
{
super(application);
mTotalOrder.setValue(0);
mTotalQuantity.setValue(0);
}
public LiveData<Integer> getTotal()
{
return mTotalOrder;
}
public LiveData<Integer> getQuantity()
{
return mTotalQuantity;
}
public void attachQuantity(LiveData<Integer> quantity)
{
mQuantities.add(quantity);
mTotalQuantity.addSource(quantity, (q) -> calculateQuantities());
}
public void detachQuantity(LiveData<Integer> quantity)
{
mQuantities.remove(quantity);
mTotalQuantity.removeSource(quantity);
calculateQuantities();
}
private void calculateQuantities()
{
int total = 0;
for (LiveData<Integer> quantity : mQuantities)
{
Integer value = quantity.getValue();
if (value != null)
{
total += value;
}
}
mTotalQuantity.setValue(total);
}
public void attachTotal(LiveData<Integer> total)
{
mOrders.add(total);
mTotalOrder.addSource(total, (q) -> calculateOrders());
}
public void detachTotal(LiveData<Integer> total)
{
mOrders.remove(total);
mTotalOrder.removeSource(total);
calculateOrders();
}
private void calculateOrders()
{
int total = 0;
for (LiveData<Integer> order : mOrders)
{
Integer value = order.getValue();
if (value != null)
{
total += value;
}
}
mTotalOrder.setValue(total);
}
}
In your fragment class add the following:
private LiveData<Integer> mQuantity = new MutableLiveData<>(0);
private LiveData<Integer> mOrderValue = new MutableLiveData<>(0);
private ViewModel mViewModel;
private FragmentBinding mBinding;
#Override
public void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mViewModel = new ViewModelProvider(requireActivity()).get(ViewModel.class);
mViewModel.attachQuantity(mQuantity);
mViewModel.attachTotal(mOrderValue);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState)
{
mBinding = DataBindingUtil.setContentView(this, R.layout.fragment);
mBinding.quantity = mQuantity;
mBinding.order_value = mOrderValue;
}
#Override
public void onDestroy()
{
super.onDestroy();
mViewModel.detachQuantity(mQuantity);
mViewModel.detachTotal(mOrderValue);
}
Add this to your product layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="quantity"
type="android.arch.lifecycle.MutableLiveData<Integer>" />
<variable
name="order_value"
type="android.arch.lifecycle.MutableLiveData<Integer>" />
</data>
...
<EditText
android:id="#+id/prod_qty"
// This does the magic
android:text="#{quantity}" />
...
<EditText
android:id="#+id/prod_price"
// And this of course...
android:text="#{order_value}" />
...
</layout>
And this to your fragment layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewmodel"
type="yourpackage.ViewModel" />
</data>
...
<EditText
android:id="#+id/total_qty"
// This does the magic
android:text="#{viewmodel.quantity}" />
...
<EditText
android:id="#+id/order_value"
// And this of course..
android:text="#{viewmodel.total}" />
...
</layout>
Note that in both classes you need to get the viewmodel from the activity, not from the fragment itself, so you share the same viewmodel for both classes:
ViewModelProvider(requireActivity()).get(ViewModel.class);
If you only get values of LiveData objects from within the UI Thread (which is the case in my code, as onChange of LiveData and binding updates are always called from the UI thread), you do not need to synchronize the lists in the ViewModel. Otherwise you need to make the whole story thread safe.
It is easy to understand that you want to take action when changing the value in a text field. So the first thing is to add a TextChangeListener or TextWatcher. Then, you have to work on the received text value to update the rest of the dependencies: Your product list or whatever it is.
Just a few basic things you need to take care of:
If you are working with fragment communication, propagate your changes by reloading in onResume of the fragment or activity. Or you can use EventBus or any other suitable mechanism.
Be sure to notify the adapter once you have changed the underlying data. I see a call to "notify**" after your code mProducts.get(position).setQuantity(val); is missing in your Product adapter. When modifying the underlying data, it is necessary to notify the adapter using "notify**" calls to update the recycler view.
The MutableLiveData error you posted above can be cleared with MutableLiveData declaration such as private final MutableLiveData mutableData = new MutableLiveData(0) in your case. You can have a function to just return LiveData as LiveData getData() { return mutableData; }
I am trying to create a class that creates very dynamic dialogs for my Android application.
These are examples of the dialogs I want to create:
What I need is a dynamic dialog creator. When I have a list with View objects (buttons (all with different click methods) and a title), I want to pass the list to a method that builds a dialog and shows it.
My question is: how can I make these dynamic dialogs ?
I thought of using an adapter to fill the dialogs with the view objects, but that doesn't look possible?
What do I have so far?
The code for this (not dynamic) dialog :
overlay.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:id="#+id/overlay_master_view">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:id="#+id/linie"
android:orientation="vertical"
android:background="#drawable/tile_button_wordtile">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Menu"
android:padding="5dp"
android:textColor="#color/white"
android:background="#color/transparant"
android:layout_margin="10dp"/>
<Button
android:layout_width="wrap_content"
android:padding="5dp"
android:layout_margin="10dp"
android:layout_height="wrap_content"
android:textColor="#color/white"
android:background="#drawable/tile_button_functiontile"
android:text="Annuleren"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
OverlayManager.java:
public static void onCoachMark(Activity c){
dialog = new Dialog(c);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
dialog.setContentView(R.layout.overlay);
dialog.setCanceledOnTouchOutside(true);
//for dismissing anywhere you touch
View masterView = dialog.findViewById(R.id.overlay_master_view);
masterView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
}
Extend a DialogFragment and override the onCreateView method
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.overlay, container, false);
return v;
}
and finally display it using
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
DialogFragment newFragment = new YourDialogFragment();
newFragment.show(ft, "dialog");
more info - here
I've seen similar questions to mine here, but none of the solutions have helped (I've tried many).
So I have a fragment, which I'm create an instance of both in my main activity and in another activity. The fragment has methods to change various TextViews, and everything works great when I call those methods from my main activity. However, when I try to do the same in my other activity, I keep getting a null pointer exception that the textView isn't found. Here is the relevant code:
activity where it doesn't work:
TextView p1n;
TextView p2n;
TextView p1s;
TextView p2s;
ScoreFragment SF;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tic_tac_toe);
SF = new ScoreFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.frag_frame_ttt, SF);
ft.commit();
Intent intent = getIntent();
Log.d(jl, intent.getStringExtra(P1_NAME_KEY));
if (intent != null) {
if (intent.getStringExtra(P1_NAME_KEY) != null && p1n != null) {
SF.setp1name(intent.getStringExtra(P1_NAME_KEY));
}
if (intent.getStringExtra(P2_NAME_KEY) != null && p2n != null) {
SF.setp2name(intent.getStringExtra(P2_NAME_KEY));
}
if (p1s != null) {
SF.setp1score(intent.getIntExtra(P1_SCORE_KEY, 0));
}
if (p2s != null) {
SF.setp2score(intent.getIntExtra(P2_SCORE_KEY, 0));
}
Log.d(jl, Integer.toString(intent.getIntExtra(P2_SCORE_KEY, 0)));
}
Since p1n, p2n, p1s, and p2s are always null, nothing happens.
Here is the frame layout i'm trying to put the fragment in,
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/frag_frame_ttt"
android:paddingBottom="20dp"
/>
and here is my relevant fragment code:
...
TextView p1name;
TextView p2name;
TextView p1score;
TextView p2score;
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_score, container, false);
p1name = (TextView) v.findViewById(R.id.p1_name);
p2name = (TextView) v.findViewById(R.id.p2_name);
p1score = (TextView) v.findViewById(R.id.p1_score);
p2score = (TextView) v.findViewById(R.id.p2_score);
Log.d(jl, "onCreateView successful");
return v;
}
public void setp1name(String name) {
p1name.setText(name);
}
public void setp2name(String name) {
p2name.setText(name);
}
public void setp1score(int score) {
p1score.setText(Integer.toString(score));
}
public void setp2score(int score) {
p2score.setText(Integer.toString(score));
}
and the relevant fragment xml:
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Player 1"
android:id="#+id/p1_name"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" : " />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:id="#+id/p1_score"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Player 2"
android:id="#+id/p2_name"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" : " />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:id="#+id/p2_score"/>
</LinearLayout>
</LinearLayout>
So after doing some debugging I am quite certain that the issue has to do with the findViewById method in onCreateView() not finding anything, but I've tried moving where I findViewById (such as in each method where the text is being set), but it still hasn't worked.
Any help would be much appreciated.
Got it!
Aside from my stupid bug in my activity where I only set the text if the textview variables (the ones I never set) aren't null...
I had to move all of the code pertaining to my fragment (except for the initialize and the add / commit) from onCreate to onStart. Guess I was trying to preform actions on these textviews before the fragment actually inflated(? sorry I'm new to android, this may be incorrect).
I have created a ViewPager with three "pages". The code is this
MainActivity.java
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
PagerTabStrip pagerTabStrip = (PagerTabStrip) findViewById(R.id.pager_tab_strip);
FragmentPagerAdapter fragmentPagerAdapter = new MyFragmentPagerAdapter(
getSupportFragmentManager());
viewPager.setAdapter(fragmentPagerAdapter);
pagerTabStrip.setDrawFullUnderline(true);
pagerTabStrip.setTabIndicatorColor(Color.DKGRAY);
}
}
MyFragmentPageAdapter.java
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
private String[] pageTitle = {
"Page1", "Page2", "Page3"
};
public MyFragmentPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new PageFragment();
Bundle arguments = new Bundle();
arguments.putString("pageIndex", Integer.toString(position + 1));
fragment.setArguments(arguments);
return fragment;
}
#Override
public int getCount() {
return pageTitle.length;
}
#Override
public CharSequence getPageTitle(int position) {
return pageTitle[position];
}
}
PageFragment.java
public class PageFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_page, null);
return view;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_tab_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33B5E5"
android:textColor="#FFFFFF"
android:paddingTop="10dp"
android:paddingBottom="10dp" />
</android.support.v4.view.ViewPager>
</RelativeLayout>
fragment_page.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="20dp"
android:textSize="16sp"
android:textStyle="italic"
android:gravity="center_horizontal"
android:textColor="#color/red"
android:text="#string/inf" />
<TextView
android:id="#+id/textView2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="60dp"
android:textSize="28sp"
android:gravity="center_horizontal"
android:textStyle="bold"
android:text="#string/ben" />
<TextView
android:id="#+id/textView3"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="130dp"
android:gravity="center_horizontal"
android:textSize="18sp"
android:text="Prova"
/>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_centerInParent="true"
android:text="#string/verifica" />
</RelativeLayout>
But now i visualize in all three pages the same thing. If I for example on page 2 I want a TextView with the text "This is the 2 page" and on the third page a TextView with the text "This is the page 3" and in the first page two TextView with the button ... how can I? I'm going crazy, please let pass me the code to do this thing. Please.
Once you inflate PageFragment's layout you need to get a reference of the TextView so you can display the position on it via the Bundle you are passing using setArguments(). Use your view variable inside onCreateView() to get a reference of the TextView. (i.e. view.findViewById()). Then use getArguments() in your PageFragment to retrieve the Bundle with that has position, and set the TextView to that value.
this is a good example for what you want.
Just create a function in your page fragment class to configure elements and modify onCreateView to attach childs.
public class PageFragment extends Fragment {
TextView tv1 ;
// ...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_page, null);
/// Attach your childs
tv1 = view.findViewById(R.id.textView1);
return view;
}
public void configure(int position) {
tv1 .setText("This is "+ position);
}
}
Then just call the function configure in getItem function
#Override
public Fragment getItem(int position) {
PageFragment fr = new PageFragment();
fr.configure(position + 1);
return fr;
}
I have a fragment with an XML layout file. in it I have an 2 clickable ImageViews.
for each ImageView I set an onClick method for example: android:onClick="commentFragmentRemoveOnClick".
In the FragmentActivity (The Activity no the Fragment) I defined it this way:
public void commentFragmentRemoveOnClick(View v)
{
}
No this Fragment is of type CommentFragment and it has a public void getFragmentTag()method
to get it's tag that I save in earlier time. I need to get an instance of the fragment in which the image was clicked to get it's tag.
I tried:
((CommentFragment)v).getParentFragment().getFragmentTag();
and:
((CommentFragment)v).getParent().getFragmentTag();
but eclipse gives me error on both of them, how is this done properly?
To make it more clear this is my CommentFragment:
public class CommentFragment extends Fragment {
private final static String TAG = CommentFragment.class.getSimpleName();
private String fragmentTag;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.comment_fragment_layout,
container, false);
Bundle bundle = getArguments();
String text = bundle.getString("comment");
String fullUser = bundle.getString("user");
String user = fullUser.substring(0, fullUser.indexOf("#"));
String at = bundle.getString("at");
TextView tvCmment = (TextView) rootView.findViewById(R.id.tvComment);
TextView tvUser = (TextView) rootView.findViewById(R.id.tvUser);
TextView tvAt = (TextView) rootView.findViewById(R.id.tvDate);
tvCmment.setText(text);
tvUser.setText(user);
tvAt.setText(at);
return rootView;
}
public void setText(String item)
{
TextView view = (TextView) getView().findViewById(R.id.tvComment);
view.setText(item);
}
public void setFragmentTag(String tag)
{
this.fragmentTag = tag;
}
public String getFragmentTag()
{
return this.fragmentTag;
}
}
and the layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/llCommentContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#drawable/try2">
<TextView
android:id="#+id/tvUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/tvComment"
android:layout_alignParentTop="true"
android:background="#color/my_gray"
android:text="demo"
android:textStyle="bold"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textColor="#color/my_even_darker_gray" />
<TextView
android:id="#+id/tvComment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/tvDate"
android:padding="5dp"
android:text="This task is described in more details if you click on it."
android:textColor="#color/my_even_darker_gray" />
<TextView
android:id="#+id/tvAt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:paddingRight="5dp"
android:textColor="#color/my_even_darker_gray"
android:layout_toRightOf="#+id/tvUser"
android:background="#color/my_gray"
android:text="at" />
<TextView
android:id="#+id/tvDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/tvAt"
android:layout_alignBottom="#+id/tvAt"
android:layout_toRightOf="#+id/tvAt"
android:background="#color/my_gray"
android:text="12/02"
android:textColor="#color/my_even_darker_gray" />
<ImageView
android:id="#+id/iEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/tvComment"
android:layout_marginRight="4dp"
android:clickable="true"
android:contentDescription="#drawable/add_comment_button"
android:onClick="commentFragmentEditOnClick"
android:src="#drawable/add_comment_button" />
<ImageView
android:id="#+id/iRemove"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/iEdit"
android:layout_toRightOf="#+id/iEdit"
android:layout_marginRight="4dp"
android:clickable="true"
android:contentDescription="#drawable/add_comment_button"
android:onClick="commentFragmentRemoveOnClick"
android:src="#drawable/add_comment_button" />
</RelativeLayout>
I would love for a little assistance.
Thanks.
I have a general advice for you that would solve your problem and help you in the future -
don't use android:onClick in the xml file, use setOnClickListener in the code itself - need to avoid mixing your views with other parts of the app as much as possible.
Try to keep the Fragment independent of its activity.
If the image is part of the fragment, why does the listener is part of the FragmentActivity?
Use setOnClickListener in the fragment itself, and you might be able to use this Framgent in other pats of the app without being depended on the Activity.
It would also solve your problem of identifying the fragment in which the image was clicked.
v is not an instance of Fragment, that's why Eclipse does not like your code. If you want the instance of a fragment you have to use the FragmentManager and one of its findFragmentByXXX methods.
To get the instance of the fragment that the ImageView was clicked in I did the following:
in the Fragment I set two onClickListeners for both of the images like this:
iEdit = (ImageView)rootView.findViewById(R.id.iEdit);
iEdit.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Log.d(TAG, "pressed edit button");
((PicturesAndCommentsActivity) getActivity()).commentFragmentEditOnClick(fragmentTag);
}
});
iRemove = (ImageView)rootView.findViewById(R.id.iRemove);
iRemove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
Log.d(TAG, "pressed remove button");
((PicturesAndCommentsActivity) getActivity()).commentFragmentRemoveOnClick(fragmentTag);
}
});
and in the fragment activity I defined those two methods like this:
public void commentFragmentRemoveOnClick (String tag)
{
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(fragmentManager.findFragmentByTag(tag)).commit();
}
for removing the fragment, and Now I'm working on editing the fragment.