自定义温度控制控件
百度的自定义控件
package com.learn.navigationdemo;
import static com.learn.navigationdemo.Util.dpToPx;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class MPickerView extends View {
private static final String TAG = MPickerView.class.getSimpleName();
public static final float SPEED = 5;
/**
* 行距与mTextSizeNormal之比,保证View内显示的内容在适当的位置
*/
private final float RATE = 2.7f;
private final Paint mPaintNormal;
private final Paint mPaintSelect;
private final Paint mPaintText;
private final Paint mPaintLine;
private float mTextSizeNormal;
private float mTextSizeSelect;
private final float mTextAlphaSelect;
private final float mTextAlphaNormal;
private float mPaddingStart;
private float mPaddingEnd;
/**
* 选中的位置
*/
private int mSelectPosition;
/**
* 开始触摸的位置
*/
private float mStartTouchY;
/**
* 手指滑动的距离
*/
private float mMoveDistance;
private int mWidth;
private int mHeight;
private String mText;
private final Timer mTimer;
private MTimerTask mTask;
private final Handler mHandler;
private final Context mContext;
private final List<String> mData;
private final Resources mResources;
private OnSelectListener mOnSelectListener;
public MPickerView(Context context) {
this(context, null);
}
public MPickerView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
mResources = mContext.getResources();
mPaintNormal = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintSelect = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintText = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintNormal.setTextAlign(Paint.Align.CENTER);
mPaintSelect.setTextAlign(Paint.Align.CENTER);
mPaintNormal.setTextSize(mTextSizeNormal);
mPaintSelect.setTextSize(mTextSizeSelect);
mPaintText.setTextSize(dpToPx(context, 15));
mPaintSelect.setColor(0xffa000);
mPaintNormal.setColor(0xa2a2a2);
mPaintText.setColor(mResources.getColor(R.color.colorPickViewDefaultSelect));
mPaintLine.setColor(mContext.getResources().getColor(R.color.colorDivider));
mPaintLine.setStrokeWidth(dpToPx(context, 0.5f));
mHandler = new MHandler(this);
mData = new ArrayList<>();
mTimer = new Timer();
mTextAlphaSelect = 255;
mTextAlphaNormal = 120;
}
public void setOnSelectListener(OnSelectListener onSelectListener) {
this.mOnSelectListener = onSelectListener;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
mTextSizeSelect = mResources.getDisplayMetrics().density * 70 / 3;
mTextSizeNormal = mTextSizeSelect / 2f;
// 默认宽高
mPaintSelect.setTextSize(mTextSizeSelect);
mPaintNormal.setTextSize(mTextSizeNormal);
int mDefaultWidth = (int) (mPaintSelect.measureText("0000") + mPaintText.measureText("℃") * 2);
Paint.FontMetricsInt mAnIntSelect = mPaintSelect.getFontMetricsInt();
Paint.FontMetricsInt mAnIntNormal = mPaintNormal.getFontMetricsInt();
int mDefaultHeight = mAnIntSelect.bottom - mAnIntSelect.top + (mAnIntNormal.bottom - mAnIntNormal.top) * 4;
if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT &&
getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
setMeasuredDimension(mDefaultWidth, mDefaultHeight);
} else if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
setMeasuredDimension(mDefaultWidth, heightSize);
} else if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
setMeasuredDimension(widthSize, mDefaultHeight);
}
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaddingStart = getPaddingStart();
mPaddingEnd = getPaddingEnd();
// 绘制中间位置
draw(canvas, 1, 0, mPaintSelect);
// 绘制上方数据
for (int i = 1; i < mSelectPosition - 2; i++) {
draw(canvas, -1, i, mPaintNormal);
}
// 绘制下方数据
for (int i = 1; (mSelectPosition + i) < mData.size() - 2; i++) {
draw(canvas, 1, i, mPaintNormal);
}
invalidate();
}
private void draw(Canvas canvas, int type, int position, Paint paint) {
float space = RATE * mTextSizeNormal * position + type * mMoveDistance;
float scale = parabola(mHeight / 4.0f, space);
float size = (mTextSizeSelect - mTextSizeNormal) * scale + mTextSizeNormal;
int alpha = (int) ((mTextAlphaSelect - mTextAlphaNormal) * scale + mTextAlphaNormal);
paint.setTextSize(size);
paint.setAlpha(alpha);
float x = mWidth / 2.0f;
float y = mHeight / 2.0f + type * space;
Paint.FontMetricsInt fmi = paint.getFontMetricsInt();
float baseline = y + (fmi.bottom - fmi.top) / 2.0f - fmi.descent - 2;
float width = mPaintText.measureText("℃");
if (position == 0) {
canvas.drawText(mData.get(mSelectPosition) + "℃", x - width / 2 + mPaddingStart - mPaddingEnd, baseline, paint);
} else {
canvas.drawText(mData.get(mSelectPosition + type * position), x - width / 2 + mPaddingStart - mPaddingEnd, baseline, paint);
}
}
private float parabola(float zero, float x) {
float y = (float) (1 - Math.pow(x / zero, 2));
return y < 0 ? 0 : y;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mStartTouchY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
mMoveDistance += (event.getY() - mStartTouchY);
if (mMoveDistance > RATE * mTextSizeNormal / 2) {
// 向下滑动
moveTailToHead();
mMoveDistance = mMoveDistance - RATE * mTextSizeNormal;
} else if (mMoveDistance < -RATE * mTextSizeNormal / 2) {
// 向上滑动
moveHeadToTail();
mMoveDistance = mMoveDistance + RATE * mTextSizeNormal;
}
mStartTouchY = event.getY();
invalidate();
break;
case MotionEvent.ACTION_UP:
if (Math.abs(mMoveDistance) < 0.0001) {
mMoveDistance = 0;
return true;
}
if (mTask != null) {
mTask.cancel();
mTask = null;
}
mTask = new MTimerTask(mHandler);
mTimer.schedule(mTask, 0, 10);
}
return true;
}
public void setData(@NonNull List<String> data) {
if (mData != null) {
mData.clear();
mData.addAll(data);
mSelectPosition = data.size() / 2;
}
}
public void increaseData() {
setSelectPosition(mSelectPosition + 1);
}
public void decreaseData() {
setSelectPosition(mSelectPosition - 1);
}
public void setText(String mText) {
this.mText = mText;
}
private void moveHeadToTail() {
if (mData.size() > 0) {
String head = mData.get(0);
mData.remove(0);
mData.add(head);
}
}
private void moveTailToHead() {
if (mData.size() > 0) {
String tail = mData.get(mData.size() - 1);
mData.remove(mData.size() - 1);
mData.add(0, tail);
}
}
private void setSelectPosition(int position) {
mSelectPosition = position;
int value = mData.size() / 2 - mSelectPosition;
if (value < 0) {
for (int i = 0; i < -value; i++) {
moveHeadToTail();
mSelectPosition--;
}
} else if (value > 0) {
for (int i = 0; i < value; i++) {
moveTailToHead();
mSelectPosition++;
}
}
invalidate();
}
public void setDefaultValue(@NonNull String value) {
if (mData.size() > 0) {
for (int i = 0; i < mData.size(); i++) {
if (value.equals(mData.get(i))) {
setSelectPosition(i);
break;
}
}
}
}
public String getSelectValue() {
return mData.size() > 0 ? mData.get(mSelectPosition) : "";
}
static class MHandler extends Handler {
private final WeakReference<View> mWeakReference;
MHandler(View view) {
this.mWeakReference = new WeakReference<>(view);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MPickerView mPickerView = (MPickerView) mWeakReference.get();
if (mPickerView != null) {
if (Math.abs(mPickerView.mMoveDistance) < SPEED) {
mPickerView.mMoveDistance = 0;
if (mPickerView.mTask != null) {
mPickerView.mTask.cancel();
mPickerView.mTask = null;
if (mPickerView.mOnSelectListener != null)
mPickerView.mOnSelectListener.onSelect(mPickerView, mPickerView.mData.get(mPickerView.mSelectPosition));
}
} else {
mPickerView.mMoveDistance = mPickerView.mMoveDistance - mPickerView.mMoveDistance /
Math.abs(mPickerView.mMoveDistance) * SPEED;
}
mPickerView.invalidate();
}
}
}
static class MTimerTask extends TimerTask {
final Handler handler;
MTimerTask(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
handler.sendMessage(handler.obtainMessage());
}
}
public interface OnSelectListener {
void onSelect(View view, String data);
}
}
效果跟预期不符,所以放弃了。想着使用ViewPager2应该也可以实现,如下:
ViewPager2实现
布局文件
androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/view_pager_layout"
android:layout_width="wrap_content"
android:layout_height="240px"
android:background="@color/purple_200"
android:clipChildren="false"
app:layout_constraintBottom_toTopOf="@+id/decrease"
app:layout_constraintEnd_toEndOf="parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/rightViewPager"
android:layout_width="200px"
android:layout_height="100px"
android:background="@color/teal_200"
android:clipChildren="false"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
item布局文件
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/temp"
android:layout_width="match_parent"
android:layout_height="100px"
android:gravity="center"
android:text="111"
android:textSize="32px"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
注意:布局必须为match_parent
Adapter
package com.learn.navigationdemo.temp;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.learn.navigationdemo.R;
import com.learn.navigationdemo.databinding.ItemBinding;
import java.util.ArrayList;
import java.util.List;
public class TempAdapter extends RecyclerView.Adapter<TempAdapter.MyViewModel> {
private static final String TAG = "TempAdapter";
private List<String> mList = new ArrayList<>();
private ItemBinding mItemBinding;
public void setList(List<String> list) {
if (mList != null) {
mList.clear();
mList.addAll(list);
}
notifyDataSetChanged();
}
@NonNull
@Override
public MyViewModel onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
mItemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
R.layout.item, parent, false);
return new MyViewModel(mItemBinding);
}
@Override
public void onBindViewHolder(@NonNull MyViewModel holder, int position) {
if (holder instanceof MyViewModel) {
holder.binding(position);
}
}
@Override
public int getItemCount() {
return mList == null ? 0 : mList.size();
}
public class MyViewModel extends RecyclerView.ViewHolder {
ItemBinding mBinding;
public MyViewModel(@NonNull ItemBinding itemBinding) {
super(itemBinding.getRoot());
mBinding = itemBinding;
}
public void binding(int position) {
if (position == 0) {
mBinding.temp.setText("LO");
} else if (position == mList.size() - 1) {
mBinding.temp.setText("HI");
} else {
mBinding.temp.setText(mList.get(position) + "℃");
}
}
}
}
修改滑动速度
package com.learn.navigationdemo.temp;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.animation.AccelerateDecelerateInterpolator;
import androidx.viewpager2.widget.ViewPager2;
/**
* 设置ViewPage2的切换时间
*/
public class MyPagerHelper {
private static final String TAG = "MyPagerHelper";
/**
* 保存前一个animatedValue.
*/
private static int previousValue;
/**
* 切换Item.
*
* @param pager viewpager2
* @param item 下一个跳转的item
* @param duration scroll时长
*/
public static void setCurrentItem(final ViewPager2 pager, int item, long duration) {
previousValue = 0;
int currentItem = pager.getCurrentItem();
int pagerHeight = pager.getHeight();
int pxToDrag = pagerHeight * (item - currentItem);
Log.d(TAG, "setCurrentItem: pxToDrag = " + pxToDrag);
final ValueAnimator animator = ValueAnimator.ofInt(0, pxToDrag);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (int) animation.getAnimatedValue();
float currentPxToDrag = (float) (currentValue - previousValue);
pager.fakeDragBy(-currentPxToDrag);
previousValue = currentValue;
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
pager.beginFakeDrag();
}
@Override
public void onAnimationEnd(Animator animation) {
pager.endFakeDrag();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(duration);
animator.start();
}
}
设置Transform
package com.learn.navigationdemo.temp;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.viewpager2.widget.ViewPager2;
public class TempTransformer implements ViewPager2.PageTransformer {
//自由控制缩放比例
private static final float MAX_SCALE = 1f;
private static final float MIN_SCALE = 0.6f;
@Override
public void transformPage(@NonNull View page, float position) {
if (position <= 1) {
float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);
page.setScaleX(scaleFactor);
page.setScaleY(scaleFactor);
} else {
page.setScaleX(MIN_SCALE);
page.setScaleY(MIN_SCALE);
}
}
}
使用
mBinding.rightViewPager.setAdapter(mTempAdapter);
mBinding.rightViewPager.setOffscreenPageLimit(3);
mBinding.rightViewPager.setPageTransformer(new TempTransformer());
mBinding.rightViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
Log.d(TAG, "onPageSelected: position = " + position);
}
});
mTempAdapter.setList(mList);
其实这样实现的效果已经满足需求,但是项目上要求的是左右两个相同的同时可以调节,使用的时候发现有些小问题,改了半天放弃了,决定使用ViewPager实现一下:
ViewPager
布局文件
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="300px"
android:clipChildren="false"
app:layout_constraintBottom_toTopOf="@+id/mp_view"
app:layout_constraintEnd_toEndOf="@+id/mp_view"
app:layout_constraintStart_toStartOf="@+id/mp_view">
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="100px"
android:layout_height="300px"
android:background="@color/teal_200"
android:clipChildren="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
item布局
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/temp"
android:layout_width="match_parent"
android:layout_height="100px"
android:gravity="center"
android:text="111"
android:textSize="32px"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Adapter
package com.learn.navigationdemo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.viewpager.widget.PagerAdapter;
import com.learn.navigationdemo.databinding.ItemBinding;
import java.util.ArrayList;
import java.util.List;
public class MyAdapter extends PagerAdapter {
private static final String TAG = "MyAdapter";
private List<String> mList = new ArrayList<>();
private ItemBinding mBinding;
public void setList(List<String> list) {
if (mList != null) {
mList.clear();
mList.addAll(list);
}
notifyDataSetChanged();
}
@Override
public int getCount() {
return mList.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
//加载vp的布局
mBinding = DataBindingUtil.inflate(LayoutInflater.from(container.getContext()), R.layout.item, container, false);
mBinding.getRoot().setTag(position);
//给布局控件赋值
if (position == 0) {
mBinding.temp.setText("LO");
} else if (position == mList.size() - 1) {
mBinding.temp.setText("HI");
} else {
mBinding.temp.setText(mList.get(position) + "℃");
}
mBinding.getRoot().setRotation(90);
//添加一个布局(不添加无效果)
container.addView(mBinding.getRoot());
return mBinding.getRoot();
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
//移除视图
container.removeView((View) object);
}
}
设置Transform
package com.learn.navigationdemo;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.ViewPager;
public class ViewPagerTransformer implements ViewPager.PageTransformer {
//自由控制缩放比例
private static final float MAX_SCALE = 1f;
private static final float MIN_SCALE = 0.6f;
@Override
public void transformPage(@NonNull View page, float position) {
if (position < 1) {
float scaleFactor = MIN_SCALE + (1 - Math.abs(position)) * (MAX_SCALE - MIN_SCALE);
page.setScaleX(scaleFactor);
page.setScaleY(scaleFactor);
} else {
page.setScaleX(MIN_SCALE);
page.setScaleY(MIN_SCALE);
}
}
}
自定义Scroller
package com.learn.navigationdemo;
import android.content.Context;
import android.view.animation.Interpolator;
import android.widget.Scroller;
public class FixedSpeedScroller extends Scroller {
private int mCurrentDuration = 200;
public FixedSpeedScroller(Context context) {
super(context);
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mCurrentDuration);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mCurrentDuration);
}
public void setCurrentDuration(int time) {
mCurrentDuration = time;
}
public int getCurrentDuration() {
return mCurrentDuration;
}
}
使用
MyAdapter myAdapter = new MyAdapter();
myAdapter.setList(mList);
mBinding.viewPager.setAdapter(myAdapter);
mBinding.viewPager.setOffscreenPageLimit(3);
//设置View Pager垂直
mBinding.viewPager.setRotation(-90);
mBinding.viewPager.setPageTransformer(false, new ViewPagerTransformer());
mBinding.viewPager.setCurrentItem(mList.size() / 2);
//修改滑动速度
try {
Field field = ViewPager.class.getDeclaredField("mScroller");
field.setAccessible(true);
FixedSpeedScroller scroller = new FixedSpeedScroller(mBinding.viewPager.getContext(),
new AccelerateInterpolator());
field.set(mBinding.viewPager, scroller);
scroller.setCurrentDuration(200);
} catch (Exception e) {
}
mBinding.viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
Log.d(TAG, "onPageSelected: position = " + position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
这里要说明为什么ViewPager是垂直的,原因在于对ViewPager进行了viewPager.setRotation(-90);以及子视图的
mBinding.getRoot().setRotation(90);,这样就使得ViewPager是垂直的啦!!!但是这样实现的效果发现滑动的过程中会出现,上下两个item也会变大的问题还有就是刷新的问题,很烦,推倒重来使用Recycler View实现
RecyclerView
布局文件
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/leftRec"
android:layout_width="200px"
android:layout_height="300px"
android:background="@color/teal_200"
app:layout_constraintBottom_toTopOf="@+id/increase"
app:layout_constraintStart_toStartOf="parent" />
item布局
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="100px">
<TextView
android:id="@+id/temp_item"
android:layout_width="match_parent"
android:layout_height="100px"
android:gravity="center"
android:text="111"
android:textSize="32px"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
解决首部和尾部不能居中的问题
package com.learn.navigationdemo.temp;
import android.graphics.Rect;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
public class GalleryItemDecoration extends RecyclerView.ItemDecoration {
public static final int MARGIN_VIEW_HEIGHT = 100;
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
//获取当前Item的position
int position = parent.getChildAdapterPosition(view);
//获得Item的数量
int itemCount = parent.getAdapter().getItemCount();
int topMargin;
if (position == 0) {
topMargin = MARGIN_VIEW_HEIGHT;
} else {
topMargin = 0;
}
int bottomMargin;
if (position == itemCount - 1) {
bottomMargin = MARGIN_VIEW_HEIGHT;
} else {
bottomMargin = 0;
}
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
layoutParams.setMargins(0, topMargin, 0, bottomMargin);
view.setLayoutParams(layoutParams);
super.getItemOffsets(outRect, view, parent, state);
}
}
Adapter
package com.learn.navigationdemo;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.learn.navigationdemo.databinding.ItemBinding;
import com.learn.navigationdemo.databinding.RecItemBinding;
import java.util.ArrayList;
import java.util.List;
public class RecAdapter extends RecyclerView.Adapter<RecAdapter.MyViewModel> {
private static final String TAG = "TempAdapter";
private List<String> mList = new ArrayList<>();
private RecItemBinding mItemBinding;
public void setList(List<String> list) {
if (mList != null) {
mList.clear();
mList.addAll(list);
}
notifyDataSetChanged();
}
@NonNull
@Override
public MyViewModel onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
mItemBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
R.layout.rec_item, parent, false);
return new MyViewModel(mItemBinding);
}
@Override
public void onBindViewHolder(@NonNull MyViewModel holder, int position, @NonNull List<Object> payloads) {
super.onBindViewHolder(holder, position, payloads);
Log.d(TAG, "onBindViewHolder: payloads = " + payloads);
}
@Override
public void onBindViewHolder(@NonNull MyViewModel holder, int position) {
if (holder instanceof MyViewModel) {
holder.binding(position);
}
}
@Override
public int getItemCount() {
return mList == null ? 0 : mList.size();
}
public class MyViewModel extends RecyclerView.ViewHolder {
RecItemBinding mBinding;
public MyViewModel(@NonNull RecItemBinding itemBinding) {
super(itemBinding.getRoot());
mBinding = itemBinding;
}
public void binding(int position) {
if (position == 0) {
mBinding.tempItem.setText("LO");
} else if (position == mList.size() - 1) {
mBinding.tempItem.setText("HI");
} else {
mBinding.tempItem.setText(mList.get(position) + "℃");
}
}
}
}
使用
recAdapter.setList(mList);
//使得recyclerView的item可以以每个为单位滑动
PagerSnapHelper pagerSnapHelper = new PagerSnapHelper();
pagerSnapHelper.attachToRecyclerView(mBinding.leftRec);
//使得首部和尾部居中
mBinding.leftRec.addItemDecoration(new GalleryItemDecoration());
mBinding.leftRec.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false));
mBinding.leftRec.setAdapter(recAdapter);
mBinding.leftRec.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
//暂停
if (layoutManager instanceof LinearLayoutManager) {
int firstCompletelyVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
Log.d(TAG, "onViewCreated: firstCompletelyVisibleItemPosition = " + firstCompletelyVisibleItemPosition);
}
}
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//设置item进行缩放
int childCount = recyclerView.getChildCount();
int height = recyclerView.getHeight();
for (int i = 0; i < childCount; i++) {
View child = recyclerView.getChildAt(i);
int top = child.getTop();
int bottom = child.getBottom();
// 遍历recyclerView子项,以中间项中心偏移量为基准进行缩放
float scale = (bottom - top) * 1.0f / 2 + top - height * 1.0f / 2;
float scaleFactor = MIN_SCALE + (1 - Math.min(1, Math.abs(scale / child.getHeight()))) * (MAX_SCALE - MIN_SCALE);
child.setScaleX(scaleFactor);
child.setScaleY(scaleFactor);
}
}
});
其实这样写需求已经满足了,但是由于需要两个同时调节,这样写代码重复度太高了,可以考虑简单封装一下,但是局限性很高,这里就不贴了,至此才算真正完成了,爽了!!!