I discovered very strange behavior of CardView's shadow.
I just start to develop an app, and there is absolutely no any business-logic or something like that. But anyway...
I just add few views to my fragments layout, and discover, that after every screen rotation cardview's shadow getting darker. After 5-6 rotations it already looks like completely black. I guess, the problem can be somewhere in canvas, but no idea where and why - i even didn't start customize anything.
I hope somebody already solve similar problem with cardview, and now can share that experience.
Thank you!
Here is screenshots, code, dependencies and xml:
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:iot="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="#+id/content_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="#dimen/common_gap"
iot:cardElevation="10dp"
iot:cardUseCompatPadding="true">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<DatePicker
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="#dimen/common_gap"
android:calendarViewShown="true"
android:spinnersShown="false" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:paddingLeft="#dimen/common_gap"
android:paddingRight="#dimen/common_gap"
android:text="#string/choose_date_confirm_button"
android:textColor="#color/colorPrimary" />
</LinearLayout>
</ScrollView>
</android.support.v7.widget.CardView>
</LinearLayout>
Java (Nothing else in fragment class)
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.date_choose_fragment, container, false);
return rootView;
}
dependencies
compile 'com.android.support:appcompat-v7:25.0.1'
compile 'com.android.support:cardview-v7:25.0.1'
Screenshots
This is most likely not due to any bug with CardView or its shadow draw. Rather, this is likely the result of multiple Fragments with transparent backgrounds, stacked one atop another, and the darkening shadow is the additive effect of the shadows' translucency.
Active Fragment instances are automatically recreated when the Activity is, which happens by default upon an orientation change. If you're unconditionally adding a dynamic Fragment instance, for example, in the Activity's onCreate() method, that one will be added along with any instances recreated from the Activity's prior state. Effectively, each time you rotate your device, you're adding one more Fragment to the stack, and the shadow gets a little bit darker.
This can be demonstrated with just a simple TextView, to show that it's not an issue specific to CardView.
fragment.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Hello world!"
android:textSize="60sp"
android:textStyle="bold"
android:textColor="#fffbc02d"
android:shadowColor="#70707070"
android:shadowDx="10"
android:shadowDy="10"
android:shadowRadius="10" />
In the example Activity's onCreate() method, we add a dynamically created Fragment with the given layout, as described above.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction()
.add(android.R.id.content, new MainFragment()).commit();
}
public static class MainFragment extends Fragment {
public MainFragment() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment, container, false);
}
}
}
This image shows successive captures after having rotated the device, twice for each step.
If you were to put a log print in the Fragment's onCreateView() method, you would see that an additional instance is created upon each rotation. At the end of that sequence, we have eleven Fragments in play.
One way to prevent this is to check if the Fragment is already attached to the FragmentManager before creating and adding a new one, which we can do by adding a tag in the FragmentTransaction. For example:
if (getFragmentManager().findFragmentByTag("main") == null) {
getFragmentManager().beginTransaction()
.add(android.R.id.content, new MainFragment(), "main").commit();
}
Alternatively, if you don't need to dynamically transact the Fragment after startup, you could instead statically define it in the layout, and the FragmentManager will handle the check and transaction itself.
<fragment
android:id="#+id/main_fragment"
android:name="com.mycompany.myapp.MainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Related
I want to show my java code in a fragment with a code view now my problem is that my code perform only for scrolling down but i want to scroll may code horizontally and vertically at the same time so now what can i do?
i already tried by nesting horizontalscrollview and scrollview but it dose not working and my app gone crush.
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="saiful" />
<thereisnospon.codeview.CodeView
android:id="#+id/codeViewId"
android:layout_width="match_parent"
android:layout_height="match_parent">
</thereisnospon.codeview.CodeView>
</LinearLayout>
</ScrollView>
and my java file is
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_java, container, false);
codeView = view.findViewById(R.id.codeViewId);
codeView.setTheme(CodeViewTheme.ANDROIDSTUDIO).fillColor();
codeView.showCode(Content.java);
return view;
}
Do not mess with Horizontal and vertical scrollviews. Here is good library for that. Give it a try.
"A bidirectional panning container for Android with native scrolling for APIs 7 and up."
Since I began to create the inheritors from Android Views, I frequently see the error Binary XML file line XX: Error inflating class. In this special case it will be the BottomSheet.
public class MyBottomSheet extends TableLayout {
BottomSheetBehavior myBottomSheetBehavior;
ImageView testImageView;
public MyBottomSheet(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
testImageView = (ImageView) findViewById(R.id.imageView); // still OK...
myBottomSheetBehavior = BottomSheetBehavior.from(this); // crashes Here
testImageView.setOnClickListener(onClickListener); // or here if to remove the previous row
}
// ...
}
My app has multiple tabs with individual fragments. The BottomSheet requires only in one of them, however if I dont't include the BottomSheet in the MainActivity markup, it will not move. So the code is:
activity_main.xml
<?xml version="1.0"encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- ... -->
<include layout="#layout/my_bottom_sheet"/>
</android.support.design.widget.CoordinatorLayout>
</android.support.v4.widget.DrawerLayout>
my_bottom_sheet.xml
<?xml version="1.0" encoding="utf-8"?>
<com.example.bottomsheettest.widgets.MyBottomSheet
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/myBottomSheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="*"
tools:context="com.example.bottomsheettest.MainActivityFragment"
tools:showIn="#layout/activity_main">
<TableRow>
<ImageView
android:id="#+id/imageView"
android:src="#mipmap/ic_launcher"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
</TableRow>
</com.example.bottomsheettest.widgets.MyBottomSheet>
MainActivityFragment.java
public class MainActivityFragment extends Fragment {
private static final int LAYOUT = R.layout.fragment_main;
private MainViewFAB fab;
private MyBottomSheet addNewItemToInboxBottomSheet;
public MainActivityFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
MainActivity activity = (MainActivity)getActivity();
fab = activity.getMainViewFab();
addNewItemToInboxBottomSheet = (MyBottomSheet) activity.findViewById(R.id.myBottomSheet);
return inflater.inflate(LAYOUT, container, false);
}
}
I supposeI missed something important about Android Views inheritance. But this case especially strange. In the MyBottomSheet class, there are no problem when getting the ImageView from the BottomSheet. Consequently, the access to BottomSheet from the respective class is available. However, if try to manipulate somethig related with BottomSheet, the exception will be.
I share the source code (.zip) created in the Android Studio during accept the some answer. There are no tabs in shared app, however I kept the fragment structure because it exists in the original app.
When creating a View subclass that is meant to be inflated from a layout, there are several things that won't be available in the constructor at runtime.
For one, child Views of your custom View defined in the layout will not have been inflated and attached yet, so any attempt to get references to them with findViewById() will return null there. Instead, this should be done no earlier than onFinishInflate(), and moving your ImageView initialization to that method will solve that particular error.
Also, your custom View itself will not have had its own LayoutParams set yet in the constructor. This is causing the issue with the BottomSheetBehavior.from() call there, since that method simply retrieves the Behavior from the LayoutParams constructed during inflation from layout attributes on the View. In the onAttachedToWindow() method, the LayoutParams will have been set, and you can make the BottomSheetBehavior.from() call there.
Lastly, I would just mention that an InflateException is thrown whenever anything goes wrong with inflation. The root cause of the failure will be listed further on in the stack trace, and you should look there to find the more relevant details.
In AndroidStudio, I selected "New->Fragment->Fragment (List)" to create a list of items. It works fine and displays all the items; however, I would like to have a title at the top.
If I add another TextView to the "fragment_item_list.xml" file, then the title appears in all the items in the list. From other questions I figured that if I create another LinearLayout xml layout file (something like "list_header.xml") and put a TextView in it, I can use a layout inflater to inflate this layout in the fragment activity, e.g. in onCreateView,
View header = inflater.inflate(R.layout.list_header,container,false);
but then I don't know what to do with header to make it display somewhere in the fragment. I can add it to the original activity by calling container.addView(header); but how can I add it to the fragment?
I don't want to change the ActionBar title, firstly just for aesthetics, and secondly because the fragment covers it up. Ideally there would be a header like in an alert dialog.
Let me try to understand you. You want to add a title to your fragment list (like an header), not in the ActionBar. Right?
Looking the fragment_item_list.xml we have this: (I follow your steps: "New->Fragment->Fragment (List)")
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView 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:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:listitem="#layout/fragment_item" />
The RecyclerView is a container used for populate a list, in other words, the RecyclerView (or ListView) contain all the list only. So, you have to add another container (like LinearLayout, RelativeLayout, etc.) as root of the layout to add more views to the layout. Example using the LinearLayout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/text_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World! I'm a header!"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/list"
android:name="com.veroapps.myapplication.ItemFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:listitem="#layout/fragment_item" />
</LinearLayout>
With this you will have a list with a title at the top. Now, you can manage the title TextView in the ItemFragment(name of the fragment generated by Android Studio). And of course there are more ways to do that, but this is an easy one.
Hope this help you.
In your Fragment java class, there should be a method called onCreateView this is where you set the layout for your Fragment (and where the list is added). It will look something like this:
public static class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
In this Fragment the layout is inflated by this code inflater.inflate(R.layout.example_fragment, container, false); and this means there's is an xml file defining the layout called example_fragment.xml.
Your code will be the same, when you find this XML file. You can add other views inside it.
You will want to add another TextView above the RecyclerView or ListView already in that file.
Something like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
...
android:text="YOUR TITLE" />
<RecyclerView
... />
</LinearLayout>
I'm following the android training in android's website. I am stuck at some point in fragments. The problem is that I can't get the reference to my textview in a fragment.
TextView view = (TextView) getActivity().findViewById(R.id.article_s);
I have two fragments in one activity. One is a plain simple ListFragment and the other is a plain simple TextView. Here is fragments and activity layout xml files.
ArticleFragment:
<!-- This is fragment_article.xml -->
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some Text"
android:textSize="18sp"
android:id="#+id/article_s"/>
MainActivity (My container to all fragments)
<!-- This is 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">
<fragment
android:layout_height="match_parent"
android:name="com.example.bora.fragmentsmyway.HeadlinesFragment"
android:id="#+id/headlines_fragment"
android:layout_weight="1"
android:layout_width="0dp" />
<fragment
android:layout_height="match_parent"
android:name="com.example.bora.fragmentsmyway.ArticleFragment"
android:layout_weight="2"
android:id="#+id/article_fragment"
android:layout_width="0dp" />
</LinearLayout>
There is a public method in my ArticleFragment which takes a string to update the content of the textview of itself:
public void updateView(String article) {
TextView view = (TextView) getActivity().findViewById(R.id.article_s);
try{
view.setText(article);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
After all the views are created, I call the updateView method from my MainActivity. But I get a NullPointerException when I try to find the article TextView. I have tried cleaning, changing the TextView's resource id.
However I have found a solution for this problem. I don't know why but it seems to work when I wrap TextView with a LinearLayout in the fragment_article.xml:
<LinearLayout
xmlns:android="..."
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some Text"
android:textSize="18sp"
android:id="#+id/article_s" />
</LinearLayout>
But I am wondering this: How can, in the tutorial samples, above code work and can't work when I wrote? I checked every code letter by letter but there is no difference between mine ant theirs. Is it because of the versions?
I'm working with the API 23 which is marshmallow.
Make sure you fragment is attached to the activity before calling updateView
this
TextView view = (TextView) getActivity().findViewById(R.id.article_s);
will give you NPE cause it does not belong to the activity
The views belong to the Fragments in which case you do
View view = inflater.inflate(R.layout.fragment_layout, container, false);
TextView textView = (TextView) view.findViewById(R.id.article_s);
Specifically, the fragment can access the Activity instance with getActivity() and easily perform tasks such as find a view in the activity layout:
Read Communicating with activity # https://developer.android.com/guide/components/fragments.html
So you use getActivity to find views that belong to activity which is not the case in your code.
Edit -
Wrapping it with a LinearLayout should not make any difference as it is just a viewgroup. If you just need a single textview no need for LinearLayout.
Read the accepted answer at : Difference between getActivity() and view in Fragment
use this code : you given wrong id to on TextView
TextView view = (TextView) getActivity().findViewById(R.id.article_s);
This is return NPE because your try to find the wrong id.
There are two different way you can resolve issue.
1) First one
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some Text"
android:textSize="18sp"
android:id="#+id/article"/>
TextView view = (TextView) getActivity().findViewById(R.id.article);
Another way keep your XML as it is & try to do below change in java code.
2) Second One
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some Text"
android:textSize="18sp"
android:id="#+id/article_s"/>
TextView view = (TextView) getActivity().findViewById(R.id.article_s);
It doesn't work like this inside a fragment class by the way you should upload your main activity codes or your fragment class if you are using it inside the main activity, you don't need to use getActivity()
if it is inside a fragment class you need to apply it like this:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.your_fragment_layout_xml, container, false);
TextView AboutUs = (TextView) rootView.findViewById(R.id.id_of_textview);
I have an android activity which has three fragments and in one of the fragments I am using list view to display a list. The list can be long and the view needs to be scroll able. When the activity starts onCreateView method of all fragments is called. This is code for onCreateView method
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView;
rootView=inflater.inflate(R.layout.files, container,false);
WebService.getFiles((UsersPOJO)getArguments().getSerializable("currentUser"));
return rootView;
}
R.layout.files has listView.
The problem is when the activity starts layout of all the three fragments in that activity shrinks when a soft keypad pops up. I tried to set isScrollContainer to false on individual layout but it isn't working any solutions to this problem.
EDIT: R.layout.files
<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:background="#color/WhiteBackground"
android:orientation="vertical">
<ProgressBar
android:id="#+id/filesLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
<TextView
android:id="#+id/noFiles"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/edit_text_left_margin"
android:layout_marginRight="#dimen/edit_text_right_margin"
android:layout_marginTop="#dimen/heading_top_margin"/>
<ListView
android:id="#+id/filesListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</ListView>
</LinearLayout>
Take a look at windowsSoftInputMode attribute inside your AndroidMenifest.xml file. Just set windowsSoftInputMode to adjustPanin your <activity>.