I've looked on SO for a solution to this and I can't find one that works for my situation. I'm a beginner with Android development, so let me know if I'm doing something obviously wrong.
First a little background on the structure of my app. I use a navigation drawer with fragments for each of the pages, similar to the navigation drawer example in the Android documentation. On one of the pages I want to dynamically add TextViews to the LinearLayout of the fragment for that page when some event happens. The event isn't important in this case - it just calls a method in my activity.
So in my activity I have a method - addText(). Whenever addText() is called, I want to create a TextView, and then add this to the LinearLayout in the fragment. (the LinearLayout with id diary_layout)
How do I do this?
I have tried the following method. When this method is called, I do not see the text in the page.
public void textAdd(){
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View contentView = inflater.inflate(R.layout.fragment_diary, null);
LinearLayout diaryLayout = (LinearLayout) contentView.findViewById(R.id.diary_layout);
TextView newTextView = new TextView(this);
newTextView.setText("Testing");
diaryLayout.addView(newTextView);
}
This is the structure of the layout file for the fragment:
<LinearLayout
android:id="#+id/theLinearLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/diary_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MyActivity$PlaceholderFragment">
</LinearLayout>
</ScrollView>
Activity Layout:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<!-- The navigation drawer -->
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="10dp"
android:background="#FFFFFF"/>
Thanks in advance!
You definitely don't want to inflate the content each time you add text. That would load the initial layout again, which is not what you want.
You didn't show how you construct your fragments, but based on your description, that you want to add a new TextView to a LinearLayout in one of the existing Fragments. I would expect you would first fetch the fragment, and then call some method in the fragment to add text. Something like:
public void textAdd(){
FragmentManager fm = getFragmentManager();
MyFragment myFragment = (MyFragment) fm.findFragmentById(R.id.my_fragment);
if (myFragment != null) {
LinearLayout diaryLayout = (LinearLayout) myFragment.findViewById(R.id.diary_layout);
TextView newTextView = new TextView(this);
newTextView.setText("Testing");
diaryLayout.addView(newTextView);
}
}
I think you need to add layout params to your textview.. try it this way..
TextView newTextView = new TextView(this);
newTextView.setText("Testing");
newTextView .setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
diaryLayout.addView(newTextView);
Related
Two Layout files:
activity_maps.xml
<FrameLayout
android:id="#+id/fragment_container"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.jawadh.startthreeproject.MapsActivity" />
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/place_autocomplete_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.google.android.gms.location.places.ui.PlaceAutocompleteFragment"
/>
</FrameLayout >
second.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/view_container"
android:layout_height="50dip"
android:layout_width="50dip"
>
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android" />
<TextView
android:id="#+id/textViewSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/textViewDest"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
In my activity, once the mapsActivity gets loaded and working fine. I want to load the view of second.xml over the exisiting view.
So, I am trying this:
final FrameLayout frameLayout = (FrameLayout)View.inflate(getApplicationContext(),R.layout.second,null);
final Button button = (Button)frameLayout.findViewById(R.id.button);;
button.setBackgroundColor((Color.GRAY));
button.setText("Direction");
button.setY(300);
button.setX(300);
TextView textViewSource = (TextView)frameLayout.findViewById(R.id.textViewSource);
textViewSource.setText(place.getAddress().toString());
textViewSource.setTextColor(Color.BLACK);
textViewSource.setBackgroundColor(Color.WHITE);
frameLayout.setBackgroundColor(Color.BLUE);
Expectation: This last part of code should put te second.xml view(framelayout) over the exisiting view.
Warning: DO NOT use application context for inflating views!
You created the second layout here:
final FrameLayout frameLayout = (FrameLayout)View.inflate(this, R.layout.second,null);
Now you have to attach it to view hierarchy. Fragment container sounds nice enough:
FrameLayout container = (FrameLayout) findViewById(R.id.fragment_container);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
container.addView(frameLayout, lp);
EDIT
Alternatively you could inflate AND attach new view in one go like so:
FrameLayout container = (FrameLayout) findViewById(R.id.fragment_container);
final FrameLayout frameLayout = (FrameLayout)View.inflate(this, R.layout.second, container);
...because FrameLayout will provide you with these LayoutParams by default:
/**
* Returns a set of layout parameters with a width of
* {#link android.view.ViewGroup.LayoutParams#MATCH_PARENT},
* and a height of {#link android.view.ViewGroup.LayoutParams#MATCH_PARENT}.
*/
#Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
Well, a little more detail was required.
And hey, whatever you are doing, you are not doing it the best way.
Anyways, you inflated the view in frameLayout but you are not adding this to the present parent.
Am not sure what exactly you want to achieve but I think you are missing that part.
You can replace view by set visibility to GONE.
In your case, you should create one xml file instead of two. In xml file, take one linearlayout with orientation vertical. In this linearlayout take two framelayouts.When your activity starts, set second framelayout's visibility to GONE. When map is loaded in first framelayout, set it's visibility to GONE and second framelayout's visibility to VISIBLE. When you do this, second framelayout will automatically replace first framelayout.
sample code:
private LinearLayout llLogin;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
llLogin = (LinearLayout) findViewById(R.id.loginlayout);
llLogin.setVisibility(View.GONE);
I have several activities which extend my class DrawerActivity, so they will have a navigation drawer. Only one of these activities requires a ViewPager.
Question: How can I add a ViewPager to only one of the activities, ActivityA?
I am somewhat familiar with creating a ViewPager, but in this situation I'm unsure of where to put the ViewPager code, and what layouts to use. I've seen a few examples including the official tutorial on Google's developer site, but I'm not sure how to best implement it into my application.
I've provided some relevant code below, but please let me know if you need to see more. Any advice is appreciated, thanks!
In DrawerActivity's onCreate:
setContentView(R.layout.activity_fragment);
if (fragment == null)
{
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
Layout activity_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
<ListView android:id="#+id/leftDrawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="left"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
In ActivityA:
public class ActivityA extends DrawerActivity
{
//this is all I do in this activity
#Override
protected Fragment createFragment()
{
UUID id = (UUID) getIntent().getSerializableExtra(FragmentA.EXTRA_ID);
return FragmentA.newInstance(id);
}
}
In FragmentA's onCreateView:
View v = inflater.inflate(R.layout.fragment_a, parent, false);
Layout fragment_a.xml is a simple LinearLayout with a few Button and TableLayout children.
fragment_a.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>
and create an adapter for example FragmentStatePagerAdapter and fill it with what you want to show in viewpager. notice that because you are using viewpager inside a fragment you should pass ChildFragmentManaget instead of activity FragmentManager.
I have a TabHost with several tabs, which content is defined as a FrameLayout, which wraps a TextView, each one of them having a lot of text, more than it can be shown within the screen layout, so I had to enable vertical scrolling for every tab.
The main thing is that those tabs are created dynamically (programatically), so I have to specify all the options this way:
final SoftReference<TabHost> th = new SoftReference<TabHost>((TabHost) ((Activity) globvars.getContext()).findViewById(android.R.id.tabhost));
final TabSpec setContent = th.get().newTabSpec(tag).setIndicator(tabview).setContent(new TabContentFactory() {
public View createTabContent(String tag) {
view.setBackground(globvars.getContext().getResources().getDrawable(R.drawable.rounded_edges));
view.setPadding(25, 25, 25, 25);
view.setTextColor(Color.WHITE);
view.setLines(50);
view.setMaxLines(maxLines);
view.setEllipsize(TextUtils.TruncateAt.START);
view.setHorizontalScrollBarEnabled(false);
view.setVerticalScrollBarEnabled(true);
view.setMovementMethod(new ScrollingMovementMethod());
view.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
view.setVerticalFadingEdgeEnabled(true);
view.setGravity(Gravity.BOTTOM);
view.setOverScrollMode(1);
view.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11);
view.setTypeface(Typeface.MONOSPACE);
return view;
}
});
Using this approach, I can scroll backwards and forwards indeed, but visually the scrollbar is not shown. I'm mean this bar:
Am I missing something? Does the scrollbar have to be defined by a customized drawable by imperative?
Thanks!
------ EDIT (12-31-2013) ------
I've been looking around and still can't find any solution to this. I've tried as many combinations of parameters as I was able to find, but no result. Particularly, I've tried this and also wrapping the FrameLayout within a ScrollView, but instead of showing a scrollbar at the TextView itself, the whole TextView is wrapped within a scrollbar and grows when buffer gets bigger and bigger, that's not what I want.
Any help appreciated!
------ EDIT (01-17-2014) ------
Well, at this point, I can assure I've tried any logical step (well, at least to me) to make this work and still can't! I clarify that I have about 7-8 additional activities and I have no trouble with scrolling in any of them. I just work with TabHost in this one, though. So I'm starting a bounty on this, because that's already endangering my mental sanity.
I'm posting my layout below:
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/fondo_imagen"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<LinearLayout
android:id="#+id/TabContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="99"
android:orientation="vertical">
<TabHost
android:id="#+android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/TabLinearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Horizontal scrolling for the tab widget -->
<HorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
android:scrollbars="none">
<TabWidget
android:id="#+android:id/tabs"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</HorizontalScrollView>
<FrameLayout
android:id="#+android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp" />
</LinearLayout>
</TabHost>
</LinearLayout>
<!-- Some additional LinearLayouts that don't have anything to do with the tab widget -->
...
</LinearLayout>
------ EDIT (01-19-2014) ------
Ok, based on corsair992's answer, I could finally get this working. My real mistake was assuming that even the method that creates the tab (posted above) receives a TextView as parameter, working with a View in the TabSpec definition would be casting it to the TextView. So indeed, I wasn't aware I was actually setting the scrollbars on a View (didn't know the View class didn't provide a public programatic method to configure scrollbars neither), so I followed corsair992's advice and created a separate layout with this content:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/tabsContent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:background="#drawable/rounded_edges"
android:gravity="bottom"
android:padding="8dp"
android:scrollHorizontally="false"
android:scrollbarStyle="insideOverlay"
android:scrollbars="vertical"
android:textColor="#FFFFFF"
android:textSize="11sp"
android:typeface="monospace"
tools:ignore="SmallSp" />
So now, instead of calling the above method which sets all those attributes to the View, I simply inflate this layout and set the MovementMethod:
final TabSpec setContent = th.get().newTabSpec(tag).setIndicator(tabview).setContent(new TabContentFactory() {
public View createTabContent(String tag) {
// tabs_content is the layout above
final View ll_view = LayoutInflater.from(globvars.getContext()).inflate(R.layout.tabs_content, null);
final TextView view = (TextView) ll_view.findViewById(R.id.tabsContent);
view.setMovementMethod(new ScrollingMovementMethod());
return ll_view;
}
});
It appears that the base View class does not provide a public method for initializing scroll bars if they are not specifically enabled in an XML layout resource. However, there is no reason you can't define your tab content in an XML resource, enable vertical scroll bars by setting the android:scrollbars attribute to vertical, and inflate it from the TabContentFactory dynamically.
Something like this in your case:
public View createTabContent(String tag) {
Activity activity = (Activity) globvars.getContext();
TextView view = (TextView) LayoutInflater.from(activity).inflate(R.layout.mytabcontent,
(ViewGroup) activity.findViewById(android.R.id.tabcontent), false);
view.setMovementMethod(new ScrollingMovementMethod());
view.setText("My Text");
return view;
}
I have main activity with only ViewPager on it. The first tab page fragment contains:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/llEventsTabPage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/lvEvents"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
I want to show details fragment when user taps item in ListView:
lvEvents.setAdapter(adapter);
lvEvents.setOnItemClickListener(
new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
Fragment eventFragment = new EventFragment();
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.llEventsTabPage, eventFragment);
fragmentTransaction.commit();
}
}
);
Code 'fragmentTransaction.commit();' is called, onCreateView of EventFragment is called, but after 'fragmentTransaction.commit();' nothing happens. No errors, no result. Just list view is still displaying and working.
What am I doing wrong? I've found a few examples, my code looks the same, but not working and I can do nothing with that.
Thank you!
When you do a replace or add, all it's going to do is add the Fragment's View to the container that you specify. The only difference is this:
replace will remove the first existing Fragment inside the container previously that is handled by the FragmentManager specified.
add will simply add the Fragment to the container.
In your case, you have a LinearLayout container which holds a ListView that is of size match_parent. What this means is, when the ChildFragmentManager adds your Fragment to the container, it will add it to a LinearLayout. The fragment is actually below the ListView outside the scope of the View.
Change LinearLayout to FrameLayout and your Fragment will appear over the ListView.
I'm not be sure. but I use two layout structures.
first layout structure
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
in this case, you need two fragment.
one is a EventFragment and other one is a Fragment for ListView.
so you should additionally create fragment for ListView.
second layout structure
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<FrameLayout android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
in this case, you commit R.id.fragment_container instead R.id.llEventsTabPage.
I think it would operate....
I was trying to fix this for a while and couldn't find the problem. I have a fragment in which I have ProgressBar that is centered. Here is the xml file content of fragment.
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<LinearLayout
android:id="#+id/details_form"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="false"
android:orientation="vertical"
android:visibility="gone" >
...
</LinearLayout>
</merge>
I also have activity and I just add this fragment to the activity. Here is the xml of activity
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/details_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
tools:context=".MyActivity"
tools:ignore="MergeRootFrame" />
The problem is when I navigate to this activity inside my application the progress is shown on the left side, it is not centered. I am not sure why is this happening, so I thought someone will see something I am missing. Thanks.
EDIT:
In onCreate event of my activity code (MyActivity.java) I have this code:
DetailsFragment detailsFragment = new DetailsFragment();
agreementDetailsFragment.setArguments(arguments);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.details_container,
detailsFragment).commit();
and in my fragment .java file in onCreateView I have this code
View rootView = null;
/*
* Get root view
*/
LinearLayout wrapper = new LinearLayout(getActivity());
inflater.inflate(R.layout.details_fragment, wrapper, true);
rootView = wrapper;
The problem is when I navigate to this activity inside my application
the progress is shown on the left side, it is not centered. I am not
sure why is this happening, so I thought someone will see something I
am missing. Thanks
The layout with the merge tag will have as a parent a LinearLayout. In a LinearLayout the android:layout_gravity will not work and you'll need a more permissive layout like a RelativeLayout or a FrameLayout(I'm assuming that the ProgressBar and the details_form LinearLayout will replace each other using the visibility property):
RelativeLayout wrapper = new RelativeLayout(getActivity());
inflater.inflate(R.layout.details_fragment, wrapper, true);