ListView item LongClick state for selector - android

On the default ListViews if you long press on an item the background fades from dark blue to light blue(on Galaxy Tab. Its orange to light orange on some other devices) during the time it takes to register a LongClick. I am assuming this is done somehow with a selector but thus far I've only seen how to use selectors for state:selected, state:focused, and state:pressed.
This page doesn't seem to show anything about a LongClick state so perhaps my assumption that this is accomplished with a selector is incorrect?
Can anyone fill me in on how the default ListView gets this effect and how I can apply it to other views?

So it turned out to be a little bit more difficult than I had thought but I have it working almost correctly now.
Here is the OnTouchListener I ended up using:
listOnTouchListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent me){
if (me.getAction() == MotionEvent.ACTION_DOWN){
//This means a finger has come down on top of our view
//We are going to start the animation now.
Log.i(myTag, "Action Down");
Context mContext = getApplicationContext();
Resources res = mContext.getResources();
TransitionDrawable transition = (TransitionDrawable) res.getDrawable(R.drawable.listtransition);
v.setBackgroundDrawable(transition);
//LongClick took approx. 510-530 milliseconds to register after OnTouch. So I set the duration at 500 millis.
transition.startTransition(500);
}else if (me.getAction() == MotionEvent.ACTION_UP){
//This means we didn't hold long enough to get a LongClick
//Set the background back to the normal one.
v.setBackgroundResource(R.drawable.bubblelight);
}else if (me.getAction() == MotionEvent.ACTION_MOVE){
//Do Nothing
}else if (me.getAction() == MotionEvent.ACTION_CANCEL){
Log.i(myTag, "Action Cancel");
//This means we are scrolling on the list, not trying to longpress
//So set the background back to the normal one.
v.setBackgroundResource(R.drawable.bubblelight);
}
return false;
}
};
I also used an OnLongClickListener inside this I set the background back to the normal one.
Here is the Transition XML:
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/bubblelight1" />
<item android:drawable="#drawable/bubbledark" />
</transition>
You may be asking whats with the bubblelight1? More on that in a moment.
Here is the getView() Method I use inside my adapter to return the views that get displayed in the List:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
Status s = items.get(position);
if (s != null) {
v.setOnTouchListener(listOnTouchListener);
v.setOnLongClickListener(listOnLongClickListener);
tweetTxt = (TextView) v.findViewById(R.id.tweetTxt);
timeTxt = (TextView) v.findViewById(R.id.timeTxt);
if (tweetTxt != null) {
tweetTxt.setText(s.getText());
tweetTxt.setOnTouchListener(gestureListener);
}
if(timeTxt != null){
timeTxt.setText(getTimeFromNow(s.getCreatedAt().getTime()));
//timeTxt.setText(s.getCreatedAt().toLocaleString());
}
}
LinkifyWithTwitter.addLinks(tweetTxt, Linkify.ALL);
return v;
}
v.setOnTouchListener(listOnTouchListener); and
v.setOnLongClickListener(listOnLongClickListener); are the lines that set up the view with the Listeners that I've shown above.
Now about the bubblelight1. bubblelight and bubbledark are the nine patch images I am using when I tried this the first time whenever the transition started instead of the background transitioning from bubblelight to bubbledark, bubblelight would grow bigger and bubbledark would appear inside of bubblelight. So I had a big bubble that was light, a smaller bubble that was dark, then the text inside that. To fix this issue I made a copy of bubblelight and made the bottom and right edges of the ninepatch completely filled in. I just had to do the first image in the transition though, not the second. If I did the second image that way then my text would jump out of the bubble and some it would get shown over the top and along the sides of the bubble. I am not entirely sure why this was happening, or why this fix happened to work. But It does the job for now.

http://developer.android.com/guide/topics/ui/menus.html#context-menu
When the user performs a long-press on an item in a ListView and the list is registered to provide a context menu, the list item signals to the user that a context menu is available by animating its background color—it transitions from orange to white before opening the context menu. (The Contacts application demonstrates this feature.)
So its an animation that is used. I believe it uses the View's own default On...() methods to display it. You may need to worry about giving it clickable="true" or longClickable="true" attributes.

In addition to your OnTouchListener, you can use a Runnable to revert back the background to it's original state so that you don't need to explicitly do it in the OnLongClick handler.
Handler myHandler = new Handler();
...
transition.startTransition(ViewConfiguration.getLongPressTimeout());
ResetBG r = new ResetBG(transition);
myHandler.postDelayed(r, ViewConfiguration.getLongPressTimeout());
where ResetBG is:
class ResetBG implements Runnable {
protected TransitionDrawable myTran;
public Runnable(TransitionDrawable tran) {
myTran = tran;
}
public void run() {
myTran.resetTransition();
}
}

