Zoom the listview - android

I have a listview containing a textview and I need to zoom this textview on button click but I am not able to do it, I tried everything to override the simplecursor adapter and override the getview() method but couldn't zoom the textview on button click, the button is outside the listview and my code is:
this is the listview layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<CheckBox
android:id="#+id/bt_rating"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:button="#android:drawable/btn_star"
android:onClick="onclick"/>
<TextView
android:id="#+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/FontSizeInListView"
android:gravity="right"
/>
</LinearLayout>
Edit
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder(){
Binds the Cursor column defined by the specified index to the specified view
public boolean setViewValue(View view, Cursor cursor, int columnIndex){
if(view.getId() == R.id.text1){
tv=(TextView)view;
}}**
so that way I get the textview but sure only the last one created will be rendered and in the zoom I do tv.settextsize(..)
but only the last textview created on page will change because I only have the id of that one so how can I get all the textviews and not just the last one created?

In your custom adapter, add a variable (with public setters and getters) to represent zoom level. In your getView method, use this variable to change the text views' text sizes (just add that right before your return line. You must always set the size to something, since the views are reused.
Then on your button that changes the zoom level, change the adapter's zoom variable and then call notifyDataSetChanged on it to force it to call getView on all its visible views. (This is assuming you subclassed ArrayAdapter).

It worked What I did is:
adapter =new SimpleCursorAdapter(this,R.layout.rating,cu,new String[]{"Title","Fav"}, new int[]{R.id.text1,R.id.bt_rating},CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
//added in last update
adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder(){
/** Binds the Cursor column defined by the specified index to the specified view */
public boolean setViewValue(View view, Cursor cursor, int columnIndex){
if(view.getId() == R.id.text1){
tv=(TextView)view;
tv.setTextSize(SizeOfTextInListView);
}
});
And in the zoom button:
//zoom in button click
final Button zoom_in_btn = (Button) findViewById(R.id.button_zoom_in);
zoom_in_btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(Zoom_counter<10){
SizeOfTextInListView= SizeOfTextInListView+Zoom_In_Out_value;
adapter.notifyDataSetChanged();
Zoom_counter++;
}
}
});
and it worked perfectly..

Related

Android TV ListView does not return to previously selected item

enter image description hereI am trying to get ListView returning to the previously selected item. I have a screen split in two parts, where on the left part is a ListView and on the right part is TextView, showing selected text.
Use case: an item is selected and with Dpad right arrow is made move to the TextView, then back with Dpad left arrow to the ListView, move several items down with Dpad arrow down. Then again with Dpad right arrow move to the TextView and left arrow back. The problem is that a different item is selected, not the last one selected, which is not intuitive, moreover it is randomly selected position instead of the position of the last selected item.
Here is listing of my test ListView:
public class MainActivity extends AppCompatActivity {
private static final String LOG_TAG = MainActivity.class.getSimpleName();
private TextView m_program_description;
ListView listView;
ArrayList<String> arrayList = new ArrayList<>(Arrays.asList("C-Language", "Java", "Data Structure",
"Networking", "Operating System", "Compiler Design", "Theory Of Computation",
"Software Engineering", "Web Engineering"));
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
// simple_list_item_1 is a built in layout. It is part of Android OS, instead of creating our own
// xml layout we are using built-in layout
ArrayAdapter arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, arrayList);
listView.setAdapter(arrayAdapter);
listView.setOnItemClickListener((adapterView, view, i, l) -> {
view.setSelected(true);
view.setActivated(true);
});
listView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
Log.e(LOG_TAG, "onItemSelected() called");
m_program_description = findViewById(R.id.program_description);
m_program_description.setMovementMethod(new ScrollingMovementMethod());
m_program_description.setText(arrayList.get(position));
}
#Override
public void onNothingSelected(AdapterView<?> parent)
{
}
});
}
}
and layout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="2">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<!--ListView to store list items-->
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="#+id/program_description"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="10dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="25dp"
android:focusable="true"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:scrollbars="vertical"
android:fadeScrollbars="false"
android:textSize="16sp"
android:gravity="start" >
</TextView>
</LinearLayout>
</LinearLayout>
I appreciate your help.
By behaviour observation (i.e.,without drilling the ListView source code from AOSP website),
I believe you shall store the selected position in an instance variable and then reselect the item in ListView if it is not focus then focus again.
In order to store the selected position:
int mItemSelected = -1; // new instance variable
...
listView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
mItemSelected = position; // store position to mItemSelected
Log.e(LOG_TAG, "onItemSelected() called position=" + position);
TextView m_program_description = findViewById(R.id.program_description);
m_program_description.setMovementMethod(new ScrollingMovementMethod());
m_program_description.setText(arrayList.get(position));
}
#Override
public void onNothingSelected(AdapterView<?> parent)
{
}
});
In order to re-select the item when focus (With hack, will be explained after the code sample):
listView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean isFocus) {
Log.d(LOG_TAG, "onFocusChange: isFocus=" + isFocus + ", mItemSelected=" + mItemSelected);
if (isFocus && mItemSelected != -1) {
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
${YOUR_ACTIVITY}.this.runOnUiThread(() -> {
listView.setItemChecked(mItemSelected, true);
listView.setSelection(mItemSelected);
listView.getChildAt(mItemSelected).requestFocus();
});
}
};
Timer timer = new Timer();
timer.schedule(timerTask, 0);
}
}
});
The related code shall be the three lines using mItemSelected as argument. Maybe any of them will work and I am just too lazy to verify it.
The concern here is not about the implementation of selection, it is more about the life cycle of ListView when focus has changed.
Originally, I hadn't use a Timer to run the code. Same issue was met then. I guess there is a life cycle event which will set the position incorrectly.
Flow
Focus ListView
Move to item position X
Trigger ListView#setOnItemSelectedListener
Set mItemSelected to X
Press DPad to move to TextView
Press DPad to move back to ListView
Trigger ListView#setOnFocusChangeListener
ListView select item X
Unknown life cycle event moves the item unintentionally
So after adding a Timer, step 9 and 8 will be swapped and therefore the result will be expected. This is the hacking done here and you can see I even didn't add a delay to the Timer.
If anyone can provide WHY step 9 occurs, please also let me know.

