Set button in custom view (canvas) - java

I would like to set up a button that would allow me to move to another activity while I finished drawing my painting.
The question is I don't know how to set up this button in the view class because it doesn't listen to any listeners.

In your drawing view, define your interface
public class MyDrawingView extends View
{
protected MyPaintingListener m_paintingListener;
public interface MyPaintingListener
{
// you can define any parameter as per your requirement
public void paintingEnded();
}
public void onCreateView()
{
// Create your view
}
public void draw()
{
// Draw your painting
// then
if(m_paintingListener != null)
m_paintingListener.paintingEnded();
}
public void setListener(MyPaintingListener p_listener)
{
m_paintingListener = p_listener;
}
}
In your current Fragment or Activity:
public class MyActivity extends Activity
implements MyDrawingView.MyPaintingListener
{
protected MyDrawingView m_drawingView;
public void OnActivityCreated(Bundle savedInstanceState)
{
// In this method or another, create your drawingView
m_drawingView = new MyDrawingView();
m_drawingView.setListener(this);
m_drawingView.paint();
}
#Override
public void paintingEnded()
{
// Set up your button;
}
}

Related

How to listen for lottie animation end from activity

I have activity that contain fragment.
This fragment have a lottie animation with lottie_loop="false",
that means, once the animation finish first loop , the animation will be and.
I want to listen for this event(animation end) in activity that contain this fragment, but some this wrong with my code, and I have white screen.
I created interface for listen to even , and this is my code:
Fragment with lottie animation:
public class EntryFragmentAnimation extends Fragment {
private View view;
private LottieAnimationView mLavTwoHearts;
private boolean isAnimationEnd = false;
private OnAnimationEndListener iOnAnimationEndListener;
public interface OnAnimationEndListener {
void onAnimationEnd(boolean isAnimationEnd);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_entry_animation, container, false);
initView(view);
initAnimation();
return view;
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
iOnAnimationEndListener = (OnAnimationEndListener) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement OnAnimationEndListener");
}
}
private void initView(View view) {
mLavTwoHearts = view.findViewById(R.id.lavTwoHearts);
}
private void initAnimation() {
mLavTwoHearts.playAnimation();
mLavTwoHearts.addAnimatorListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isAnimationEnd = true;
iOnAnimationEndListener.onAnimationEnd(isAnimationEnd);
}
});
}
}
And an activity
public class LoginActivity extends AppCompatActivity implements EntryFragmentAnimation.OnAnimationEndListener {
private boolean isAnimationEnd = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
setEntryScreen();
listenToAnimationEnd();
}
private void setEntryScreen(){
getSupportFragmentManager()
.beginTransaction()
.add(R.id.container_login_fl, new EntryFragmentAnimation())
.commit();
}
private void listenToAnimationEnd(){
while (!isAnimationEnd){
Log.d(TAG, "listenToAnimationEnd: Animation playing");
}
Log.d(TAG, "listenToAnimationEnd: animation end");
}
#Override
public void onAnimationEnd(boolean isAnimationEnd) {
this.isAnimationEnd = isAnimationEnd;
}
}
While running the app , only white screen appear and in logcat running endless log with Animation playing
Instead of a listener I would suggest you to better use a ViewModel. You only need to create ViewModel class and create its instance in fragment but using the activity scope so that it will be available for all the fragment contained within the activity including activity itself.
In your fragment create a Shared ViewModel instance like below:
activity?.let {
sharedViewModel = ViewModelProviders.of(it).get(SharedViewModel::class.java)
}
Once the animation ends update the the ViewModel
sharedViewModel?.onAnimationFinished()
Note: Inside you ViewModel class, have any live data member which is being obeserved by your Activity and then just update the variable within the function.
In the activity we just need to create instance of our ViewModel and observe the required data like this
val sharedViewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java)
sharedViewModel.animationEndEvent.observe(this, Observer {
it?.let {
// do some thing
}
})

Android: Fragments using a method from MainActivity not defined in the interface?

