2015-04-26 31 views
8

Sto tentando di eseguire uno swipe per sbloccare la funzione utilizzando un SeekBar. Il look sto puntando è mostrato qui:Impostazione della larghezza di SeekBar per rendere l'effetto "scorri per sbloccare"

enter image description here

Questa è composta da due immagini, uno sfondo, e un pulsante. Metto sia lo sfondo che SeekBar in un FrameLayout in modo che SeekBar si trovi in ​​cima allo sfondo.

Come così:

<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> 

Purtroppo il risultato finale assomiglia a questo (in Eclipse):

enter image description here

Mi sembra di essere in grado di effettuare il SeekBar corrispondere alle dimensioni del FrameLayout . Puoi vedere la dimensione della Seekbar rappresentata da una sottile cornice blu nell'immagine sopra. La cornice ha due piccoli quadrati blu solidi che puoi afferrare con il puntatore del mouse per ridimensionare. Ma se uso il puntatore del mouse per trascinare il quadratino blu in modo che corrisponda alla larghezza completa di FrameView, non appena ho rilasciato il mouse, il quadrato torna alla sua dimensione originale (troppo piccola).

Cosa posso fare per risolvere questo problema? .. Se riesco a ottenere lo scorrimento per sbloccare in un modo fondamentalmente diverso, quindi mi interessa anche quello.

+0

Hai già trovato una soluzione? – Techfist

+0

@Techfist: No ... quindi ho appena iniziato una taglia. – Mick

+0

@Luksprog: Sembra tutto a posto (non posso testarlo adesso), ma comunque, dovresti tagliare e incollare il tuo "commento" in una "risposta" altrimenti non puoi raccogliere il premio. – Mick

risposta

7

Come ho promesso, vedrò cosa posso fare. Non ho usato le tue immagini e ho usato la grafica Android per fare il disegno in quanto rende tutto più personalizzabile e scalabile. Se insisti nel disegnare le tue immagini, usa canvas.drawBitmap ... è piuttosto semplice. La logica principale può rimanere la stessa.

Posso tornare e aggiungere animazioni e effetti visivi fantasiosi, ma per ora ho lasciato un po 'di codice commentato per giocare con ombreggiatori e sfumature perché al momento sono un po' corto.

Andiamo a quello ... Prima cassa attrs.xml in /resources/ e aggiungere questo ad esso.

<?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> 

E poi SlideToUnlock.java

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); 
     } 
    } 
} 

activity_main.xml

<?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> 

MainActivity.java

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"); 
    } 
} 

È possibile scaricare l'intero progetto here. Divertiti :)

Questo è il risultato finale.

Slide to unlock

+0

Ho paura di non avere idea di cosa sia questa roba di gradle. Ho provato a mettere attrs.xml direttamente nella directory delle risorse, ma eclipse si lamenta "nome della directory delle risorse non valido" che presumo significhi che deve essere in una directory specifica all'interno delle risorse ... La mia ipotesi è ... layout? – Mick

+0

Scusa se ho pensato che stai usando Android Studio. Sta usando cose gradle che hai menzionato. Per Eclipse basta seguire il tutorial passo passo. Non ho eclissi su questo pc, ma potrei provare a realizzare un progetto di eclissi quando torno a casa. –

+0

Così ho inserito attrs.xml in risorse \ layout, quindi ho creato la classe SlideToUnlock.java ... eclipse si lamenta che "lo stile non può essere risolto o non è un campo". Stranamente, un altro errore è "Il metodo drawRoundRect (RectF, float, float, Paint) nel tipo Canvas non è applicabile per gli argomenti (int, int, int, int, float, float, Paint)" – Mick