I am developing a simple app where you can see a list of musicians, and when you click on a musician, you get some details about it (genre, top hits and biography).
The functionality that I want to achieve is this: in case you're viewing it on a wide screen, let the list of musicians be on the left and the details should appear on the right (once a musician is clicked); if it's a narrow screen, the details should appear separately on a new screen. The functionality should be accomplished with fragments and Framelayouts.
So I have the activity_main.xml, and I went to Add new resource file -> layout file and I added activity_main.xml (w600dp) which I expect to automatically load on landscape-oriented smartphones or tablets.
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/muzicari_lista"
android:layout_weight="1">
</FrameLayout>
</LinearLayout>
w600dp/activity_main.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="match_parent">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/lista_muzicara"></FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/detalji_muzicar"></FrameLayout>
</LinearLayout>
XML's of fragments that contain the list and the details are fairly simple with a few textblocks.
Here's the onCreate method of the mainActivity's class:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
unosi = new ArrayList<Muzicar>(); //let's presume there's something in this list
wideL = false;
FragmentManager fm = getFragmentManager();
//fetching FragmentManager
FrameLayout ldetalji = (FrameLayout)findViewById(R.id.detalji_muzicar);
if(ldetalji!=null){
//layout for wide screens
wideL=true;
FragmentDetalji fd;
fd = (FragmentDetalji)fm.findFragmentById(R.id.detalji_muzicar);
//checking if there is FragmentDetalji already created:
if(fd==null) {
//if not, we're creating it now
fd = new FragmentDetalji();
fm.beginTransaction().replace(R.id.detalji_muzicar, fd).commit();
}
}
FragmentLista fl = (FragmentLista)fm.findFragmentByTag("Lista");
//we're checking if there's already fl created
if(fl==null){
//if it hasn't been created:
fl = new FragmentLista();
Bundle argumenti = new Bundle();
argumenti.putParcelableArrayList("Alista",unosi);
fl.setArguments(argumenti);
fm.beginTransaction().replace(R.id.muzicari_lista, fl).commit();
}else{
//case when we change from portrait to landscape, and there was FragmentDetalji already open
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Classes FragmentDetalji and FragmentLista don't do much special besides utilizing onCreateView (though I can add them if they might be the source of the trouble).
The problem is that no matter what I use for loading this app, activity_main gets loaded in its default form, not the w600dp version! What am I doing wrong?
To provide alternative layout resources, you need to create a sub-directory inside your res folder named layout-sw600dp and place your altered layout in there, with the EXACT name as the other small screen layout. Then your Activity should automatically look in this folder. So if your xml file is titled activity_main.xml it should have the exact same name in the layout-sw600dp folder as well.
You can also supply alternate layouts for landscape by creating a sub-directory called layout-land or layout-sw600dp-land for large screen.
Also note that there are differences between using sw600dp and w600dp -- See this question for more info: Difference between sw600dp and w600dp?
Related
This link says that to make the app display a layout, you create a main_layout.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" >
<Button android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a Button" />
</LinearLayout>
and then load it in onCreate method:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// main_layout.xml is compiled into the R.layout.main_layout object
setContentView(R.layout.main_layout);
}
My problem is that I am coding in C, and have the C version of "onCreate" method:
JNIEXPORT
void ANativeActivity_onCreate(ANativeActivity *activity, void *savedState,
size_t savedStateSize) {
....
}
is it possible to load the layout and make the app display it in the C language?
C uses "ANativeActivity" that it doesn't has any of Java methods and resources/objects. Even if you manually parse that XML you should MANUALLY implement all Widgets/Components in C.....so it's near impossible due to high amount of work involved in it.
Usually someone chooses C on Android to do "some special work" that is not available on normal Java or due to performance issues on it.
I am getting an error of 'Resource.Layout' does not contain a definition for 'activity_main'. But I am confused, why it is showing this type of error. Because activity_main is available in Resource.Layout, but still showing the same error.
Here is the code,
Resources => Layout => activity_main.axml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="25px"
android:minHeight="25px">
<android.webkit.WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/webView" />
</LinearLayout>
Resources => MainActivity.cs
[Activity(Label = "BSSTMatrimonial", MainLauncher = true)]
public class MainActivity : Activity
{
WebView webView = null;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
// webView = FindViewById<WebView>(Resource.Id.webView);
//webView.SetWebViewClient(new ExtendWebViewClient());
webView.LoadUrl("www.bsstmatrimony.com");
WebSettings webSettings = webView.Settings;
webSettings.JavaScriptEnabled = true;
}
}
Try to Clean & Rebuild your solution. Even you can delete & re-add .axml file.
If still won't work write click on .axml file
Go to properties -->Build action
Make sure Build action set to AndroidResource.
It is a harmless error that can be ignored but you can search your files for Resource.Designer.cs. It is likely that you have two, one in your project's obj/debug folder and one in your project's Resources folder. Check for activity_main in both, it is possible that the file in your Resources folder doesn't have it.
I've been encountering this problem a lot. I think the problem lies in the fact that as xamarin is updated, it changes the variable names and file names in the templates. So if you are using code from a tutorial, if you are seeing this problem, its likely outdated. This means that you have to rename something to fit the current template.
In this case I had to change
SetContentView(Resource.Layout.Main);
to
SetContentView(Resource.Layout.activity_main);
I'm attempting to use fragments to give a different display depending on whether the app is being run on a phone or a tablet - as fragments are supposed to be used.
I have the following XML for my layouts:
layout/main.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" >
<RelativeLayout
android:id="#+id/list_fragment_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
layout-large/main.xml:
<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="horizontal"
android:baselineAligned="false" >
<RelativeLayout
android:id="#+id/list_fragment_view"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
<RelativeLayout
android:id="#+id/sales_agreement_fragment_view"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="7" />
</LinearLayout>
I havetried using FrameLayouts instead of the RelativeLayouts in the second example - it didn't seem to make any difference.
My Activity onCreate() code is as follows:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager manager = getFragmentManager();
View salesAgreementLayout = findViewById(R.id.sales_agreement_fragment_view);
Fragment formsListFragment = new KingdomSpasFormsListFragment();
FragmentTransaction fragmentTransaction = manager.beginTransaction();
fragmentTransaction.add(R.id.list_fragment_view,formsListFragment);
if (salesAgreementLayout != null) {
Fragment salesAgreementFragment = new SalesAgreementFragment();
fragmentTransaction.add(R.id.sales_agreement_fragment_view, salesAgreementFragment);
}
fragmentTransaction.commit();
}
However, running this (whether on a phone or a tablet results in the following error:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.kingdomspas.android.kingdomspasforms/com.kingdomspas.android.kingdomspasforms.activities.KingdomSpasFormsActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f070000 (com.kingdomspas.android.kingdomspasforms:id/list_fragment_view) for fragment KingdomSpasFormsListFragment{527f671c #0 id=0x7f070000}
I've Googled this extensively as it seems to be a common problem. The main solution, however, seem to be that the original layout specified in setContentView() doesn't contain the Views later referenced in the add() methods. However, this is definitely not the problem in my case (unless I'm being ridiculously blind - I've checked and re-checked).
In fairness, I'm not actually certain that this is the best UI design for my app - I'm wondering about tabs perhaps - but, either way, I'd really like to understand what the problem is here and what I'm doing wrong - else I'm likely doomed to repeat it in the future.
Here is a great tutorial on multipane fragments for android. http://www.vogella.com/tutorials/AndroidFragments/article.html
With regards to your problem if you add static fragments in your layout it will solve your problem. If you have a definite need for dynamic fragments I would suggest doing a check for what sort of device that application is running on before you find the view i.e.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager manager = getFragmentManager();
View salesAgreementLayout = findViewById(R.id.sales_agreement_fragment_view);
Fragment formsListFragment = new KingdomSpasFormsListFragment();
FragmentTransaction fragmentTransaction = manager.beginTransaction();
fragmentTransaction.add(R.id.list_fragment_view,formsListFragment);
if (isTablet()){
Fragment salesAgreementFragment = new SalesAgreementFragment();
fragmentTransaction.add(R.id.sales_agreement_fragment_view, salesAgreementFragment);
}
fragmentTransaction.commit();
}
public boolean isTablet() {
return (getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
>= Configuration.SCREENLAYOUT_SIZE_LARGE;
}
the is tablet method was adapted from How to detect device is Android phone or Android tablet?
I am developing an application according to this example. I defined a landscape layout for header.xml in a layout-land folder, but when I change the orientation to landscape, defined layout does not appear in the screen.
Do know Why ?
Thanks
Updated :
Activity Code :
public class ACENewsFeedActivity extends ListActivity {
// Progress Dialog
private ProgressDialog pDialog;
// Array list for list view
ArrayList<HashMap<String, String>> rssItemList = new ArrayList<HashMap<String,String>>();
RSSParser rssParser = new RSSParser();
List<RSSItem> rssItems = new ArrayList<RSSItem>();
RssFeed rssFeed;
private static String TAG_TITLE = "title";
private static String TAG_LINK = "link";
private static String TAG_DESRIPTION = "description";
private static String TAG_PUB_DATE = "pubDate";
//private static String TAG_GUID = "guid"; // not used
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.rss_item_list);
/**
* Calling a backgroung thread will loads recent articles of a website
* #param rss url of website
* */
new loadRSSFeedItems().execute();
}
....
}
XMl Layout in landscape mode :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layoutHeader"
android:layout_width="fill_parent"
android:layout_height="50dip"
android:layout_alignParentTop="true"
android:background="#layout/header_gradient"
android:orientation="horizontal">
<!-- Logo -->
<!-- Refresh -->
<!-- Plus Button -->
<ImageButton
android:id="#+id/btnAddSite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="5dip"
android:background="#null"
android:src="#drawable/plus"
android:layout_centerVertical="true" />
<ImageView
android:id="#+id/logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="#drawable/logo" />
<ImageView
android:id="#+id/refreshList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:src="#drawable/refresh" />
</RelativeLayout>
Android allows you to provide different versions of resource files to support specific device configurations including screen size/resolution and (as you are trying to do) device orientation. When android is loading a layout file it will look first in the res/layout-port folder (if it is in portrait orientation) or in the res/layout-land folder (if it is in landscape orientation). If it doesn't find the file it will then look in the regular res/layout folder.
Additionally, as noted here, when certain device configurations change (like device orientation) during runtime android will restart whatever process is currently running by saving the state, destroying it, and then starting it with the saved state info. This allows it to load the layout files again, and it will look it the folder for the new orientation when it tries to load them.
So, if you start your application in portrait it will load the file in res/layout-port or res/layout. If you then rotate the device to landscape it will destroy your process and restart. However, this time it will be in landscape so it will check res/layout-land instead for the layout files.
If you have your files set up this way but it is not operating as you think it should, I'd first verify that it is definitely not using the correct files by putting two different header.xml files in the layout-land and layout-port folders, maybe one with a red background and one with a green background. Make sure to double-check the file references and maybe use Toast to post some debugging info on-screen to ensure that it is inflating layouts properly.
The default behavior is for android to handle the orientation change (which involves destroying your activity and creating a new instance of it which will reload all layout files). This default behavior will always occur unless your activity tag in your manifest file contains the property android:configChanges="orientation". (This tag can take arguments other than orientation - android will handle the config changes for all events except the ones you pass as arguments to this tag.)
If you include the android:configChanges="orientation" tag you are telling android NOT to destroy your activity and NOT to reload layout files when the orientation of the device changes. Instead of its default behavior it will call a method (which you define) to allow you to make any changes you wish to make to handle the orientation change yourself rather than letting android handle it automatically. It's intended so that if destroying your activity would be a major inconvenience it doesn't have to be automatically destroyed.
EDIT: added some things from the comment discussion
you should the define android:configChanges="orientation" in the manifest file for that activity and override the onConfigChanged() method in that setContentView()
Like so:
#Override
public void onConfigurationChanged(Configuration newConfig) {
setContentView(R.layout.your_xml);
super.onConfigurationChanged(newConfig);
}
First Basically I need to have layout when application starts.
Second I am getting data from views i have in this layout.
Third Im setting next layout and doing hard code work with data, that I got in step 2.
I can't figure out how to do this.
You can re-use the framework class ViewAnimator without any animations. It's not the prettiest solution, but should get the job done.
main.xml:
<?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="vertical">
<ViewAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:id="#+id/viewFlipper" />
</LinearLayout>
MyActivity.java:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
viewAnimator = (ViewAnimator)findViewById(R.id.viewFlipper);
viewOne = createViewOne();
viewTwo = createViewTwo();
viewAnimator.addView(viewOne);
viewAnimator.addView(viewTwo);
...
}
private void someMethod() {
... do my background task ...
viewAnimator.setDisplayedChild(1); // viewTwo
}
have you gone through the google notepad tutorials? They explain using a list screen and loading a edit/add screen used to modify you sqlite database