How to get included views with Android Databinding? - android

I'm playing with Android databinding library and I'm trying to use it with included layouts.
The code I have is like this:
activity_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id = "#+id/linearLayout">
<include
layout="#layout/view" />
</LinearLayout>
</layout>
view.xml
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id = "#+id/myView">
</View>
MainActivity.java
public MainActivity extends AppCompatActivity{
private ActivityMainBinding mBinding;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
LinearLayout layout = mBinding.linearLayout; // this field is visible
View myView = mBinding.myView // THIS FIELD IS NOT VISIBLE
}
}
As I have written in comments the view myView which is declared in an "included" layout is not visible. If I replace the with the actual code in the view.xml then mBinding.myView becomes visible, the cause seems to be the include then.
The official documentation states only that
"Data binding does not support include as a direct child of a merge element."
but in my case View is a child of LinearLayout, it's not a direct child..
Any hints?

You need to provide an ID to the include statement:
<include android:id="#+id/included"
layout="#layout/view" />
Now you can access the include view:
View myView = mBinding.included;
If your included layout is a binding layout, the include will be a generated Binding. For example, if view.xml is:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#{#android:color/black}"
android:id="#+id/myView"/>
</layout>
then the layout field will be a ViewBinding class:
View myView = mBinding.included.myView;

Related

Collapsingtoolbar in fragment not show/hide header when scrolling

I replace fragment in a activity and in my fragment I need a CoordinatorLayout.
Here is my code :
CoordinatorActivity class:
public class CoordinatorActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coordinator);
Fragment newFragment = new FragmentCoordinator();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fr_main, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
activity_coordinator.xml file:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:id="#+id/fr_main"
tools:context="com.app.hoatv.CoordinatorActivity">
</FrameLayout>
FragmentCoordinator class:
public class FragmentCoordinator extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_coordinator, container, false);
}
}
fragment_coordinator.xml file :
<?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"
tools:context="com.app.hoatv.CoordinatorActivity">
<android.support.design.widget.CoordinatorLayout
android:layout_height="match_parent"
android:layout_width="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:elevation="0dp"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme">
<include layout="#layout/layout_group_header"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_height="match_parent"
android:layout_width="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:fillViewport="true">
<android.support.v7.widget.AppCompatTextView
android:layout_height="1000dp"
android:layout_width="match_parent"
android:text="#string/lorem"
android:background="#color/colorAccent"
android:id="#+id/container"/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
layout_group_header.xml:
<?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="100dp"
android:background="#a70000">
</LinearLayout>
but when I scrolling NestedScrollView layout_group_header.xml not show or hide. It always show in my fragment screen.
What happened in my code? and How I can fix it?
What happened in my code? and How I can fix it?
There are few things which you should consider. First, you are opening a view(LinearLayout) inside AppBarLayout which there might be a Toolbar but that's not just the case.
First part: (Important one): The best idea and correct way of creating such layouts is to first, remove LinearLayout from the root of the fragment_coordinator layout then copy-paste the codes from fragment_coordinator to activity_coordinator. After that, use FrameLayout as the content's Container inside NestedScrollView.
Making Changes Part (As your requirements): After all, you can place codes anywhere you want in the main layout, for example, if you want the layout_group_header to be hidden after scrolling in the layout, you may wanna use layout_group_header codes inside fragment_coordinator which it will be a scrolling content. Othewise, you can use the codes inside CoordinatorLayout or anywhere instead of including it like that.
P.s: Design is completely seems to be wrong. Use first part which is an important part of creating such layouts. Note that there will be some changes inside java-kotlin sides too. (Changing layout address or etc)

Use ViewStub as generic layout in android

As I mentioned in the title, I would like to use ViewStub as a generic layout. What I mean is, currently I have my base activity class and base fragment class to be extended for other activities or fragments. So since I have generic classes, I wonder if I can have a generic layout. Is it possible?
Example layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:fitsSystemWindows="true"
tools:context=".activities.Activity_Main">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/toolbar" />
<ViewStub
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/viewStub"
/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
Where #+id/viewStub content will change according to desired layout.
Yes, you can do that programmatically by using the setLayoutResource() method to which you pass the desired layout id.
ViewStub stub = (ViewStub) findViewById(R.id.viewStub);
stub.setLayoutResource(R.layout.some_layout);
View inflatedLayout = stub.inflate();
When inflate() is invoked, the ViewStub is replaced by the inflated View and the inflated View is returned. This lets applications get a reference to the inflated View without executing an extra findViewById().
Here is the reference.

Inflate a Viewstub that contains a Data Binding