Related

buttons in listView not always triggered

I have a listview and in each cell it has a RelativeLayout with 7 buttons.
before the list is scrolled all the buttons work fine (all trigger when clicked) for all visible listView items, but after listView was scrolled some items turn to not clickable (no matter which button in the item I click), and it's random, after another scroll the same item can turn clickable, and other which was before turns to not clickable.
I have noticed that it usually happens (item turns not clickable) after scrolling all the way up.
Another thing that i have noticed that seldom (after 4-5 unsuccessful clicks in a row) the button triggers a few times in a row (like it was delayed). But usually it's not happening after a number of unsuccessful clicks.
In my original code I created an arrayList of RelativeLayouts (each for listView Item), and put the arrayList into adapter. For every 7 buttons (for each cell) I set 7 ids corresponding to their's place in arraylist.
In that way I implemented the OnClick event in the main class.
Here is 3 buttons (out of 7):
for (int i = 0; i < EXPEND_BUTTONS.length; i++) {
if (view.getId() == EXPEND_BUTTONS[i]) {
handleEmojiPanel(i);
break;
}
if (view.getId() == BUTTONS[i] || view.getId() == IMAGES[i]) {
ShowTopItem item = new ShowTopItem(getActivity(), i);
item.show();
break;
}
}
Because of the problem I change the code.
I handled the OnClick event for the buttons in the adapter itself in the getView method (for 2 buttons only):
public View getView(final int position, View convertView, ViewGroup parent) {
pos = position;
Button btn = (Button) listOfObjects.get(position).getChildAt(0);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ShowTopItem item = new ShowTopItem(getActivity(), position + listChosen);
item.show();
}
});
Button imageBtn = (Button) listOfObjects.get(position).getChildAt(2);
imageBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ShowTopItem item = new ShowTopItem(getActivity(), position + listChosen);
item.show();
}
});
return listOfObjects.get(position);
}
I have the same result. Nothing changed.
I have looked all over the internet, and it seems that I'm the only one who encountered such issue.
Id anybody knows what can be the issue here?
If some other code is needed, please feel free to ask.
I did not find the reason, but I changed ListView to ScrollView, and all works fine now.
Maybe there is some kind of bug in ListView, but in this case, I wonder why I did not find any complains regarding it.
Anyway, works perfect with ScrollView.

Android Studio changing background color from fragment not working?

I am trying to change the background color of my whole application through a settings page, I have searched for a long time and so far cannot find a solution.
So, inside the fragment I have a button, and it acts as a toggle. When clicking the background color changes as it should, from white to grey interchangeably.
Here is the logic for the button:
Button changeBGButton = (Button) view.findViewById(R.id.btn_change_bg);
changeBGButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (((MainActivity)getActivity()).bgWhite == true)
{
//White is true, set to grey
((MainActivity)getActivity()).bgWhite = false;
((MainActivity)getActivity()).bgGrey = true;
Toast.makeText(getActivity(), "Set is white to false, grey to true.", Toast.LENGTH_SHORT).show();
}
else if (((MainActivity)getActivity()).bgWhite == false && ((MainActivity)getActivity()).bgGrey == true)
{
//White is true, set to grey
((MainActivity)getActivity()).bgWhite = true;
((MainActivity)getActivity()).bgGrey = false;
Toast.makeText(getActivity(), "Set is white to true, grey to false.", Toast.LENGTH_SHORT).show();
}
}
});
The main activity, inside OnCreateView override method is responsible for changing the background color, and it does. Upon clicking the button it changes.
But...
When pressing the back button to return to the previous screen in the backstack the background becomes white, if I then go to the settings page again it is grey, and again changes to white on pressing back.
It is acting as if only the fragment has the background changed, but the layout contentLayout only exists on the mainLayout not the fragment.
I suspect during the calling of the Fragment Lifecycle Methods the background is being reset, But I do not know how to make it persist as no instance is saved on the back button pressed.
Anyway. Here is the logic that changes the background, including the overriding method:
#Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs)
{
if (contentMain != null) //Only do this if we have a hope at not crashing the application/
if (bgWhite == true && bgGrey == false)
{
contentMain.setBackgroundColor(Color.parseColor("#FFFFFF"));
}
else if (bgGrey == true && bgWhite == false)
{
contentMain.setBackgroundColor(Color.parseColor("#888888"));
}
return super.onCreateView(parent, name, context, attrs);
}
I have tried to do it inside of the OnBackstackChangeListener too but the same result is experienced. Please help me out.
Cheers.
The problem is a bit ambiguous, but by what i think the problem is mainly because the color you are setting is from the onCreateView() method of your fragment, if the contentMain layout in resident on the activity which holds the fragments then you can create a method on that activity that change the color from the activity rather than the onCreateView of the fragment.
Thus you button click will look like this::
(MainActivity)getActivity().changeBgColor(bgGrey);
so the changes that you make here are done through the activity which controls all the fragments rather than the fragment itself.
Hope that help, good luck.

