I have an Android Project with 2 modules. I have MainActivity in both modules:
com.example.MainActivity
com.example.paid.PaidMainActivity
Both modules have res/layout/main.xml and they differ a bit.
Free version:
<?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">
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Paid version:
<?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">
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/paidView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
PaidMainActivity extends MainActivity and layout is set with setContentView in the parent activity. At the moment 90% of the functionality is same and is done in MainActivity.
public class MainActivity {
TextView text1;
TextView paidView;
public void onCreate() {
text1 = findViewById(R.id.text1);
paidView = findViewById(R.id.paidView);
}
public void onResume() {
text1.setText("This is just a text");
if (paidView != null) {
paidView.setText("All features unlocked");
}
}
}
ViewBinding generates two MainBinding java classes that I could use in either class but then I would have to refactor a lot of code (this sample is oversimplified). I would also have duplicate code in both Activities because I can't use the same binding object and override some functionality. Is there a way I can use view binding and a merged xml file with all the (#Nullable) views?
Related
I wonder that Whether the resource id in Android xml can be used before being declared? when I test it in a demo application , compiled in Android Studio and ran in the phone both work. The xml code in demo as following:
<?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">
<LinearLayout
android:id ="#+id/view"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#color/black"
android:layout_alignBottom="#id/bt"/>
<Button
android:id="#+id/bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" am a button" />
</RelativeLayout>
The Activity code as following:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Trying to change a layout from an ImageButton but when i run it on my phone it does not switch instead it says program has stopped.
Java;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageButton ImageButton = (ImageButton) findViewById(R.id.image);
ImageButton.setBackgroundColor(1);
ImageButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view)
{
setContentView(R.id.aaa);
}
});
}
}
XML for first layout:
<?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"
tools:context="com.example.bassammetwally.anew.MainActivity">
<RelativeLayout
android:layout_width="420dp"
android:layout_height="50dp"
android:background="#3955a1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Writer's Block"
android:textColor="#ffffff"
android:textSize="30dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="4dp"
android:id="#+id/Asd"/>
<ImageButton
android:layout_width="20dp"
android:layout_height="40dp"
android:src="#drawable/pen"
android:layout_marginLeft="380dp"
android:layout_marginTop="5dp"
android:scaleType="fitXY"
android:adjustViewBounds="true"
android:id="#+id/image"/>
</RelativeLayout>
</LinearLayout>
Second layout to change to;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/aaa">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ans"/>
</LinearLayout>
I think it might have something to do with my syntax.
You need to use a layout reference instead of an id
setContentView(R.layout.view);
Where view.xml is the layout you want.
You may want to rethink your approach, though. Using Fragments is preferred over completely replacing the layout because your ImageButton is no longer usable and you'll need to recall findViewById for any new views that are displayed.
If you just want to load a layout file and add it to the current layout, see Inflating one layout
In my activity IndividualActivity i have set the contextview of individual.xml now i also want to add another sub_individual.xml in the activity without removing, replacing or hiding the individual.xml so that they remain together.
public class IndividualActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.individual);
...
}
}
individual.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"
tools:context=".IndividualActivity"
android:background="#drawable/default_wall" >
<ListView
android:id="#+id/listx"
android:layout_width="fill_parent"
android:layout_height="380dp"
android:dividerHeight="1dp"/>
...
sub_individual.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="40dip"
android:layout_marginLeft="0dp"
android:background="#323331"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="5dip"
android:text="custom title bar" >
<ImageView
android:id="#+id/bk_btn"
android:layout_width="35dip"
android:layout_height="35dip"
android:background="#DDD" />
...
This functionality is supported by using Fragments. See http://developer.android.com/guide/components/fragments.html
You can use this from xml
Use "include" tag in your first xml and add second xml in this tag.
Sorry if this looks so easy, but I looked to the N+1 video about dialogs and it's showing creating a dialog in code and not by using the layout.
Here's what I did:
ChangePasswordView.axml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="16dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:id="#+id/oldpassword"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="#string/YourOldPassword"
android:inputType="textPassword"
local:MvxBind="Text OldPassword" />
<EditText
android:id="#+id/newpassword"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="#string/YourNewPassword"
local:MvxBind="Text NewPassword" />
<Button
android:text="#string/ChangePassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
local:MvxBind="Click ChangePasswordCommand"
android:paddingRight="42dp"
android:paddingLeft="42dp" />
</LinearLayout>
</FrameLayout>
ChangePasswordView.cs:
[Activity]
public class ChangePasswordView : MvxDialogActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
DroidResources.Initialise(typeof(Resource.Layout));
this.SetContentView(Resource.Layout.ChangePassword);
}
}
Calling the display of the dialog from a view model:
void ChangePassword()
{
this.ShowViewModel<ChangePasswordViewModel>();
}
I also have Setup.cs:
public class Setup : MvxAndroidDialogSetup
{
...
}
Running results in an error complaining about:
Your content must have a ListView whose id attribute is 'android.R.id.list
I think there is some confusion here about what 'Dialog' is
Dialog 1 - https://github.com/migueldeicaza/MonoTouch.Dialog and https://github.com/kevinmcmahon/MonoDroid.Dialog
A Dialog in the sense of http://slodge.blogspot.co.uk/2013/05/n23-dialogs-n1-days-of-mvvmcross.html is a MonoTouch.Dialog or MonoDroid.Dialog based 'data form'.
These are defined in code - because that's what MonoTouch.Dialog and MonoDroid.Dialog are about. For Droid, you can override individual Elements of the display - each Element is loaded from a resource - but you can't load the whole 'Activity' as a resource.
Dialog 2 - http://developer.android.com/guide/topics/ui/dialogs.html
If you are not looking for MonoTouch.Dialog style pages, but are instead looking for Android native popup dialogs, then there isn't much about these in MvvmCross. There is a sample of a fragment resource-based dialog in https://github.com/slodge/MvvmCross-Tutorials/blob/master/Fragments/FragmentSample.UI.Droid/Views/HomeView.cs and some interesting recent discussion about how to display them in MvvmCross Dialog
I am trying to turn a couple buttons into a reusable component in Android. I have successfully gotten the XML / UI portion working, but I can't figure out how to make code behind it reusable between activities, short of recoding it everywhere. I am new to Android, so I apologize if this is obvious.
I've already reviewed this post several times: Android layout Tricks 3 - Part 1 but it seems to be missing a few files, and I do not have enough experience to rebuild them.
A dumbed down version of my main layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<WebView android:id="#+id/webview"
android:layout_width="fill_parent"
android:layout_height="375px"
android:layout_alignParentTop="true" />
<include layout="#layout/navbar"/>
</RelativeLayout>
and then of my "component":
<?xml version="1.0" encoding="UTF-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center">
<ImageButton android:id="#+id/Button1"
android:layout_width="71px"
android:layout_height="wrap_content"
android:background="#drawable/button1"
android:layout_alignParentBottom="true" />
<ImageButton android:id="#+id/Button2"
android:layout_width="75px"
android:layout_height="wrap_content"
android:background="#drawable/button1"
android:layout_toRightOf = "#+id/Button1"
android:layout_alignParentBottom="true" />
</LinearLayout>
</merge>
If you have any additional critiques on my XML, I would appreciate that too.
What I do is make an actual component that contains all of the common code and use it directly. Here is a dumbed down version of the component class:
public class NavigationBar extends LinearLayout {
public NavigationBar(Context context) {
super(context);
setupView(context);
hookupButtons(context);
}
public NavigationBar(Context context, AttributeSet attrs) {
super(context, attrs);
setupView(context);
hookupButtons(context);
}
private void setupView(Context context) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// inflate whatever layout xml has your common xml
inflater.inflate(R.layout.navigation_bar, this);
}
}
In my class hookupButtons does exactly what you think it would do. :-)
Then my in all my layout xmls look similar to this:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.dragonglobal.dragonplayer.ui.widgets.NavigationBar
android:id="#+id/nav_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ListView
android:id="#+id/list_of_playlists"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
In the onCreate of each activity I also have this (that you can adapt to whatever you need):
NavigationBar navbar = (NavigationBar) findViewById(R.id.nav_bar);
navbar.setText("Playlists");
Of course you will need to add whatever imports you need.
EDIT
Just a clarification: My navigation_bar.xml looks very similar to yours except I don't have the merge lines in mine.
EDIT 2
Here is what hookupButtons looks like. I'm only showing one button but you should get the idea.
private void hookupButtons(final Context context) {
ImageButton playlistsBtn = (ImageButton)findViewById(R.id.nav_playlists_btn);
if (context instanceof PlaylistsActivity) {
playlistsBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.nav_playlists_active));
} else {
playlistsBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(context, PlaylistsActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
context.startActivity(i);
}
});
}
}
By using in XML layout, you're making only the layout reusable, not any Java code that uses it.
You must create a subclass of View, if you want to reuse Java logic as well. The tutorial from your link has a sample that fits your need very well:
public class OkCancelBar extends LinearLayout {
...