In the code below, onItemLongClick works only when I comment out the onTouchListener. I need to be able to register swipes as well as long clicks. What am I doing wrong?
public class MainPageActivity extends ListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
...
getListView().setLongClickable(true);
getListView().setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(getApplicationContext(), "long click", Toast.LENGTH_SHORT).show();
return true;
}
});
getListView().setOnTouchListener(new OnSwipeTouchListener() {
public void onSwipeBottom() {
Toast.makeText(MainPageActivity.this, "bottom", Toast.LENGTH_SHORT).show();
}
});
}
}
If you are overriding onTouch, onDown, or other methods like that, in OnTouchListener, SimpleGestureListener or the like, you need to make sure that your are returning false, in order for the event to propagate correctly.
Related
I use a GestureListener on an image to detect a Double Tap.
holder.image.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return holder.myDoubleTapDetector.onTouchEvent(event);
}
});
And I use the library Zoomy to make the images zoomable.
Zoomy.Builder builder = new Zoomy.Builder(mActivity).target(holder.image);
builder.register();
Both work perfectly fine for them alone.
But adding both at the same time does not work! Only the one that was added last works.
How can I have both of them working?
Zoomy provides a solution for that:
Because Zoomy works by attaching a View.OnTouchListener to the registered View, View.OnClickListener can not be set along with Zoomy, so a TapListener, LongPressListener and DoubleTapListener are provided to ensure the View still can listen for gestures. A ZoomListener is also provided if you are interested in zoom events.
In Code:
Zoomy.Builder builder = new Zoomy.Builder(this)
.target(mZoomableView)
.tapListener(new TapListener() {
#Override
public void onTap(View v) {
//View tapped, do stuff
}
})
.longPressListener(new LongPressListener() {
#Override
public void onLongPress(View v) {
//View long pressed, do stuff
}
}).doubleTapListener(new DoubleTapListener() {
#Override
public void onDoubleTap(View v) {
//View double tapped, do stuff
}
})
.zoomListener(new ZoomListener() {
#Override
public void onViewStartedZooming(View view) {
//View started zooming
}
#Override
public void onViewEndedZooming(View view) {
//View ended zooming
}
});
I have MainActivity and SpinnerActivity, I want to get selected spinner item value from SpinnerActivity into the MainActivity. I tried to declare String as Static, I also tried with getter but without any success.
in Spinner Activity I also have if statement, how can I get value outside "if statement" and "#Override method" into another class?
MainActivity.class
public class MainActivity extends AppCompatActivity {
SpinnerActivity spinnerActivity = new SpinnerActivity();
Spinner spinnerProvince;
String selectedSpinnerProvince = spinnerActivity.inSpinnerSelectedProvince;
// String selectedSpinnerProvince = SpinnerActivity.inSpinnerSelectedProvince;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
spinnerProvince = findViewById(R.id.spinnerProvince);
populateSpinnerProvinces();
spinnerProvince.setOnItemSelectedListener(spinnerActivity);
}
public void populateSpinnerProvinces() {
ArrayAdapter<String> provincesAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.province));
provincesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerProvince.setAdapter(provincesAdapter);
}
}
SpinnerActivity.class
public class SpinnerActivity implements android.widget.AdapterView.OnItemSelectedListener {
public String inSpinnerSelectedProvince;
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getId() == R.id.spinnerProvince) {
inSpinnerSelectedProvince = parent.getItemAtPosition(position).toString();
Toast.makeText(parent.getContext(), parent.getItemAtPosition(position).toString(), Toast.LENGTH_SHORT).show();
} else {// code here}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
I were about to advice you to use Intent to share data between both activities when i noticed that your "SpinnerActivity" is not really an Activity since it not extends Android Activity class (AppCompactActivity or other classes like this).
Your SpinnerActivity is a Listener. You can use it to implement the action to trigger when an action is performed on your Spinner view. For that you need to do it inside the "#Override" method of onItemSelected.
If you don't like to use the previous methode because of the Override methode you should implement directly the action to trigger at on click events on your spinner view in your MainActivity by doing this:
public class MainActivity extends AppCompatActivity {
SpinnerActivity spinnerActivity = new SpinnerActivity();
Spinner spinnerProvince;
String selectedSpinnerProvince = spinnerActivity.inSpinnerSelectedProvince;
// String selectedSpinnerProvince =
SpinnerActivity.inSpinnerSelectedProvince;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
spinnerProvince = findViewById(R.id.spinnerProvince);
populateSpinnerProvinces();
//spinnerProvince.setOnItemSelectedListener(spinnerActivity);
spinnerProvince.setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getId() == R.id.spinnerProvince) {
inSpinnerSelectedProvince = parent.getItemAtPosition(position).toString();
Toast.makeText(parent.getContext(), parent.getItemAtPosition(position).toString(), Toast.LENGTH_SHORT).show();
} else {// code here}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
public void populateSpinnerProvinces() {
ArrayAdapter<String> provincesAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_spinner_item,
getResources().getStringArray(R.array.province));
provincesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerProvince.setAdapter(provincesAdapter);
}
}
thanks for helping. I was trying to implement an add to favorite function in my recycler view, everything is working fine except for one thing. I am unable to commit the changed image button in my recycler view, every time I press the button, the post is added to the favorites and the image button turns yellow, but as soon as I move to some other fragment, the yellow button goes back to its initial stage. Can anyone of you help me on how can I make my button commit to the changes in recycler view. Below is my relevant code.
Initialization of buttons in holder class:
class UsersViewHolder1 extends RecyclerView.ViewHolder {
View mView;
private ImageButton mFavouritesBlack, mFavouritesYellow;
private GestureDetector mGestureDetector;
private Heart mHeart;
public UsersViewHolder1(View itemView) {
super(itemView);
mView = itemView;
mFavouritesBlack = mView.findViewById(R.id.ad_start_fav);
mFavouritesYellow = mView.findViewById(R.id.ad_start_fav1);
}
}
OnBindViewHOlder class(I omitted the irrelevant code):
protected void onBindViewHolder(#NonNull final UsersViewHolder1 Holder, final int position, #NonNull
Ad ad) {
Holder.setTitle(ad.getTitle());
Holder.setPrice(ad.getPrice());
Holder.setCategory(ad.getCategory());
Holder.setImage(ad.getImage(), getContext());
Holder.setTime(ad.getTime());
String user_id = getRef(position).getKey();
final String kk = user_id.toString();
Holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent mew = new Intent(getActivity(), ExpandActivity.class);
mew.putExtra("user_id", kk);
startActivity(mew);
}
});
Holder.mFavouritesBlack.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mFav.child(puid).child(kk).child("fav_status").setValue("Added as fav").addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(getContext(),"Added to Fav",Toast.LENGTH_SHORT).show();
if (Holder.mFavouritesBlack.isShown())
Holder.mFavouritesBlack.setVisibility(View.GONE);
Holder.mFavouritesYellow.setVisibility(View.VISIBLE);
}
});
return true;
}
});
Holder.mFavouritesYellow.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mFav.child(puid).child(kk).removeValue().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(getContext(),"Removed from Fav",Toast.LENGTH_SHORT).show();
if (Holder.mFavouritesYellow.isShown())
Holder.mFavouritesBlack.setVisibility(View.VISIBLE);
Holder.mFavouritesYellow.setVisibility(View.GONE);
}
});
return true;
}
});
}
What you are trying to implement is selection inside a recyclerview which requires saving state, that is you will have to save the favourite items say in a SparseBooleanArray which can be used to save favourite adapter positions, and inside onBindViewHolder check if the favourites array contains the adapter position and toggle imageview (There is no need to use two images instead you can change the color of drawable), please refer this artcle
That is because you are saving the flags when a click happened,but when the views are redrawn you are not resetting the images accordingly. Inside the onBindViewHolder add the following code.
//Replace the if condition statement with the state value check(Abstract code shown below)
if(mFav.child(puid).child(kk).child("fav_status").getValue(),equals("Added as fav")){
Holder.mFavouritesBlack.setVisibility(View.GONE);
Holder.mFavouritesYellow.setVisibility(View.VISIBLE);
}else{
Holder.mFavouritesBlack.setVisibility(View.VISIBLE);
Holder.mFavouritesYellow.setVisibility(View.GONE);
}
After 2 days of messed up searches and work I finally removed my the problem was that recycler view isn't able to hold the state by itself after change, that's why we need to provide a way to store the state (or the image in my case) so that it can remember it everytime it recycles the view, but instead I added the direct statement through which it checks whether the favourite node is present in database or not and based on that the buttons behaved. Below is the code.
mFav.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.child(puid).hasChild(kk)){
Holder.mFavouritesBlack.setVisibility(View.GONE);
Holder.mFavouritesYellow.setVisibility(View.VISIBLE);
}else{
Holder.mFavouritesBlack.setVisibility(View.VISIBLE);
Holder.mFavouritesYellow.setVisibility(View.GONE);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Holder.mFavouritesBlack.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mFav.child(puid).child(kk).child("fav_status").setValue("Added as fav").addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(getContext(), "Added to Fav", Toast.LENGTH_SHORT).show();
if (!itemStateArray.get(adapterPosition, false))
Holder.mFavouritesBlack.setVisibility(View.GONE);
Holder.mFavouritesYellow.setVisibility(View.VISIBLE);
}
});
return true;
}
});
Holder.mFavouritesYellow.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mFav.child(puid).child(kk).removeValue().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(getContext(), "Removed from Fav", Toast.LENGTH_SHORT).show();
if (itemStateArray.get(adapterPosition, false))
Holder.mFavouritesBlack.setVisibility(View.VISIBLE);
Holder.mFavouritesYellow.setVisibility(View.GONE);
}
});
return true;
}
});
But huge thanks to everyone who tried to help.
I'm new to android, started it about a month ago, and now I'm trying to make a "Shopping List" app for the sake of practice. In this app I have a ListView, where user can insert items via EditText above that ListView. When user longClick on item, ContextMenu with "Edit", "Delete" and "Mark" fields appears. I have already made "Delete" button work, but I still have problems with "Edit" function. To make this function work I created DialogFragment class, so when user presses the "Edit" button, this DialogFragment appears. This DF has EditText field, where we enter data we want to change. Here is DialogFragment class code:
public class AlertEdit extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder bd = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
bd.setView(inflater.inflate(R.layout.alert, null))
.setTitle("Edit")
.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
((MyActivity)getActivity()).doPositiveClick();
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
((MyActivity)getActivity()).doNegativeClick();
}
});
return bd.create();
}
as you can see, we have positive button here, which calls doPositiveClick method from MyActivity, which appears to be the main activity.
.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
((MyActivity)getActivity()).doPositiveClick();
}
So, here is the MyActivity class code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
lw = (ListView) findViewById(R.id.listView);
edtxt = (EditText) findViewById(R.id.editText);
alertEd = (EditText) findViewById(R.id.alertEdit);
goods = new ArrayList<String>();
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, goods);
lw.setAdapter(adapter);
lw.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> adapter, View v,
int position, long id) {
}
});
registerForContextMenu(lw);
edtxt.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction()== KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_ENTER) {
goods.add(0, edtxt.getText().toString());
adapter.notifyDataSetChanged();
edtxt.setText("");
return true;
}
}
return false;
}
});
}
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo info){
super.onCreateContextMenu(menu, v, info);
getMenuInflater().inflate(R.menu.actions, menu);
}
public boolean onContextItemSelected(MenuItem item) {
position = (int) info.id;
switch (item.getItemId()) {
case R.id.cnt_mnu_delete:
goods.remove(position);
adapter.notifyDataSetChanged();
return true;
case R.id.cnt_mnu_edit:
}
return super.onContextItemSelected(item);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.my, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void doPositiveClick()
{
}
public void doNegativeClick()
{
}
public void showDialog()
{
DialogFragment frag = new AlertEdit();
frag.show(getFragmentManager(), "edit");
}
}
My problem is that I have no idea how to create that Edit function. I tryied to use AdapterContextMenuInfo, but it works only in onContextItemSelected method, because it requires and Item to work with. Hope you help me and sorry for the possible lack of information, ask me any additional questions please.
P.S. I'm trying to make this dialog for almost two weeks already and I'm really frustrated because of that.
I'm using this method - it's simple and you may adapt it to your needs:
First of all make an interface to handle your result, for example:
public interface OnDialogResultListener {
public void onDialogResult(String result);
}
Then use your dialog with additional view, like this:
public void showDialogAndGetResult(final int title, final String message, final String initialText, final OnDialogResultListener listener) {
// additional View - use appropriate View to your needs:
final EditText editText = new EditText(this);
editText.setText(initialText);
new AlertDialog.Builder(MainActivity.this)//
.setTitle(title)//
.setMessage(message)//
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (listener != null) {
listener.onDialogResult(editText.getText().toString());
}
}
})//
.setNegativeButton(android.R.string.cancel, null)//
.setView(editText)//
.show();
}
At last implement this interface in your activity:
public class YourActivity Extends Activity implements OnDialogResultListener{
...
#Override
public void onDialogResult(String result) {
//do what you need
}
...
}
Edit:
You may replace EditText by any View, including Layouts.
Still you may use the same scheme to return result from your DialogFragment descendant - just pass OnDialogResultListener in constructor or initializing method. I would say AlertDialog is more lightweight and DialogFragment allows more control and you may use both according to your needs.
I am new to Android dev. The way I have been handling clicks has been by setting the android:onClick attribute in the manifest file for buttons. What I am wondering is the best way to handle long clicks in general. I have read about implementing onLongClick(), but is there a way to use handlers (like above), rather than having to extend View? It would be very helpful, as I would rather not have to rebuild my entire project with an extended View class.
EDIT
I should clarify. I have a ListView and I want to set what will happen when I long click on an element in the list. Each element in the list is a TextView. As per one of the answers, I have added the below code, and now I get a force close:
public class TwitterActivity extends ListActivity {
List<String> tweets = new LinkedList<String>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(this, R.layout.layout, tweets));
TextView view = (TextView) findViewById(R.id.ListTemplate);
view.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Toast toast = new Toast(TwitterActivity.this);
toast.setText("LongClick");
toast.show();
return true;
}
});
//...
}
}
For a ListActivity if you want to respond to long clicks on the list elements do this:
public class TwitterActivity extends ListActivity {
List<String> tweets = new LinkedList<String>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(this, R.layout.layout, tweets));
ListView lv = getListView();
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener(){
#Override
public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id)
{
Toast.makeText(TwitterActivity.this, "LongClick", Toast.LENGTH_LONG).show();
}
});
}
}
For a regular activity you could do something like this:
public class MyActivity extends Activity implements View.onLongClickListener {
View myView = null;
public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.my_activity);
myView = findViewById(r.id.my_view);
myView.setOnLongClickListener(this);
}
#Override
public void onLongClick(View v) {
//long clicked
}
}
get a handle to the button using findViewByID, then call setOnLongClickListener.
Button b = (Button)findViewByID (R.id.button1);
b.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
//to do
}
});
Sure this is fairly simple:
ImageButton i = (ImageButton) findViewById(R.id.myButton);
i.setOnLongClickListener(new myLongListener());
private class myLongListener implements View.OnLongClickListener {
#Override
public void onClick(View v) {
//your code here
}
}
hope this helps!
You don't have to extend the View class in most cases. View has a method called setOnLongClickListener which you can use directly as all derived classes like Button or TextView, etc. will also have.
The only event handler that has an XML attribute is android:onClick. All other event handlers are registered at runtime from Java code. Technically, even android:onClick is registered at runtime from Java code, but you do not have to write the Java code in question.
So you need to do something like this:
View.OnLongClickListenerhandler = View.OnLongClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.myButton: // doStuff
break;
case R.id.myOtherButton: // doStuff
break;
}
}
}
findViewById(R.id.myButton).setOnLongClickListener(handler);
findViewById(R.id.myOtherButton).setOnLongClickListener(handler);