android Toast and View help - java

I am trying to create a Helper class to display Toasts in my android app, as follows.
public class ToastHelper{
final static Toast toastAlert(String msg) {
LayoutInflater inflater = LayoutInflater.from(Main.self.getApplicationContext());
View layout = inflater.inflate(R.layout.toast_layout, (ViewGroup) findViewById(R.id.toast_layout_root));
TextView tv = (TextView)layout.findViewById(R.id.toast_text);
tv.setText(msg);
Toast toast = new Toast(Main.self.getApplicationContext());
toast.setDuration(Toast.LENGTH_SHORT);
toast.setView(layout);
return toast;
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toast_layout_root"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip"
android:background="#FFF"
>
<TextView android:id="#+id/toast_text"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:textColor="#000"
/>
My code is based on the example at: http://developer.android.com/guide/topics/ui/notifiers/toasts.html
My problem is, when I try to inflate the view, I can't call findViewById without the View from the activity I am calling toastAlert in. Is there a way I can access that view?

My only thought would be to pass a View into the method. It wouldn't be so bad, the all would look like this:
class.toastAlert(this, "My Toast");

I use this to get the LayoutInflator
LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);
I don't know if that will help or not.

Related

Incorrect displaying FrameLayout item in listview

FrameLayout for some reason doesn't work perfectly in listview. I got this incorrect displaying in emulator. In Android Studio items looks nicely. Please help me :)
In Android Studio
In emulator
item.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="100dp"
android:padding="10dp">
<TextView
android:id="#+id/txtName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title"
android:layout_gravity="center"
android:textSize="27sp"
android:textStyle="bold"/>
<TextView
android:id="#+id/txtGenre"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Genre"
android:layout_gravity="bottom|right"
android:textSize="18sp"
android:textStyle="italic"/>
<TextView
android:id="#+id/txtId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ID"
android:textSize="18sp"
android:textStyle="italic"
android:layout_gravity="bottom|left"/>
</FrameLayout>
Adapter code
public class MyFilmListAdapter extends ArrayAdapter<Film> {
Context context;
ArrayList<Film> films;
public MyFilmListAdapter(#NonNull Context context, ArrayList<Film> films) {
super(context, R.layout.item_film, films);
this.context = context;
this.films = films;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
Film f = films.get(position);
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.item_film, null, false);
TextView name = v.findViewById(R.id.txtName);
TextView genre = v.findViewById(R.id.txtGenre);
TextView id = v.findViewById(R.id.txtId);
name.setText(f.getName() + "");
genre.setText(f.getGenre() + "");
id.setText(f.getId() + "");
return v;
}
}
I tried to use LinerLayout and it has correct displaying, however I need FrameLayout.
According to the official documentation
FrameLayout is designed to block out an area on the screen to display a single item. Generally, FrameLayout should be used to hold a single child view, because it can be difficult to organise child views in a way that's scalable to different screen sizes without the children overlapping each other.
You can, however, add multiple children to a FrameLayout and control their position within the FrameLayout by assigning gravity to each child, using the android:layout_gravity attribute.
So you can use LinearLayout inside it.
and nowadays better is you should use Recyclerview with ConstraintLayout

Can I convert a View to Layout?

In android, one can Inflate a Layout file and will get a View in return.
For Example:
LayoutInflater layoutInflater = LayoutInflater.from(context);
View myView = layoutInflater.inflate(R.layout.example_layout, null);
But I'm trying if I can get a Layout back from that inflated layout which is now a View?
Something by which I can retrieve back the original Layout from the Inflated View.
LayoutInflater layoutInflater = LayoutInflater.from(context);
LinearLayout myView = (LinearLayout)layoutInflater.inflate(R.layout.example_layout, null);
That's it!
Just be sure that the root view in your layout.example_layout is a LinearLayout or whatever layout you desire. Otherwise you'll have a ClassCastException
Every layout or ViewGroup extends View, that's why the inflate method returns a View, it's up to you then performing the right cast.
Consider the layout below. It has a text view only.
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="#dimen/mediumTextSize"
android:textColor="#color/black_text_color"
/>
After inflation you can directly get the textView as its the only view contain in layout.
LayoutInflater inflater=LayoutInflater.from(this);
TextView view=(TextView)inflater.inflate(R.layout.temp,null);
Now consider the layout below .
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/txtName"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textColor="#color/black_text_color"
android:textSize="#dimen/largeTExtSize" />
<TextView
android:id="#+id/csvName"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textColor="#color/black_text_color"
android:textSize="#dimen/largeTExtSize" />
</LinearLayout>
On inflation.
LayoutInflater inflater=LayoutInflater.from(this);
View view=inflater.inflate(R.layout.temp,null);
//Or you can do
// LinearLayout view=(LinearLayout)inflater.inflate(R.layout.temp,null);
TextView txt=view.findViewById(R.id.txtId);

