本文实例为大家分享了Android ScrollView实现上下滑动功能的具体代码,供大家参考,具体内容如下
package com.example.zhuang;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Scroller;
public class MyScrollView extends ViewGroup {
private int mScreeHeight;//屏幕高度
private Scroller mScroller;
private int mLastY;
private int mStart;
private int mEnd;
private Context context;
public MyScrollView(Context context) {
super(context);
initView(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public MyScrollView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
//DisplayMetrics 类提供了一种关于显示的通用信息,如显示大小,分辨率和字体。
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
mScreeHeight = dm.heightPixels;//高度(像素)
mScroller = new Scroller(context);
}
//继承ViewGroup必须要实现的方法
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();//获取子view的个数
//设置ViewGroup的高度
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
mlp.height = mScreeHeight * childCount;
setLayoutParams(mlp);
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
//参数为相对父容器的左上右下位置,第三个参数必须为r
child.layout(0, i * mScreeHeight, r, (i + 1) * mScreeHeight);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int y = (int) event.getY();//相对于view的y值,getRawY()是相对屏幕
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastY = y;//上一次的y值
mStart = getScrollY();//记录触摸起点
break;
case MotionEvent.ACTION_MOVE:
if(!mScroller.isFinished()) {
mScroller.abortAnimation();//放弃移到最终位置
}
int dy = mLastY - y;//偏移距离
//如果滑动距离小于0或大于屏幕高度,不偏移
if(getScrollY()<0){
dy = 0;
}
if(getScrollY() getHeight()-mScreeHeight){
dy = 0;
}
scrollBy(0,dy);//移动
mLastY = y;
break;
case MotionEvent.ACTION_UP:
int dScrollY = checkAlignment();//整体移动的距离
if(dScrollY 0){
if(dScrollY < mScreeHeight / 3){
mScroller.startScroll(0,getScrollY(),0,-dScrollY);
}else{
mScroller.startScroll(0,getScrollY(),0,mScreeHeight-dScrollY);
}
}else{
if(-dScrollY < mScreeHeight / 3){
mScroller.startScroll(0,getScrollY(),0,-dScrollY);
}else{
mScroller.startScroll(0,getScrollY(),0,-mScreeHeight-dScrollY);
}
}
break;
}
postInvalidate();
return true;
}
private int checkAlignment(){
mEnd = getScrollY();//记录触摸终点
boolean isUp = ((mEnd - mStart) 0) ? true : false;
int lastPrev = mEnd % mScreeHeight;
int lastNext = mScreeHeight - lastPrev;
if(isUp){
return lastPrev;//向上
}else
return -lastNext;
}
@Override
public void computeScroll() {
super.computeScroll();
if(mScroller.computeScrollOffset()){//返回true,表示还未移动完
scrollTo(0,mScroller.getCurrY());//移到当前位置
postInvalidate();
//invalidate()是用来刷新View的,必须是在UI线程中进行工作。
//postInvalidate()可以在非UI线程调用
}
}
}
知识点:
1、获取屏幕参数代码:
DisplayMetrics metric = new DisplayMetrics();
//API 17之后使用,获取的像素宽高包含虚拟键所占空间,在API 17之前通过反射获取
context.getWindowManager().getDefaultDisplay().getRealMetrics(metric);
//获取的像素宽高不包含虚拟键所占空间
//context.getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels; // 宽度(像素)
int height = metric.heightPixels; // 高度(像素)
float density = metric.density; // dp缩放因子
int densityDpi = metric.densityDpi; // 广义密度
float xdpi = metric.xdpi;//x轴方向的真实密度
float ydpi = metric.ydpi;//y轴方向的真实密度
屏幕高度值包含了状态栏的像素,非沉浸模式下真实的Activity高度需要减去状态栏的高度。获取状态栏高度代码:
private int getStatusBarHeight() {
Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
return rect.top;
}
屏幕参数Width和Height的值和屏幕方向有关,另外4个值和屏幕方向无关。
更多Android进阶指南 可以扫码 解锁 《Android十大板块文档》
1.Android车载应用开发系统学习指南(附项目实战)
2.Android Framework学习指南,助力成为系统级开发高手
3.2024最新Android中高级面试题汇总+解析,告别零offer
4.企业级Android音视频开发学习路线+项目实战(附源码)
5.Android Jetpack从入门到精通,构建高质量UI界面
6.Flutter技术解析与实战,跨平台首要之选
7.Kotlin从入门到实战,全方面提升架构基础
8.高级Android插件化与组件化(含实战教程和源码)
9.Android 性能优化实战+360°全方面性能调优
10.Android零基础入门到精通,高手进阶之路
敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