IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android自定义纵向的SeekBar(解决fromuser参数一直为false的问题) -> 正文阅读

[移动开发]Android自定义纵向的SeekBar(解决fromuser参数一直为false的问题)

?VerticalSeekBar.java

package com.sidebar.pro.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import com.sidebar.pro.R;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@SuppressLint("AppCompatCustomView")
public class VerticalSeekBar extends SeekBar {
    private static final String TAG = VerticalSeekBar.class.getSimpleName();
    public static final int ROTATION_ANGLE_CW_90 = 90;//从上到下
    public static final int ROTATION_ANGLE_CW_270 = 270;//从下到上
    private int mRotationAngle = ROTATION_ANGLE_CW_270;//我这里是从下到上
    private IUpEventListener iUpEventListener;

    //用户滑动seekbar手指离开时的回调。(调用mSeekbar.setUpEvent();)
    public void setUpEvent(IUpEventListener iUpEventListener) {
        this.iUpEventListener = iUpEventListener;
    }
    public interface IUpEventListener {
        void upEvent();
    }

    public VerticalSeekBar(Context context) {
        super(context);//注意是super 而不是调用其他构造函数
        initialize(context, null, 0, 0);
    }

    public VerticalSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize(context, attrs, 0, 0);
    }

    public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initialize(context, attrs, defStyle, 0);
    }

    private void initialize(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar, defStyleAttr, defStyleRes);
            final int rotationAngle = a.getInteger(R.styleable.VerticalSeekBar_seekBarRotation, 0);
            if (isValidRotationAngle(rotationAngle)) {
                mRotationAngle = rotationAngle;
            }
            a.recycle();
        }
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(h, w, oldh, oldw);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }

    protected void onDraw(Canvas c) {
        if (mRotationAngle == ROTATION_ANGLE_CW_270) {
            //从下到上
            c.rotate(270);
            c.translate(-getHeight(), 0);//注意旋转后需要移动才可显示出来
        } else if (mRotationAngle == ROTATION_ANGLE_CW_90) {
            //从上到下
            c.rotate(90);
            c.translate(0, -getWidth());
        }

        super.onDraw(c);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                setPressed(true);//移动的时候设置按下效果,然后重新绘制thumb
                if (getThumb() != null) {
                    // This may be within the padding region.
                    invalidate(getThumb().getBounds());
                }
                calProgress(event);//这里利用反射将fromuser设置为true
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                setPressed(false);//放手的时候取消按下效果,重新绘制thumb
                if (getThumb() != null) {
                    // This may be within the padding region.
                    invalidate(getThumb().getBounds());
                }
                calProgress(event);//这里利用反射将fromuser设置为true
                if (null != iUpEventListener) {
                    iUpEventListener.upEvent();
                }
                break;
        }
        return true;
    }

    private static boolean isValidRotationAngle(int angle) {
        return (angle == ROTATION_ANGLE_CW_90 || angle == ROTATION_ANGLE_CW_270);
    }

    //直接调用seekbar.setProgress()发现thumb图片位置一直不对,解决方法如下 重写setProgress
    @Override
    public void setProgress(int progress) {
        super.setProgress(progress);
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }

    //fromUser参数一直为false,利用反射
    private void reflectSetProgress(int progress) {
        //反射方法 boolean setProgressInternal(int progress, boolean fromUser, boolean animate)
        try {
            Class clazz = ProgressBar.class;
            Method method = clazz.getDeclaredMethod("setProgressInternal", int.class, boolean.class, boolean.class);
            method.setAccessible(true);
            method.invoke(this, progress, true, false);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private void calProgress(MotionEvent event) {
        if (mRotationAngle == ROTATION_ANGLE_CW_270) {
            //从下到上
            int progress = getMax() - (int) (event.getY() * (getMax() * 2 + 1) / (getHeight() * 2) + 0.5);
            Log.d(TAG, "set progress " + progress + " max " + getMax() + " getY " + event.getY() + " getHeight " + getHeight());
            progress = progress > 0 ? progress : 0;
            reflectSetProgress(progress);
        } else if (mRotationAngle == ROTATION_ANGLE_CW_90) {
            //从上到下
            reflectSetProgress((int) (getMax() * event.getY() / getHeight()));
        }
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }

}

?VerticalSeekBar.java(2)

package com.iflytek.myapplication.verticalsk;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import com.iflytek.myapplication.R;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@SuppressLint("AppCompatCustomView")
public class VerticalSeekBar extends SeekBar {
    private static final String TAG = VerticalSeekBar.class.getSimpleName();
    public static final int ROTATION_ANGLE_CW_90 = 90;//从上到下
    public static final int ROTATION_ANGLE_CW_270 = 270;//从下到上
    private int mRotationAngle = ROTATION_ANGLE_CW_270;

    public VerticalSeekBar(Context context) {
        super(context);//注意是super 而不是调用其他构造函数
        initialize(context, null, 0, 0);
    }

    public VerticalSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize(context, attrs, 0, 0);
    }

    public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initialize(context, attrs, defStyle, 0);
    }

    private void initialize(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar, defStyleAttr, defStyleRes);
            final int rotationAngle = a.getInteger(R.styleable.VerticalSeekBar_seekBarRotation, 0);
            if (isValidRotationAngle(rotationAngle)) {
                mRotationAngle = rotationAngle;
            }
            a.recycle();
        }
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(h, w, oldh, oldw);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }

    protected void onDraw(Canvas c) {
        if(mRotationAngle == ROTATION_ANGLE_CW_270) {
            //从下到上
            c.rotate(270);
            c.translate(-getHeight(), 0);//注意旋转后需要移动才可显示出来
        } else if(mRotationAngle == ROTATION_ANGLE_CW_90) {
            //从上到下
            c.rotate(90);
            c.translate(0, -getWidth());
        }

        super.onDraw(c);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                setPressed(true);//移动的时候设置按下效果,然后重新绘制thumb
                if (getThumb() != null) {
                    // This may be within the padding region.
                    invalidate(getThumb().getBounds());
                }
                calProgress(event);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                setPressed(false);//放手的时候取消按下效果,重新绘制thumb
                if (getThumb() != null) {
                    // This may be within the padding region.
                    invalidate(getThumb().getBounds());
                }
                calProgress(event);
                break;
        }
        return true;
    }

    private static boolean isValidRotationAngle(int angle) {
        return (angle == ROTATION_ANGLE_CW_90 || angle == ROTATION_ANGLE_CW_270);
    }

    //直接调用seekbar.setProgress()发现thumb图片位置一直不对,解决方法如下 重写setProgress
    @Override
    public void setProgress(int progress) {
        super.setProgress(progress);
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }


    private void reflectSetProgress(int progress) {
        //反射方法 boolean setProgressInternal(int progress, boolean fromUser, boolean animate)
        try {
            Class clazz = ProgressBar.class;
            Method method = clazz.getDeclaredMethod("setProgressInternal",int.class,boolean.class,boolean.class);
            method.setAccessible(true);
            method.invoke(this,progress,true,false);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private void calProgress(MotionEvent event) {
        if(mRotationAngle == ROTATION_ANGLE_CW_270) {
            //从下到上
            int progress =  getMax() - (int)(event.getY()*(getMax()*2+1)/(getHeight()*2)+0.5);
            Log.d(TAG,"set progress "+progress + " max "+getMax() + " getY "+event.getY() +" getHeight "+getHeight());
            progress = progress>0?progress:0;
            reflectSetProgress(progress);
        } else if(mRotationAngle == ROTATION_ANGLE_CW_90) {
            //从上到下
            reflectSetProgress((int) (getMax() * event.getY() / getHeight()));
        }
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }
}

theme--styles

<declare-styleable name="VerticalSeekBar">
        <attr name="seekBarRotation">
            <enum name="CW90" value="90" />
            <enum name="CW270" value="270" />
        </attr>
    </declare-styleable>
<com.sidebar.pro.view.VerticalSeekBar
      android:id="@+id/seekBar_bright"
      android:layout_width="wrap_content"
      android:layout_height="match_parent"
      android:background="@null"
      android:max="100"
      android:paddingTop="@dimen/dp0"
      android:paddingBottom="@dimen/dp0"
      android:progressDrawable="@drawable/bg_seek_bar"
      android:splitTrack="false"
      android:thumb="@mipmap/icon_thumb"
      android:thumbOffset="@dimen/dp25" />

bg_seek_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!--设置滑轨颜色:滑过部分和未滑过部分-->
    <!--未滑过部分滑轨颜色-->
    <item
        android:id="@android:id/background"
        android:height="@dimen/dp5"
        android:gravity="center">
        <shape>
            <corners android:radius="@dimen/dp67"/>
            <solid android:color="@color/c30black"/>
        </shape>
    </item>
    <!--滑过部分滑轨颜色-->
    <item
        android:id="@android:id/progress"
        android:height="@dimen/dp8"
        android:gravity="center">
        <clip>
            <shape>
                <corners android:radius="@dimen/dp67"/>
                <solid android:color="@color/white"/>
            </shape>
        </clip>
    </item>
</layer-list>

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-15 11:54:32  更:2021-10-15 11:56:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:37:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码