Android ListView - Change active item's text's color

I'd like to create a custom effect on my ListView in Android. I have a list with text items - a kind a menu. And I'd like to change the text's color (and add a shadow for it!), when the Android changes the background under the list element.
I've a custom view (wich extends the TextView), where I overrided the onTouchEvent() function, and created a function, which changes the text's color back.
#Override
public boolean onTouchEvent(MotionEvent event){
Log.v(TAG, "" + event.getAction());
if (event.getAction() == MotionEvent.ACTION_DOWN){
Log.v(TAG, "Touch started.");
setShadowLayer(6, 0, 0, getResources().getColor(R.color.selectedTextShadow));
setTextColor(getResources().getColor(R.color.selectedTextColor));
boolean b = super.onTouchEvent(event);
Log.v(TAG, "Action down, super returns: " + (b ? "true" : "false"));
//return true;
}
return super.onTouchEvent(event);
}
public void endSelection(){
setShadowLayer(0, 0, 0, getResources().getColor(R.color.textColor));
setTextColor(getResources().getColor(R.color.textColor));
}
And in the ListFragment I override the onListItemClick() function, to call the endSelection function of the view.
#Override
public void onListItemClick (ListView l, View v, int position, long id){
Log.v(TAG, "Clicked on: " + position);
((ListRowText) v.findViewById(R.id.subMenuRow_menuItem)).endSelection();
}
It's almost perdect. But (as you can see it in this video), it does not change back the color, when I "swipe" my finger somewhere else, and the color "stucks".
Is there a better way, to do this?
I've found the StateListDrawables, but I cannot add a shadow for StateListDrawable. Or can I?
Thanks!
As Patty P said you can just create a state selector but in your case I think what you want is a text selector.
http://developer.android.com/guide/topics/resources/color-list-resource.html
You simply create a folder called color in your res folder and you can add selectors just like in the case of the list selector.
You can then use it as text color.
android:textColor="#color/mystatelist"
The states are the same
Clean looking UI by the way. You'll probably want to take a look at Android Asset Studios' Holo colors generator and generate a list selector to get a look at all the events that are being tracked on touch. For your individual list item views you may want to make a separate state list drawable for just the text view and style it according with your list selector. Here is a list of states that the generated selector handles:
state_window_focused=false
state_focused=true && state_enabled=false && state_pressed=true
state_focused=true && state_enabled=false
state_focused=true && state_pressed=true
state_focused=false && state_pressed=true
state_focused=true

EditText not receiving TAB key events - stock soft vk

