How to access child elements of a TextSwitcher using view binding? - android

I'm using the Android view binding to get an automatically generated binding class of my XML. In my XML definitions I'm using a TextSwitcher control with two child elements of the type TextView.
In code I access the child views of the TextSwitcher like this:
...
_binding = MyViewBinding.inflate((LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE), this, true);
((TextView)_binding.myTextSwitcher.getChildAt(0)).setTextColor(_mySpecialColor);
((TextView)_binding.myTextSwitcher.getChildAt(1)).setTextColor(_mySpecialColor);
...
Is there an easier way to access the child views of the myTextSwitcher directly with the MyViewBinding class without the need to cast them?
The XML definitions looks like this:
<TextSwitcher
android:id="#+id/myTextSwitcher"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/text2"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</TextSwitcher>

All the time I was searching at the wrong location in the generated binding class.
Those TextView's are there directly accessible on my _binding variable.
// this does work
_binding.text1.setTextColor(_headerLabelColor);
_binding.text2.setTextColor(_headerLabelColor);
I thought they need to be accessible as child's of my TextSwitcher but it seems I learned something now.
// this does not work but I expected it to
_binding.myTextSwitcher.text1.setTextColor(_headerLabelColor);
_binding.myTextSwitcher.text2.setTextColor(_headerLabelColor);

Related

How can i merge two recycler views such that they scroll one after another?

I tried to implement this answer and it worked but only if the both list are prepopulated already, but in my case one list is prepopulated and the other is incremented/decremented dynamically.
Here is my layout structure
Black box represents the recycle list which can be incremented/decremented dynamically, and its main action is to show the users favorite fonts.
Red box represents all the fonts which are available and they are prepopulated.
i want both these list to flow each-other in scroll, such that user can not notice that these are actually two different list.
my xml code :
<?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:padding="#dimen/home_section_padding"
android:background="#color/background"
android:orientation="vertical"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:layout_width="match_parent"
android:id="#+id/editText"
android:textColorHint=" #C0C0C0"
android:hint="Paste"
android:textColor="#color/text_color"
android:inputType="text"
android:layout_height="wrap_content"/>
<Button
android:layout_width="match_parent"
android:text="Style"
android:textStyle="bold"
android:textColor="#color/text_color"
android:layout_marginBottom="10dp"
android:fontFamily="serif-monospace"
android:textAppearance="?android:textAppearanceLarge"
android:background="#drawable/round_shape_for_button"
android:onClick="fire"
android:id="#+id/button"
android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyelerViewFav"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</androidx.recyclerview.widget.RecyclerView>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyelerView"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp" />
</LinearLayout>
There is 2 options, You can either use ConcatAdapter to combine both adapters in one adapter and use one RecyclerView (Recommended). Or use NestedScrollView to wrap both your RecyclerViews and make sure to set both RecyclerView heights to wrap_content.
But based on what you are trying to achieve, I would recommend to use ConcatAdapter(adapter1, adapter2) to wrap both your adapters and set that new adapter on one RecyclerView. You will still be able to control each adapter by itself Add, Remove and calling notifyDataSetChanged on the changed adapter will reflect changes on the RecyclerView.
I think you should use two lists in one RecyclerView adapter.And have two different view holders.Whenever you need to make a change just make the change in specific array list (1 or 2) and call notifyDatasetChanged() on the single adapter you have.
Something like this answer
Create 2 different xml file apart from activity_main.xml ,create 2 external java file associated with these 2 XML file for user handling code purposes. Give your desired layout for recycler view in those 2 XML file,map those XML file in MainActivity.java class using some java class which will extend RecyclerView.Adapter class and override some methods as onCreateViewHolder(),onBindViewHolder().To inflate the recycler view data ,create 1 more java file which will use some getter() & setter() inorder to populate the recycler view with data by the help of the class extending RecyclerView.Adapter class.

Android App setContentView(R.layout.activity_main) vs View binding - layout_gravity not respected