So I'm having some design pattern confusion/issues. I have a Fragment that needs to call methods from the MainActivity that's not defined in the Fragment's interface. An obvious solution would be just to cast the attached Activity as a MainActivity, but doesn't that defeat the purpose of the interface?
This is my MainActivity has methods a(), b(), and c():
public class MainActivity extends Activity implements AInterface, CInterface {
#Override
public void a(){//method A body}
public void b(){//method b body} //no Override
#Override
public void c(){//method C body}
}
This is my Fragment Class and NEEDS a(), b() and c().
Method c() is from another Fragment's interface:
public class SomeFragment extends Fragment{
private AInterface mActivity;
#Override
public void onAttach(Activity activity) {
mActivity = (AInterface)activity;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.my_layout, container, false);
mActivity.a();
(MainActivity) mActivity.b(); //is it ok to just call it like this?
(MainActivity) mActivity.c(); //is it ok to just call it like this?
return v;
}
public interface AInterface{
public void a();
}
}
Is this the correct way of calling those methods? Thanks.
I would not do it like this, since your are creating a tight coupling between your Activity and your fragment.
A better approach would be to use a callback.
public class MenuFragment extends Fragment {
public interface Interface1{
public void b();
}
public interface Interface2 extends Interface1{
public void a();
}
public interface Interface3 extends Interface1{
public void c();
}
Interface2 mCallback;
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try {
mCallback = (Interface2 ) activity;
}
catch (ClassCastException e) {
throw new ClassCastException(activity.toString()+ " must implement ItemselectedCallback");
}
}
#Override
public void onDetach(){
mCallback = null;
super.onDetach();
}
//somewhere
mCallback.a();
}
Your activity would then implement the callback interface and handle the callbacks.
public class TaskActivity extends Activity implements MenuFragment.Inferface2, MenuFragment.Interface3{
public void a() {
//do something
}
public void b() {
//do something
}
public void c() {
//do something
}
}
Yes you can do that and it will work, BUT you will also need to be careful when the casting failed (solveable with instanceof)
It will also make your SomeFragment class coupled to your MainActivity class which is not a best practice.
I think the better and safer approach is to use interface.

How to create interface between Fragment and adapter?

I have fragment with ListView, say MyListFragment, and custom CursorAdapter.
I'm setting onClickListener in this adapter for the button in the list row.
public class MyListAdapter extends CursorAdapter {
public interface AdapterInterface {
public void buttonPressed();
}
...
#Override
public void bindView(final View view, final Context context, final Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
...
holder.button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// some action
// need to notify MyListFragment
}
});
}
}
public MyListFragment extends Fragment implements AdapterInterface {
#Override
public void buttonPressed() {
// some action
}
}
I need to notify fragment when the button is pressed. How to invoke this interface?
Help, please.
Make a new constructor and an instance variable:
AdapterInterface buttonListener;
public MyListAdapter (Context context, Cursor c, int flags, AdapterInterface buttonListener)
{
super(context,c,flags);
this.buttonListener = buttonListener;
}
When the Adapter is made, the instance variable will be given the proper reference to hold.
To call the Fragment from the click:
public void onClick(View v) {
buttonListener.buttonPressed();
}
When making the Adapter, you will have to also pass your Fragment off to the Adapter. For example
MyListAdapter adapter = new MyListAdapter (getActivity(), myCursor, myFlags, this);
since this will refer to your Fragment, which is now an AdapterInterface.
Keep in mind that on orientation of the Fragment changes, it will most likely be recreated. If your Adapter isn't recreated, it can potentially keep a reference to a nonexistent object, causing errors.
Using Eventbus:
Examples:
https://github.com/kaushikgopal/RxJava-Android-Samples/tree/master/app/src/main/java/com/morihacky/android/rxjava/rxbus
or
https://github.com/greenrobot/EventBus
Using Interfaces:
I understand the current answer but needed a more clear example. Here is an example of what I used with an Adapter(RecyclerView.Adapter) and a Fragment.
Create Callback Interface:
public interface AdapterCallback {
void onMethodCallback();
}
Passing in Callback/Fragment:
This will implement the interface that we have in our Adapter. In this example, it will be called when the user clicks on an item in the RecyclerView.
In your Fragment:
public class MyFragment extends Fragment implements AdapterCallback {
private MyAdapter mMyAdapter;
#Override
public void onMethodCallback() {
// do something
}
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mMyAdapter = new MyAdapter(this); // this class implements callback
}
}
Use the Callback in your Adapter:
In the Fragment, we initiated our Adapter and passed this as an argument to the constructer. This will initiate our interface for our callback method. You can see that we use our callback method for user clicks.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(AdapterCallback callback) {
this.mAdapterCallback = callback;
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mAdapterCallback.onMethodCallback();
}
});
}
}
or Use the Fragment in your Adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(Fragment fragment) {
try {
this.mAdapterCallback = ((AdapterCallback) fragment);
} catch (ClassCastException e) {
throw new ClassCastException("Fragment must implement AdapterCallback.");
}
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
mAdapterCallback.onMethodCallback();
} catch (ClassCastException exception) {
// do something
}
}
});
}
}
Follow the 2 steps below for receive callback from Adapter in Fragment (or Activity)
First: In your Adapter
public class ListAdapter extends RecyclerView.Adapter < RecyclerListAdapter.ItemViewHolder > {
...
private ListAdapterListener mListener;
public interface ListAdapterListener { // create an interface
void onClickAtOKButton(int position); // create callback function
}
public RecyclerListAdapter(Context mContext, ArrayList < Items > listItems, ListAdapterListener mListener) { // add the interface to your adapter constructor
...
this.mListener = mListener; // receive mListener from Fragment (or Activity)
}
...
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
holder.btnOK.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// use callback function in the place you want
mListener.onClickAtOKButton(position);
}
});
...
}
...
}
Second: In your Fragment (or Activity), there are 2 ways for implement callback method
Way 1
public MyListFragment extends Fragment {
...
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
...
ListAdapter adapter = new ListAdapter(getActivity(), listItems, new ListAdapter.ListAdapterListener() {
#Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
});
...
}
}
Way 2
public MyListFragment extends Fragment implements ListAdapter.ListAdapterListener {
...
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
ListAdapter adapter = new ListAdapter (getActivity(), listItems, this);
...
}
#Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
}
This is very similar to the way an activity and a fragment should communicate. In the constructor of your adapter, pass a reference of your fragment, cast it to your interface and just call yourReference.buttonPressed() on your onClick method.
a solution for NPE is first to make conctractor in your Fragment like that
public MyFragment MyFragment(){
return this;
}
then initialize your listener is adapter like that
Lisener lisener = new MyFragment();
Make a constructor like that:
public MyAdapter(Activity activity,AlertMessageBoxOk alertMessageBoxOk) {
this.mActivity = activity;
mAlertMessageBoxOk = alertMessageBoxOk;
}
call the interface from adapter use any event
mAlertMessageBoxOk.onOkClick(5);
after that implement AlertMessageBoxOk interface to your fragment like this,
class MyFragment extends Fragment implements AlertMessageBoxOk {
#Override
public void onOkClick(int resultCode) {
if(resultCode==5){
enter code here
}
}
}

