- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我在我的项目中使用了Vertical Viewpager
。
但也有一些问题,
当页面有很多 onclick() 事件时,滚动太费力
fling 事件不会改变页面
我尝试使用手势检测器,但它在没有转换的情况下更改页面的速度太快(没有调用 transformPage())
当我滚动页面时,有时也会触发 onclick() 事件
所以我决定在 PagerSnapHelper
的帮助下将 Recyclerview 用作 Viewpager
。
它工作正常。但问题是,
how to do the transition or animation when the item is changed (like I did in ViewPager)
例如,Viewpager 中的 Zoomout 过渡或堆栈过渡。
我试过了 stackLayoutManager但滚动并尝试此操作需要更多时间 related link .它不起作用。
我研究了如何降低 viewpager 的滚动速度 和如何在 recyclerview 中制作动画。我没有得到解决方案。
谁能帮帮我!!!是否可能,或者我需要使用任何其他小部件。
我尝试了#ADM 的建议,效果很好,但是 doesn't support PagerSnapHelper.
我在上面的链接中更改了堆栈布局管理器,但它不支持 scrollToPosition() 和 PagerSnapHelper。
代码:
public class StackLayoutManager extends LinearLayoutManager {
private static final String TAG = "StackLayoutManager";
//the space unit for the stacked item
private int mSpace = 0;
/**
* the offset unit,deciding current position(the sum of {@link #mItemWidth} and {@link #mSpace})
*/
private int mUnit;
//item width
private int mItemWidth;
private int mItemHeight;
//the counting variable ,record the total offset including parallex
private int mTotalOffset;
//record the total offset without parallex
private int mRealOffset;
private ObjectAnimator animator;
private int animateValue;
private RecyclerView.Recycler recycler;
private int lastAnimateValue;
private int initialOffset;
private boolean initial;
private int mMinVelocityX;
private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
private int pointerId;
private Method sSetScrollState;
RecyclerView recyclerView;
public StackLayoutManager(Context context) {
super(context, VERTICAL, false);
setAutoMeasureEnabled(true);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
this.recycler = recycler;
detachAndScrapAttachedViews(recycler);
//got the mUnit basing on the first child,of course we assume that all the item has the same size
View anchorView = recycler.getViewForPosition(0);
measureChildWithMargins(anchorView, View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
mItemWidth = anchorView.getMeasuredWidth();
mItemHeight = getDecoratedMeasuredHeight(anchorView);
mUnit = mItemHeight;
//because this method will be called twice
initialOffset = mUnit;
mMinVelocityX = ViewConfiguration.get(anchorView.getContext()).getScaledMinimumFlingVelocity();
fill(recycler, 0);
}
@Override
public void onLayoutCompleted(RecyclerView.State state) {
super.onLayoutCompleted(state);
if (!initial) {
fill(recycler, initialOffset, false);
initial = true;
}
}
@Override
public void onAdapterChanged(RecyclerView.Adapter oldAdapter, RecyclerView.Adapter newAdapter) {
initial = false;
mTotalOffset = mRealOffset = 0;
}
private int fill(RecyclerView.Recycler recycler, int dy, boolean apply) {
return fillFromTop(recycler, dy);
}
public int fill(RecyclerView.Recycler recycler, int dy) {
return fill(recycler, dy, true);
}
private int fillFromTop(RecyclerView.Recycler recycler, int dy) {
if (mTotalOffset + dy < 0 || (mTotalOffset + dy + 0f) / mUnit > getItemCount() - 1)
return 0;
detachAndScrapAttachedViews(recycler);
mTotalOffset += dy;
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (recycleVertically(child, dy))
removeAndRecycleView(child, recycler);
}
int curPos = mTotalOffset / mUnit;
int leavingSpace = getHeight() - (left(curPos) + mUnit);
int itemCountAfterBaseItem = leavingSpace / mUnit + 2;
int e = curPos + itemCountAfterBaseItem;
int start = curPos - 1 >= 0 ? curPos - 1 : 0;
int end = e >= getItemCount() ? getItemCount() - 1 : e;
int left = getWidth() / 2 - mItemWidth / 2;
//layout views
for (int i = start; i <= end; i++) {
View view = recycler.getViewForPosition(i);
float alpha = alpha(i);
addView(view);
measureChildWithMargins(view, 0, 0);
int top = (left(i) /* - ( 1 - scale ) * view.getMeasuredHeight() */ );
int right = view.getMeasuredWidth() + left;
int bottom = view.getMeasuredHeight() + top;
layoutDecoratedWithMargins(view, left, top, right, bottom);
view.setAlpha(alpha);
view.setScaleY(1);
view.setScaleX(1);
}
return dy;
}
private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mVelocityTracker.addMovement(event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (animator != null && animator.isRunning())
animator.cancel();
pointerId = event.getPointerId(0);
}
if (event.getAction() == MotionEvent.ACTION_UP) {
if (v.isPressed())
v.performClick();
mVelocityTracker.computeCurrentVelocity(1000, 14000);
float xVelocity = mVelocityTracker.getYVelocity(pointerId);
int o = mTotalOffset % mUnit;
int scrollX;
if (Math.abs(xVelocity) < mMinVelocityX && o != 0) {
if (o >= mUnit / 2)
scrollX = mUnit - o;
else
scrollX = -o;
Log.d("scrollx","from scroll");
Log.d("scrollx", "" + scrollX);
brewAndStartAnimator(300, (int) (scrollX));
}
}
return false;
}
};
private RecyclerView.OnFlingListener mOnFlingListener = new RecyclerView.OnFlingListener() {
@Override
public boolean onFling(int velocityX, int velocityY) {
int o = mTotalOffset % mUnit;
int s = mUnit - o;
int scrollX;
int vel = absMax(velocityX, velocityY);
if (vel > 0) {
scrollX = s;
} else
scrollX = -o;
Log.d("scrollx","from fling");
Log.d("scrollx",""+scrollX);
brewAndStartAnimator(100, scrollX);
// setScrollStateIdle();
return true;
}
};
private int absMax(int a, int b) {
if (Math.abs(a) > Math.abs(b))
return a;
else return b;
}
@Override
public void onAttachedToWindow(RecyclerView view) {
super.onAttachedToWindow(view);
this.recyclerView=view;
view.setOnTouchListener(mTouchListener);
view.setOnFlingListener(mOnFlingListener);
}
private void brewAndStartAnimator(int dur, int finalX) {
animator = ObjectAnimator.ofInt(StackLayoutManager.this, "animateValue", 0, finalX);
animator.setDuration(dur);
animator.start();
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
lastAnimateValue = 0;
recyclerView.scrollToPosition(findFirstCompletelyVisibleItemPosition());
}
@Override
public void onAnimationCancel(Animator animation) {
lastAnimateValue = 0;
recyclerView.smoothScrollToPosition(findFirstCompletelyVisibleItemPosition());
}
});
}
private float alpha(int position) {
float alpha;
int curPos = mTotalOffset / mUnit;
float n = (mTotalOffset + .0f) / mUnit;
if (position > curPos)
alpha = 1.0f;
else {
alpha = 1 - (n - position) / 1;
}
return alpha <= 0.001f ? 0 : alpha;
}
@Override
public void scrollToPosition(int pos)
{
scrollToPositionWithOffset(pos, 0);
}
private int left(int position) {
int curPos = mTotalOffset / mUnit;
int tail = mTotalOffset % mUnit;
float n = (mTotalOffset + .0f) / mUnit;
float x = n - curPos;
return ltr(position, curPos, tail, x);
}
private int ltr(int position, int curPos, int tail, float x) {
int left;
if (position <= curPos) {
if (position == curPos) {
left = (int) (mSpace * (1 - x));
} else {
left = (int) (mSpace * (1 - x - (curPos - position)));
}
} else {
if (position == curPos + 1)
left = mSpace + mUnit - tail;
else {
int baseStart = (int) (mUnit + mUnit);
left = (int) (baseStart + (position - curPos - 2) * mUnit - (position - curPos - 2) * (mUnit));
if (BuildConfig.DEBUG)
Log.i(TAG, "ltr: curPos " + curPos + " pos:" + position + " left:" + left + " baseStart" + baseStart + " curPos+1:" + left(curPos + 1));
}
left = left <= 0 ? 0 : left;
}
return left;
}
@SuppressWarnings("unused")
public void setAnimateValue(int animateValue) {
this.animateValue = animateValue;
int dy = this.animateValue - lastAnimateValue;
fill(recycler, dy, false);
lastAnimateValue = animateValue;
}
@SuppressWarnings("unused")
public int getAnimateValue() {
return animateValue;
}
private boolean recycleVertically(View view, int dy) {
return view != null && (view.getTop() - dy < 0 || view.getBottom() - dy > getHeight());
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
return fill(recycler, dy);
}
@Override
public boolean canScrollHorizontally() {
return false;
}
@Override
public boolean canScrollVertically() {
return true;
}
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.MATCH_PARENT);
}
@SuppressWarnings("unused")
public interface CallBack {
float scale(int totalOffset, int position);
float alpha(int totalOffset, int position);
float left(int totalOffset, int position);
}
}
如果 recyclerview 无法实现,请帮助我如何处理 VerticalViewPager。我试过设置字段值,但它不起作用。
try {
Class cls = this.getClass().getSuperclass();
Field distanceField = cls.getDeclaredField("mFlingDistance");
distanceField.setAccessible(true);
distanceField.setInt(this, distanceField.getInt(this)/2);
}catch (Exception ignored) {
Log.d("error", ignored.toString());
}
try {
Class cls = this.getClass().getSuperclass();
Field minVelocityField = cls.getDeclaredField("mMinimumVelocity");
minVelocityField.setAccessible(true);
minVelocityField.setInt(this, minVelocityField.getInt(this) /2);
} catch (Exception ignored) {
Log.d("error", ignored.toString());
}
try {
Class cls = this.getClass().getSuperclass();
Field maxVelocityField = cls.getDeclaredField("mMaximumVelocity");
maxVelocityField.setAccessible(true);
maxVelocityField.setInt(this, maxVelocityField.getInt(this)/2);
}catch (Exception ignored) {
Log.d("error", ignored.toString());
}
最佳答案
试试这个
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import java.util.ArrayList;
import android.support.animation.DynamicAnimation;
import android.support.animation.FlingAnimation;
public class MainActivity extends AppCompatActivity {
CustomVerticalViewPager viewPager;
ArrayList<DataModel> arrayList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArray();
viewPager = findViewById(R.id.viewPager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
FlingAnimation fling = new FlingAnimation(viewPager, DynamicAnimation.SCROLL_X);
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
CustomAdapter adapter = new CustomAdapter(this, arrayList);
viewPager.setAdapter(adapter);
}
private void initArray() {
for (int i = 0; i < 10; i++) {
DataModel dataModel = new DataModel();
dataModel.setTitle("Title item No :- " + i);
dataModel.setContent(" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras auctor blandit dignissim. Suspendisse id lorem nulla. Proin urna lacus, posuere sed lacus a, dapibus consectetur neque. Donec in metus sagittis, consequat tellus eget, consequat ex. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec dui nisi, scelerisque eu nunc id, aliquet sagittis leo. Nunc ac ornare diam. Vestibulum sed elit euismod, ornare metus a, convallis ipsum. Nulla aliquam mi enim, porttitor commodo lacus dictum cursus. Phasellus sed eros sagittis, feugiat sapien ac, accumsan odio. In posuere congue lorem, quis pharetra mi tincidunt et. Nam tincidunt erat eu dapibus faucibus.\n" +
"\n");
arrayList.add(dataModel);
}
}
}
LAYOUT
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">
<com.example.nilesh.testapp.CustomVerticalViewPager
android:layout_width="match_parent"
android:id="@+id/viewPager"
android:layout_height="match_parent" />
</LinearLayout>
CustomVerticalViewPager
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class CustomVerticalViewPager extends ViewPager {
private GestureDetector gestureDetector;
public boolean isScrollEvent;
public CustomVerticalViewPager(Context context) {
super(context);
init();
}
public CustomVerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
gestureDetector=new GestureDetector(getContext(),new GestureListener());
setPageTransformer(true, new VerticalPageTransformer());
setOverScrollMode(OVER_SCROLL_NEVER);
try {
Field mScroller;
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
FixedSpeedScroller scroller = new FixedSpeedScroller(getContext(), new DecelerateInterpolator());
scroller.setScrollDuration(250);
mScroller.set(this, scroller);
} catch (Exception e) {}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return gestureDetector.onTouchEvent((ev));
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean res= gestureDetector.onTouchEvent((ev));
if((ev.getAction() == MotionEvent.ACTION_CANCEL ||ev.getAction()==MotionEvent.ACTION_UP)) {
if(isScrollEvent) {
try {
endFakeDrag();
} catch (Exception e) {}
}
return true;
}
// Log.d("event", "ontouch " + res);
return res;
}
private class FixedSpeedScroller extends Scroller {
private int mDuration = 500;
public FixedSpeedScroller(Context context) {
super(context);
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
public void setScrollDuration(int duration) {
mDuration = duration;
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, mDuration);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy) {
super.startScroll(startX, startY, dx, dy, mDuration);
}
}
private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
isScrollEvent=false;
// Log.d("touch","singletap");
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// Log.d("touch","fling");
isScrollEvent=false;
try {
float diffY = e2.getY() - e1.getY();
if (diffY > 20) {
onSwipeDown();
return false;
} else if(diffY<-20){
onSwipeUp();
return false;
}
else
{
endFakeDrag();
}
} catch (Exception exception) {
exception.printStackTrace();
}
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// Log.d("touch", "scroll" + " " + distanceX);
beginFakeDrag();
fakeDragBy(-distanceY);
isScrollEvent=true;
return true;
}
}
public void onSwipeUp() {
setCurrentItem(getCurrentItem() + 1);
}
public void onSwipeDown() {
setCurrentItem(getCurrentItem() - 1);
}
}
CustomAdapter
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class CustomAdapter extends PagerAdapter {
Context context;
ArrayList<DataModel> arrayList = new ArrayList<>();
LayoutInflater mLayoutInflater;
public CustomAdapter(Context context, ArrayList<DataModel> arrayList) {
this.context = context;
this.arrayList = arrayList;
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return arrayList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == ((LinearLayout) object);
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
View itemView = mLayoutInflater.inflate(R.layout.custom_layout, container, false);
TextView tvTitle = itemView.findViewById(R.id.tvTitle);
TextView tvContent = itemView.findViewById(R.id.tvContent);
tvContent.setText(arrayList.get(position).getContent());
tvTitle.setText(arrayList.get(position).getTitle());
tvTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "clicked position :" + position + " " + arrayList.get(position).getTitle(), Toast.LENGTH_SHORT).show();
}
});
container.addView(itemView);
return itemView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((LinearLayout) object);
}
}
DataModel
public class DataModel {
String title, content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
custom_layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="Nilesh"
android:textColor="#000"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvContent"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
希望对你有帮助
对于 throw 效果使用 Move views using a fling animation
Fling-based animation uses a friction force that is proportional to an object's velocity. Use it to animate a property of an object and want to end the animation gradually. It has an initial momentum, which is mostly received from the gesture velocity, and gradually slows down. The animation comes to an end when the velocity of the animation is low enough that it makes no visible change on the device screen.
关于android - 如何像垂直 Viewpager 变换一样为 RecyclerView 设置动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50147206/
我目前面临将 ViewPager 放入另一个 ViewPager 中的问题,两者都可滑动。我成功创建了我的第一个 ViewPager,它包含三个页面,中间一个是第二个(内部)ViewPager,其中包
在我的主要 Activity 中,我有一个水平 viewpager。在 viewpager 的一个 fragment 中,我有另一个垂直 viewpager。两者都很好。但是对于水平 viewpage
我想创建一个 ViewPager(包含三个项目),其中每个 View 都是另一个 ViewPager(包含两个项目)。用户然后像这样滑动项目: ViewPager1[0] ViewPager2[0]
如何修复这个错误 setupWithViewPager(android.support.v4.view.ViewPager) in TabLayout cannot br applied to (an
我有一个包含 3 张图片的数组的 viewPage,我想在缩放其中一张时锁定 viewPager,因为当我在右侧滚动时,会出现下一张照片!这是我的代码 enter code here public
我是第一次实现 ViewPager,我遇到了一些问题,因为我收到以下错误: 06-20 10:40:51.366 11377-11377/com.example.ruelas.elite E/Andr
我真的是 android 的新手,如果对我的类(class)作业有任何帮助,我将不胜感激。 我需要做的: 1) 在一个 Activity 中有两个 ViewPagers(未嵌套) 2)两个ViewPa
我正在自定义我的 Android 应用程序以在四个方向上滑动,我正在使用 ViewPager 水平 和 VerticalViewPager 滑动垂直滑动(这就像对 DirectionalViewPag
我需要为平板电脑创建一个 ViewPager,在平板电脑的左侧会有导航按钮供用户选择。例如。 左侧导航将有 4 个图像按钮,每个项目将用户带到不同的教程。每个图像按钮都会加载一个 ViewPager。
我用过Vertical Viewpager在我的显示数据集合的项目中。在单个数据(项目)中,我有更多图像要显示。所以我尝试使用 viewpager。 但是当我水平滚动时,它会阻止垂直 Viewpage
我有一个父级 ViewPager,它的每个页面都包含一个子级 ViewPager。子 ViewPager 可能包含一个 ListView 或一个垂直的 ScrollView。我想将子级 ViewPag
我的任务是创建一个非常不正统的布局,只能通过另一个 viewpager 的第二个 Pane 内的 viewpager 来完成,幸运的是外部 viewpager 需要被锁定所以任务更现实一些,但是意外的
目标是根据屏幕方向(纵向或横向)以不同的布局在屏幕上显示两个 fragment ( fragment A、 fragment B)。 当设备处于纵向模式时,一次仅显示 Frag A 和 Frag B
我想禁用父 viewpager 中的子 viewpager 的滑动。 我目前使用这个自定义子 viewpager public class CustomViewPager extends ViewPa
我有两个 ViewPager - 一个在另一个下面。现在客户希望我们添加扩展底部 ViewPager(具有三个 ListView)以覆盖顶部 ViewPager 的可能性。当我将两个 ViewPage
我用谷歌搜索了这个问题很多天。找到一个解决方案,在Viewpager的开头和结尾添加一个空白View。当viewpager.getcurrentItem()==0时,则重新指向1。在我看来这种做法非常
我从适配器设置标题后,标题未出现在 PagerTabStrip 中 这是我的 Activity public class MainActivity extends AppCompatActivity
我有一个 ViewPager,其中包含多个 TextView,它们具有不同的字体大小。此外,我还获得了增加/减少字体大小的按钮,通过添加其默认大小加上一个名为 STEP 的值(该值通过 inc/dec
我有一个嵌套的 ViewPager,效果非常好。唯一的问题是,一旦子 ViewPager 位于最后一项并且我进一步滚动,父 ViewPager 就会滚动。我不想要这种行为。 我如何实现这一目标? 这是
我想显示一个带有滑动抽屉的 Viewpager。Viewpager 用于滚动图像,我想在该 viewpager 的顶部放置一个滑动抽屉(从顶部到按钮)。 我附上了我的示例代码。如果您对如何实现此屏幕有
我是一名优秀的程序员,十分优秀!