My app has a ListView and an EditText sitting below it. For some reason, the TAB key doesn't trigger the onKeyListener. All other keys I'm handling (DEL, ENTER, DPAD_UP/DOWN/CENTER) are received just fine. I added a breakpoint in dispatchKeyEvent, again no luck receiving TAB events.
My app previously had a large TextView for displaying text and during this time, TAB events were received fine. The ListView has now replaced the TextView.
I'm completely mystified as to why the TAB event is no longer being received. This is on a stock Xoom, running ICS 4.0.4 & stock N1, with 2.3.6.
I've compared my current code against the version using a TextView and much of the code is just to handle the ListView in the place of the TextView. Apart from nextFocusLeft and nextFocusRight attributes, nothing else has changed for the EditText.
Edit: I just tried with Go Keyboard and Hacker's Keyboard and TAB is received fine. It appears this is with just some virtual keyboards
I think I may see the problem. Looking at the source for ListView.java, there is a mechanism to consume key events that shift focus within a list item. Check out the comments preceding this method as well as the block of comments in the middle of the method.
/**
* To avoid horizontal focus searches changing the selected item, we
* manually focus search within the selected item (as applicable), and
* prevent focus from jumping to something within another item.
* #param direction one of {View.FOCUS_LEFT, View.FOCUS_RIGHT}
* #return Whether this consumes the key event.
*/
private boolean handleHorizontalFocusWithinListItem(int direction) {
if (direction != View.FOCUS_LEFT && direction != View.FOCUS_RIGHT) {
throw new IllegalArgumentException("direction must be one of"
+ " {View.FOCUS_LEFT, View.FOCUS_RIGHT}");
}
final int numChildren = getChildCount();
if (mItemsCanFocus && numChildren > 0 && mSelectedPosition != INVALID_POSITION) {
final View selectedView = getSelectedView();
if (selectedView != null && selectedView.hasFocus() &&
selectedView instanceof ViewGroup) {
final View currentFocus = selectedView.findFocus();
final View nextFocus = FocusFinder.getInstance().findNextFocus(
(ViewGroup) selectedView, currentFocus, direction);
if (nextFocus != null) {
// do the math to get interesting rect in next focus' coordinates
currentFocus.getFocusedRect(mTempRect);
offsetDescendantRectToMyCoords(currentFocus, mTempRect);
offsetRectIntoDescendantCoords(nextFocus, mTempRect);
if (nextFocus.requestFocus(direction, mTempRect)) {
return true;
}
}
// we are blocking the key from being handled (by returning true)
// if the global result is going to be some other view within this
// list. this is to acheive the overall goal of having
// horizontal d-pad navigation remain in the current item.
final View globalNextFocus = FocusFinder.getInstance().findNextFocus(
(ViewGroup) getRootView(), currentFocus, direction);
if (globalNextFocus != null) {
return isViewAncestorOf(globalNextFocus, this);
}
}
}
return false;
}
Are there multiple focusable items within a single list element? If so, this code will consume the tab key. If that is the case, then you may want to make some of the items unfocusable or consider another design option.

Popup Balloons Disappear Randomly after tap of OverlayItem on MapView

I have an application that uses the mapview-overlay-manager code to draw map markers on a MapView using the LazyLoadManager from a web api. As I drag the map, the markers load/unload as expected.
On the tap of a marker I inflate a balloon.xml file and use it to show a balloon above the marker. This is where the problem is. It works, but then suddenly (which I cannot repeat on a consistently) the balloon overlay will stop showing up on the screen.
Its odd though, because the marker still shows that its been tapped, but then the balloon stops showing up. I've checked that the balloon is not null (which it is not), and that the itemInfo is not null. Its just not getting added to the MapView after the call to .addView(...), yet all the params are valid.
Side note: Anytime this happens, all of the overlays turn real dark and the overlay shadows go from semi-transparent to black. I have no idea what is causing that, but it happens at the same time, which makes me believe its a drawing problem.
Code for the above problem is below. Any tips/ideas/etc would be appreciated.
#Override
public boolean onSingleTap(MotionEvent e, ManagedOverlay overlay, GeoPoint point, ManagedOverlayItem item) {
if(mBalloon != null)
{
mMapView.removeView(mBalloon);
mBalloon = null;
}
if(item != null) {
//Toast.makeText(getApplicationContext(), item.getTitle(), Toast.LENGTH_SHORT).show();
MapView.LayoutParams balloonLayoutParams = new MapView.LayoutParams(350, MapView.LayoutParams.WRAP_CONTENT, item.getItemInfo().getMarkerPoint(mMapView.getProjection()), MapView.LayoutParams.BOTTOM_CENTER);
if(mBalloon == null) {
if(mLayoutInflater == null) {
mLayoutInflater = getLayoutInflater();
}
ViewGroup parent = (ViewGroup)mMapView.getParent();
mBalloon = (BalloonLayout) mLayoutInflater.inflate(R.layout.balloon_layout, parent, false);
}
TextView title = (TextView)mBalloon.findViewById(R.id.title);
title.setText(item.getItemInfo().getTitle());
TextView subTitle = (TextView)mBalloon.findViewById(R.id.subTitle);
subTitle.setText(item.getItemInfo().getBalloonSubTitle());
if(DEBUG) Log.d(TAG, "Setting on click listener.");
((ImageButton)mBalloon.findViewById(R.id.go_button)).setOnClickListener(new ViewItemInfoListener(item.getItemInfo()));
mMapView.addView(mBalloon, balloonLayoutParams);
}
return false;
}
});
// Fires off the background event to get the
overlayManager.populate();
}
Have you considered during an OnDrag: removing all the markers and save in a temporary list, start a timer (prob 200-500 ms), and then after the timer has expired repopulate the markers. If another OnDrag occurs before the timer expires, then restart the timer.
Ok, I found the problem. There is a parent method calling this method. Unfortunately this method was being called twice. Once on the onFocusChanged() and once in onCreate(). Removing one of them cured the issue. The icons and balloons were double drawing themselves because of this.

Categories

Resources