I have tried to overwrite onOverScrolled() but it is not triggered:
public class MyRecyclerView extends RecyclerView {
public MyRecyclerView(#NonNull Context context) {
super(context);
}
public MyRecyclerView(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyRecyclerView(#NonNull Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
Toast.makeText(getContext(), "overScrolled", Toast.LENGTH_SHORT).show();
}
}
My RecyclerView has recyclerView.setOverScrollMode(View.OVER_SCROLL_ALWAYS);
Try this to find bottom overscroll and top overscroll
Find bottom overscroll and top overscroll Using LayoutManager
import android.os.Bundle;
import java.util.ArrayList;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
RecyclerView myRecyclerView;
ArrayList<String> arrayList = new ArrayList<>();
DataAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myRecyclerView = findViewById(R.id.myRecyclerView);
LinearLayoutManager linearLayoutManager= new LinearLayoutManager(this){
#Override
public int scrollVerticallyBy ( int dx, RecyclerView.Recycler recycler, RecyclerView.State state ) {
int scrollRange = super.scrollVerticallyBy(dx, recycler, state);
int overScroll = dx - scrollRange;
if (overScroll > 0) {
Utils.printLog("NILU_PILU :-> BOTTOM OVERSCROLL");
} else if (overScroll < 0) {
Utils.printLog("NILU_PILU :-> TOP OVERSCROLL");
}
return scrollRange;
}
};
myRecyclerView.setLayoutManager(linearLayoutManager);
myRecyclerView.setHasFixedSize(true);
addDataToList();
adapter = new DataAdapter(this, arrayList);
myRecyclerView.setAdapter(adapter);
}
private void addDataToList() {
for (int i = 0; i < 50; i++) {
arrayList.add("NILU_PILU :-> " + i);
}
}
}
Find bottom overscroll Using RecyclerView.addOnScrollListener()
myRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
int pos = linearLayoutManager.findLastVisibleItemPosition();
int numItems = myRecyclerView.getAdapter().getItemCount();
if (pos >= numItems - 1 ) {
Utils.printLog("NILU_PILU :-> BOTTOM OVERSCROLL");
}
}
}
});
Here is a solution I found on reddit:
Instead of a custom recyclerview, you create a custom LinearLayoutManager and just overwrite your layout managers scrollVerticallyBy() method and check if dx/dy minus the value returned by the super implementation is != 0. Then overscroll has occured.
#Override
public int scrollVerticallyBy ( int dx, RecyclerView.Recycler recycler,
RecyclerView.State state ) {
int scrollRange = super.scrollVerticallyBy(dx, recycler, state);
int overscroll = dx - scrollRange;
if (overscroll > 0) {
// bottom overscroll
} else if (overscroll < 0) {
// top overscroll
}
return scrollRange;
}
Related
I have ItemTouchHelper class that uses swiping and drag and drop for performing actions. But i want to change drag and drop behavior. It should swap positions of 2 elements, the first one I dragged and the other one where it is dropped on. i want to exchange the items of the dragged & dropped positions. not to change positions of all items among both of them.
How to do it
this is my class for drag and drop
public class ItemTouchHelper extends
androidx.recyclerview.widget.ItemTouchHelper.Callback {
private Drawable icon;
private Context context;
private ColorDrawable background;
private final ItemTouchHelperListener dragDropListener;
public ItemTouchHelper(Context context, Drawable icon,
ItemTouchHelperListener dragDropListener) {
this.icon = icon;
this.dragDropListener = dragDropListener;
this.context = context;
this.background = new ColorDrawable(context.getResources().getColor(R.color.deleteItem));
}
#Override
public void onChildDraw(#NonNull Canvas c, #NonNull RecyclerView recyclerView,
#NonNull RecyclerView.ViewHolder viewHolder,
float dX, float dY,
int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX,
dY, actionState, isCurrentlyActive);
View itemView = viewHolder.itemView;
int iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
int iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
int iconBottom = iconTop + icon.getIntrinsicHeight();
if (dX > 0) {
background = new ColorDrawable(context.getResources().getColor(R.color.deleteItem));
iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
iconBottom = iconTop + icon.getIntrinsicHeight();
int iconRight = itemView.getLeft() + iconMargin + icon.getIntrinsicWidth();
int iconLeft = itemView.getLeft() + iconMargin;
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(itemView.getLeft(), itemView.getTop(),
itemView.getLeft() + ((int) dX),
itemView.getBottom());
} else if (dX < 0) {
int iconRight = itemView.getRight() - iconMargin;
int iconLeft = itemView.getRight() - iconMargin - icon.getIntrinsicWidth();
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
background.setBounds(itemView.getRight(), itemView.getTop(),
itemView.getRight() + ((int) dX),
itemView.getBottom());
} else {
background.setBounds(0, 0, 0, 0);
icon.setBounds(0, 0, 0, 0);
}
background.draw(c);
icon.draw(c);
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder,
int direction) {
dragDropListener.deleteElementDialog(viewHolder.getAdapterPosition());
}
#Override
public int getMovementFlags(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder) {
int dragFlags = UP | DOWN;
int swipeFlags = START | END;
return makeMovementFlags(dragFlags, swipeFlags);
}
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder,
#NonNull RecyclerView.ViewHolder target) {
dragDropListener.onRowMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
#Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder,
int actionState) {
if (actionState != ACTION_STATE_IDLE && actionState != ACTION_STATE_SWIPE) {
dragDropListener.onRowSelected(viewHolder);
}
super.onSelectedChanged(viewHolder, actionState);
}
#Override
public void clearView(#NonNull RecyclerView recyclerView,
#NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, Objects.requireNonNull(viewHolder));
dragDropListener.onRowClear(Objects.requireNonNull(viewHolder));
}
#Override
public boolean isLongPressDragEnabled() {
return true;
}
}
and this is my ItemTouchHelperListener:
public void setItemTouchHelperListener() {
ItemTouchHelperListener itemTouchHelperListener = new
ItemTouchHelperListener() {
#Override
public void onRowMoved(int fromPosition, int toPosition) {
presenter.rowMoved(fromPosition, toPosition);
}
#Override
public void onRowSelected(RecyclerView.ViewHolder myViewHolder) {
if (myViewHolder instanceof ElementsAdapter.ElementsViewHolder) {
elementsAdapter.rowSelected((ElementsAdapter.ElementsViewHolder) myViewHolder);
presenter.rowSelected(myViewHolder.getAdapterPosition());
}
}
#Override
public void onRowClear(RecyclerView.ViewHolder myViewHolder) {
if (myViewHolder instanceof ElementsAdapter.ElementsViewHolder) {
elementsAdapter.rowClear((ElementsAdapter.ElementsViewHolder) myViewHolder);
presenter.rowClear(myViewHolder.getAdapterPosition());
}
}
#Override
public void deleteElementDialog(int adapterPosition) {
createDeleteDialog(adapterPosition);
}
};
You can achieve this by registering both the dragged item using onMove() method, and the dropped item using clearView() method; then modify the data source of your RecyclerView adapter; so you can use a temp item that stores the dragged item; then set the dropped-by item with the dragged one; and finally put the temp item on the dropped one.
Then utilize RecyclerView adapter notifyItemChanged() for both items to update the layout with this change
Note: here I disabled the swiping as your question mainly on the drag & drop
final int[] oldPos = new int[1];
final int[] newPos = new int[1];
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP |
ItemTouchHelper.DOWN |
ItemTouchHelper.LEFT |
ItemTouchHelper.RIGHT,
0) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
oldPos[0] = viewHolder.getAdapterPosition();
newPos[0] = target.getAdapterPosition();
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
}
#Override
public void clearView(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
moveItem(oldPos[0], newPos[0]);
}
});
private void moveItem(int oldPos, int newPos) {
Item temp = mItems.get(oldPos);
mItems.set(oldPos, mItems.get(newPos));
mItems.set(newPos, temp);
mAdapter.notifyItemChanged(oldPos);
mAdapter.notifyItemChanged(newPos);
}
The result
I totally agree with #Zain answer but there is one problem i.e suppose you want to replace the 1st item with 3rd then you will click and hold the 3rd item and drag it over the 1st item. Once you dropped, you will notice the 3rd item will get again shifted to its original position and after that, both items will get updated properly. It doesn't look good.
I've just slightly modified the #Zain answer.
private int fromPos = -1;
private int toPos = -1;
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new
ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN |
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, 0) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView,
#NonNull RecyclerView.ViewHolder viewHolder,
#NonNull RecyclerView.ViewHolder target) {
toPos = target.getAdapterPosition();
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder,
int direction) {}
#Override
public void onSelectedChange(#NonNull RecyclerView.ViewHolder
viewHolder, int actionState) {
switch(actionState){
case ItemTouchHelper.ACTION_STATE_DRAG:{
fromPos = viewHolder.getAdapterPosition();
break;
}
case ItemTouchHelper.ACTION_STATE_IDLE: {
//Execute when the user dropped the item after dragging.
if(fromPos != -1 && toPos != -1
&& fromPos != toPos) {
moveItem(fromPos, toPos);
fromPos = -1;
toPos = -1;
}
break;
}
}
private void moveItem(int oldPos, int newPos) {
Item temp = mItems.get(oldPos);
mItems.set(oldPos, mItems.get(newPos));
mItems.set(newPos, temp);
mAdapter.notifyItemChanged(oldPos);
mAdapter.notifyItemChanged(newPos);
}
I have put one recycler view in my project. I want that it will be auto-scroll horizontally. For achieving this I have made one custom class. but I also want that existing functions which I put on my recycler view will also remain.
CustomLinearLayoutManager:
public class CustomLinearLayoutManager extends LinearLayoutManager {
public CustomLinearLayoutManager (Context context) {
super(context);
}
public CustomLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public CustomLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
final LinearSmoothScroller linearSmoothScroller =
new LinearSmoothScroller(recyclerView.getContext()) {
private static final float MILLISECONDS_PER_INCH = 200f;
#Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return CustomLinearLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
#Override
protected float calculateSpeedPerPixel
(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
Home Class
private RecyclerView recyclerViewHeaderSlider;
private HeaderSliderAdapter headerSliderAdapter;
private List<Banner> banners;
banners = new ArrayList<>();
headerSliderAdapter = new HeaderSliderAdapter(getActivity(), banners);
recyclerViewHeaderSlider = view.findViewById(R.id.bannerSlider);
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerViewHeaderSlider);
recyclerViewHeaderSlider.setHasFixedSize(true);
recyclerViewHeaderSlider.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false));
headerSliderAdapter.setOnClick(this);
recyclerViewHeaderSlider.setAdapter(headerSliderAdapter);
I want to implement my custom linear layout manager with Home class.
You can use Runnable to autoscroll Horizontal RV
public void autoScroll(){
speedScroll = 0;
handler = new Handler();
runnable = new Runnable() {
int count = 0;
#Override
public void run() {
if(count == tickerAdapter.getItemCount())
count = 0;
else {
if(count < tickerAdapter.getItemCount()){
rvTicker.smoothScrollToPosition(++count);
handler.postDelayed(this,speedScroll);
}else {
count = 0;
}
}
}
};
handler.postDelayed(runnable,speedScroll);
}
I want to get vertical scrolling (one item at a time) but can't find they way to implement viewpager on my code. can anyone help me in implementing view pager on my code. I tried using Fragment for getting vertical scroll but no luck. Any help will be appreciated. Thanks in advance.
Here is my code,
MainActivity -
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
seekBar = (SeekBar) findViewById(R.id.seekBar);
songAdapter = new SongAdapter(this, _songs);
recyclerView.setAdapter(songAdapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
linearLayoutManager.getOrientation());
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.addItemDecoration(dividerItemDecoration);
songAdapter.setOnItemClickListener(new SongAdapter.OnItemClickListener() {
#Override
public void onItemClick(final Button b, View view, final SongInfo obj, int position) {
if (b.getText().equals("Stop")) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
b.setText("Play");
} else {
Runnable runnable = new Runnable() {
#Override
public void run() {
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(obj.getSongUrl());
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
seekBar.setProgress(0);
seekBar.setMax(mediaPlayer.getDuration());
Log.d("Prog", "run: " + mediaPlayer.getDuration());
}
});
b.setText("Stop");
} catch (Exception e) {
}
}
};
myHandler.postDelayed(runnable, 100);
}
}
});
checkUserPermission();
Thread t = new runThread();
t.start();
}
public class runThread extends Thread {
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d("Runwa", "run: " + 1);
if (mediaPlayer != null) {
seekBar.post(new Runnable() {
#Override
public void run() {
seekBar.setProgress(mediaPlayer.getCurrentPosition());
}
});
Log.d("Runwa", "run: " + mediaPlayer.getCurrentPosition());
}
}
}
}
private void checkUserPermission() {
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 123);
return;
}
}
//getMp3Songs();
loadSongs();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case 123:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//getMp3Songs();
loadSongs();
} else {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();
checkUserPermission();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void loadSongs() {
Uri uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
// Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Audio.Media.IS_MUSIC + "!=0";
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String url = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
Log.i("DATA111", url);
mediaMetadataRetrieve = new MediaMetadataRetriever();
mediaMetadataRetrieve.setDataSource(url);
art = mediaMetadataRetrieve.getEmbeddedPicture();
if (art != null) {
songImage = BitmapFactory.decodeByteArray(art, 0, art.length);
}
SongInfo s = new SongInfo(name, artist, url, songImage);
_songs.add(s);
} while (cursor.moveToNext());
}
cursor.close();
songAdapter = new SongAdapter(MainActivity.this, _songs);
}
}
}
SongAdapter -
private ArrayList<SongInfo> _songs = new ArrayList<SongInfo>();
private Context context;
private OnItemClickListener mOnItemClickListener;
public SongAdapter(Context context, ArrayList<SongInfo> songs) {
this.context = context;
this._songs = songs;
}
public interface OnItemClickListener {
void onItemClick(Button b, View view, SongInfo obj, int position);
}
public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mOnItemClickListener = mItemClickListener;
}
#Override
public SongHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View myView = LayoutInflater.from(context).inflate(R.layout.row_songs, viewGroup, false);
return new SongHolder(myView);
}
#Override
public void onBindViewHolder(final SongHolder songHolder, final int i) {
final SongInfo s = _songs.get(i);
songHolder.tvSongName.setText(_songs.get(i).getSongname());
songHolder.tvSongArtist.setText(_songs.get(i).getArtistname());
songHolder.tvAlbum_art.setImageBitmap(_songs.get(i).getThaImage());
songHolder.btnAction.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(songHolder.btnAction, v, s, i);
}
}
});
}
#Override
public int getItemCount() {
return _songs.size();
}
public class SongHolder extends RecyclerView.ViewHolder {
TextView tvSongName, tvSongArtist;
Button btnAction;
ImageView tvAlbum_art;
public SongHolder(View itemView) {
super(itemView);
tvSongName = (TextView) itemView.findViewById(R.id.tvSongName);
tvSongArtist = (TextView) itemView.findViewById(R.id.tvArtistName);
tvAlbum_art = (ImageView) itemView.findViewById(R.id.album_art);
btnAction = (Button) itemView.findViewById(R.id.button_action);
}
}
}
VerticalViewPager -
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
this(context, null);
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
#Override
public boolean canScrollHorizontally(int direction) {
return false;
}
#Override
public boolean canScrollVertically(int direction) {
return super.canScrollHorizontally(direction);
}
private void init() {
setPageTransformer(true, new VerticalPageTransformer());
setOverScrollMode(View.OVER_SCROLL_NEVER);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final boolean toIntercept = super.onInterceptTouchEvent(flipXY(ev));
flipXY(ev);
return toIntercept;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
final boolean toHandle = super.onTouchEvent(flipXY(ev));
flipXY(ev);
return toHandle;
}
private MotionEvent flipXY(MotionEvent ev) {
final float width = getWidth();
final float height = getHeight();
final float x = (ev.getY() / height) * width;
final float y = (ev.getX() / width) * height;
ev.setLocation(x, y);
return ev;
}
private static final class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
final int pageWidth = view.getWidth();
final int pageHeight = view.getHeight();
if (position < -1) {
view.setAlpha(0);
} else if (position <= 1) {
view.setAlpha(1);
view.setTranslationX(pageWidth * -position);
float yPosition = position * pageHeight;
view.setTranslationY(yPosition);
} else {
view.setAlpha(0);
}
}
}
}
Start with this simple example:
1) MnnnnnActivity.class:----------
public class MnnnnnActivity extends AppCompatActivity {
private VerticalViewPager vp;
private MPagerAdapter mPagerAdapter;
private int lastPage = 0;
private List<String> songs = new ArrayList<String>();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout5);
vp = (VerticalViewPager) findViewById(R.id.vp);
for(int i = 0 ; i<10 ; i++){
songs.add(i , "song " + i);
}
mPagerAdapter = new MPagerAdapter(getApplicationContext(), songs);
vp.setAdapter(mPagerAdapter);
vp.setOffscreenPageLimit(1);
vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if(lastPage > position){ //left
}else{ // right
}
lastPage = position;
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
}
2) MPagerAdapter.class:-----
public class MPagerAdapter extends PagerAdapter {
private Context mContext;
private List<String> songs = new ArrayList<String>();
public MPagerAdapter(Context context , List<String> songs) {
mContext = context;
this.songs = songs;
}
#Override
#NonNull
public Object instantiateItem(#NonNull final ViewGroup collection, final int position) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View layout = (View) inflater.inflate(R.layout.layout_list, collection, false);
TextView tv = (TextView) layout.findViewById(R.id.tv_song);
tv.setText(songs.get(position));
Button b = (Button) layout.findViewById(R.id.b_song);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(mContext , "Play " + songs.get(position) , Toast.LENGTH_LONG).show();
}
});
collection.addView(layout);
return layout;
}
#Override
public void destroyItem(ViewGroup collection, int position, Object view) {
collection.removeView((View) view);
}
#Override
public int getCount() {
return songs.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public CharSequence getPageTitle(int position) {
return songs.get(position);
}
}
3) VerticalViewPager.class:-------
//https://stackoverflow.com/questions/13477820/android-vertical-viewpager
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(Context context) {
super(context);
init();
}
public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
setPageTransformer(true, new VerticalPageTransformer());
setOverScrollMode(OVER_SCROLL_NEVER);
}
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev);
//https://stackoverflow.com/questions/15365915/viewpager-nested-in-viewpager
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
this.getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_DOWN:
this.getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
this.getParent().requestDisallowInterceptTouchEvent(true);
break;
}
return intercepted;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
4) VerticalPageTransformer.class:-----------
//https://stackoverflow.com/questions/13477820/android-vertical-viewpager
public class VerticalPageTransformer implements ViewPager.PageTransformer {
#Override
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(pageWidth * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
5) layout5.xml:--------
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.admin.accessories.VerticalViewPager
android:id="#+id/vp"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.admin.accessories.VerticalViewPager>
</android.support.constraint.ConstraintLayout>
6) layout_list.xml:--------
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:text="SName"
android:layout_marginBottom="20dp"
android:id="#+id/tv_song"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Play"
android:id="#+id/b_song"/>
</LinearLayout>
7) Output:---------
Simple solution is try rotating viewpager and its child view
mViewPager.setRotation(90);
It will rotate view pager and it's child views as well. Now rotate child view again in opposite direction.
childView.setRotation(270);
I have a RecyclerView holding CardViews with a favorite button within each card. I would like the favorite button to only be clicked for each specific card. I am currently using a ViewHolder to maintain each of the components in each card and the favorite button is one of those components.
How can I use an onClick() defined in a separate class within the ViewHolder?
Using this code currently only actives the onTouchEvent() for the favoriteButton
viewHolder.favoriteButton.setOnClickListener(new LikeButtonView(mContext));
AppAdapter.java
public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> {
PackageManager packageManager;
private List<App> apps;
private int rowLayout;
private Context mContext;
public AppAdapter(List<App> apps, int rowLayout, Context context) {
this.apps = apps;
this.rowLayout = rowLayout;
this.mContext = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
packageManager = this.mContext.getPackageManager();
View v = LayoutInflater.from(viewGroup.getContext()).inflate(rowLayout, viewGroup, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
App appObject = apps.get(i);
viewHolder.appName.setText(appObject.getApplicationName());
viewHolder.versionNumber.setText(String.valueOf(appObject.getVersionNumber()));
viewHolder.updateDate.setText(String.valueOf(appObject.getLastUdpateTime()));
viewHolder.appIcon.setImageDrawable(appObject.getAppIcon());
viewHolder.appChangelog.setText(appObject.getChangelogText());
viewHolder.favoriteButton.setOnClickListener(new LikeButtonView(mContext));
}
LikeButtonView.java
public class LikeButtonView extends FrameLayout implements View.OnClickListener {
private static final DecelerateInterpolator DECCELERATE_INTERPOLATOR = new DecelerateInterpolator();
private static final AccelerateDecelerateInterpolator ACCELERATE_DECELERATE_INTERPOLATOR = new AccelerateDecelerateInterpolator();
private static final OvershootInterpolator OVERSHOOT_INTERPOLATOR = new OvershootInterpolator(4);
#Bind(R.id.ivStar)
ImageView ivStar;
private boolean isChecked;
private AnimatorSet animatorSet;
public LikeButtonView(Context context) {
super(context);
init();
}
public LikeButtonView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LikeButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public LikeButtonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
LayoutInflater.from(getContext()).inflate(R.layout.view_like_button, this, true);
ButterKnife.bind(this);
setOnClickListener(this);
}
#Override
public void onClick(View v) {
isChecked = !isChecked;
ivStar.setImageResource(isChecked ? R.drawable.ic_star_rate_on : R.drawable.ic_star_rate_off);
if (animatorSet != null) {
animatorSet.cancel();
}
if (isChecked) {
ivStar.animate().cancel();
ivStar.setScaleX(0);
ivStar.setScaleY(0);
animatorSet = new AnimatorSet();
ObjectAnimator starScaleYAnimator = ObjectAnimator.ofFloat(ivStar, ImageView.SCALE_Y, 0.2f, 1f);
starScaleYAnimator.setDuration(350);
starScaleYAnimator.setStartDelay(0);
starScaleYAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR);
ObjectAnimator starScaleXAnimator = ObjectAnimator.ofFloat(ivStar, ImageView.SCALE_X, 0.2f, 1f);
starScaleXAnimator.setDuration(350);
starScaleXAnimator.setStartDelay(0);
starScaleXAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR);
animatorSet.playTogether(
starScaleYAnimator,
starScaleXAnimator
);
animatorSet.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationCancel(Animator animation) {
ivStar.setScaleX(1);
ivStar.setScaleY(1);
}
});
animatorSet.start();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
ivStar.animate().scaleX(0.7f).scaleY(0.7f).setDuration(150).setInterpolator(DECCELERATE_INTERPOLATOR);
setPressed(true);
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
boolean isInside = (x > 0 && x < getWidth() && y > 0 && y < getHeight());
if (isPressed() != isInside) {
setPressed(isInside);
}
break;
case MotionEvent.ACTION_UP:
ivStar.animate().scaleX(1).scaleY(1).setInterpolator(DECCELERATE_INTERPOLATOR);
if (isPressed()) {
performClick();
setPressed(false);
}
break;
}
return true;
}
}
I'm trying to create a custom preference for an Android application that limits the number of items the user can select. Once the limit is reached the unselected items should be disabled and only the currently selected items are enabled.. If there are less items selected than the limit all items should be enabled.
Here are the two classes I've cobbled together. The code runs fine but no the CheckedTextView is not checked. As a result no state is maintained.
First the view class...
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.ListView;
public class LimitedMultiChoiceView extends ListView
implements AdapterView.OnItemClickListener
{
private static final String SEPARATOR = "OV=I=XseparatorX=I=VO";
private static final String LIMITEDSELECTION="limitedSelection";
private static final String SUPERSTATE="superState";
private String mSelection = "";
public LimitedMultiChoiceView(Context context, CharSequence[] items, int limit)
{
this(context, null, 0, items, limit);
} // LimitedMultiChoiceView(Context context)
public LimitedMultiChoiceView(Context context, AttributeSet attrs, CharSequence[] items, int limit)
{
this(context, attrs, 0, items, limit);
} // LimitedMultiChoiceView(Context context, AttributeSet attrs)
public LimitedMultiChoiceView(Context context, AttributeSet attrs
, int defStyle, CharSequence[] items, int limit)
{
super(context, attrs, defStyle);
setAdapter(new ItemAdapter(context, android.R.layout.simple_list_item_multiple_choice, items, limit));
} // LimitedMultiChoiceView(Context context, AttributeSet attrs, int defStyle)
public String getSelection()
{
return mSelection;
} // String getSelection()
public void onItemClick(AdapterView<?> parent, View child, int position, long id)
{
// For now we don't need anything...
// we think the ItemAdapter manages what we need for each item.
} // void onItemClick(AdapterView<?> parent, View child, int position, long id)
#Override
public void onRestoreInstanceState(Parcelable toParce)
{
Bundle state=(Bundle)toParce;
super.onRestoreInstanceState(state.getParcelable(SUPERSTATE));
mSelection = state.getString(LIMITEDSELECTION);
} // void onRestoreInstanceState(Parcelable toParce)
#Override
public Parcelable onSaveInstanceState()
{
Bundle state=new Bundle();
state.putParcelable(SUPERSTATE, super.onSaveInstanceState());
state.putString(LIMITEDSELECTION, mSelection);
return(state);
} // Parcelable onSaveInstanceState()
public void setSelection(String value)
{
mSelection = value;
} // void setSelection(String value)
class ItemAdapter extends ArrayAdapter<CharSequence>
{
CharSequence[] mItems = null;
int mLimit = 1;
public ItemAdapter(Context context, int viewResId, CharSequence[] items, int limit)
{
super(context, viewResId, items);
mItems = items;
mLimit = limit;
} // ItemAdapter(Context context, int viewResId, CharSequence[] strings, int limit)
public boolean areAllItemsEnabled()
{
// Since we are in a limited selection list not all items can be
// selected so this always returns false, there is no calculating
// to do.
return false;
} // boolean areAllItemsEnabled()
public boolean isEnabled(int position)
{
boolean[] clickedIndexes = new boolean[this.getCount()];
boolean result = false;
int selectedCount = 0;
mSelection = "";
for (int item=0; item < clickedIndexes.length; item++ )
{
View itemView = this.getView(item, null, LimitedMultiChoiceView.this);
if (itemView instanceof CheckedTextView)
{
CheckedTextView check = (CheckedTextView)itemView;
// First we turn the check mark on or off...
if (item == position)
{
check.setChecked(!check.isChecked());
} // (item == position)
// Now we count how many are checked and mark our tracking array
if (check.isChecked())
{
clickedIndexes[item] = true;
mSelection += check.getText() + SEPARATOR;
}
else
{
clickedIndexes[item] = false;
} // (check.isChecked())
} // (itemView instanceof CheckedTextView)
if (clickedIndexes[item])
selectedCount++;
} // (int item=0; item< clickedIndexes.length; item++ )
if (selectedCount >= mLimit)
{
if (clickedIndexes[position])
{
result = true;
}
else
{
result = false;
} // (clickedIndexes[position])
}
else
{
result = true;
} // (selectedCount >= mLimit)
return result;
} // boolean isEnabled(int position)
} // class ItemAdapter extends ArrayAdapter<CharSequence>
} // class LimitedMultiChoiceView extends ListView
This is the preference class...
import android.content.Context;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.view.View;
public class ListPreferenceLimitedMultiSelect extends ListPreference
{
int mLimit = 3;
LimitedMultiChoiceView mList = null;
String mSelection = "";
public ListPreferenceLimitedMultiSelect(Context context)
{
this(context, null);
} // ListPreferenceLimitedMultiSelect(Context context)
public ListPreferenceLimitedMultiSelect(Context context, AttributeSet attr)
{
super(context, attr);
} // ListPreferenceLimitedMultiSelect(Context context, AttributeSet attr)
#Override
protected void onBindDialogView(View v)
{
super.onBindDialogView(v);
mList.setSelection(mSelection);
} // void onBindDialogView(View v)
#Override
protected View onCreateDialogView()
{
mList = new LimitedMultiChoiceView(getContext()
, this.getEntries(), mLimit);
return(mList);
} // View onCreateDialogView()
#Override
protected void onDialogClosed(boolean positiveResult)
{
super.onDialogClosed(positiveResult);
if (positiveResult)
{
if (callChangeListener(mList.getSelection()))
{
mSelection = mList.getSelection();
persistString(mSelection);
} // (callChangeListener(mList.getSelection()))
} // (positiveResult)
} // void onDialogClosed(boolean positiveResult)
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue)
{
mSelection =(restoreValue ? getPersistedString(mSelection) : (String)"");
} // void onSetInitialValue(boolean restoreValue, Object defaultValue)
} // class ListPreferenceLimitedMultiSelect extends ListPreference
Thanks,
\ ^ / i l l