Java 设置SeekBar的宽度以使;滑动以解锁";影响

Java 设置SeekBar的宽度以使;滑动以解锁";影响,java,android,xml,swipe,android-seekbar,Java,Android,Xml,Swipe,Android Seekbar,我正在尝试使用SeekBar进行滑动解锁功能。我的目标外观如下所示: 它由两个图像、一个背景和一个按钮组成。我将背景和SeekBar放在一个框架布局中,这样SeekBar应该位于背景之上 像这样: <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" >

我正在尝试使用SeekBar进行滑动解锁功能。我的目标外观如下所示:

它由两个图像、一个背景和一个按钮组成。我将背景和SeekBar放在一个框架布局中,这样SeekBar应该位于背景之上

像这样:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:text="Testing 123..." />

    <FrameLayout
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" >

        <ImageView
            android:id="@+id/ImageView01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:scaleType="center"
            android:src="@drawable/unlockback" />

        <SeekBar
            android:id="@+id/myseek"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clickable="false"
            android:max="100"
            android:progressDrawable="@android:color/transparent"
            android:thumb="@drawable/unlockbut" />

    </FrameLayout>

</LinearLayout>

不幸的是,最终结果如下(在eclipse中):

我似乎无法使SeekBar与FrameLayout的大小匹配。您可以在上图中看到由一个蓝色细框表示的Seekbar的大小。框架有两个蓝色的小正方形,你可以用鼠标指针抓取它们来调整大小。但是,如果我使用鼠标指针拖动蓝色小正方形以匹配FrameView的全宽,那么只要我放开鼠标,正方形就会弹回到其原始(太小)大小


我能做些什么来解决这个问题?。。如果我能以一种根本不同的方式实现刷卡解锁,那么我也对此感兴趣。

正如我承诺的那样,我会看看我能做些什么。我没有使用你的图片,也没有使用android图形来绘制,因为这使整个事情更具可定制性和可伸缩性。如果你坚持画你的图像,使用。。。这很简单。主要逻辑可以保持不变

我可能会回来添加一些奇特的动画和视觉效果,但现在我留下了一些注释代码来使用着色器和渐变,因为我现在时间有点短

让我们开始吧。。。首先将
/resources/
中的attrs.xml装入板条箱,并将其添加到其中

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SlideToUnlock">
        <attr name="sliderColor" format="color"/>
        <attr name="cancelOnYExit" format="boolean"/>
        <attr name="slideToUnlockText" format="string"/>
        <attr name="slideToUnlockTextColor" format="color"/>
        <attr name="slideToUnlockBackgroundColor" format="color"/>
        <attr name="cornerRadiusX" format="dimension"/>
        <attr name="cornerRadiusY" format="dimension"/>
    </declare-styleable>
</resources>
你可以下载整个项目。享受:)

这是最终结果


以下是可能对您有所帮助的库


您已经找到了解决方案吗?@Techfist:没有。。。所以我刚开始悬赏。@Luksprog:听起来不错(我现在无法测试),但无论如何,你应该把你的“评论”剪切粘贴到“回答”中否则你就无法获得赏金。我不确定你是否应该使用进度条:/n你能给我提供拇指图像,我看看我能做些什么吗?恐怕我不知道gradle的东西是怎么回事。我尝试将attrs.xml直接放在资源目录中,但eclipse抱怨“资源目录名无效”,我想这意味着它需要放在资源中的某个特定目录中。。。我猜是。。。布局?对不起,我以为你在使用Android studio。它使用的是你提到的gradle的东西。对于eclipse,只需遵循循序渐进的教程。我在这台电脑上没有eclipse,但我回家后可能会尝试制作一个eclipse项目。。。eclipse抱怨“styleable无法解析或不是字段”。奇怪的是,另一个错误是“类型画布中的drawRoundRect(RectF,float,float,Paint)方法不适用于参数(int,int,int,int,int,float,float,Paint)”我正在使用API级别21中添加的方法,您有那个API吗?我将在以后解决这个问题,我昨天时间不够。只需注释掉if,并使用带有path的。您应该将attrs.xml放在resources\values not layout中,然后执行一个干净的rubuildAPI 21?。。。六羟甲基三聚氰胺六甲醚。。。对于一个商业产品来说不是很好,这已经失去了60%的市场份额。
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.EmbossMaskFilter;
import android.graphics.MaskFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Typeface;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by ksenchy on 29.4.2015.
 */
public class SlideToUnlock extends View {

    public interface OnSlideToUnlockEventListener {
        public void onSlideToUnlockCanceled();

        public void onSlideToUnlockDone();
    }

