I created a custom LayoutManager and TouchHelper.Callback to have a tinder-like card stack. I want my layout manager to allow only the first item to have a touch event. Firstly I override the isItemViewSwipeEnabled() of ItemTouchHelper.Callback to disable touch event for each child. As the last step, I need to allow the first item to have a touch event only. However, I am failed to do so. Is anybody know how to overcome it?
StackLayoutManager to create child views.
StackTouchHelperCallback to disallow default touch events.
StackView a custom RecyclerView.
This is the custom view hierarchy I developed. If anybody developed some kind of views, can them help me? Thanks in advance.
You can override the getMovementFlags method and return 0 in case you dont want to allow any movement, otherwise return appropriate direction flags.
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder:RecyclerView.ViewHolder): Int {
return if(viewHolder.adapterPosition == 0) /* return appropriate direction flags */ else 0
}
Related
When I have a recycler view with 12 items, when accessibility focus goes onto cell number 3, for example, talkback announces "Double tap to activate. Item 3 of 12".
I want to keep the action but stop it from announcing the item position and item count. How can I do this? I have tried to assign a delegate to the recycler view but not sure what to override in the delegate.
How can I do this?
So I figured it out. An AccessibilityNodeInfo has a method called SetCollectionInfo(). CollectionInfo has properties like rowCont and columnCount.
I simply set the info to null.
Note, the below is xamarin:
private class TabLayoutTabAccessibilityDelegate: View.AccessibilityDelegate
{
public override void OnInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info)
{
base.OnInitializeAccessibilityNodeInfo(host, info);
info.SetCollectionInfo(null);
}
}
This is a functionality that should not be disabled: it lets people using Talkback know that they are in a list, how long is the list, which element is currently focused (are there more elements above/below).
I'm trying to implement an autoplay feature for video items in a RecyclerView (linear vertical layout). I can't figure out how to know when a certain item is currently on/off the screen so I can autoplay/pause the video. If I put the code in onBindViewHolder method all videos start playing simultaniously. Couldn't find a solution by googling it either. Help, please!
For Recyclerview you should rely on your layout manager to give you this information.
https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager
or
https://developer.android.com/reference/android/support/v7/widget/LinearLayoutManager
Assign a layout to the RecyclerView when you assign the adapter. Then use it to see what is visible.
Let me help a bit more with some Psedo Kotlin code for you to help with the player aspect.
Let's pretend you have some object that is bound into each row that can trigger the playing and has a unique ID. Let's call that an ActiveRowPlayer for this example.
NOTE*
If you are using databinding, it is simple to bind your video player playing content to a property in your model that is populating the row, but that's different story for a different post.
You can make an interface like:
interface IActivePlayerUpdater{
fun onUpdateCurrentPlayer
}
You can make a helper method like:
in your activity, you can implement an interface like :IActivePlayerUpdater and override the methods for it.
override fun onUpdateCurrentPlayer(){
var activeRowPlayer = recyclerView.layoutManager.findFirstCompletelyVisibleItemPosition()
if(activeRowplayer.someID != currentRowPlayer.someID){
currentRowPlayer.stopPlaying
currentRowPlayer = activeRowPlayer
activeRowPlayer.startPlaying
}
}
Then pass it into your adapter and just monitor your onBind method and anytime a new onBind is called that means the content has moved enough to trigger a new row item.
MyAdapterConstructor(IActivePlayerUpdater myCallback)
fun recyclerView.onBindMethod(stuffThatComesHere){
//do normal stuff
myCallback.onUpdateCurrentPlayer()
}
Keep in mind, this is just pseudo to help you on your journey. not intended to be direct copy and paste.
----NOTE* REQUESTED FROM COMMENT TO SUPPLY HOW TO TOUCH VIEWMODEL FROM OUTSIDE OF ADAPTER---
#Goran, this example I had setup a long time ago to avoid
notifyDataSetChanged on selection changed to toggle a checkbox for
each item. I eventually moved to a better option, but you asked how do
you get the viewmodel, here is a sample. rvCameraRoll was my
recyclerView, I was using it to display camera media, but that is not
relevant, just focus on getting the viewModel piece.
The only part you should care about is getting the ViewHolder, I just left the rest there in case it helps you with anything else.
int count = rvCameraRoll.getChildCount();
for (int i = 0; i < count; i++) {
MediaModelGridAdapter.ViewHolder childRow = (MediaModelGridAdapter.ViewHolder)rvCameraRoll.getChildViewHolder(rvCameraRoll.getChildAt(i));
if(isVisible) {
childRow.imgCellSelected.setVisibility(View.VISIBLE);
if(getMediaModelList().get(i).getIsSelected()){
childRow.imgCellSelected.setBackgroundResource(R.drawable.ic_ap_selected_on);
}
}else{
//check that exists, because after fresh delete list may be short while updating cells
if(getMediaModelList().size() > i) {
getMediaModelList().get(i).setIsSelected(false);
}
childRow.imgCellSelected.setBackgroundResource(R.drawable.ic_ap_selected_off);
childRow.imgCellSelected.setVisibility(View.GONE);
}
}
OLD
leaving this for anyone using a ListView
There is a OnScrollListener for ListView
You can override the
onScrollStateChanged(AbsListView view, int scrollState)
and
the
onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
this will give you the ListView item that is visible. So by using the onScroll you can detect which items are visible and determine which one to play and stop playing.
if you use with recyclerview
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.OnScrollListener
The RecyclerView is only holding the items and the LayoutManager is responsible for displaying the items, so in order to get the ones that are visible to the user, assuming that you use LinearLayoutManager, you should call :
((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
or
((LinearLayoutManager)recyclerView.getLayoutManager()).findLastVisibleItemPosition();
Quick, probably simple, question. I have a view whose background is animating, and during that time, I want to disable the user from interacting with the view. My view is a FrameLayout, and I'm capturing touch events with onTouchEvent(). Solutions I've tried:
1) First setOnTouchListener(null), then setOnTouchListener(this). Problem is, my view only calls onTouchEvent(MotionEvent), and not onTouch(View, MotionEvent), so I can't pump through the Events there.
2) First setEnabled(false), then setEnabled(true). The source code says: A disabled view that is clickable still consumes the touch events, it just doesn't respond to them. Problem is, MotionEvents still get pumped through in onTouchEvent().
3) requestDisallowInterceptTouchEvent(false), then (true). This only handles touch events from the parent.
The solution I have working is using a boolean variable isAnimating, and checking the value of that in onTouchEvent(). I'd rather not do this, because it looks ugly to me and I'd rather use the API for it than reinvent the wheel, sooo... anyone got any ideas? Thanks.
Try:
setFocusable() and setFocusableInTouchMode()
Try:
#Override
public boolean onTouchEvent(MotionEvent event) {
//Check if event is on your view
if(event.getY()>view.getTop()&&event.getY()<view.getBottom()&&event.getX()>view.getLeft()&&event.getX()<view.getRight()){
//event occured inside your view
}
//here return super or as your logic prefer
return super.onTouchEvent(event);
}
I'm working on improving the accessibility within my app.
I have pretty complicated layout with cards. Each card has some clickable objects inside it, but it also has the global click-listener.
When I enable Talkback, select the card (not something inside it!), double-clicking (to open the card), the card gets the touch-event in the middle of the card.
As a result, nested object got click event and react respectively.
The question is how to determine, which item is in TalkBack's focus (green-rectangle-thing for me)? The idea is to disable inside touch-listeners, if card itself is in focus.
API level I want to support is 16 (Android 4.1+)
Thanks!
I think what would work best for you, is to override the accessibility delegate of layout view, listening for accessibility focus events. When focus is added to a card, remove listeners, when focus leaves your cards re attach your listeners. Attach this delegate to your layout view, and you should be able to watch as various views within your layout obtain and give up accessibility focus.
class MyAccessibilityDelegate extends View.AccessibilityDelegate {
#Override
public boolean onRequestSendAccessibilityEvent(ViewGroup viewGroup, View child, AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
//Do stuff in here! Maybe also do different stuff when focus is cleared!
}
return super.onRequestSendAccessibilityEvent(viewGroup, child, event);
}
}
The apis for this were added in API level 14 so you should be good to go!
I'm implementing a custom calendar using a GridView.
For this Calendar I have 3 view types, {DAY, TITLE, BLANK}
Is there a way to make certain items in a GridView not clickable?
What I'm trying to avoid is the press state animations for the items that aren't clickable. It ok it the user presses them, I can recognize that it's not the valid view in my onItemClickListener(). This is purely for UI purposes.
I found the solution. Don't know why I didn't search for ListViews in the first place.
You need to override the isEnabled() Function
Returning false will make it non-clickable. True will keep is clickable.
#Override
public boolean isEnabled(int position) {
switch(getItemViewType(position)) {
case CellTypes.BLANK:
case CellTypes.TITLE:
default :
return false;
case CellTypes.DAY:
return true;
}
}
In the adapter for your GridView, implement one of the get() method to return a reference to the object being clicked. I'm assuming that your adapter wraps a list of your "Calendar" objects.
In the onItemClickListener for your GridView, call get(index) or get(id) on the adapter to get a reference to the object being clicked. Check its type to see if it is one that you do not wish to be clickable, and return before executing the logic that is usually called when a clickable item is clicked.
In XML: android:clickable="false" and in code: setClickable(false);