My abstract class extended from Activity class consists of three Views as described in the following XML snippet:
<?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"
android:background="#drawable/bg">
<LinearLayout
android:id="#+id/top_border">
...
</LinearLayout>
<View
android:id="#+id/activity_content"
...
/>
<LinearLayout
android:id="#+id/bottom_border">
...
</LinearLayout>
</LinearLayout>
And in onCreate() method I set this XML-layout as content view.
I want the Activitys which extend this one to override onCreate() and there define the activity_content View remaining borders immutable.
For example like this:
abstract public class MyActivity extends Activity {
protected View mContent;
#Override
protected onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.common_layout);
initializeContent();
}
abstract void initializeContent();
}
class OneActivity extends MyActivity {
#Override
protected void initializeContent() {
mContent = View.inflate(this, R.layout.some_view, null); // i.e. concrete View (e.g. LinearLayout, FrameLayout, GridView, etc.)
}
}
But when I do so my mContent remain the same as it was when I defined it in MyActivity's onCreate().
How can I change view's type/content depends on what Activity is in foreground?
First change the view in your main layout into a view group (for example, a LinearLayout). Then you can add views to it. If you add a unique view, it will have exactly the effect you want to achieve.
class OneActivity extends MyActivity {
#Override
protected void initializeContent() {
final ViewGroup viewGroup = (ViewGroup) findViewById(R.id.activity_content);
viewGroup.addView(View.inflate(this, R.layout.some_view, null));
}
}
In your case that should work. If your custom view group contained other views from higher up in the hierarchy, you can clean it before adding your custom view:
viewGroup.removeAllViews();
It works, I do exactly that in most of my projects.
An alternative is to look at the Fragments API, available for latest versions of the SDK.
You can't override class data members in Java, use methods instead
Related
I am trying to make a Button which will always be on standby like Floating Action button despite whatever context it may be in but shall sustain all above my activities, How could I achieve this please refer me a link or give me an idea.
One solution is to create a single activity with the button and then use fragments instead of the current activities.
class ActivityOne extends BaseActivity{
#Override
protected View childView(){
return getLayoutInflator().inflate(R.layout.activity_one, null);
}
}
class ActivityTwo extends BaseActivity{
#Override
protected View childView(){
return getLayoutInflator().inflate(R.layout.activity_two, null);
}
}
public abstract class BaseActivity extends Activity{
protected abstract View childView();
#Override
protected void onCreate(SavedInstanceState savedInstanceState){
super.onCreate(savedInstanceState);
RelativeLayout baseLayout;
ViewStub stub;
baseLayout = (RelativeLayout)
this.getLayoutInflater().inflate(R.layout.layout_base, null);
stub = (ViewStub) baseLayout.findViewById(R.id.base_content_stub);
// Replace viewstub with content.
baseLayout.removeView(stub);
baseLayout.addView(childView(), stub.getLayoutParams());
super.setContentView(baseLayout);
}
}
layout_base.xml
<RelativeLayout
....
>
<ViewStub
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:id="#+id/base_content_stub"/>
<Button
.... // <---- common to all activities
/>
</RelativeLayout>
Your best bet would probably be to make an abstract activity that contains that button and adds it to the layouts of all activity that inherit from it. That way you don't have to duplicate the code in every activity.
It's not possible to use the same button for every activity. You could use the same layout, but you'd have to create the button anew every time you created a new activity. You might be able to avoid that if you did some fancy stuff with the action bar that is frankly not worth it. I suggest you look at using fragments instead of activities, in which case you can have your layout file for you activity look something like this:
<LinearLayout android:id="#+id/fragment_container"
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"
tools:context="coop.nisc.intern2016.ui.MainActivity">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="#string/button_text" />
<RelativeLayout
android:id="fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Then, you can use a FragmentManager to put the fragment into the fragment_container. The code could look something like this:
private void showCustomFragment() {
FragmentManager fragmentManager = getSupportFragmentManager();
customFragment = new customFragment();
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, customFragment, customFragment.TAG)
.commit();
}
Create a BaseActivity class as a usual activity and a corresponding xml layout file with any layout you want. Add your button inside this layout, and a FrameLayout below the button. Code your button inside the onCreate() of the above activity. Your button's done.
Now, make all your other activities extend the BaseActivity, the super.onCreate() will take care of the button. Instead of setContentView() use:
FrameLayout contentFrameLayout = (FrameLayout) findViewById(R.id.content_frame); //Remember this is the FrameLayout area within your base activity xml
getLayoutInflater().inflate(R.layout.the_layout_you_want_to_load, contentFrameLayout);
'the_layout_you_want_to_load'
is the layout xml of your current activity.
Here is my BindingAdapter:
public class Bindings{
#BindingAdapter({"font"})
public static void setFont(TextView textView, String fontName) {
textView.setTypeface(FontCache.getInstance(textView.getContext()).get(fontName));
}
}
*Instead of using "font" as the annotation parameter, I've tried "bind:font", "android:font", and "app:font", and made all the corresponding changes in the layout, but the BindingAdapter is still not called
Here is the layout where I use the BindingAdapter (bind_layout.xml):
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data></data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
font="#{`fontawesome-webfront`}"
android:text="#string/double_left"/>
</LinearLayout>
</layout>
*this layout is included in the Activity's layout which is set using DatabindingUtils.setContentView
Here is the activity whose layout includes bind_layout.xml:
public class ACreateSemester extends AppCompatActivity {
private List<CreateItemView> mCreateItemViews;
private LinearLayout mItemContainer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DataBindingUtil.setContentView(this,R.layout.a_create_items);
mItemContainer = (LinearLayout) findViewById(R.id.item_container);
mItemContainer.addView(new CreateItemView(this, Item.getDefaultItem()));
}
}
The three files I referenced here are listed in their entirety.
The way I know the BindingAdapter is not being called is because I set a breakpoint on the method and also in the body, and the breakpoint is never reached.
Any idea why the BindingAdapter is not firing?
Please, also make sure that you have made this steps.
Apply plugin: 'kotlin-kapt' in your app level build.gradle.
Set lifecycle owner to binding from your activity's onCreate() method e.g.
binding.lifecycleOwner = this, where this is your Activity.
Change font="#{fontawesome-webfront}" to app:font="#{fontawesome-webfront}"
in your xml.
Add some Id to your button in xml layout.
I think you missed to connect your view with viewModel in activity.
public class ACreateSemester extends AppCompatActivity {
private List<CreateItemView> mCreateItemViews;
private LinearLayout mItemContainer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ACreateItemsBinding binding = DataBindingUtil.setContentView(this,R.layout.a_create_items);
mItemContainer = (LinearLayout) findViewById(R.id.item_container);
mItemContainer.addView(new CreateItemView(this,Item.getDefaultItem()));
binding.setView(YourViewHere);
}
Following is a xml: welcome_view.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white" >
<ImageView
android:id="#+id/welcome_bg"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.demo.src.WelcomeLayout
android:id="#+id/welcome_ad"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
This is the MainActivity, I setContentView with layout welcome_view.xml.
class MainActivity extends Activity
{
onCreate()
{
setContentView(R.layout.welcome_view);
ViewGroup view1 = findViewByID(R.id.ad_view);
}
}
WelcomeLayout has been contained in the welcome_view.xml. Please tell me the view in the following class is different with the one in above class??? Why, tell me some the inner mechanism.
class WelcomeLayout extends FrameLayout
{
onCreate()
{
super(context);
View.inflate(context, R.layout.welcome_view, null);
ViewGroup view2 = findViewById(R.id.ad_view);
}
}
Thanks!
reference:Difference between setContentView and LayoutInflater
setContentView is an Activity method only. Each Activity is provided with a FrameLayout with id "#+id/content" (i.e. the content view). Whatever view you specify in setContentView will be the view for that Activity. Note that you can also pass an instance of a view to this method, e.g. setContentView(new WebView(this)); The version of the method that you are using will inflate the view for you behind the scenes.
on the other hand, have a lifecycle method called onCreateView which returns a view (if it has one). The most common way to do this is to inflate a view in XML and return it in this method. In this case you need to inflate it yourself though. Fragments don't have a "setContentView" method
Note:link might be destroy so answer pasted.
I have a flying in menu which based on ViewGroup.
I want that there will be a basic layout and in any activity i would be able to insert to the view group new layout and afterwards to erase it.
But it doesn't work!!! Can you help me please.
class:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.root = (FlyOutContainer) this.getLayoutInflater().inflate(R.layout.activity_main, null);
this.setAdditionalLayout(findViewById(R.id.physical_layout));
this.setContentView(root);
}
ViewGroup:
<com.nurielweizmann.calculator.view.viewgroup.FlyOutContainer xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#444488"
android:orientation="vertical"
android:id="#+id/menu">
............
</RelativeLayout>
</com.nurielweizmann.calculator.view.viewgroup.FlyOutContainer>
Function:
FlyOutContainer root;
public void setAdditionalLayout(View view){
root.addView(view,1);
}
Thanks in Advance
Try overriding the setContentView(int) instead of the onCreate(Bundle).
Make sure your base layout XML has a ViewGroup (FrameLayout, for example) available to put each Activity's content.
When overriding the setContentView(int), inflate your base layout first then inflate the Activity's layout and place the Activity's layout on the FrameLayout available.
I tried to replace a Fragment in FragmentActivity run-time.
fragment_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
MyFragmentActivity.java
public class MyFragmentActivity extends SlidingFragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_activity);
}
// Will be called by AsyncTaskLoader's onLoadFinished.
public void selectActiveContent() {
// MyFragment's top level is LinearLayout
Fragment fragment = new MyFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.content, fragment).commitAllowingStateLoss();
}
However, I realize the outcome is not optimized.
I realize the FrameLayout supplied through my own fragment_activity.xml, is being attached to another parent FrameLayout.
Instead of
FrameLayout
FrameLayout
LinearLayout
LinearLayout
ListView
I wish to have
FrameLayout
LinearLayout
LinearLayout
ListView
May I know how I can achieve so? Is it possible I can have a fragment_activity.xml without a ViewGroup (FrameLayout) ?
While the <merge> element was specifically designed for removing useless levels of view hierarchy, per this answer, you cannot use merge tags in Fragments and you must instead use a ViewGroup root view as you noticed, the lightest weight (i.e., fastest to render) being a FrameLayout.