How to relate a View to a layout - android

I am in the process of converting an Android app to use fragments so as to support tablets in landscape mode.
There are two activities that I want to display side-by-side on a tablet in landscape mode. Currently, the first activity (DisplayNotams) has a button that calls an intent to display the second (Chart). The first is a text display of individual items, using a pager to view them one at a time, and the second is a chart on which the items are plotted.
The Chart does not use an xml layout file, as it creates its own ChartView thus:
ChartView mView;
mView = new ChartView(this, mCentreLat, mCentreLong, mRadius);
setContentView(mView);
(The class ChartView extends View, and contains most of the drawing code.)
I am using the github example commonsguy/cw-omnibus/LargeScreen/EU4you to base my revised code on. The problem (for me) is that this uses different layout xml files in layout and layout-large-land to distinguish between the two. Since I only have a layout xml file for DisplayNotams, and none for Chart, I am at a loss as to how to proceed.
Is there any way I can adapt the example to my situation?
For reference, the two xml files in EU4You are as follows.
In layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/countries"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
In layout-large-land:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:id="#+id/countries"
android:layout_weight="30"
android:layout_width="0px"
android:layout_height="fill_parent"
/>
<FrameLayout
android:id="#+id/details"
android:layout_weight="70"
android:layout_width="0px"
android:layout_height="fill_parent"
/>
</LinearLayout>
'countries' would correspond to my DisplayNotams, and 'details' would correspond to my Chart.
Thanks to those who answered. This is what I came up with, replacing
ChartView mView;
mView = new ChartView(this, mCentreLat, mCentreLong, mRadius);
setContentView(mView);
with
ChartView mView;
mView = new ChartView(this, mCentreLat, mCentreLong, mRadius);
setContentView(R.layout.chart);
FrameLayout fl = (FrameLayout)findViewById(R.id.chart_frame);
fl.addView(mView);
and creating a new chart.xml file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/chart_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

There's a group of addView functions available to ViewGroup. You can use that to add children to the FrameLayouts.
ChartView mView;
mView = new ChartView(this, mCentreLat, mCentreLong, mRadius);
FrameLayout frame = (FrameLayout) findViewById(R.id.countries);
frame.addView(mView);

Instead of using setContentView(mView) you can return your ChartView in the onCreateView-Method of your Fragment Class:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ChartView mView;
mView = new ChartView(this, mCentreLat, mCentreLong, mRadius);
return mView;
}

Related

Android: View.inflate not showing the second layout on screen

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);

Fragment content position in Android

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);

Android: match_parent is ignored when using addView

In my application I'm adding a view dynamically to the layout using addView.
The added view was inflated beforehand using
andorid:layout_width="match_parent"
however, after the adding the view using
parentView.addView(view, index);
The view is addded but dosen't fill the parent's width
I guess this is because the calculation to the "match_parent" size is done beforehand,
when the view is inflated, and therefore it has no reference of how to set the corect width
is this the case?
is there a way for me to tell the view to recalculate the layout params?
my Code:
activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/blue_bg">
<ImageView android:id="#+id/myImg"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:src="#drawable/myImg"
android:scaleType="fitXY"/>
<LinearLayout android:id="#+id/addressItemContainer"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_below="#id/myImg" android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<View android:id="#+id/placeHolder"
android:layout_width="match_parent" android:layout_height="match_parent"/>
</LinearLayout>
</RelativeLayout>
inserted_view.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content" android:background="#drawable/blue_selector">
.... internal views
</LinearLayout>
java code:
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = li.inflate(R.layout.inserted_view, null);
... fill inserted view fields ...
View aiv = findViewById(R.id.placeHolder);
ViewGroup parent = (ViewGroup) aiv.getParent();
int index = parent.indexOfChild(aiv);
parent.removeView(aiv);
parent.addView(view, index);
Tx for the help :)
Ok, just add this code
View aiv = findViewById(R.id.placeHolder);
aiv.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
Mark as resolved, please.
View view = findViewById(R.id.placeHolder);
view .setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
//addView(view)
Thanks Dmytro Danylyk. Now its work prefectly.