Android EditText: enable only scrolling but stop comsuming clicks

I am contributing to an app project and I have this issue.
I have a Horizontal LinearLayout with an ArrayAdapter list of Items: image -- EditText -- image
I use EditText to enable scrolling horizontally a long text field while disabling cursor and click events. The parent layout needs to manage the click event on the items + horizontal swipe to change tabs in Main View
The code works properly:
If EditText has a long text: I can scroll horizontally the text to read it all. At the end of the text, the parent layout takes the swipe and can change tabs
I can long touch on the EditText to enable a select checkmark from the parent layout
The cursor and slider are properly hidden in the EditText
The only issue is that EditText consumes the simple click events and never passes them to the parent layout. When I click the images or when I click on the right/left of the EditText, the parent layout properly captures the click action on the adapter item. If I click directly on the EditText, the event is consumed and never reaches the parent layout setOnItemClickListener.
Here's a short video of how it is working now. The click at 10 seconds position in video must be done outside the text: https://www.youtube.com/watch?v=P306p7AcwAI
Here is the xml sample:
https://github.com/PhilZ-cwm6/SMBSync2/blob/philz/SMBSync2/src/main/res/layout/sync_task_item_view.xml
<LinearLayout
android:id="#+id/profile_list_sync_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="#+id/sync_task_master_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical|top"
android:src="#drawable/ic_16_server" />
<EditText
android:id="#+id/sync_task_master_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="none"
android:background="#android:color/transparent"
android:cursorVisible="false"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="true"
android:ellipsize="end"
android:lines="1"
android:text="Master"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="#+id/sync_task_direction_image"
android:layout_width="12dp"
android:layout_height="18dp"
android:layout_gravity="center"
android:scaleType="fitXY"
android:src="#drawable/arrow_right_enabled" />
<ImageView
android:id="#+id/sync_task_target_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="top"
android:src="#drawable/ic_16_server" />
<EditText
android:id="#+id/sync_task_target_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="none"
android:background="#android:color/transparent"
android:cursorVisible="false"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:singleLine="true"
android:ellipsize="end"
android:lines="1"
android:text="Target"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
the adapter code extract:
https://github.com/PhilZ-cwm6/SMBSync2/blob/philz/SMBSync2/src/main/java/com/sentaroh/android/SMBSync2/AdapterSyncTask.java
public class AdapterSyncTask extends ArrayAdapter<SyncTaskItem> {
final public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
final SyncTaskItem o = getItem(position);
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
holder = new ViewHolder();
holder.tv_row_master = (EditText) v.findViewById(R.id.sync_task_master_info);
holder.tv_row_target = (EditText) v.findViewById(R.id.sync_task_target_info);
}
if (o != null) {
holder.tv_row_master.setText("source dir path");
holder.tv_row_master.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); //disable auto-correct highlight in EditText
holder.tv_row_target.setText(destination dir path);
holder.tv_row_target.setTextColor(mTextColor);
holder.tv_row_target.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); //disable auto-correct highlight in EditText
}
return v;
}
static class ViewHolder {
EditText tv_row_master, tv_row_target;
}
}
And the ActivityMain that needs the onClick events:
https://github.com/PhilZ-cwm6/SMBSync2/blob/philz/SMBSync2/src/main/java/com/sentaroh/android/SMBSync2/ActivityMain.java
private void setSyncTaskListItemClickListener() {
mGp.syncTaskListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SyncTaskItem item = mGp.syncTaskAdapter.getItem(position);
editSyncTask(item.getSyncTaskName(), item.isSyncTaskAuto(), position);
}
});
}
These are really simple code snippets
Basically, the original code works properly with a TextView but long text path cannot be viewed/scrolled in a single line. Using HorizontalScrollView works also but doesn't pass any event, include swipe and long press to the parent if the click happens on the text field.
The EditText trick fixes all except the simple click events when they happen on the EditTex box. Wired because long touch and swipe are properly passed. Also, the setOnItemClickListener doesn't capture any event when clicking on the EditText, but captures them if it is a TextView
Any idea how to fix this ? I thought about a custom EditText but ended up unsure how would the ArrayAdapter get the EditText position. Am I obliged to use a second adapter for the EditText ?
best regards
Edit: I can add this code to the getView() of Adapter:
holder.tv_row_target.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//click events of EditText are captured
}
});
However, I cannot propagate them to the ListView or a Parent view from the onClick()
This would avoid a heavy rewrite in code based on actions that Parent should do on click
Edit: see next post with proper fix to preserve the native ListView animation
I fixed it this way:
in adapter:
holder.tv_row_target.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((ActivityMain) mContext).dispatchSyncTaskListItemClick(o, position);
}
});
In MainActivity:
public void dispatchSyncTaskListItemClick(SyncTaskItem item, int position) {
// my actions
}
That way, I can pass the needed info (position, object item) to the activity
I am open to any other suggestion to simply propagate the click to the parent ListView so that it handles it directly
Proper fix:
I post this for any one having the same issue. I saw so many threads on this but no one ever came with a good fix
My previous answer has an issue: it doesn't preserve the native ListView onClick fading animation
I tried the performclick() but it is the same.
I finally fixed it completely using MotionEvent to pass the touch events to the list view
In Adapter: I set the onClick listeners for click and long click and send the action to MainActivity where the ListView action code is present
Adapter listeners:
holder.tv_row_target.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((ActivityMain) mContext).dispatchSyncTaskListItemClick(o, position);
}
});
holder.tv_row_target.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
v.setHapticFeedbackEnabled(false);
((ActivityMain) mContext).dispatchSyncTaskListLongClick(o, position);
return true;//notify long touch event is consumed
}
});
In Main Activity: The setOnItemLongClickListener and setOnItemClickListener must be set there. The issue was to click the EditText or a an icon which handles touch and perform the ListView action and animation
// simulate click on teh ListView item
public void dispatchSyncTaskListItemClick(SyncTaskItem item, int position) {
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
int first_visible_pos = mGp.syncTaskListView.getFirstVisiblePosition();
View v = mGp.syncTaskListView.getChildAt(position - first_visible_pos);
float x = v.getX() + 1;//view items start at 0, MotionEvent doesn't handle the UP action at 0
float y = v.getY();
//first touch
MotionEvent motionDown = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
motionDown.setSource(InputDevice.SOURCE_TOUCHSCREEN);
mGp.syncTaskListView.onTouchEvent(motionDown);
//release touch
downTime = SystemClock.uptimeMillis();
eventTime = SystemClock.uptimeMillis();
MotionEvent motionUp = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
motionUp.setSource(InputDevice.SOURCE_TOUCHSCREEN);
mGp.syncTaskListView.onTouchEvent(motionUp);
motionUp.recycle();
motionDown.recycle();
}
// simulate long touch
public void dispatchSyncTaskListLongClick(SyncTaskItem item, int position) {
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
int first_visible_pos = mGp.syncTaskListView.getFirstVisiblePosition();
View v = mGp.syncTaskListView.getChildAt(position - first_visible_pos);
MotionEvent motion = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, v.getX(), v.getY(), 0);
motion.setSource(InputDevice.SOURCE_TOUCHSCREEN);
mGp.syncTaskListView.onTouchEvent(motion);
motion.recycle();
}
The hardest part was the x+1 because my View started at float x = 0.0, and the UP action was not considered until it is > 0. Not sure why ? ACTION_DOWN handles it properly
The other thing to take care of is the getChildAt: it returns the view position starting from first visible position and not the adapter passed position. Else, you get a null returned view.
Now, it works just like when interacting with the ListView
New edit: added v.setHapticFeedbackEnabled(false); to remove the duplicate haptic feedback on long touch !
Remaining issue: I feel all this is a workaround. There is still a small delay on the animation trigger when long click. The ideal would be the EditText View completely letting ListView to handle the onClick
So probably only a custom HorizontalScrollView or a custom EditText would fix it