I have an abstract BaseActivity class with this layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
<ViewStub
android:id="#+id/activity_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
All activities in the app extends BaseActivity and overrides a method called getLayoutResID to provide its layout resource id which is inflated in the ViewStub. I do this to avoid having the Toolbar in each layout. The code in the base class that is used to inflate the layout is this:
private void setupLayout() {
setContentView(R.layout.activity_base);
ViewStub viewStub = (ViewStub) findViewById(R.id.activity_layout);
viewStub.setLayoutResource(getLayoutResID());
viewStub.inflate();
}
One of my activities use the new Data Binding system, below its layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.myapp.User" />
</data>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{user.name}" />
</layout>
Although the data binding works perfectly the problem is that the ToolBar is not visible. Any idea why the data binding engine removes/hides the toolbar in this activity?
ViewStubs requires special attention as they replace themselves when being inflated, rather than populating themselves.
Read more on data-binding/guide#viewstubs
Another solution (to avoid ViewStub altogether) is to let your ConcreteActivities include a toolbar layout in their layout - instead of inflating a stub containing the toolbar. You'll also have less headache if you ever want to use custom a toolbar for an activity.

Using MPChartLibrary within a fragment

I am working on an Android project and I am trying to implement a Library called MPAndroidChart from https://github.com/PhilJay/MPAndroidChart.
I am trying to implement it in a fragment but I keep getting an error and I cannot see why.
Below is my activity.
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment chartFragment = new ChartFragment();
transaction.replace(R.id.fragmentContainer, chartFragment);
transaction.commit();
}
}
Below is my activities layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/toolbar" />
<FrameLayout android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Below is my Fragment class
public class ChartFragment extends Fragment
{
private LineChart mChart;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.graph, container, false);
return v;
}
}
And below is the layout for the fragment
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.github.mikephil.charting.charts.LineChart
android:id="#+id/lineChart1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
At the moment it crashes when it tries to inflate the view in my OnCreateView function.
The error I am getting is:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.MyCompany.ChartTest/com.MyCompany.ChartTest.MainActivity}:
android.view.InflateException: Binary XML file line #5: Error
inflating class com.github.mikephil.charting.charts.LineChart
I honestly do not see anything that could be wrong.
The only difference I see between the Fragments used in the example project is that they use wrap_content instead of match_parent for the width and height of the chart.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.github.mikephil.charting.charts.LineChart
android:id="#+id/lineChart1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
I've managed to confirm where the problem is.
I have my apps theme defined in a library that is used by my various other apps, but for some reason when referencing the theme from the library when using MPAndroidChartLib I get this exception. If I copy and paste the theme style from my Library and it to my apps own styles file and reference this instead it works fine.
Try this, it may help:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.github.mikephil.charting.charts.LineChart
android:id="#+id/lineChart1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
The line:
xmlns:app="http://schemas.android.com/apk/res-auto"
is important.
I hope it helps.
I struggled with this exact issue and finally found a working solution.
The clue was an error message on the design preview of the chart fragment:
The following classes could not be instantiated:
charting.charts.LineChart
Exception Details
java.lang.ClassNotFoundException:
com.nineoldandroids.animation.ValueAnimator$AnimatorUpdateListener
Adding com.nineoldandroids:library:2.4.+ to my project's build.gradle file fixed the issue:
dependencies {
compile 'com.android.support:support-v4:19.1.0'
compile 'joda-time:joda-time:2.5'
compile 'com.nineoldandroids:library:2.4.+'
compile files('libs/MPChart.jar')
}
Adding lines below in onCreate() did the trick for me
getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);

How do I add a custom view to ViewFlipper

I have a ViewFlipper defined that contains 3 views...
<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/flipper" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include android:id="#+id/first" layout="#layout/first_view" />
<include android:id="#+id/second" layout="#layout/second_view" />
<include android:id="#+id/third" layout="#layout/third_view" />
</ViewFlipper>
I also have a custom View defined within my Activity...
private class CompassView extends View {
#Override
protected void onDraw(Canvas canvas) {
...
}
}
Some how, I need these linked together so that the 'third_view' defined in the XML layout file needs to be a CompassView, or have a CompassView added to it.
What I can do is drop the 'third_view' from the layout and then add in the CompassView manually..
viewFlipper = (ViewFlipper)findViewById(R.id.flipper);
viewFlipper.addView(new CompassView(this));
But then I lose the ability to define other view controls within the layout file.
Can I add CompassView to 'third_view' declaratively?
If the question is how to add a custom view in an Android XML layout file, try this:
<com.example.CustomView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</com.example.CustomView>
The open and close tags should just be the fully qualified class of your custom view.

Categories

Resources