setText in another layout

So I'm having a little bit of trouble trying to change the text of a TextView in another layout. My MainActivity.java sets the content view as activity_main.xml, which <include>s app_bar_main.xml, which <include>s content_main.xml, where my main app layout is displayed (it's a Navigation Drawer Activity in Android Studio).
Part of my code in MainActivity.java is shown below:
String user, organisation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Default code to include navigation drawer here
if (savedInstanceState == null) {
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
user = bundle.getString("user");
organisation = bundle.getString("organisation");
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View hamburgerMenu = inflater.inflate(R.layout.nav_header_main, null);
TextView navUsername = (TextView) hamburgerMenu.findViewById(R.id.nav_username),
navOrgGroup = (TextView) hamburgerMenu.findViewById(R.id.orgGroup);
navUsername.setText(user);
navOrgGroup.setText(organisation);
}
}
}
And my nav_header_main.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="#dimen/nav_header_height"
android:background="#drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:theme="#style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="#dimen/nav_header_vertical_spacing"
android:contentDescription="#string/user"
android:src="#android:drawable/sym_def_app_icon" />
<TextView
android:id="#+id/nav_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="#dimen/nav_header_vertical_spacing"
android:text="#string/user"
android:textAppearance="#style/TextAppearance.AppCompat.Body1" />
<TextView
android:id="#+id/orgGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/email" />
</LinearLayout>
But for some reason the TextViews in nav_header_main.xml never changes. It remains as the default values set in the XML file. Why is this so? Thanks in advance!
Since my comment helped solve:
In my code I'm using somewhat of a different strategy to change the TextView in the navigation drawer. View v = navigationView.getHeaderView(0); TextView emailTextView = (TextView) v.findViewById(R.id.emailTextView);
As for the explanation, you might take a look at this question. It'd be redundant that I copy the text here.
your hamburgerMenu has inflated but not add to any viewGroup to show it

On setAdapter it does not invoke getView method of Adapter

The problem is getView method does not get called even when I do setAdapter on listView. Please see may code below. I dont get any error message. It just does not display reviewer data. Would you please suggest what I am doing incorrect.
MovieReviewerFragmemt class I have below code:
#Override
protected void onPostExecute (ArrayList movieDetailsArray){
getMovieArrayList(movieDetailsArray);
ListView listView = (ListView) rootView.findViewById(R.id.movie_detail_reviewerlist);
MovieAddlDetail detail = (MovieAddlDetail) movieDetailsArray.get(0);
MovieReviewers[] list = detail.getReviewerArrayList();
Log.v(LOG_TAG, "MovieReviewerFragment - CustomReviewerAdapter - calling adapter");
movieDetailAdapter = new CustomReviewerAdapter(getActivity(), list);
movieDetailAdapter.notifyDataSetChanged();
listView.setAdapter(movieDetailAdapter);
}
CustomerReviewAdapter:
public class CustomReviewerAdapter extends ArrayAdapter {
private Context context;
private LayoutInflater inflater;
private final String LOG_TAG1 = CustomReviewerAdapter.class.getSimpleName();
private MovieReviewers[] reviewers;
public CustomReviewerAdapter(Context context, MovieReviewers[] reviewers) {
super(context, R.layout.fragment_detail, reviewers);
Log.v(LOG_TAG1, "CustomReviewerAdapter - constructor");
this.context = context;
this.reviewers = reviewers;
inflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.v(LOG_TAG1, "CustomReviewerAdapter - getView");
if (convertView == null) {
inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.fragment_detail_reviewer, parent, false);
Log.v(LOG_TAG1, "CustomReviewerAdapter - getView - convertview was null");
}
TextView textView1 = (TextView) convertView.findViewById(R.id.movie_detail_reviewerlist_author);
TextView textView2 = (TextView) convertView.findViewById(R.id.movie_detail_reviewerlist_content);
textView1.setText(reviewers[position].getAuthor());
textView2.setText(reviewers[position].getContent());
Log.v(LOG_TAG1, "CustomReviewerAdapter - getView - data set");
return convertView;
}
}
Fragment Detail Reviewer:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id ="#+id/imageView_layout"
android:orientation = "vertical">
<TextView
android:layout_width="match_parent" android:layout_height="wrap_content"
android:id="#+id/movie_detail_reviewerlist_author"
android:textAlignment="center"
android:textStyle="bold"
android:gravity="center_vertical"
android:focusable="false"
android:focusableInTouchMode="false"
android:textAppearance="?android:attr/textAppearanceLarge"
android:descendantFocusability="blocksDescendants"/>
<TextView
android:layout_width="match_parent" android:layout_height="wrap_content"
android:id="#+id/movie_detail_reviewerlist_content"
android:textAlignment="center"
android:textStyle="bold"
android:gravity="center_vertical"
android:focusable="false"
android:focusableInTouchMode="false"
android:textAppearance="?android:attr/textAppearanceLarge"
android:descendantFocusability="blocksDescendants"/>
Fragment Detail:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/movie_detail_list"
android:editable="false" />
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/movie_detail_reviewerlist"
android:editable="false" />
Below is activity from which fragment is being initiated. The first fragment is working fine and is being displayed. However the second fragment is where I dont get anything displayed. Is below correct way to initiate two fragments?
Detail Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
Bundle extras = getIntent().getExtras();
intentData = extras.getStringArray("moviedetails");
MovieDetailFragment movieDetailFragment = new MovieDetailFragment();
movieDetailFragment.setMovieDetails(intentData);
MovieReviewerFragment movieReviewerFragment = new MovieReviewerFragment();
movieReviewerFragment.setMovieDetails(intentData);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container_1, movieDetailFragment)
.add(R.id.container_2, movieReviewerFragment)
.commit();
}
}
You must call the LayoutInflater like this:
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
You have to switch the lines
movieDetailAdapter.notifyDataSetChanged();
listView.setAdapter(movieDetailAdapter);
To
listView.setAdapter(movieDetailAdapter);
movieDetailAdapter.notifyDataSetChanged();
First you set the adapter, then you send the notification. If you do this the reverse way, there is no ListView which may display the updated data.
You can automate these notifications with
movieDetailAdapter.setNotifyOnChange(true)