Accessing a method in MainActivity, from another class

I think I am making a design error in my Android app somewhere. My (simplified) code is pasted below.
I am using the writeMidi method in MainActivity. However, I would also like to use it, or actually just trigger it, when "onItemSelected" is triggered in the custom listener.
I am a bit torn on how to do that. Should I redesign this code to fit the customlistener in the main activity?
Thanks for any help.
public class MainActivity extends Activity{
int song = 0;
int[] music;
public int instrument;
public CustomOnItemSelectedListener listener;
// *******************************************************
// set Layout - on create
// *******************************************************
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
instrument = 0;
listener = new CustomOnItemSelectedListener();
addListenerOnSpinnerItemSelection();
//more stuff, including using the writeMidi method
};
public void addListenerOnSpinnerItemSelection(){
instrumentSp = (Spinner) findViewById(R.id.instrument);
instrumentSp.setOnItemSelectedListener(listener);
}
public void writeMidi(int[] music, int count) {
// so some stff
}
}
and in a separate file;
public class CustomOnItemSelectedListener implements OnItemSelectedListener {
private int instrument = 0;
public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
Toast.makeText(parent.getContext(),
"Please wait a minute for the instrument to be changed. ", Toast.LENGTH_SHORT).show();
instrument = pos;
}
public int getInstrument(){
return instrument;
}
}
Use broadcast receiver in main class and send different type of broadcast(Different messages) to activate different methods in main activity.
You could create a Listener interface 'InstrumentSelectedListener', or something like that. Then have your MainActivity implement that interface, register it as a listener on your CustomOnItemSelectedListener, and fire a 'writeMidiNow' event in your onItemSelected.
You would end up with something like:
public class MainActivity extends Activity implements OnInstrumentSelectedListener{
int song = 0;
int[] music;
public int instrument;
public CustomOnItemSelectedListener listener;
// *******************************************************
// set Layout - on create
// *******************************************************
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
instrument = 0;
listener = new CustomOnItemSelectedListener();
addListenerOnSpinnerItemSelection();
//more stuff, including using the writeMidi method
};
public void addListenerOnSpinnerItemSelection(){
instrumentSp = (Spinner) findViewById(R.id.instrument);
instrumentSp.setOnItemSelectedListener(listener);
}
public void onInstrumentSelected(int instrument) {
// do some stuff with the instrument.
}
public void writeMidi(int[] music, int count) {
// so some stff
}
}
And
public class CustomOnItemSelectedListener implements OnItemSelectedListener {
public interface OnInstrumentSelectedListener{
public void onInstrumentSelected(int instrument);
}
private int instrument = 0;
private OnInstrumentSelectedListener instrumentlistener;
public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
Toast.makeText(parent.getContext(),
"Please wait a minute for the instrument to be changed. ", Toast.LENGTH_SHORT).show();
instrument = pos;
if(instrumentListener != null)
instrumentListener.onInstrumentSelected(instrument);
}
public void setInstrumentListener(OnInstrumentSelectedListener listener) {
this.instrumentListener = listener;
}
public int getInstrument(){
return instrument;
}
}
2 ways to do it:
- First will be passing the context of MainActivity class to CustomOnItemSelectedListener class.
- Second way is quick and dirty, make the writeMidi() method as static, but you should keep in mind that static methods can access only static members, Not non-static members.
I tried a number of the solutions suggested, but could get none of them to fully work.
So I solved it by not using a separate class like this:
instrumentSp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {

Android application event handling

Is there a standard set of Listener/Observer/Observable classes in Android for managing application events in Android?
I'm not talking about UI or other Android API events, but rather custom app events like GameOverEvent, LevelClearedEvent, etc.
Is there a preferred interface to implement/extend so that I can implement things like:
public void addGameOverListener(GameOverListener listener)
It's easy,, you just need to create your own EventListener
public interface onGameFinishedListener {
public void onGameFinished(GameView gameView);
}
and some class which has onGameFinished() method
public abstract class GameView extends SurfaceView implements SurfaceHolder.Callback{
List<onGameFinishedListener> listeners;
public GameThread gameThread;
protected int width;
protected int height;
public GameView(Context context) {
super(context);
width = 320;
height = 480;
listeners = new ArrayList<onGameFinishedListener>();
}
public abstract void init();
public void registerGameFinishedListener(onGameFinishedListener listener) {
listeners.add(listener);
}
protected void GameFinished(GameView gameView) {
for (onGameFinishedListener listener : listeners) {
synchronized(gameThread.getSurfaceHolder()) {
listener.onGameFinished(gameView);
}
}
}
}
and then you implement the onGameFinishedListener in your activity or view which you want to do operation when the game finish,
public class RocketActivity extends GameActivity implements onGameFinishedListener {
private final int MENU = 0;
private final int END = 1;
private final int CONFIRMATION = 2;
private RelativeLayout layout;
private RocketView rocketView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new RelativeLayout(this);
rocketView = new RocketView(this);
rocketView.registerGameFinishedListener(this);
rocketView.init();
layout.addView(rocketView);
setContentView(layout);
}
#Override
public void onGameFinished(GameView gameView) {
runOnUiThread(new Runnable() {
#Override
public void run() {
showDialog(END);
}
});
}
}
there. no need to rely on Android for EventListener. :)
Have you tried EventBus by GreenRobot?
It is basically a pretty standard implementation of an eventBus for handling application wide events.
It provides inter-thread communication which is quite neat.
Pretty similar to what you get for GWT

Categories