I decided to finally jump into Kotlin this month as a hobby project. I'm working through a Udacity course (Android app dev with Kotlin).
I was just trying to replace the viewById with View binding (as a test for me). Which works fine.
But why if I use setContentView(view) from the binding does my layout no longer respect the gravity?
My layout file for my main activity is linear, with center-vertical layout_gravity
<<?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="wrap_content"
android:orientation="vertical"
android:layout_gravity="center_vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:textSize="30sp"
android:layout_gravity="center_horizontal"/>
<Button
android:id="#+id/roll_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/roll"
android:layout_gravity="center_horizontal"
/>
</LinearLayout>
When I use the old setContentView(R.layout.main_activity) in my activity, this displays as expected in the center of the screen
class MainActivity : AppCompatActivity() {
#RequiresApi(Build.VERSION_CODES.P)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Let's do it the trad way without binding
setContentView(R.layout.activity_main)
val rollButton: Button = findViewById(R.id.roll_button)
Image with central gravity
If I swap this out for view binding instead and replace the setContentView as shown below
var binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
The app still runs, but now the text and button are at the top of the screen.
image top aligned
I was just testing that I could make this work in general, as I'd prefer to use in real life (anything to reduce nullPointer exceptions). But if I can't even get a simple example to work properly I'm stuffed.
Does anyone know what I am doing wrong? Or what concept I'm missing?
Try to change android:layout_gravity="center_horizontal" to android:layout_gravity="center" or maybe try to use RelativeLayout I heard that it's one of the best layouts.
I'm having trouble with this same problem. I was looking at the documentation for View Binding and it states:
"View binding doesn't support layout variables or layout expressions,
so it can't be used to declare dynamic UI content straight from XML
layout files."
I'm wondering if it's related to that? I'm still very new to this, but it's the only thing I can find so far that makes some sense to me.
UPDATE: Found another question asking the same thing (How to use View Binding with Linear Layout?)
Changed android:layout_gravity="center_vertical" to android:gravity="center", but then had an issue with the preview in Layout Editor not showing it centered; to remedy that I added tools:layout_gravity="center_vertical" so the activity_main.xml shows this now at the top:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
tools:layout_gravity="center_vertical"
android:orientation="vertical"
tools:context=".MainActivity">
Might not be the best solution, but works to show you the preview and then when you actually run it!
XML layout_-prefixed attributes work with the parent view. When you inflate a view without a parent, the layout_* attributes have no effect.
An activity's setContentView(int) normally delegates to PhoneWindow#setContentView(int) that implicitly uses a parent container layout when inflating the XML layout. That's why the 1-arg inflation works in an activity.
View binding does not implicitly supply any parent layouts. You need to explicitly supply it with the three-arg inflate(int, View, boolean) method call where the first arg is the layout id, second one is the parent and the third controls whether the inflated layout should be added to the parent when inflating.
The usual an easy use case is to use fragments where the onCreateView() callback supplies you with a parent container layout and you can just return inflate(id, container, false).
The PhoneWindow content layout is lazily generated, so you kinda have a chicken-and-egg problem. Calling setContentView() generates the content layout but when calling it you kinda want to already have inflated the view binding with a parent content layout.
My suggestion is to move the layout code away from your activity and instead use a fragment for it. Then you can use view binding in your fragment.

Common method for activity and fragment

I have a layout section which is part of a Fragment and its a layout for the activity.
fragment.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none”>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp">
<include layout="#layout/sectional_component"/>
<include layout="#layout/list_component" />
<include layout="#layout/usage_component" />
</RelativeLayout>
</ScrollView>
list_component.xml
<LinearLayout
android:id="#+id/list"
style="#style/VerticalMatchParent">
// programatically added top 3 customer list
</LinearLayout>
activity_list.xml
<LinearLayout
android:id="#+id/list"
style="#style/VerticalMatchParent">
// programmatically render all customer list
</LinearLayout>
I'm new to android. I wanted to use a common method for rendering the list based on the request (3 or all). For now, I have written a separate method in Fragment and in an activity to handle this.
I want to make it as a single method which can be used by the fragment as well as an activity since the functionality is nearly same. I tried to make it as a separate util method, but the issue I'm facing is inside the method I have do manipulations for the view elements not sure how to do it without inflating the view element layouts. Already the layouts having the view elements are inflated in the respective Fragment and Activity.
Kindly provide a solution for this.
There are multiple approaches to do this, one of them would be to create an static method inside a separated class, pass the required parameters and call it wherever you want.
Class MyClass:
public class MyClass {
public static View myMethod(View myView){
// Do whatever you want with your View
return myView;
}
}
Call to myMethod from MyClass:
View modifiedView = MyClass.myMethod(myView);
If you need to handle some Views send them to the method as a list, array or whatever
If you plan on populating a list, you can go for listView. And write an adapter class to populate your list on it.
Note: You need a separate layout file with design for listView saved under you layout folder.
Hope this helps!

Under what circumstances will a layout element be null when fetched using findViewById(R.id.*)?

I have a layout as below:
Let's name it my_layout.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="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:background="#19396a"
/>
<TextView
android:id="#+id/textView2"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:background="#19396a"
/>
</LinearLayout>
<ListView
android:id="#+id/uilistView"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
In my activity I have a method in which I initialize all the UI elements i.e I do mapping of activity UI variables to layout.
Assume, the method is as below:-
//used to initialize UI elements
//called in oncreate() method
public void initializeUIelements() {
......
activity_listView = (ListView) findViewById(R.id.uilistView);
}
Here, activity_listView is a class level variable of type ListView
In my project, I have res\layout as well as res\layout-land and my_layout.xml exists in both the folders.
But sometimes during activity restart/when it's created I get a NullpointerException while initializing activity_listView that comes from R.java.
I know:
We get NullpointerException similar to what I am asking when an
element does not exist in any of the layout folder(i.e it exists in layout-land but does not exist in layout folder).
But here,the element exists in both folders and even though I get this inconsistent error
i.e. I am not able to produce it always but sometimes it starts coming.
So,please help me in analyzing as what may be the reasons when we get this error apart from the one mentioned by me above.
Thanks in advance.
If you could provide a more specific example, it might be easier to debug the exact problem. A few reasons why your View might be null:
The layout you've set as the content view does not include a view with this id:
If you reference a View that exists in the R file (a file that holds references to all elements within the res folder), say uilistview, in an Activity where you are not setting it's layout container as the content view (in this case this would be my_layout.xml), you will not get an error in Eclipse or whatever IDE you are using. Android will look for a View with this id within the layout, and if it can't find it, it will return a null value.
You call findViewById too early
You must use the method setContentView(R.layout.some_layout) before you try to access any of the elements with findViewById(). Logically, it makes sense - you need to tell Android where it should look where it's find an element
Looking for an element inside an inflated View
This is similar to the first, but it's common. If you've inflated a view and then want to manipulate a View inside the inflated View, you must instruct Android to look in the right place. For example:
RLayoutInflater layoutInflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View smallerView = layoutInflater.inflate(R.layout.mylayout);
If you want to reference something within mylayout.xml, you would need to use this:
TextView text = (TextView) smallerView.findViewById(R.id.text_view);
rather than:
TextView text = (TextView) findViewById(R.id.text_view);
The first indicates to look into the inflated view by placing the findViewById method on the inflated view, while the second one applies it to the current View of the Activity, which will cause a null value to be return.
Clean your project
This is the most frustrating answer, because this is not your fault. Sometimes the R.java class messes up and causes wrong references to id's while it is being compiled/built. Try cleaning your project and correcting the wrong references by looking for Project -> Clean in the main bar of Eclipse (or the IDE you're using).

Sharing data with custom canvas view

I'm a beginner at android programming, so excuse me if my wording is slightly incorrect.
I have a custom canvas view along with a TextView inside a linear layout, defined in the layout file as
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="#+id/blah"
android:layout_width="fill_parent"
android:layout_height="60dp"
android:gravity="top|center_horizontal"
/>
<com.*.Overlay android:id="#+id/combined"
android:layout_width="fill_parent"
android:layout_height="100dp"
/>
</LinearLayout>
I need to be able to read the text contained in the TextView from within the Overlay custom class that I created.
(The overlay class takes in 2 bitmaps and puts one on top of the other. The bitmaps used will depend on the text in the TextView.)
I considered using intents, but the Overlay class doesn't have an onCreate method.. All my code is within the onDraw method. I also added the necessary constructors.
I'm not sure what to try next, perhaps try accessing the parent linearlayout and then its child textview?
Hope I managed to explain everything in a non-confusing manner
Ok, managed to fix the issue... sort of
I found out that Views need to be contained in Activities.. so I created a new Activity with my custom view as an inner class, passed an intent with the necessary data to the activity and was able to use it successfully in my custom canvas view.
I was a bit surprised I didn't get any responses, but I guess that's because I'm new here

Categories

Resources