Is it possible to change the location of the button on the dialog to the outside of the dialog itself? something like this (the red squares are buttons):
I know I can get the button with :
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
but I couldn't find on the manual the way to change it's location.
<?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"
android:gravity="center"
android:padding="20dp"
android:background="#00000000">
<LinearLayout
android:background="#drawable/border_background"
android:layout_gravity="center"
android:gravity="center"
android:padding="20dp"
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="vertical">
<TextView
android:layout_width="250dp"
android:layout_height="wrap_content"
android:text="#string/update_app"
android:textSize="18sp"
android:textColor="#color/white"
android:layout_gravity="center_horizontal"
android:gravity="center" />
</LinearLayout>
<Button
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_marginTop="20dp"
android:background="#123456"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="14sp"
android:onClick="onUpdateClicked"
android:text="Button" />
Instead of using default alert dialog, make a custom layout something like my layout here. And perform desired action on button.
You can call n show this layout without inflating like this.
EDIT:1
public void showUpdateLayout() {
mParentView = (ViewGroup) findViewById(android.R.id.content);
if (mParentView != null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);
mUpdateLayout = inflater.inflate(R.layout.upadte_layout, mParentView, false);
mParentView.addView(mUpdateLayout);
if (mUpdateLayout != null) {
mUpdateLayout.setVisibility(View.VISIBLE);
}
}
Write this method in ur public Class (or Custom Aprent Activity). and call this method when u need to alert.
you should make custom dialog and set it's root view background color to be transparent: android:background="#android:color/transparent"
You will need to create a custom DialogFragment. Below I will give an analytical example of how to implement one and call it with several parameters each time, so you won't need to repeat code each time you want an Dialog with different message.
CustomAlertDialog.java
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
/**
* Custom DialogFragment class
*/
public class CustomAlertDialog extends DialogFragment implements
View.OnClickListener {
/**
* Interface for receiving the wanted callbacks
* */
public interface CallbacksListener
{
public void onPositiveButtonClicked();
public void onNegativeButtonClicked();
}
private CallbacksListener callbacksListener;
public void setCallbacksListener(CallbacksListener callbacksListener)
{
this.callbacksListener = callbacksListener;
}
public CustomAlertDialog()
{
//empty constructor
}
private String titleString;
private String messageString;
private String positiveString;
private String negativeString;
#Override
public void setArguments(Bundle bundle)
{
titleString = bundle.getString("titleString");
messageString = bundle.getString("messageString");
positiveString = bundle.getString("positiveString");
negativeString = bundle.getString("negativeString");
}
public static CustomAlertDialog newInstance(AlertDialogStrings alertDialogStrings)
{
CustomAlertDialog customAlertDialog = new CustomAlertDialog();
Bundle b = new Bundle();
b.putString("titleString", alertDialogStrings.titleString);
b.putString("messageString", alertDialogStrings.messageString);
b.putString("negativeString", alertDialogStrings.negativeString);
b.putString("positiveString", alertDialogStrings.positiveString);
customAlertDialog.setArguments(b);
return customAlertDialog;
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
View v = getActivity().getLayoutInflater().inflate(R.layout.custom_alert_dialog, null);
TextView titleTV = (TextView) v.findViewById(R.id.title_customAlertDialog);
TextView messageTV = (TextView) v.findViewById(R.id.message_customAlertDialog);
Button positiveButton = (Button) v.findViewById(R.id.okBtn_customAlertDialog);
Button negativeButton = (Button) v.findViewById(R.id.cancelBtn_customAlertDialog);
titleTV.setText(titleString);
messageTV.setText(messageString);
positiveButton.setText(positiveString);
negativeButton.setText(negativeString);
positiveButton.setOnClickListener(this);
negativeButton.setOnClickListener(this);
builder.setView(v);
return builder.create();
}
#Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.okBtn_customAlertDialog:
callbacksListener.onPositiveButtonClicked();
dismiss();
break;
case R.id.cancelBtn_customAlertDialog:
callbacksListener.onNegativeButtonClicked();
dismiss();
break;
default:
break;
}
}
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
try
{
callbacksListener = (CallbacksListener) activity;
}
catch (ClassCastException e)
{
throw new ClassCastException(activity.toString()
+ " must implement CallbacksListener");
}
}
#Override
public void onDetach()
{
super.onDetach();
callbacksListener = null;
}
/**
* Class for saving the wanted Strings we want to have on our CustomDialog implementation
* */
public static class AlertDialogStrings
{
public String titleString;
public String messageString;
public String positiveString;
public String negativeString;
public AlertDialogStrings(String title, String message, String positiveString, String negativeString)
{
this.messageString = message;
this.titleString = title;
this.positiveString = positiveString;
this.negativeString = negativeString;
}
}
}
custom_alert_dialog.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/black"
android:textSize="22sp"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:text="My Title Here"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:id="#+id/title_customAlertDialog"/>
<TextView
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="7dp"
android:id="#+id/message_customAlertDialog"
android:layout_below="#id/title_customAlertDialog"
android:textColor="#color/darkGray"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_marginTop="7dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:measureWithLargestChild="true"
android:layout_below="#+id/message_customAlertDialog"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true">
<Button
android:layout_height="wrap_content"
style="?android:attr/buttonBarButtonStyle"
android:textSize="13sp"
android:textColor="#color/primaryColorDark"
android:layout_width="wrap_content"
android:layout_weight="1.0"
android:text="#string/cancel"
android:id="#+id/cancelBtn_customAlertDialog"/>
<Button
android:layout_width="wrap_content"
android:layout_weight="1.0"
android:layout_marginRight="10dp"
android:textSize="13sp"
android:textColor="#color/primaryColorDark"
android:layout_height="wrap_content"
style="?android:attr/buttonBarButtonStyle"
android:text="#string/ok"
android:id="#+id/okBtn_customAlertDialog"/>
</LinearLayout>
To show your customAlertDialog:
private void popUpAlertDialog()
{
String title = "My title here?";
String message = "My Message here";
String positiveString = "OK";
String negativeString = "Cancel";
CustomAlertDialog.AlertDialogStrings customDialogStrings =
new CustomAlertDialog.AlertDialogStrings
(title, message, positiveString, negativeString);
CustomAlertDialog customAlertDialog =
CustomAlertDialog.newInstance(alertDialogStrings);
customAlertDialog.show(getSupportFragmentManager(), "customAlertDialog");
customAlertDialog.setCallbacksListener(new CustomAlertDialog.CallbacksListener()
{
#Override
public void onPositiveButtonClicked()
{
//do something
}
#Override
public void onNegativeButtonClicked()
{
//do something
}
});
}
The AlertDialogStrings class helps us maintain our wanted strings in a way that we can re-use our class with different strings each time and the CallbacksListener helps as settle the way of the OnClick responds each time. Note that this design follows the Material Design Dialog style principles.
Yes.
All you have to do is create a custom dialog layout.
In order to achieve that you would create a LinearLayout with Transparent BG color and inside it you can do whatever is it that you want.
A quick example:
<LinearLayout android:orientation="vertical"
android:layout_width="300"
android:layout_height="500"
android:background="#android:color/transparent">
<LinearLayout android:orientation="vertical"
android:layout_width="270"
android:layout_height="200">
... your content here
</LinearLayout>
<Button android:layout_width="270"
android:layout_height="200"
android:margin_top="10"/>
</LinearLayout>
If you are using a builder to create your Dialog , you would go for this:
LayoutInflater inflater = getActivity().getLayoutInflater();
builder.setView(inflater.inflate(R.layout.your_dialog_layout, null))
...otherwise
Dialog newDialog = new Dialog();
newDialog.setContentView(R.layout.your_dialog_layout);
Related
I want to get familiar with Android and started taking some Udacity courses. Currently, we have to make an ImageButton play some audio on click for language-learning purposes.
I thought it would be nice if the button toggled as well, for example, in a paused state, it should display a "play" icon and in a playing state, a "pause" icon. This is very simple to achieve using an OnClickListener and it also works properly, up to 1 small detail: the user has to click the button twice.
After some searching, I found out that the first click is used to focus the view in that position and the second view is when the fired OnClickEvent is actually handled. I tried to change the focusable and focusableInTouchModeattributes to all possible combinations in all possible places, but it didn't work.
Here is my main Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView numbersView = findViewById(R.id.numbers);
numbersView.setOnClickListener(v -> {
Intent numbersIntent = new Intent(MainActivity.this, NumbersActivity.class);
startActivity(numbersIntent);
});
TextView familyView = findViewById(R.id.family);
familyView.setOnClickListener(v -> {
Intent familyIntent = new Intent(MainActivity.this, FamilyActivity.class);
startActivity(familyIntent);
});
TextView colorView = findViewById(R.id.colors);
colorView.setOnClickListener(v -> {
Intent colorsIntent = new Intent(MainActivity.this, ColorActivity.class);
startActivity(colorsIntent);
});
TextView phrasesView = findViewById(R.id.phrases);
phrasesView.setOnClickListener(v -> {
Intent phrasesIntent = new Intent(MainActivity.this, PhrasesActivity.class);
startActivity(phrasesIntent);
});
}
}
Here is the corresponding xml:
<?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=".MainActivity"
android:orientation="vertical"
android:divider="?android:dividerHorizontal"
android:showDividers="middle"
android:background="#212121">
<TextView
android:id="#+id/numbers"
style="#style/CategoryStyle"
android:layout_height="wrap_content"
android:text="#string/numbers"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="#b794f6"/>
<TextView
android:id="#+id/family"
style="#style/CategoryStyle"
android:layout_height="wrap_content"
android:text="#string/family"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="#90CAF9"/>
<TextView
android:id="#+id/colors"
style="#style/CategoryStyle"
android:layout_height="wrap_content"
android:text="#string/colors"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="#EEEEEE"/>
<TextView
android:id="#+id/phrases"
style="#style/CategoryStyle"
android:layout_height="wrap_content"
android:text="#string/phrases"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:textColor="#FFE082"/>
Here is my NumbersActivity (the other activities are very much alike):
public class NumbersActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.word_list);
ListView view = findViewById(R.id.coolList);
List<Word> words = new ArrayList<>(Arrays.asList(
new Word("lutti", "one", R.drawable.number_one, R.raw.test_audio),
new Word("otiiko", "two", R.drawable.number_two, R.raw.test_audio),
new Word("tolookosu", "three", R.drawable.number_three, R.raw.test_audio),
new Word("oyyisa", "four", R.drawable.number_four, R.raw.test_audio),
new Word("massokka", "five", R.drawable.number_five, R.raw.test_audio),
new Word("temmokka", "six", R.drawable.number_six, R.raw.test_audio),
new Word("kenekaku", "seven", R.drawable.number_seven, R.raw.test_audio),
new Word("kawinta", "eight", R.drawable.number_eight, R.raw.test_audio),
new Word("wo'e", "nine", R.drawable.number_nine, R.raw.test_audio),
new Word("na'aacha", "ten", R.drawable.number_ten, R.raw.test_audio)));
WordAdapter itemsAdapter = new WordAdapter(this, words, getColor(R.color.numbers_category));
view.setAdapter(itemsAdapter);
}
}
//I know that doing it like this isn't that great, I just needed to get something up and running and worry about these changes later.
Here is the xml to that:
<?xml version="1.0" encoding="utf-8"?>
<ListView 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/coolList"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:divider="#B0BEC5"
android:dividerHeight="2dp"
android:background="#212121"
android:focusable="false"
android:focusableInTouchMode="false"></ListView>
Here is the Word Class:
public class Word {
private String miwokTranslation;
private String defaultTranslation;
private int ressourceID = -1; //just init, in order to check for it later
private int audioID;
public Word(String miwokTranslation, String defaultTranslation, int ressourceID, int audioID) {
this.miwokTranslation = miwokTranslation;
this.defaultTranslation = defaultTranslation;
this.ressourceID = ressourceID;
this.audioID = audioID;
}
public Word(String miwokTranslation, String defaultTranslation, int audioID) {
this.miwokTranslation = miwokTranslation;
this.defaultTranslation = defaultTranslation;
this.audioID = audioID;
}
public String getMiwokTranslation() {
return miwokTranslation;
}
public String getDefaultTranslation() {
return defaultTranslation;
}
public int getResourceID() {
return ressourceID;
}
public int getAudioID() {
return audioID;
}
#Override
public String toString() {
return miwokTranslation + "\n" + defaultTranslation;
}
}
Here is the corresponding Adapter:
public class WordAdapter extends ArrayAdapter<Word> {
private final int color;
Context context;
public WordAdapter(#NonNull Context context, #NonNull List<Word> objects, int color) {
super(context, 0, objects);
this.color = color;
this.context = context;
}
#RequiresApi(api = Build.VERSION_CODES.O)
#SuppressLint("ClickableViewAccessibility")
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
}
Word item = getItem(position);
ImageView image = convertView.findViewById(R.id.list_item_icon);
if(item.getResourceID() == -1) {
image.setVisibility(View.GONE);
} else {
image.setImageResource(item.getResourceID());
}
TextView miwokWord = convertView.findViewById(R.id.miwok_word);
miwokWord.setText(item.getMiwokTranslation());
miwokWord.setTextColor(color);
TextView defaultWord = convertView.findViewById(R.id.default_word);
defaultWord.setText(item.getDefaultTranslation());
defaultWord.setTextColor(color);
ImageButton button = convertView.findViewById(R.id.imageButton);
MediaPlayer mediaPlayer = MediaPlayer.create(context, item.getAudioID());
button.setOnClickListener(v -> {
if (!mediaPlayer.isPlaying()) {
button.setImageResource(R.drawable.play_icon);
mediaPlayer.start();
} else {
button.setImageResource(R.drawable.pause_icon);
mediaPlayer.pause();
}
});
return convertView;
}
}
The Annotations are these due to previous efforts and I didn't remove them, in case i'd need them again.
Last but not least, here is the xml of the adapter:
<?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="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:minHeight="?android:attr/listPreferredItemHeight"
android:padding="16dp"
android:focusable="true"
android:focusableInTouchMode="false">
<ImageView
android:id="#+id/list_item_icon"
android:layout_width="88dp"
android:layout_height="88dp"
android:contentDescription="#string/magic"
android:background="#424242"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingStart="16dp"
tools:ignore="RtlSymmetry">
<TextView
android:id="#+id/miwok_word"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:textStyle="bold"/>
<TextView
android:id="#+id/default_word"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
<ImageButton
android:id="#+id/imageButton"
android:layout_width="73dp"
android:layout_height="match_parent"
android:contentDescription="#string/playsound"
android:src="#drawable/play_icon"/></LinearLayout>
I have been sitting on this for some good couple of hours by now without any significant progress and at this Point i don't have any clues about what to do next.
Any Help would be appreciated.
Thanks in Advance
Not sure why you concluded that focus has anything to do with your problem.
If the default beginning state of the icon is android:src="#drawable/play_icon" and the default beginning state of the mediaPlayer is "not playing", wouldn't the first click result in button.setImageResource(R.drawable.play_icon); which just...sets the play icon again? So the first click changes the icon from play to play, and the second sets it from play to pause.
Have you tried debugging your code with a breakpoint? Set one in your click listener and see what happens.
I create a class for custom dialog and I used PrettyDialog. I want an edittext on dialog. I use Inflater but Error: getActivity -> mHost:null. I tried create getTextDialogFragment() method, then getLayoutInflater error mHost null. What can I do fix that?
TextDialogFragment:
public class TextDialogFragment extends DialogFragment {
private EditText edtDialog;
public interface SingleChoiceListener{
void onPositiveButtonClicked();
void onNegativeButtonClicked();
}
TextDialogFragment.SingleChoiceListener mListener;
#NonNull
public PrettyDialog onCreateTextDialog(Context context) {
PrettyDialog prettyDialog = new PrettyDialog(context);
LayoutInflater inflater=getActivity().getLayoutInflater();
View view=inflater.inflate(R.layout.dialog_text,null);
prettyDialog.setContentView(view);
prettyDialog.setMessage("sdf");
prettyDialog.setIcon(R.drawable.question_icon);
prettyDialog.setCanceledOnTouchOutside(false);
prettyDialog.addButton("EVET", R.color.pdlg_color_white, R.color.pdlg_color_green, new PrettyDialogCallback() {
#Override
public void onClick() {
mListener.onPositiveButtonClicked();
prettyDialog.dismiss();
}
});
prettyDialog.addButton("HAYIR", R.color.pdlg_color_white, R.color.pdlg_color_red, new PrettyDialogCallback() {
#Override
public void onClick() {
mListener.onNegativeButtonClicked();
prettyDialog.dismiss();
}
});
edtDialog=view.findViewById(R.id.edtDialog);
prettyDialog.show();
return prettyDialog;
}
public void setListener(TextDialogFragment.SingleChoiceListener singleChoiceListener){
mListener=singleChoiceListener;
}
}
this layout that I want add to dialog. Dialog has to work edittext+prettydialog:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:layout_margin="8dp">
<EditText
android:id="#+id/edtDialog"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#null"
android:focusable="true"
android:hint="Giriş yapınız"
android:gravity="center"
android:imeOptions="actionDone"
android:inputType="text"
android:textColor="#android:color/black"
android:textColorHint="#android:color/darker_gray"
android:textSize="40sp">
</EditText>
</RelativeLayout>
Try below code
View view=LayoutInflater.from(context).inflate(R.layout.dialog_text,null);
Instead of
LayoutInflater inflater=getActivity().getLayoutInflater();
View view=inflater.inflate(R.layout.dialog_text,null);
I hope this can help you!
Thank You.
I am creating an android application in which i want to use Snack Bar,
In a that snack bar i want 2 different words on which we have to perform 2 different actions.
From the Google design specifications:
Each snackbar may contain a single action, neither of which may be “Dismiss” or “Cancel.”
For multiple actions, use a dialog.
Thanks Shailesh, I had to modify the code in order to make it work for me.
my_snackbar.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:id="#+id/my_snackbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/dark_grey"
android:padding="15dp">
<TextView
android:id="#+id/message_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".6"
android:gravity="center_vertical"
android:text="Two button snackbar"
android:textColor="#color/white"/>
<TextView
android:id="#+id/first_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".2"
android:gravity="center"
android:text="ONE"
android:textColor="#FFDEAD"/>
<TextView
android:id="#+id/second_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".2"
android:gravity="center"
android:text="TWO"
android:textColor="#FFDEAD"/>
</LinearLayout>
In your activity call this method whenever you want to show the snackbar:
private void showTwoButtonSnackbar() {
// Create the Snackbar
LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
snackbar = Snackbar.make(this.findViewById(android.R.id.content), message, Snackbar.LENGTH_INDEFINITE);
// Get the Snackbar layout view
Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
// Set snackbar layout params
int navbarHeight = getNavBarHeight(this);
FrameLayout.LayoutParams parentParams = (FrameLayout.LayoutParams) layout.getLayoutParams();
parentParams.setMargins(0, 0, 0, 0 - navbarHeight + 50);
layout.setLayoutParams(parentParams);
layout.setPadding(0, 0, 0, 0);
layout.setLayoutParams(parentParams);
// Inflate our custom view
View snackView = getLayoutInflater().inflate(R.layout.my_snackbar, null);
// Configure our custom view
TextView messageTextView = (TextView) snackView.findViewById(R.id.message_text_view);
messageTextView.setText(message);
TextView textViewOne = (TextView) snackView.findViewById(R.id.first_text_view);
textViewOne.setText("ALLOW");
textViewOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Allow", "showTwoButtonSnackbar() : allow clicked");
snackbar.dismiss();
}
});
TextView textViewTwo = (TextView) snackView.findViewById(R.id.second_text_view);
textViewTwo.setText("DENY");
textViewTwo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("Deny", "showTwoButtonSnackbar() : deny clicked");
snackbar.dismiss();
}
});
// Add our custom view to the Snackbar's layout
layout.addView(snackView, objLayoutParams);
// Show the Snackbar
snackbar.show();
}
To get nav bar height:
public static int getNavBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
As #Elias N answer's each Snackbar may contain a single action. If you want to set more then action in Snackbar then you need to create your own layout. Please try this i hope this will help you.
Create one xml file my_snackbar.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="50dp"
android:background="#000000">
<TextView
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight=".7"
android:gravity="center_vertical"
android:text="Please select any one"
android:textColor="#color/white"/>
<TextView
android:id="#+id/txtOne"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight=".1"
android:gravity="center"
android:text="ONE"
android:textColor="#color/red"/>
<TextView
android:id="#+id/txtTwo"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight=".1"
android:gravity="center"
android:text="TWO"
android:textColor="#color/red"/>
</LinearLayout>
Now in your activity file do the following code.
public void myCustomSnackbar()
{
// Create the Snackbar
LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Snackbar snackbar = Snackbar.make(llShow, "", Snackbar.LENGTH_LONG);
// Get the Snackbar's layout view
Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
layout.setPadding(0,0,0,0);
// Hide the text
TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
textView.setVisibility(View.INVISIBLE);
LayoutInflater mInflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
// Inflate our custom view
View snackView = getLayoutInflater().inflate(R.layout.my_snackbar, null);
// Configure the view
TextView textViewOne = (TextView) snackView.findViewById(R.id.txtOne);
textViewOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("One", "First one is clicked");
}
});
TextView textViewTwo = (TextView) snackView.findViewById(R.id.txtTwo);
textViewTwo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Two", "Second one is clicked");
}
});
// Add the view to the Snackbar's layout
layout.addView(snackView, objLayoutParams);
// Show the Snackbar
snackbar.show();
}
For more detail please read this documentation and here.
You can use BottomSheetDialog and disguise it as a SnackBar. Only difference would be that it will be dismissed by swiping down instead of right and it can stay there until user dismissed it while SnackBar eventually fades away.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="#+id/fragment_history_menu_bottom"
style="#style/Widget.Design.BottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
android:background="#color/cardview_dark_background"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<android.support.v7.widget.AppCompatTextView
android:id="#+id/appCompatTextView"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_weight="0.6"
android:text="Load More ?"
android:textAppearance="#style/TextAppearance.Design.Snackbar.Message"
android:textColor="#color/cardview_light_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="#+id/fragment_history_bottom_sheet_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|end"
android:layout_weight="0.4"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<android.support.v7.widget.AppCompatButton
style="#style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Yes" />
<android.support.v7.widget.AppCompatButton
style="#style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No"
android:textColor="#color/cardview_light_background" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
and use it as following (Kotlin)
val dialog = BottomSheetDialog(this)
dialog.setContentView(this.layoutInflater.inflate(R.layout.bottom_sheet_load_prompt,null))
dialog.show()
result will be similar to SnackBar
Here is a proper solution with Kotlin I first deployed it when working on Fulguris.
Using Kotlin extension we expand our Snackbar class as follows:
/**
* Adds an extra action button to this snackbar.
* [aLayoutId] must be a layout with a Button as root element.
* [aLabel] defines new button label string.
* [aListener] handles our new button click event.
*/
fun Snackbar.addAction(#LayoutRes aLayoutId: Int, #StringRes aLabel: Int, aListener: View.OnClickListener?) : Snackbar {
addAction(aLayoutId,context.getString(aLabel),aListener)
return this;
}
/**
* Adds an extra action button to this snackbar.
* [aLayoutId] must be a layout with a Button as root element.
* [aLabel] defines new button label string.
* [aListener] handles our new button click event.
*/
fun Snackbar.addAction(#LayoutRes aLayoutId: Int, aLabel: String, aListener: View.OnClickListener?) : Snackbar {
// Add our button
val button = LayoutInflater.from(view.context).inflate(aLayoutId, null) as Button
// Using our special knowledge of the snackbar action button id we can hook our extra button next to it
view.findViewById<Button>(R.id.snackbar_action).let {
// Copy layout
button.layoutParams = it.layoutParams
// Copy colors
(button as? Button)?.setTextColor(it.textColors)
(it.parent as? ViewGroup)?.addView(button)
}
button.text = aLabel
/** Ideally we should use [Snackbar.dispatchDismiss] instead of [Snackbar.dismiss] though that should do for now */
//extraView.setOnClickListener {this.dispatchDismiss(BaseCallback.DISMISS_EVENT_ACTION); aListener?.onClick(it)}
button.setOnClickListener {this.dismiss(); aListener?.onClick(it)}
return this;
}
We then need to define our button resource:
<?xml version="1.0" encoding="utf-8"?>
<!--
Used to create and extra button in our snackbar popup messages.
Though most properties including layout params and colors are overridden at runtime.
They are just copied from the standard snackbar action button to make sure they both lookalike.
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/snackbar_extra_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginStart="0dp"
android:layout_gravity="center_vertical|right|end"
android:paddingTop="14dp"
android:paddingBottom="14dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:textColor="?attr/colorAccent"
style="?attr/borderlessButtonStyle"/>
Here is how you use it:
Snackbar.make(aView, aMessage, aDuration).setAction(R.string.button_one) {
// Do your thing after regular button press
}.addAction(R.layout.snackbar_extra_button, R.string.button_two){
//Do your thing after extra button push
}.show()
Another hacky workaround you could try (works in my case).
final Snackbar snackbar = Snackbar.make(view, "UNDO MARKED AS READ", Snackbar.LENGTH_LONG);
snackbar.setAction("DISMISS", new View.OnClickListener() {
#Override
public void onClick(View v) {
if (snackbar != null)
snackbar.dismiss();
}
});
View snackbarView = snackbar.getView();
int snackbarTextId = android.support.design.R.id.snackbar_text;
TextView textView = (TextView) snackbarView.findViewById(snackbarTextId);
textView.setTextColor(Color.WHITE);
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (snackbar != null)
snackbar.dismiss();
// undo mark as unread code
}
});
snackbar.show();
Following Shaileshs solution:
snackbar class
public class SnackbarOfflineErrorNotification {
/**
* A view from the content layout.
*/
#NonNull
private final View view;
#NonNull
private Context context;
/**
* The snack bar being shown.
*/
#Nullable
private Snackbar snackbar = null;
/**
* Construct a new instance of the notification.
*
* #param view A view from the content layout, used to seek an appropriate anchor for the
* Snackbar.
*/
public SnackbarOfflineErrorNotification(#NonNull final View view, #NonNull Context context) {
this.view = view;
this.context = context;
}
public void showOfflineError (){
if (snackbar == null){
//create snackbar
snackbar = Snackbar.make(this.view, R.string.offline_text, LENGTH_INDEFINITE);
// Create the Snackbar
LinearLayout.LayoutParams objLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// Get the Snackbar's layout view
Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
layout.setPadding(0,0,0,0);
// Hide the text
TextView textView = (TextView) layout.findViewById(android.support.design.R.id.snackbar_text);
textView.setVisibility(View.INVISIBLE);
// Inflate our custom view
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View snackView = inflater.inflate(R.layout.snackbar_offline, null);
// Configure the view
Button btnOne = (Button) snackView.findViewById(R.id.btnOne);
btnOne.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// action 1
}
});
Button btnTwo = (Button) snackView.findViewById(R.id.btnTwo);
btnTwo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// action 2
}
});
// Add the view to the Snackbar's layout
layout.addView(snackView, objLayoutParams);
// Show the Snackbar
snackbar.show();
}
}
/**
* Hides the currently displayed error.
*/
public void hideError() {
if (snackbar != null) {
snackbar.dismiss();
snackbar = null;
}
}
}
snackbar 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="50dp"
android:background="#000000">
<TextView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight=".7"
android:gravity="center_vertical"
android:text="offline"
android:textColor="#color/white"
android:paddingLeft="16dp"/>
<Button
android:id="#+id/btnOne"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight=".1"
android:gravity="center"
android:text="one" />
<Button
android:id="#+id/btnTwo"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_weight=".1"
android:gravity="center"
android:text="two"/>
</LinearLayout>
target activity
constructor(){
snackbarOfflineErrorNotification = new SnackbarOfflineErrorNotification(findViewById(R.id.coordinator_layout), getApplicationContext());
}
public void hideSnackbar(){
snackbarOfflineErrorNotification.hideError();
}
public showSnackbar(){
snackbarOfflineErrorNotification.showOfflineError();
}
You can use "dismiss" as another actions
Snackbar snackbar = Snackbar.make(requireView(), "Marked as read", BaseTransientBottomBar.LENGTH_SHORT);
snackbar.setAction("undo", view -> {
//undo action
});
snackbar.addCallback(new Snackbar.Callback() {
#Override
public void onDismissed(Snackbar transientBottomBar, int event) {
//dismiss action
}
});
snackbar.show();
UPDATE WITH CODE (Sorry for crappy formatting of my code, some reason it had problems allowing me to post it so I had to mess with the lines for a whole to get it to allow me to save thisedit)
Here is the idea. I have an app that works with Clarifia's image recognition. I generated the app using Google's pre built navegation bar, so there is extra xml files and code for that, but it can be ignored the two needed for this is activity_main.xml and content_main.xml. anyways in content_main.xml it is a linear layout that has an imageview and a listview. My goal is to dynamically generate the listview with a list of BUTTONS. each button will have setText() done to it to give it a tag, so for example if a image selected is a dog, and the tags are dog, animal, etc, then that many buttons will be generated, with a setText() of one button being dog, the other button being animal, etc . now Since I have to do a network call, the network call is done in asynctask. After it is done, the method onPostExecute() is called and from there I get the tags. NOW since i got the tags, I want to call set an adapter that will hold an array of buttons, and loop geting the ID for each button and doing settext() on each button with the tags. from there i want to set the adapter to the list view..
Problems:
way to many to count, but I THINK i narrowed it down to me not knowing how to get the "views" from the second xml file to have the elements be used on the first xml file, because everything comes out NULL. I tried googling it but i just keep running into road blocks. I just want to name each button with a tag and put them into listview, but like i said, since these elements are in a different xml file than main_activity, I think this is the problem. so here is the code per request.
MainActivity.java
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener
{
private static final String CLASS = MainActivity.class.getSimpleName();
private Button selectButton;
private Toolbar toolbar;
private NavigationView navigationView;
private Clari
faiData cdata = null;
private ImageView imageview;
private ListView listview;
private TagAdapter adapter;
private List<Button> data;
protected Context context;
private GoogleApiClient client;
protected LinearLayout main;
#Override
protected void onCreate(Bundle savedInstanceState)
{
// THIS IS MY ATTEMPT TO DO THIS
// http://www.java2s.com/Code/Android/UI/UsingtwolayoutxmlfileforoneActivity.htm
super.onCreate(savedInstanceState);
context = MainActivity.this;
main = new LinearLayout (this);
setContentView(R.layout.activity_main);
// AUTO GENERATED stuff left out for nav bar, just showing this line*********
selectButton = (Button) findViewById(R.id.select_button);
selectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Intent media_intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// START API OVER NET
startActivityForResult(media_intent, cdata.getOKCode());
}
});
// MY STUFF********************************************************
cdata = new ClarifaiData(this);
imageview = (ImageView) findViewById(R.id.image_view);
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == cdata.getOKCode() && resultCode == RESULT_OK)
{
Uri image = intent.getData();
if (image != null) {
// LEFT OUT STUFF FOR IMAGE RESIZING***************************
//************************************************** START LOOKING HERE***************************************
new AsyncTask<Uri, Void, RecognitionResult>()
{
#Override
protected RecognitionResult doInBackground(Uri... image)
{
// SO API CALL OVER INTERNET, SO NEEDED ASYNC
return cdata.recognizeBitmap(image[0]);
}
#Override
protected void onPostExecute(RecognitionResult result)
{
super.onPostExecute(result);
if (cdata.getTags(result))
{
selectButton.setEnabled(true);
selectButton.setText("Select a photo");
// MY ATTEMPT TO GET THE
// http://www.java2s.com/Code/Android/UI/UsingtwolayoutxmlfileforoneActivity.htm
LayoutInflater inflate = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout taglayout = (LinearLayout) inflate.inflate(R.layout.tag_list_item_trio_item, null);
LinearLayout.LayoutParams parm = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
listview = (ListView) main.findViewById(R.id.tagview);
main.addView(taglayout, parm);
// this is a arraylist of tags that hold strings
List tags = cdata.getMapTags();
// data is a array of buttons, each button will be labled by each value in tags
data = new ArrayList<Button>();
for (int i = 0; i < tags.size(); i++)
{
// GET ID FOR EACH BUTTON AND PUT IT INTO ARRAY THEN SETTEXT
String loc = "button_item_" + i;
int ID = getResources().getIdentifier(loc, "id", getPackageName());
Button temp = (Button) main.findViewById(R.id.button_item_0);
temp.setText("TEST " + i);
}
// HERE IS THE PROBLEM, I NEED A WAY TO GET THE LAYOUT STUFF FROM MAIN ACTIVITY
adapter = new TagAdapter(MainActivity.this, getResources().getIdentifier("tag_list_item_trio_item", "id", getPackageName()), data);
listview.setAdapter(adapter);
}
else
bottomToast(cdata.getRecError());
}
}.execute(image);
} else {
bottomToast(cdata.getLoadError());
}
}
}
tagAdapter.java
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class TagAdapter extends ArrayAdapter<Button> {
private Context context;
private List<Button> taglist;
public TagAdapter(Context context, int resource, List<Button> objects) {
super(context, resource, objects);
Log.i("Test", "constructor " );
this.context = context;
this.taglist = objects;
}
#Override
public int getCount()
{
return taglist.size();
}
getView(int, android.view.View, android.view.ViewGroup)
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.tag_list_item_dual_item, parent, false);
final Button tag = taglist.get(position);
View view = null;
view = layoutInflater.inflate(R.layout.tag_list_item_trio_item, parent, false);
else
{
view = layoutInflater.inflate(R.layout.tag_list_item_dual_item, parent, false);
Button nameTextView = (Button) view.findViewById(R.id.first_button_dual_item);
nameTextView.setText("test");
Button nameTextView2 = (Button) view.findViewById(R.id.second_button_dual_item);
nameTextView2.setText("test2");
}
return view;
}
}
content_main.xml
<?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"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:gravity="center|bottom"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:adjustViewBounds="true"
android:id="#+id/image_view"
android:background="#653fff"
android:layout_weight="0.5"
android:padding="1dp" />
<ListView
android:id="#+id/tagview"
android:layout_width="match_parent"
android:layout_weight="0.35"
android:layout_height="0dp"
android:padding="5dp"
android:background="#68343f"
android:layout_marginTop="10dp"
android:layout_gravity="center_horizontal"
android:textAlignment="center" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:layout_gravity="center_horizontal"
android:textAlignment="center"
/>
<Button
android:id="#+id/select_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/sel_image"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:background="#3d88ec" />
</LinearLayout>
tag_list_item_trio.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_centerHorizontal="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:layout_centerInParent="true"
android:orientation="horizontal">
<Button
android:id="#+id/button_item_0"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 1"
android:textColor="#ffffff"
/>
<Button
android:id="#+id/button_item_1"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 2"
android:textColor="#ffffff"
/>
<Button
android:id="#+id/button_item_2"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 3"
android:textColor="#ffffff"
/>
</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_centerHorizontal="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:layout_centerInParent="true"
android:orientation="horizontal">
<Button
android:id="#+id/button_item_0"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 1"
android:textColor="#ffffff"
/>
<Button
android:id="#+id/button_item_1"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 2"
android:textColor="#ffffff"
/>
<Button
android:id="#+id/button_item_2"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#000000"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:text="TEST 3"
android:textColor="#ffffff"
/>
</LinearLayout>
One thing you should know is a Listview and its items are virtualized or recycled/reused or duplicated if i should say. so from how i see it i think your approach is off.
This is how i suggest you rectify it, before i get to that i want to clarify the way i understood a portion of your requirement
My goal is to dynamically generate the listview with a list of BUTTONS. each button will have setText() done to it to give it a tag, so for example if a image selected is a dog, and the tags are dog, animal, etc, then that many buttons will be generated, with a setText() of one button being dog
so you are saying you want a listView with 4 buttons on each row.
Do this, _i am taking relevant portions.
private ListView listview; //your listview
private TagAdapter adapter; // your adapter
//we are in oncreate
//i have no knowledge on cdata so bare with me here
//now remove List<Button> data; from your code
we have jumped to the TagAdapter class
private Context context;
//private List<Button> taglist; remove this also
private ArrayList<TheClassThatContainsTags> myTags;//i am assuming this will be cdata or?
//but this list should contain what setText() for a button will get its text
public TagAdapter(Context context) { //this is how your constructor will look
super(context);
Log.i("Test", "constructor " );
this.context = context;
//here you start your async task and put your async task logic here
//if the async task requires some objects or items which is not in this class
// since this is a separate class, you can inject them, when i say inject
// put them in the constructor of TagAdapter like you inject the Context
//object instance, so it might change to
// public TagAdapter(Context context,OneMoreClassIfIWant omciiw) {
// here you aysnc task will execute, now when onPostExecute is triggered/
//called you will do the following, but so remove all the code lines
// you currently have under onPostExecute
// onPostExecute has triggered
myTags = // the tag items result from onpostExecute
//now your myTags Arraylist of type TheClassThatContainsTags has been
//instantiated
}
we are now moving to getCount still in your custom adapter
#Override
public int getCount() {
return (myTags == null) ? 0 : myTags.size();
}
we are now moving to getView still in your custom adapter
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
//in your posted getview, did you edit that too? if not does it give you errors?
//nevermind
// what you do here is check if convertView is null and instantiate it
// the position here in your method parameter is the index in your myTags
// list
if(convertView == null){
//guess you know how to do this. it should be the same as your old
//getview minus this final Button tag = taglist.get(position);
// and the line below it.
}
//here we are still in the getview - what you do is ,
you find what particular button you want by convertView.findViewById()
//my understanding as i pointer out is you want to have 4 buttons in a row
//it should be something like this
Button b = convertView.findViewById(R.id.button1);
b.setText(getItem(position));//getItem() is an instance method for the
//class you are extending, and it returns an Object of Type T, which in my
//example is TheClassThatContainsTags.class;
// and you can do the same for the next 3 buttons
}
we are out of your getview and custom adapter class , and we are in your oncreate .
here set when you need your tags then you do
tagAdapter = new TagAdapter(context,anyIfDesired_OtherInjections);
listview.setAdatper(tagAdapter);
now you are done. Hope it helps, also please read listview and Arraylist Adapter so you get a foresight of what you are doing and what i have posted here. it will help you trim down the hours you waste, if you spend 12 hours on the docs your will spend 5 minutes writing this and the next time you want to replicate it will be the same 5 minutes.
Be good sir and wish you success.
I'd like to build..
A reusable dialog
Fully customizable layout (custom color or typeface, etc)
Maintain its lifecycle with referenced Activity
Use overloading which I can create several variations of dialog, i.e. combination of title, message and callbacks
In a simple way (if possible)
Currently my custom dialog class looks like :
public class CustomAlert {
public interface OnSingleClickedListener {
public void onPositiveClicked();
}
public interface OnDualClickedListener {
public void onPositiveClicked();
public void onNegativeClicked();
}
/**
* Show simple alert without callback.
* #param context
* #param msg
*/
public static void showAlert(Context context, String msg) {
final Dialog dialog = new Dialog(context);
// Do some stuff
ok.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
}
/**
* Show simple alert with callback.
* #param context
* #param msg
* #param listener
*/
public static void showAlert(Context context, String msg, final OnSingleClickedListener listener) {
final Dialog dialog = new Dialog(context);
// Do some stuff
ok.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss();
listener.onPositiveClicked();
}
});
dialog.show();
}
// Some other methods..
}
and I call these alerts from Activity like this :
if(!isFinishing()) {
CustomAlert.showAlert(MainActivity.this, getResources().getString(R.string.network_no_connection));
}
Even though I'm calling isFinishing() to check if the host Activity is running, I keep seeing BadTokenException, is your Activity running?, and I thought maybe isFinishing() is not enough.
I found this article which is using DialogFragment, but I feel like this is quite a lot of code for such a small task when I consider above requirements.
What is the most recommended and effective solution to solve this problem?
Thanks in advance!
Create a custom class like this,i have created this dialog for thumbs up and thumbs down in my application named Debongo - Restaurant Finder on play store
//recommend dialog
public void showRecommendDialog(Context mContext)
{
dialog = new Dialog(mContext,android.R.style.Theme_Holo_Dialog_NoActionBar);
dialog.setContentView(R.layout.recommend_dialog);
dialog.show();
btnThumbsUp = (ImageButton) dialog.findViewById(R.id.btn_Yes);
btnThumbsDown = (ImageButton) dialog.findViewById(R.id.btn_no);
txtMsg=(TextView) dialog.findViewById(R.id.txtMsg);
ImageButton cancelRecommend=(ImageButton) dialog.findViewById(R.id.cancelRecommend);
cancelRecommend.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
dialog=null;
}
});
btnThumbsUp.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
//do what you want
}
});
btnThumbsDown.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
//do what you want
}
});
}
Here is the layout file for the same
<?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="match_parent"
android:background="#FFFFFF"
android:gravity="center"
android:padding="5dp" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp" >
<ImageButton
android:id="#+id/cancelRecommend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="#android:color/transparent"
android:contentDescription="#null"
android:src="#drawable/com_facebook_close" />
<TextView
android:id="#+id/txtMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/cancelRecommend"
android:layout_marginBottom="#dimen/viewSpace3"
android:layout_marginLeft="#dimen/viewSpace3"
android:layout_marginRight="#dimen/viewSpace3"
android:text="Do You Want To Recommend This Restaurant ?"
android:textColor="#000000"
android:textSize="#dimen/titlebar_textSize"
tools:ignore="HardcodedText" />
<View
android:layout_width="0dip"
android:layout_height="#dimen/viewSpace3" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/txtMsg"
android:layout_centerHorizontal="true"
android:layout_gravity="center" >
<ImageButton
android:id="#+id/btn_Yes"
android:layout_width="#dimen/viewSpace5"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:contentDescription="#null"
android:src="#drawable/unselected_thumbs_up" />
<View
android:id="#+id/vvv"
android:layout_width="#dimen/viewSpace1"
android:layout_height="#dimen/viewSpace3"
android:layout_toRightOf="#id/btn_Yes" />
<ImageButton
android:id="#+id/btn_no"
android:layout_width="#dimen/viewSpace5"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/vvv"
android:background="#android:color/transparent"
android:contentDescription="#null"
android:src="#drawable/unselected_thumbs_down" />
</RelativeLayout>
</RelativeLayout>
Now when you want to open this dialog,you can just call it by using
showRecommendDialog(this);