Custom View Question

I am new to Android development and I have a question regarding custom views and using xml for view customization.
So i my code I am having a view defined using the extended view class i.e.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
draw = new DrawView(this, display.getWidth(), display.getHeight(), vibrator);
setContentView(draw);//custom view called DrawView
}
And in the DrawView class I am performing operations using the canvas.
My question is,
Can I use XML layouts combined with this view that I have defined?
I need to add a few buttons to this custom view, how can I achieve that in this scenario.
Thank you.
You can embed a custom view inside a layout. Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="horizontal" android:background="#FFFFFF">
<ListView android:id="#+id/channelsLogos" android:scrollbars="none"
android:layout_height="fill_parent" android:layout_weight=".20"
android:layout_width="100dip">
</ListView>
<test.poc.CustomScrollView
android:id="#+id/scrollViewVertical" android:scrollbars="none"
android:layout_weight=".80" android:layout_width="fill_parent"
android:layout_height="fill_parent">
</test.poc.CustomScrollView>
</LinearLayout>
CustomScrollView is a custom component in package test.poc
Make sure you use the correct constructor while doing this.

Android ScrollView can host only one direct child

I have a onclick listener from the gallery that should clear all the rows inside the tableview, then add row/rows to a tableview inside a scrollview. The fragment should change on every button click.
However I am getting: java.lang.IllegalStateException: ScrollView can host only one direct child.
myactivity button listener
TrackerFragment tf = (TrackerFragment) getFragmentManager().findFragmentById(R.id.tracker1);
tf = TrackerFragment.newInstance(listOfList.get(id).get(position));
fragmentTransaction.add(R.id.tracker1, tf);
fragmentTransaction.commit();
t1 = true; //being used
getFragmentManager().executePendingTransactions();
tracker fragment
public class TrackerFragment extends Fragment
{
private Dish dish;
public static TrackerFragment newInstance(Serializable dish)
{
TrackerFragment tf = new TrackerFragment();
Bundle args = new Bundle();
args.putSerializable("dish", dish);
tf.setArguments(args);
return tf;
}
public static TrackerFragment newInstance(Bundle bundle)
{
Dish dish = (Dish) bundle.getSerializable("dish");
return newInstance(dish);
}
#Override
public void onCreate(Bundle myBundle)
{
super.onCreate(myBundle);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.tracker, container, false);
TableLayout tableLayout = (TableLayout) v.findViewById(R.id.tracker_layout);
tableLayout.removeAllViews();
if (dish != null)
{
//display others
//display subsystem stuff
for (int i = 0; i < dish.getSubsystems().size(); i++)
{
TableRow tableRow = new TableRow(v.getContext());
tableRow.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
TextView tv = new TextView(v.getContext());
tv.setText(dish.getSubsystems().get(i).getConnFuncAddr());
tableRow.addView(tv);
tableLayout.addView(tableRow);
}
}
else
{
TableRow tableRow = new TableRow(v.getContext());
tableRow.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
TextView tv = new TextView(v.getContext());
tv.setText("Click on image to view more data");
tableRow.addView(tv);
tableLayout.addView(tableRow);
}
return v;
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Trackers -->
<LinearLayout
android:layout_height="fill_parent"
android:layout_width="300dp"
android:layout_weight="1"
android:orientation="vertical">
<fragment
android:name="android.gallery.TrackerFragment"
android:id="#+id/tracker1"
android:layout_height="500dp"
android:layout_width="300dp"
android:layout_weight="1">
</fragment>
</LinearLayout>
<!-- Gallery -->
<LinearLayout
android:layout_height="fill_parent"
android:layout_width="600dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="245dp">
<Gallery
android:id="#+id/galleryid0"
android:layout_width="fill_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="245dp">
<Gallery
android:id="#+id/galleryid1"
android:layout_width="fill_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="245dp">
<Gallery
android:id="#+id/galleryid2"
android:layout_width="fill_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
tracker.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/tracker_layout">
</TableLayout>
</ScrollView>
Does anyone know whats wrong? I am guessing I am adding a table row to the scrollview and not the tableview, however, I dont see where I am doing that wrong in my code.
In fact, you can't have things like :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
android:id="#+id/widget27"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffffff"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<TableLayout
android:id="#+id/layoutOption"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffffff"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
>
<ImageView
android:id="#+id/logoImmoweb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/logoimmoweb"
android:layout_gravity="top"
/>
...
</TableLayout>
</ScrollView>
but if you have an extra element outside the table, it crash with an java.lang.IllegalStateException: ScrollView can host only one direct child
example
<ScrollView
android:id="#+id/widget27"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffffff"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<ImageView
android:id="#+id/logoImmoweb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/logoimmoweb"
android:layout_gravity="top"
/>
<TableLayout
android:id="#+id/layoutOption"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffffff"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
>
...
</TableLayout>
</ScrollView>
Hope this help.
I know this question is quite old but I ran into the same problem and it end up being that you cant have a ScrollView as you base view for the layout.
Just wrap the Scrollview in your tracker.xml layout with a RelativeLayout and you should be good to go
You should add LinearLayout into ScrollView, it will working.
Another possibility is that the closing element is not matching. Ie.
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout ...>
...
</LinearLayout>
</LinearLayout>
The error is in the last line.
Um... don't put multiple views inside of a scroll view. Put a single view inside of it that is the kind of layout you want for your multiple views -- TableLayout, FrameLayout, etc.
edit (2nd answer):
I've been playing with the code and I'm still not sure WHY this happens, definitely there's something wrong on the fragment manager when it swapping fragments (replace(resId, fragment))
In my fragment onCreateView was this code:
View view = inflater.inflate(R.layout.post_fragment, null, false);
if (item == null)
return view;
return BuildView(view);
post_fragment is an empty canvas with 1 ScrollView, 1 LinearLayout inside it, and some other ViewGroups inside it. This is to load an empty canvas on the 1st load (item is null) and on the 2nd time, through a user input, it would get the actual data to show.
for some reason beyond my knowledge, as seen in the logcat, FragmentManagerImpl.moveToState was calling ScrollView.AddChild causing the error.
Now I changed my fragments onCreateView to:
if (item == null)
return inflater.inflate(R.layout.empty, null, false);
View view = inflater.inflate(R.layout.post_fragment, null, false);
return BuildView(view);
so that the 'empty' canvas is a FrameLayout with nothing on it, and now everything is working happily.
I'm sure this sounds like some odd error on the actual fragments framework, but it's a work around it.
1st answer:
Raptrex, as far as I can see. Yes, that table layout is the only child your scrowview have. I am having the exactly the same problem, and very frustrated trying to solve it.
From the LogCat/Debug, it seems that there's something in the Fragments manager that is calling and .AddView(view) in my ScrollView (check the log) it depends on how I change my XML layout I get this error or not, which let's say sounds pretty absurd!
Any ideas of how?why?what? I'm listening...
FATAL EXCEPTION: main
java.lang.IllegalStateException: ScrollView can host only one direct child
at android.widget.ScrollView.addView(ScrollView.java:219)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:787)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:977)
at android.app.BackStackRecord.run(BackStackRecord.java:638)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1309)
at android.app.FragmentManagerImpl$1.run(FragmentManager.java:398)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4123)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Try to use a <FrameLayout> instead of the <fragment> in your main.xml
So instead of
<fragment
android:name="android.gallery.TrackerFragment"
android:id="#+id/tracker1"
android:layout_height="500dp"
android:layout_width="300dp"
android:layout_weight="1">
</fragment>
use
<FrameLayout
android:id="#+id/tracker1"
android:layout_height="500dp"
android:layout_width="300dp"
android:layout_weight="1"
/>
It solved a similar problem with the ScrollView, where I was replacing the fragment from the activity with:
getSupportFragmentManager().beginTransaction()
.replace(R.id.details_container, new DetailsFragment(), DETAILFRAGMENT_TAG)
.commit();
I am suffering from this problem last week and then find the best possible answer of that problem.
Scrollview can host only one direct child

Categories

Resources