Android - Multiple textviews in Listview

I am populating a Listview (list.xml) with a textview (list_row.xml).
I need to add an additional textview to list_row.xml, which means I need to wrap them in a layout. However, I get a Textview ID error when I do this.
list_row.xml I need:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/nameTV"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="#FFFF00"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Main.xml
public View GetView(int inPosition, View inConvertView, ViewGroup inParent)
{
View _row = inConvertView;
if (_row == null)
{
// Inflate Row
Log.d(TAG, "Starting XML Row Inflation ... ");
LayoutInflater inflater = (LayoutInflater)
cContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
_row = inflater.inflate(R.layout.list_row, inParent, false);
Log.d(TAG, "Successfully completed XML Row Inflation!");
}
// Get item
PropertiesAd _adProperty = GetItem(inPosition);
// Get reference to TextView - country_name
cAdName = (TextView) _row.findViewById(R.id.nameTV);
//Set name
cAdName.setText(_adProperty.toString());
return _row;
}
For the sake of testing, I haven't added the second textview yet. I'm just trying to get this to work with the layout wrapper.
Everything works fine without the LinearLayout. But again, I will need it to add a second textview. Suggestions?
Thanks
ArrayAdapter:
public class ArrayAdapterAd extends ArrayAdapter<PropertiesAd>
{
private static final String TAG = "AdArrayAdapter";
private Context cContext;
private TextView cAdName;
private List<PropertiesAd> cAdList = new ArrayList<PropertiesAd>();
public ArrayAdapterAd(Context inContext, int inTextViewResourceId, List<PropertiesAd> inObjects)
{
super(inContext, inTextViewResourceId, inObjects);
this.cContext = inContext;
this.cAdList = inObjects;
}
public int GetCount()
{
return this.cAdList.size();
}
public PropertiesAd GetItem(int inIndex)
{
return this.cAdList.get(inIndex);
}
public View GetView(int inPosition, View inConvertView, ViewGroup inParent)
{
View _row = inConvertView;
if (_row == null)
{
// Inflate Row
Log.d(TAG, "Starting XML Row Inflation ... ");
LayoutInflater inflater = (LayoutInflater)
cContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
_row = inflater.inflate(R.layout.ad_list, inParent, false);
Log.d(TAG, "Successfully completed XML Row Inflation!");
}
// Get item
PropertiesAd _adProperty = GetItem(inPosition);
// Get reference to TextView - country_name
cAdName = (TextView) _row.findViewById(R.id.ad_listTextView);
//Set country name
cAdName.setText(_adProperty.toString());
return _row;
}
}
Now I see your problem... you cannot do that extending the ArrayAdapter class. Instead, extend BaseAdapter.
Here is xml for a listview "list_row" with 2 textviews
<?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="horizontal">
<TextView android:id="#+id/text1" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView android:id="#+id/text2" android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
I'm assuming the getView() is from an ArrayAdapter subclass? If so, what does your constructor look like? Perhaps you're passing in an id reference in stead of a layout reference? This will probably resolve fine if you're whole layout is nothing more than a single TextView, but could explain why an error occurs when wrapping it in a layout.
Also, don't forget to implement the rowwrapper/viewholder pattern to improve performance and recycle views. For an example, have a look here.
By the way, you may even suffice with one of the Android built-in layouts. There a two line list item layout defined in android.R.layout.simple_list_item_2. It may not suit your needs though, as the styling on the two elements is different. A custom layout is always the most flexible in the end. :)

Categories