I have a custom dialog (extends Dialog) whose contentview is a custom viewgroup. The viewgroup has a few edittext children, but I am handling the drawing and clicking of buttons myself in the viewgroup's dispatchDraw and onTouch methods (I'm trying to avoid inflating as many views as possible). Specifically: this view has no button children that I could set to be the dismiss button for the dialog. I want to dismiss the dialog from within the onTouch method of the viewgroup, but beyond simulating a press of the back key, I cannot figure out how to do this.
activity code:
public class My_Activity extends Activity {
...
public void onCreate(Bundle savedInstanceState) {
...
//if there's no Class_That_Im_Editing in the database, prompt the user to make a new one by adding information to the editviews in this custom dialog and clicking the area where I draw the ok button
my_dialog = new Custom_Dialog(this, R.style.CustomDlg, new Class_That_Im_Editing());
}
}
dialog code:
public class Custom_Dialog extends Dialog {
...
public void onCreate(Bundle savedInstanceState) {
...
setContentView(new Custom_ViewGroup(context, Class_That_Im_Editing));
}
}
viewgroup code:
public class Custom_ViewGroup extends ViewGroup implements OnTouchListener {
//this class has some edittext children but _no_ buttons
...
public boolean onTouch(View view, MotionEvent event) {
if ( logic checking if the user has clicked the button area ) {
//??? what do I put here to dismiss the dialog
}
}
}
The only other approach I can think of is using the dismissDialog(int) method, which means overriding the onCreateDialog and onPrepareDialog event handlers. But how can I call dismissDialog from within a view's onTouch method?
Maybe I need to set up a listener of some kind? If so, what would be the skeleton code to do this?
So the problem was telling a dialog to dismiss() when I wasn't in the scope where the dialog existed. Here's my solution:
Create the OnTouchListener in the same scope as the dialog - in this case, inside my main activity. Then pass it when you initialize the dialog, which in turn needs to pass it to the viewgroup.
It will look something like this:
activity code:
public class My_Activity extends Activity {
public Custom_Dialog my_dialog;
...
public void onCreate(Bundle savedInstanceState) {
OnTouchListener otl_custom_dialog = new OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
if ( logic checking if the user has clicked the button area ) {
//notice I can still access any _public_ variable within the viewgroup class
//by using my_dialog.my_custom_viewgroup.public_variable
...
//I can now call dismiss() from within this scope
my_dialog.dismiss();
}
...
}
}
...
//if there's no Class_That_Im_Editing in the database, prompt the user to make a new one by adding information to the editviews in this custom dialog and clicking the area where I draw the ok button
my_dialog = new Custom_Dialog(this, R.style.CustomDlg, new Class_That_Im_Editing(), otl_custom_dialog);
my_dialog.show();
}
}
dialog code:
public class Custom_Dialog extends Dialog {
Custom_ViewGroup my_custom_viewgroup;
OnTouchListener otl_custom_dialog;
...
public void onCreate(Bundle savedInstanceState) {
...
setContentView(new Custom_ViewGroup(context, class_that_im_editing, otl_custom_dialog));
}
}
viewgroup code:
public class Custom_ViewGroup extends ViewGroup implements OnTouchListener {
public Custom_ViewGroup(Context context, Class_That_Im_Editing class_that_im_editing, OnTouchListener otl_custom_dialog) {
...
this.setOnTouchListener(otl_custom_dialog);
}
}
I have tested this method and it works fine. Hope this helps someone else out there!
Related
I need suggestion,
I am new in android, I am trying to implement emojis like facebook in my feed
using this link
FBReaction I am able to show the emojis on click of my Like button But I am not able to remove it from my view once the emojis got selected.
Here is my code in Adapter file to show emojis view
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row_social, parent, false);
RelativeLayout rl = (RelativeLayout)view.findViewById(R.id.btReaction);
final CardView root = (CardView)view.findViewById(R.id.card_view);
rl.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ReactionView rvl = new ReactionView(mContext);
root.addView(rvl);
}
});
return new ViewHolder(view);
}
ReactionView rvl = new ReactionView(mContext);
root.addView(rvl);
Above line is used to show the emojis view.
RelativeLayout rl is my layout on click of this layout I am showing my emojis list. like below
same as above I have multiple feeds where I have like button, on click of those button I am able to show emojis view but couldn't remove it once it is selected.
I have a different class (ReactionView) to show the emojis List which is available in Git Repo
now My problem is how I remove the view once the emojis got selected.
You need to modify the custom view ReactionView class a little bit, if you notice the onTouchEvent() of that class it registers different MotionEvent's, and particularity, when the MotionEvent.ACTION_UP event is triggered, this means that the user has left their finger of the ReactionView emojis, at this time you need to remove the ReactionView from your layout.
So as you can remove your view when the onDeselect() is over, so to that, there is a couple of methods:
Method 1:
Remove the focus from the ReactionView, and implement OnFocusChangeListener on the ReactionView
public class ReactionView extends View {
...
private void onDeselect() {
deselectAnimation.prepare();
startAnimation(deselectAnimation);
// Hide the view and remove the focus from it.
setVisibility(GONE);
setFocusableInTouchMode(false);
setFocusable(false);
setFocusableInTouchMode(true);
}
In activity
rvl.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus)
root.removeView(rvl);
}
});
Method 2:
Create a listener to the ReactionView, trigger its callback in onDeselect() and implement it on your activity
public class ReactionView extends View {
...
public interface DismissListener {
void onDismiss();
}
public void setOnDismissListener(DismissListener onDismissListener) {
mOnDismissListener = onDismissListener;
}
DismissListener mOnDismissListener;
private void onDeselect() {
deselectAnimation.prepare();
startAnimation(deselectAnimation);
if (mOnDismissListener != null)
mOnDismissListener.onDismiss();
}
In activity
rvl.setOnDismissListener(new ReactionView.DismissListener() {
#Override
public void onDismiss(int selectedIndex) {
root.removeView(rvl);
}
});
You can make this with a listener.
In your ReactionView class add :
interface ReactionListener{
public void onReactionClicked();
}
Then add to the constructor of ReactionView (Context context, ReactionListener: listener). I assume you want to hide this view when the user is clicking on an emoji, so where you set click listener for that, also call listener.onReactionClicked()
Then in your adapter create the listener object and remove the view:
private ReactionListener reactionListener = new ReactionView.ReactionListener(){
#override
public void onReactionClicked(){
root.removeView(rvl);
}
INTRODUCTION
I'm practicing with canvas-graphics on android. For this I created an app where I can write a line with the finger, and erase it.
When I click the color palette, a dialog window appears with some colors. So I have 2 layouts:
1- The main layout
2- The palette layout
QUESTION
First I got the color palette in the main activity, and for each color button I have an onClick which calls to a method on main Activity.
The thing is that now I'm not able to do this onClick functionality. I think that it has something to do with that now I start this layout as a view instead as a layout, so the onClick functionality of each button doesn't work
This is palette.xml layout's button example:
<ImageButton
android:layout_width="#dimen/large_brush"
android:layout_height="#dimen/large_brush"
android:background="#FF660000"
android:onClick="paintClicked"
android:tag="#FF660000" />
When I click on each button, it starts the paintClicked method an passes the color tag.
So, how do I have to initiate the palette layout when i click on the palette button, to be able to have the information passing from this layout to the main activity?
UPDATE -- Current method to call palette.xml
final Dialog paletteDialog = new Dialog(this);
paletteDialog.setTitle("Colores:");
paletteDialog.setContentView(R.layout.palette);
LinearLayout paletteLayout = (LinearLayout) paletteDialog.findViewById(R.id.paint_colors);
bnColor = (ImageButton) paletteLayout.getChildAt(0);
bnColor.setImageDrawable(getResources().getDrawable(R.drawable.button_pressed));
paletteDialog.show();
Logcat:
java.lang.NoSuchMethodException: paintClicked [class android.view.View]
This is the paintClicked method reference:
public void paintClicked(View view){
I suggest you look at DialogFragment (if you aren't using it already). You can create a simple callback interface so that when a color is clicked, it calls back to the enclosing Activity with this information. Make the enclosing Activity implement the interface (enforced by the onAttach lifecycle method below) and have the dialog fragment call it when a color is picked.
public class ColorPickerDialog extends DialogFragment implements View.OnClickListener {
// Define a callback interface
public interface OnColorSelectedListener {
public void onColorSelected(int color);
}
private OnColorSelectedListener listener;
#Override
public void onAttach(Activity activity) {
if (!(activity instanceof OnColorSelectedListener)) {
throw new IllegalStateException("Activity must implement OnColorSelectedListener!");
}
listener = (OnColorSelectedListener) activity;
}
#Override
public void onDetach() {
listener = null;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(getActivity());
View view = inflater.inflate(R.layout.palette, container, false);
// call view.findViewById(...) for all your color buttons and
// set the OnClickListener
view.findViewById(...).setOnClickListener(this);
...
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Colores:");
builder.setView(view);
return builder.create();
}
#Override
public void onClick(View v) {
/*
* Determine the color from the view that was clicked. You can use a
* switch statement on v.getId() if they all have IDs, but there are
* other possibilities as well.
*/
int color = ...;
listener.onColorSelected(color);
dismiss();
}
}
android:onClick only works if the Context which expanded the view contains the function ("paintClicked" here).
So if you didn't expand this layout with your main Activity it could the reason it doesn't work.
It might be better for you to set Ids to the ImageButtons and use some findViewById(R.id.btnX).setOnClickListener(myListener); after displaying the buttons.
Sometimes I need to do some operations(e.g. changing layout) when the activity is just showing. What I do now is using post():
public class MyActivity extends Activity {
#Override
public void onCreate() {
...
container.post(new Runnable(){
resize(container);
});
}
}
Is there any lifecycle method like onCreate can be used to simplify the code, that I don't need to call post?
#Override
public void onX() {
resize(container);
}
I think you mean do something after the UI is displayed.
Using a global layout listener has always worked well for me. It has the advantage of being able to remeasure things if the layout is changed, e.g. if something is set to View.GONE or child views are added/removed.
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// inflate your main layout here (use RelativeLayout or whatever your root ViewGroup type is
LinearLayout mainLayout = (LinearLayout ) this.getLayoutInflater().inflate(R.layout.main, null);
// set a global layout listener which will be called when the layout pass is completed and the view is drawn
mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
// at this point, the UI is fully displayed
}
}
);
setContentView(mainLayout);
http://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener.html
I used this code, but when i click on activity at runtime, it never hits in OnTouch() method. Can someone guide me what i am doing wrong? Should i need to setcontentview of this activity? Actually i want the coordinates of activity where user touch during execution.
public class TouchTestAppActivity extends Activity implements OnTouchListener
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.touch);
}
#Override
public boolean onTouch(View arg0, MotionEvent arg1)
{
// TODO Auto-generated method stub
String test = "hello";
}
}
UPDATE:
You need to do this :
In your XML layout file, you need an ID for the root view: android:id="#+id/myView"
In youer onCreate() method, write this:
LinearView v= (LinearView) findViewById(R.id.myView);
v.setOnTouchListener(this);
Assuming that your root view is a LinearView
You should the onTouchListener to relevant GUI components.
For example:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.touch);
TextView someView = (TextView)findViewById(R.id.some_view_from_layout_xml);
someView.setOnTouchListener(this); // "this" is the activity which is also OnTouchListener
}
You have to add a the listener using setOnTouchListener() otherwise who will give call to your onTouch method. any listener works on any view. so you have to add the listener to the view eg button.setOnTouchListener(this);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View vi = inflater.inflate(R.layout.yourxml, null);
setCOntentView(vi);
vi.setOnTouchListener(this);
In onCreate, you need to set the content view (just uncommenting the second line should probably work) and then you need to set your OnTouchListener (your activity) as the onTouchListener for a view in your application.
Let's say you've got a view in your layout called "MainView"; it would look something like this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View view = findViewById(R.id.MainView);
view.setOnTouchListener(this);
}
This article has a good example:
http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-2-building-the-touch-example/1763
MainActivity.java:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setTitle(R.string.app_name);
setContentView(new SampleView(this));
}
}
SampleView.java:
public class SampleView extends View {
#Override
protected void onDraw(Canvas canvas) {
if (certaincondition = true) {
//add elements to canvas etc
} else {
//How do I do the below? The layout is defined in xml.
//I do not want to use Intent. Please help me
//create a layout from resource R.layout.idAbout and transfer control.
}
}
}
Use a layout inflater:
View newRootViewElement;
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
newRootViewElement= li.inflate(R.layout.idAbout, null);
You can inflate a layout using
View.inflate(getContext(), R.layout.idAbout, viewParent);
where viewParent is a ViewParent that will be the parent of the inflated view (and can be null).
But what are you trying to do? It's more than a little odd to start a new activity or to modify the view hierarchy from within onDraw(). You might want to post a runnable to a Handler that will do what you want on the next cycle of the event loop. To start a new activity (such as displaying “About” info for the app) you should take a look at the Intent class.