Multiple EditText in ListView, tap to focus on one EditText and focus jumps to the first

I've got EditTexts in my rows in a ListView. When I tap on one of the EditTexts the soft keyboard appears and the focus jumps to the first EditText in the list instead of staying in the field where I tapped.
Here is a video of it:
https://youtu.be/ZwuFrX-WWBo
I created a completely stripped down app to demonstrate the problem. The full code is here: https://pastebin.com/YT8rxqKa
I'm not doing anything to alter the focus in my code:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.cell_textfield, parent, false);
}
TextView label = (TextView) convertView.findViewById(R.id.textview1);
EditText textfield = (EditText) convertView.findViewById(R.id.textview2);
String text = String.format("Row %d", position);
label.setText(text);
textfield.setText(text);
return convertView;
}
I found another post on StackOverflow giving a workaround for this dumb Android behavior, which involves putting an OnFocusChangedListener on all of the textfields so they can retake focus if it's taken from them improperly.
That worked to regain focus, but then I discovered that when a textfield retakes focus the cursor ends up at the start of the text instead of end, which is unnatural and annoying to my users.
Here is a video of that:
https://youtu.be/A35wLqbuIac
Here's the code for that OnFocusChangeListener. It works to fight the stupid Android behavior of moving focus, but the cursor is misplaced after it regains focus.
View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean hasFocus) {
long t = System.currentTimeMillis();
long delta = t - focusTime;
if (hasFocus) { // gained focus
if (delta > minDeltaForReFocus) {
focusTime = t;
focusTarget = view;
}
}
else { // lost focus
if (delta <= minDeltaForReFocus && view == focusTarget) {
focusTarget.post(new Runnable() { // reset focus to target
public void run() {
Log.d("BA", "requesting focus");
focusTarget.requestFocus();
}
});
}
}
}
};
I hate having to put a bandaid on a bandaid on a bandaid to try to get Android to just behave as it would naturally be expected to behave, but I'll take what I can get.
1) Is there something I can do to fix this problem at the source and not have to have the OnFocusChangeListener at all?
2) If (1) isn't possible, then how can I make sure that when I force focus back to the correct field that I make sure the cursor is placed at the end? I tried using setSelection() right after requestFocus() but since the textfield wasn't yet focused the selection is ignored.
Here was my "solution." In short: ListViews are stupid and will always be a total nightmare when EditTexts are involved, so I changed my Fragment/Adapter code to be able to adapt to either a ListView layout or a ScrollView layout. It only works if you have a small number of rows, because the scrollview implementation isn't able to take advantage of lazy-loading and view recycling. Thankfully, any situation wherein I want EditTexts in a ListView, I rarely have more than 20 rows or so.
When inflating my view in my BaseListFragment, I get my layout id via a method that relies on a hasTextFields() method:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(getLayoutId(), container, false);
return view;
}
public boolean hasTextfields() {
return false;
}
public int getLayoutId() {
if (hasTextfields()) {
return R.layout.scrollfragment;
} else {
return R.layout.listfragment;
}
}
In my various subclasses of my BaseListFragment, if I need to have an EditText in one of my fields, I just override the hasTextFields() method to return true and then my fragment/adapter switchs over to using the basic scrollview implementation.
From there, it's a matter of making sure that the Adapter handles the standard ListView actions for both the ListView and the ScrollView scenarios. Like this:
public void notifyDataSetChanged() {
// If scrollContainer is not null, that means we're in a ScrollView setup
if (this.scrollContainer != null) {
// intentionally not calling super
this.scrollContainer.removeAllViews();
this.setupRows();
} else {
// use the real ListView
super.notifyDataSetChanged();
}
}
public void setupRows() {
for (int i = 0; i < this.getCount(); i++) {
View view = this.getView(i, null, this.scrollContainer);
view.setOnClickListener(myItemClickListener);
this.scrollContainer.addView(view);
}
}
One issue that the click listener presented is that a ListView wants an AdapterView.OnItemClickListener, but arbitrary Views inside a ScrollView want a simple View.OnClickListener. So, I made my ItemClickListener also implement View.OnClickListener and then just dispatched the OnClick to the OnItemClick method:
public class MyItemClickListener implements AdapterView.OnItemClickListener, View.OnClickListener {
#Override
public void onClick(View v) {
// You can either have your Adapter set the tag on the View to be its position
// or you could have your click listener use v.getParent() and iterate through
// the children to find the position. I find its faster and easier to have my
// adapter set the Tag on the view.
int position = v.getTag();
this.onItemClick(null, v, config.getPosition(), 0);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// ...
}
}
Then in MyEditTextListFragment, I create the adapter like this:
listener = createClickListener();
adapter = createListAdapter();
if (scrollContainer != null) {
adapter.setScrollContainer(scrollContainer);
adapter.setMenuItemClickListener(listener);
adapter.setupRows();
} else {
getListView().setOnItemClickListener(listener);
getListView().setAdapter(adapter);
}
Here is my scrollfragment.xml for reference:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:clickable="true"
>
<!--
The following LinearLayout as a focus catcher that won't cause the keyboard to
show without it, the virtual keyboard shows up immediately/always which means we
never get to the enjoy the full size of our screen while scrolling, and
that sucks.
-->
<LinearLayout
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_width="0px"
android:layout_height="0px"/>
<!--
This ListView is still included in the layout but set to visibility=gone. List
fragments require a standard ListView in the layout, so this gets us past that
check and allows us to use the same adapter code in both listview and scrollview
situations.
-->
<ListView android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"
android:background="#null"
android:layout_alignParentTop="true"
android:descendantFocusability="afterDescendants"
android:visibility="gone"
/>
<!--
This scrollview will act as our fake listview so that we don't have to deal with
all the stupid crap that comes along with having EditTexts inside a ListView.
-->
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="afterDescendants"
>
<LinearLayout
android:id="#+id/scrollContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
</LinearLayout>
</ScrollView>
</RelativeLayout>
Try this once, it worked for me:
public void setCursorPosition() {
focusTarget.requestFocus();
focusTarget.setCursorVisible(true);
other.setCursorVisible(false);
} else {
other.setCursorVisible(true);
focusTarget.setCursorVisible(false);
}
}