    private int measuredWidth, measuredHeight;
    private float density;
    private OnSlideToUnlockEventListener externalListener;
    private Paint mBackgroundPaint, mTextPaint, mSliderPaint;
    private float rx, ry; // Corner radius
    private Path mRoundedRectPath;
    private String text = "Unlock  →";

    float x;
    float event_x, event_y;
    float radius;
    float X_MIN, X_MAX;
    private boolean ignoreTouchEvents;

    // Do we cancel when the Y coordinate leaves the view?
    private boolean cancelOnYExit;
    private boolean useDefaultCornerRadiusX, useDefaultCornerRadiusY;


    /**
     * Default values *
     */
    int backgroundColor = 0xFF807B7B;
    int textColor = 0xFFFFFFFF;
    int sliderColor = 0xAA404040;


    public SlideToUnlock(Context context) {
        super(context);
        init(context, null, 0);
    }

    public SlideToUnlock(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public SlideToUnlock(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    public OnSlideToUnlockEventListener getExternalListener() {
        return externalListener;
    }

    public void setExternalListener(OnSlideToUnlockEventListener externalListener) {
        this.externalListener = externalListener;
    }

    private void init(Context context, AttributeSet attrs, int style) {

        Resources res = getResources();
        density = res.getDisplayMetrics().density;

        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.SlideToUnlock, style, 0);

        String tmp = a.getString(R.styleable.SlideToUnlock_slideToUnlockText);
        text = TextUtils.isEmpty(tmp) ? text : tmp;
        rx = a.getDimension(R.styleable.SlideToUnlock_cornerRadiusX, rx);
        useDefaultCornerRadiusX = rx == 0;
        ry = a.getDimension(R.styleable.SlideToUnlock_cornerRadiusX, ry);
        useDefaultCornerRadiusY = ry == 0;
        backgroundColor = a.getColor(R.styleable.SlideToUnlock_slideToUnlockBackgroundColor, backgroundColor);
        textColor = a.getColor(R.styleable.SlideToUnlock_slideToUnlockTextColor, textColor);
        sliderColor = a.getColor(R.styleable.SlideToUnlock_sliderColor, sliderColor);
        cancelOnYExit = a.getBoolean(R.styleable.SlideToUnlock_cancelOnYExit, false);

        a.recycle();

        mRoundedRectPath = new Path();

        mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBackgroundPaint.setStyle(Paint.Style.FILL);
        mBackgroundPaint.setColor(backgroundColor);

        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setColor(textColor);
        mTextPaint.setTypeface(Typeface.create("Roboto-Thin", Typeface.NORMAL));

        mSliderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mSliderPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mSliderPaint.setColor(sliderColor);
        mSliderPaint.setStrokeWidth(2 * density);

        if (!isInEditMode()) {
            // Edit mode does not support shadow layers
            // mSliderPaint.setShadowLayer(10.0f, 0.0f, 2.0f, 0xFF000000);
            //mSliderPaint.setMaskFilter(new EmbossMaskFilter(new float[]{1, 1, 1}, 0.4f, 10, 8.2f));
            float[] direction = new float[]{0.0f, -1.0f, 0.5f};
            MaskFilter filter = new EmbossMaskFilter(direction, 0.8f, 15f, 1f);
            mSliderPaint.setMaskFilter(filter);
            //mSliderPaint.setShader(new LinearGradient(8f, 80f, 30f, 20f, Color.RED,Color.WHITE, Shader.TileMode.MIRROR));
            //mSliderPaint.setShader(new RadialGradient(8f, 80f, 90f, Color.RED,Color.WHITE, Shader.TileMode.MIRROR));
            //mSliderPaint.setShader(new SweepGradient(80, 80, Color.RED, Color.WHITE));
            //mSliderPaint.setMaskFilter(new BlurMaskFilter(15, BlurMaskFilter.Blur.OUTER));
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measuredHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        measuredWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

        if (useDefaultCornerRadiusX) {
            rx = measuredHeight * 0.52f;
        }
        if (useDefaultCornerRadiusY) {
            ry = measuredHeight * 0.52f;
        }
        mTextPaint.setTextSize(measuredHeight / 3.0f);

        radius = measuredHeight * 0.45f;
        X_MIN = 1.2f * radius;
        X_MAX = measuredWidth - X_MIN;
        x = X_MIN;

        setMeasuredDimension(measuredWidth, measuredHeight);
    }

    private void drawRoundRect(Canvas c) {
        mRoundedRectPath.reset();
        mRoundedRectPath.moveTo(rx, 0);
        mRoundedRectPath.lineTo(measuredWidth - rx, 0);
        mRoundedRectPath.quadTo(measuredWidth, 0, measuredWidth, ry);
        mRoundedRectPath.lineTo(measuredWidth, measuredHeight - ry);
        mRoundedRectPath.quadTo(measuredWidth, measuredHeight, measuredWidth - rx, measuredHeight);
        mRoundedRectPath.lineTo(rx, measuredHeight);
        mRoundedRectPath.quadTo(0, measuredHeight, 0, measuredHeight - ry);
        mRoundedRectPath.lineTo(0, ry);
        mRoundedRectPath.quadTo(0, 0, rx, 0);
        c.drawPath(mRoundedRectPath, mBackgroundPaint);
    }

    @SuppressLint("NewApi")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (measuredHeight <= 0 || measuredWidth <= 0) {
            // There is not much we can draw :/
            return;
        }

        if (Build.VERSION.SDK_INT >= 21) {
            canvas.drawRoundRect(0, 0, measuredWidth, measuredHeight, rx, ry, mBackgroundPaint);
        }
        else {
            drawRoundRect(canvas);
        }


        // Draw the text in center
        float xPos = ((measuredWidth - mTextPaint.measureText(text)) / 2.0f);
        float yPos = (measuredHeight / 2.0f);
        float titleHeight = Math.abs(mTextPaint.descent() + mTextPaint.ascent());
        yPos += titleHeight / 2.0f;
        canvas.drawText(text, xPos, yPos, mTextPaint);


        canvas.drawCircle(x, measuredHeight * 0.5f, radius, mSliderPaint);

    }

    private void onCancel() {
        reset();
        if (externalListener != null) {
            externalListener.onSlideToUnlockCanceled();
        }
    }

    private void onUnlock() {
        if (externalListener != null) {
            externalListener.onSlideToUnlockDone();
        }
    }

    private void reset() {
        x = X_MIN;
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                ignoreTouchEvents = false;
                reset();
                return true;
            case MotionEvent.ACTION_DOWN:
                // Is within the circle??
                event_x = event.getX(0);
                event_y = event.getY(0);
                double squareRadius = radius * radius;
                double squaredXDistance = (event_x - X_MIN) * (event_x - X_MIN);
                double squaredYDistance = (event_y - measuredHeight / 2) * (event_y - measuredHeight / 2);

                if (squaredXDistance + squaredYDistance > squareRadius) {
                    // User touched outside the button, ignore his touch
                    ignoreTouchEvents = true;
                }

                return true;
            case MotionEvent.ACTION_CANCEL:
                ignoreTouchEvents = true;
                onCancel();
            case MotionEvent.ACTION_MOVE:
                if (!ignoreTouchEvents) {
                    event_x = event.getX(0);
                    if (cancelOnYExit) {
                        event_y = event.getY(0);
                        if (event_y < 0 || event_y > measuredHeight) {
                            ignoreTouchEvents = true;
                            onCancel();
                        }
                    }

                    x = event_x > X_MAX ? X_MAX : event_x < X_MIN ? X_MIN : event_x;
                    if (event_x >= X_MAX) {
                        ignoreTouchEvents = true;
                        onUnlock();
                    }
                    invalidate();
                }
                return true;
            default:
                return super.onTouchEvent(event);
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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:background="#FF000000">

    <your.package.SlideToUnlock
        android:id="@+id/slideToUnlock"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:layout_centerInParent="true"/>

    <your.package.SlideToUnlock
        android:id="@+id/slideToUnlock2"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:layout_below="@+id/slideToUnlock"
        android:layout_centerInParent="true"
        android:layout_marginTop="50dp"
        app:cancelOnYExit="true"
        app:slideToUnlockBackgroundColor="#808080"
        app:slideToUnlockText="Slide to unlock"
        app:slideToUnlockTextColor="#03A9F4"
        app:sliderColor="#AAFFE97F"/>

</RelativeLayout>
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.Toast;


public class MainActivity extends ActionBarActivity implements SlideToUnlock.OnSlideToUnlockEventListener {

    private SlideToUnlock slideToUnlockView, slideToUnlockView2;
    private Toast toast;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        slideToUnlockView = (SlideToUnlock) findViewById(R.id.slideToUnlock);
        slideToUnlockView.setExternalListener(this);

        slideToUnlockView2 = (SlideToUnlock) findViewById(R.id.slideToUnlock2);
        slideToUnlockView2.setExternalListener(this);
    }

    private void showToast(String text) {
        if (toast != null) {
            toast.cancel();
        }

        toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
        toast.show();
    }

    @Override
    public void onSlideToUnlockCanceled() {
        showToast("Canceled");
    }

    @Override
    public void onSlideToUnlockDone() {
        showToast("Unlocked");
    }
}