I'm new to android studio / java language.
I need to set up a pretty straightforward app, but the information I find doesn't let me solve the problem.
Can any of you help :)?
I want to make an app with 3 tabs
(first tab) user enters a decimal number, and after click of a button the result shows a value calculated with the means of a formula
(second tab) same as first tab but with values and formulas
(third tab) information of each formula
I've implemented a (for this use, simplified) code for the first tab.
I know how to code all the three tabs separately, but I don't know how
to merge them together in one app with 3 tabs.
I started with the tabs-template given in android studio, but it demands that every tablayout is the same. I've seen a lot of answers how to have different layouts for each tab, but how do I code the different tabs (e.g. setonclicklistener).
Second problem is that every solution uses android and I have androidx, so the imports won't take. And in dependencies I don't find design V7 or anything of that sort.
Mainactivity.java:
package com.example.soloapp;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.text.DecimalFormat;
public class MainActivity extends AppCompatActivity {
DecimalFormat numberFormat = new DecimalFormat("#.0");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button calcButton = (Button) findViewById(R.id.calcButton);
calcButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view){
EditText editNum = (EditText) findViewById(R.id.editNum);
TextView resultTextView = (TextView) findViewById(R.id.resultTextView);
double cysC = Double.parseDouble(editNum.getText().toString());
double tempResult = Math.pow(cysC,-0.931);
double resultLong = 70.69 * tempResult;
String result = numberFormat.format(resultLong);
resultTextView.setText(result);
}
});
}
}
activy_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">
<EditText
android:id="#+id/editNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:ems="10"
android:inputType="numberDecimal"
app:layout_constraintBottom_toTopOf="#+id/resultTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/resultTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginBottom="168dp"
android:text="Result"
app:layout_constraintBottom_toTopOf="#+id/calcButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/calcButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="200dp"
android:text="CALCULATE"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I'll add what you need to learn in order to create what you told.
You need to use ViewPager in Android to create swipeable tabs. (If you know WhatsApp, those swipeable three tabs are ViewPager).
You can learn more about ViewPager here.
For using ViewPagers, you need to learn what Fragments are, Fragments in Android are like small activities(but not activities). You embed these Fragments inside your Activities, so you need to put these Fragments inside the Activity that contains your ViewPager.
You can learn about Fragments here.
Although, the first ViewPager link will be sufficient for you to learn everything that you need to learn about creating Swipeable Tabs.
About the second problem that you mentioned.
According to Migrating to AndroidX,
Androidx only maps the original support library API packages into the
androidx namespace.
Basically, they just renamed the package name so that it'd be easy for them to support the updates to libraries.
You can easily find the corresponding androidx package from here.
Migrating to Androidx.
First le me start by stating I am fairly new to Java and Android Studio, so please bear with me. my background has been in Visual Basic going way back.
I have an activity that tries to verify that what was entered is a valid Item Number by UPC entered. When only one match all is good. My problem starts when the UPC entered brings back more than one matching item. What I am attempting to do (First time using fragments) is Replace part of the screen with a recycler view showing the matching items and descriptions.
When comes backs with multiple items I call an event called setupMulitpleItems with the following code:
public void setupMultiItems(String mScan){
Timber.d("Multiple matching Items");
Bundle bundle = new Bundle();
bundle.putString("valuesArray",mScan);
SelectItemFragment fragobj = new SelectItemFragment();
fragobj.setArguments(bundle);
FragmentManager fragmentManager=getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.include2, fragobj);
fragmentTransaction.commit();
Not sure how many parts of this code will actually work but I am getting underline on the replace line.
"'replace(int, android.app.Fragment)' in 'android.app.FragmentTransaction' cannot be applied to '(int, com.procatdt.stockright.activities.SelectItemFragment)'"
meesage.
I am using the following imports for Fragments.
import android.app.FragmentTransaction;
import android.app.Fragment;
import android.app.FragmentManager;
Figured I would also include the XML for the activity that is currently running when I want to use Fragment.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:background="#color/colorBackgroundGray"
tools:layout="#layout/fragment_select_item"
tools:context="com.procatdt.stockright.activities.PutAwayAreaActivity">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<include
android:id="#+id/include2"
layout="#layout/frm1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_gravity="left" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:paddingLeft="5dp"
android:orientation="vertical">
<include
android:id="#+id/include"
layout="#layout/layout_numpad5"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="220dp"
android:layout_weight="1"
android:layout_gravity="right"
/>
</LinearLayout>
</RelativeLayout>
I am trying to replace include2 with Fragment.
Hope this enough info but if anyone needs to see more let me know and I ill attach code.
You just need to pass the object of your fragment to replace method, there is no need to pass the class declaration and type of class
so just remove
// this is enough
fragmentTransaction.replace(R.id.include2, fragobj);
// remove this
//fragmentTransaction.replace(R.id.include2,android.app.Fragment SelectItemFragment);
My Problem
I've been trying to get my Recycler View's items to animate as I scroll down. These items are loaded from a local XML and passed through my custom adapter.
I'm using this library for my adapter animation
I noticed that no matter what I tried, the items would just not animate at all, or they would animate all at once (every item would slide in on screen at the same time).
What I've Tried So Far
Utilizing the library I mentioned, I tried animating items in my RecyclerView.Adapter.
> IndexFragment.java snippet
//Create an adapter
SongAdapter adapter = new SongAdapter(songs, getContext());
//Set adapter
AlphaInAnimationAdapter alphaAdapter = new AlphaInAnimationAdapter(adapter);
alphaAdapter.setFirstOnly(false);
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
This one failed somehow. I also tried the setItemAnimator method which also failed.
recyclerView.setItemAnimator(new SlideInLeftAnimator());
Layout Structure
So I assume it has something to do with my RecyclerView being inside of two NestedScrollView's.
Another person seemed to be having a similar issue
Below are some portions of my layout files
activity_main.xml
....
<!-- Fragment Container -->
<android.support.v4.widget.NestedScrollView
android:id="#+id/contentContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
....
This is where I put my fragments
index_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/nestedScrollView"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v4.widget.NestedScrollView>
This is pretty much my Recyclerview and its parent Nested Scrollview.
item_song.xml
<?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="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp">
<!--I have two text views in here. Removed them just for this snippet -->
</LinearLayout>
<!-- This displays a background on each item when I press them AKA touch effects -->
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:clickable="true"
android:background="?android:attr/selectableItemBackground" />
</FrameLayout>
This is the structure of each item in the Recyclerview. I inflate this layout for each item. Pretty straightforward.
Any ideas as to what I could do to solve this issue? Thanks.
So after much testing, I finally came up with a solution that worked.
Change the fragment container in activity_main.xml from NestedScrollView to RelativeLayout or perhaps LinearLayout.
Remove the parent NestedScrollView and keep only the RecyclerView in index_fragment.xml.
Animations now work at last. Yay!
Apparently, it is a bad idea to put your RecyclerView inside of a NestedScrollView.
I read somewhere that because of having to load the proper height of its child layout, the NestedScrollView has to wait for it to completely load, in order to know the total height of the RecyclerView. However, I'm not totally sure if that's the reason, so feel free to correct me.
Hope this helps someone!
I have the following layout (cut down to a minimal example)
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:id="#+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<EditText
android:id="#+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/free_text_default_bg"
android:gravity="center_horizontal"
android:padding="#dimen/free_text_padding"
android:text="background element is a video view" />
</RelativeLayout>
The problem is, that if I move the EditText around (it has a drag listener attached to it), it dissapears at a certain point of the screen as you can see in this screenshot.
The problem seems to only appear when I have a VideoView. Even if I don't show a video.
When I replace it with e.g. an ImageView there is no problem at all.
So my question is, what's happening and how can I resolve this?
Thanks for your time!
UPDATE 1: This only happens if the VideoView has
android:layout_height="match_parent"
when I set it to some "dp" value everything works just fine...
I did not find a solution to my question jet but I have found a workaround:
Once the layout is finished, I get the height from the parent container, subtract 1px and set this as new height for the video view.
The 1px is barely visible...
Here is the code:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
ViewGroup.LayoutParams layoutParams = videoView.getLayoutParams();
layoutParams.height = parentView.getHeight() - 1;
videoView.setLayoutParams(layoutParams);
}
I have a listview in my scroll view underneath almost a page worth of scroll before that but once my listview gets populated the scrollview moves to the top of the list view. how can I fix this/prevent this from happening?
SCROLL VIEW XML:
<ScrollView
android:id="#+id/tvscrollview"
android:layout_marginTop="8.0dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include
layout="#layout/a" />
<include
layout="#layout/b" />
<include
layout="#layout/c" />
<include
layout="#layout/d" />
<ListView
android:id="#+id/listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
I've tried doing
sv.fullScroll(ScrollView.FOCUS_UP);
and all that stuff to my scrollview but it doesnt work
We should never put a ListView inside a ScrollView.
Work Around : When ScrollView moves up/down because of listview's notifyDataSetChanged(),
Then try,
scrollview.setEnabled(false);
listview.setFocusable(false);
adapter.notifyDataSetChanged();
scrollview.setEnabled(true);
Firstly, probably you've already heard about it, but just in case: You should never put a ListView inside a ScrollView, as ListView itself already has got a ScrollView and this design goes against the whole ListView idea. If you're convinced you have to use it, probably there's a better approach to use and you may need to simplify your code somehow.
Now, even if you still want to use something like that, you may use something like this:
package your.package.name;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;
public class ScrollingListView {
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null)
return;
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
}
You simply set your adapter via .setAdapter() and afterwards call ScrollingListView.setListViewHeightBasedOnChildren(your_listview). This should redimension your window accordingly to your ListView height.
---- EDIT ----
That will be probably the ugliest workaround, but try doing the following:
ScrollView sv = (ScrollView) findViewById(R.id.your_scrollview);
sv.setEnabled(false);
// Populate your ListView
sv.setEnabled(true);
Add all the stuff on top as header to the list view.
Now that I see the code.. you can only have one ViewGroup inside a scrollview. So you would warp the two layouts into another one, BUT a ListView automatically has a scroll view in it so that wont really work.
So what you have to do is use the addHeader view in your ListActivity (of fragment) and inflate LinearLayout1 in the activity from a different xml file.
add:
android:transcriptMode="disabled"
in the list you don't want to scroll
From Android Docs
It's not possible to make a scrollable view inside a scrollable view. But as a work around this, and only in case that this listviews doesn't take much memory if all views are loaded. you can use this
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
public class NonScrollableListView extends ListView {
public NonScrollableListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Do not use the highest two bits of Integer.MAX_VALUE because they are
// reserved for the MeasureSpec mode
int heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightSpec);
getLayoutParams().height = getMeasuredHeight();
}
}
Again, it's not good to use this workaround
Just Do one thing before add items in your list
listview.setFocusable(false);
after that you can again do that
listview.setFocusable(true);
if needed it will work for sure
I would wrap the list and the other layouts in a RelativeLayout instead of a LinearLayout
<ScrollView
android:id="#+id/tvscrollview"
android:layout_marginTop="8.0dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<RelativeLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<include
layout="#layout/a" />
<include
layout="#layout/b" />
<include
layout="#layout/c" />
<include
layout="#layout/d" />
</LinearLayout>
<ListView
android:id="#+id/listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/container" />
</RelativeLayout>
</ScrollView>
This way the top border of the ListView is boun to the bottom border of the LinearLayout and will always stay under everything else.
You cant put the includes directly in the RelativeLayout! See here for more details.
I have made 2 or 3 changes in your xml file
<ScrollView
android:id="#+id/tvscrollview"
android:layout_marginTop="8.0dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"> // This will let you see the scroll bar of list view
when you scroll your list view.
<include
layout="#layout/a" />
<include
layout="#layout/b" />
<include
layout="#layout/c" />
<include
layout="#layout/d" />
<ListView
android:id="#+id/listview"
android:layout_width="fill_parent"
android:layout_height="300dp" />// Instead of wraping up your list, if you wish
you can give certain height to your list view.
</LinearLayout>
</ScrollView>
Another thing you need is write the given code in your java file.
onCreate()
{
....
ScrollView sView=(ScrollView)findViewById(R.id.tvscrollview);
yourListView.setOnTouchListener(new OnTouchListener()
{
public boolean onTouch(View arg0, MotionEvent arg1)
{
if(arg1.getAction() == MotionEvent.ACTION_DOWN || arg1.getAction() == MotionEvent.ACTION_MOVE)
{
sView.requestDisallowInterceptTouchEvent(true);
}
return false;
}
});
I hope this helps you.
You may want to achieve this by using following:
<LinearLayout
......>
<ScrollView
android:id="#+id/tvscrollview"
android:layout_marginTop="8.0dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include
layout="#layout/a" />
<include
layout="#layout/b" />
<include
layout="#layout/c" />
<include
layout="#layout/d" />
</LinearLayout>
</ScrollView>
<ListView
android:id="#+id/listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Wrap your listview outside scrollview and else inside scrollview, because You should never use a ScrollView with a ListView, because ListView takes care of its own vertical scrolling. Most importantly, doing this defeats all of the important optimizations in ListView for dealing with large lists, since it effectively forces the ListView to display its entire list of items to fill up the infinite container supplied by ScrollView.
Source Android Docs
The only solution that worked for me was to add an EditText as the first child of the layout. Ugly, I know.
<EditText
android:layout_width="0dp"
android:layout_height="0dp" />
I had the same issue I found the solution by changing the visibility of the list view in XML after setting the adapter I change the visibility to visible
listView.setAdapter(adapter);
listView.setVisibility(View.VISIBLE);
Though its a very late answer to this question and this answer has already an accepted answer, I thought putting how I solved my problem here might help others to find everything related to this problem in a single SO thread.
So here's my situation: I had a ScrollView with a ListView at the end of the layout. I know its a very bad practice to do so. I could achieve the same behaviour I wanted by attaching a header to the ListView. But anyway, my ListView got the focus when it was populated with the data and the the page was scrolled automatically to the bottom where the ListView started.
I tried with the accepted answer here, but it didn't work for me. I tried using a dummy EditText at the top of the layout so that it could request the focus automatically, but it didn't work either. Because the ListView was getting the focus after the data is loaded from a REST Api call.
Then I found this answer and this really helped. So I thought putting it in here so that others might get help from a single thread having the same problem like me.
mainScrollView.fullScroll(ScrollView.FOCUS_UP); didn't work for me either as the list was populated after the other views were populated. So I had to scroll the ScrollView to the top after the ListView is populated. So here's how I solved my problem.
mScrollView.setEnabled(false);
mIntroducerListView.setFocusable(false);
mListAdapter.notifyDataSetChanged();
// Force scroll to the top of the scroll view.
// Because, when the list view gets loaded it focuses the list view
// automatically at the bottom of this page.
mScrollView.smoothScrollTo(0, 0);
I tried the above answers, but neither of them worked. Below is my final solution.
Just override the onFinishInflate method, then do a post to scrollTo(0, 0).
#Override
protected void onFinishInflate() {
super.onFinishInflate();
this.post(new Runnable() {
#Override
public void run() {
scrollTo(0, 0);
}
});
}