Prevent Spinner dropdown dismiss when focus changed

I have a dropdown spinner which is showed when click on a button looks like this:
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Spinner
android:id="#+id/spinMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:spinnerMode="dropdown"
android:visibility="invisible" />
<ListView
android:id="#+id/lvWall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Here is snippet showing dropdown popup:
findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
spinMenu.performClick();
}
});
My spinner can show dropdown popup correctly. The problem is my layout has a listview which getting data from web service in background. When data is loading completely, all list items will be showed or refreshed, and the spinner's dropdown popup is dismiss (I even don't touch anything on screen). I think the problem is window has changed focus on other view. So how can I prevent it?
Update:
Here is my list after load data from background, it's very simple:
List<Feed> data = result;
FeedAdapter adapter = new FeedAdapter (this, data);
ListView lvWall = (ListView)findViewById(R.id.lvWall);
lvWall.setAdapter(adapter);
And data for spinner:
List<String> list = getMenus();
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, list);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinMenu.setAdapter(dataAdapter);
If I understand correctly, you have a Spinner view which you set as invisible with the only purpose of showing the popup menu, but not the Spinner view itself. In that case, the problem is probably related to this snippet in Spinner.java, more precisely in DropdownPopup.show():
public void show(int textDirection, int textAlignment) {
...
super.show();
...
// Make sure we hide if our anchor goes away.
// TODO: This might be appropriate to push all the way down to PopupWindow,
// but it may have other side effects to investigate first. (Text editing handles, etc.)
final ViewTreeObserver vto = getViewTreeObserver();
if (vto != null) {
final OnGlobalLayoutListener layoutListener = new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!Spinner.this.isVisibleToUser()) {
dismiss();
} else {
computeContentWidth();
...
What does this mean? Basically that the Spinner is set up with a ViewTreeObserver to be notified whenever a layout pass changes the views in the screen. And if the Spinner is not visible after that happens, the popup is dismissed. Loading the ListView evidently causes a change in the view hierarchy, and it's being fired when the data arrives from the server.
For general usage this is completely logical: if the Spinner is hidden, or it goes off screen, or something like that, it would be reasonable to make the popup go away. However, it's interferring with what you're attempting to do. It would be nice if you could somehow override isVisibleToUser(), but unfortunately it's marked as #hide, so that's not possible.
Might I suggest a workaround, like setting the Spinner visible but really small? Like, with a height of 1px? I believe that should be enough to fool this method.
Another option, and probably a more sensible one, would be to forgo the Spinner altogether and use a PopupMenu instead. You can anchor it to the Button, load it dynamically, and show it when the button is pressed. The visual effect should be the same.
If you think the problem is due to the change of focus . You can set it with multiple ways.
first create a focuschangeListener and onfocuschange do whatever you like
yourView.setOnFocusChangeListener(testListener);
#Override
public void onFocusChange(View arg0,
boolean isFocused)
{
if(isFocused)
{
//do your work here
}
else
{
}
}
And second way to prevent view from focus..
<!-- Dummy item to prevent AutoCompleteTextView from receiving focus -->
<LinearLayout
android:focusable="true" android:focusableInTouchMode="true"
android:layout_width="0px" android:layout_height="0px"/>
<!-- :nextFocusUp and :nextFocusLeft have been set to the id of this component
to prevent the dummy from receiving focus again -->
<AutoCompleteTextView android:id="#+id/autotext"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:nextFocusUp="#id/autotext" android:nextFocusLeft="#id/autotext"/>

Android ListView CheckedTextView Blinking

Having an issue with CheckedTextView that I can't seem to find a solution. I'm not even entirely sure what's happening.
I have a custom ListView whose rows contain TextViews and a CheckedTextView.
row.xml
<CheckedTextView
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="#+id/title"
android:text="Name"
android:gravity="center_vertical"
android:paddingRight="6dip"
android:typeface="sans"
android:checkMark="?android:attr/textCheckMark"
android:textSize="16sp"
android:textStyle="bold"/>
MyAdapterView.java
public class RuleAdapterView extends LinearLayout
{
private CheckedTextView title;
...
title = (CheckedTextView)v.findViewById(R.id.title);
title.setText(entry.getName());
title.setChecked(entry.isActive());
// setup a listener for the checkbox
title.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
((CheckedTextView) v).toggle();
}
});
}
And in the main XML file I set the ListView to android:choiceMode="multipleChoice".
So what I want is for the ListView rows to be long and short clickable and for the CheckedTextView to be separate click execution. This works with the exception of the text part of the CheckedTextView. Whenever either the CheckedTextView is pressed, the text 'flickers'. I did it slowly to figure out exactly what was going on. When you press down on the CheckTextView, the white text either disappears or toggles black (possibly inverts?) and when you release, the text reappears and the checkmark toggles. There is no 'flicker' effect when the ListView is pressed.
Any ideas on what's going on here?
Thanks
Instead of using OnClickListener you should try using OnTouchListener
ckToggle.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
CheckedTextView ck = ((CheckedTextView) v);
ck.toggle();
return false;
}
});
ListView uses its own scheme when an item is clicked (highlighting the background). You might want to check out this solution Android how to make View highlight when clicked?

Categories

Resources