Java 设置SeekBar的宽度以使;滑动以解锁";影响
我正在尝试使用SeekBar进行滑动解锁功能。我的目标外观如下所示: 它由两个图像、一个背景和一个按钮组成。我将背景和SeekBar放在一个框架布局中,这样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" >
<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");
}
}