2013-11-25 2 views
9

Ich bin auf der Suche nach einer Art "Leinwand" zu implementieren, wo X-Anzahl von TextViews/Links an "zufällige Positionen" (Positioniert wie im Bild unten) platziert werden kann. Sie können dann diese "Canvas" -Ansicht kontinuierlich nach links oder rechts scrollen und die Ansicht wird wiederholt/kreisförmig (eine Art HTML-Auswahl, außer dass Sie manuell scrollen). In den einfachsten Fällen suche ich nur nach horizontalem Scrollen - aber ein Beispiel für einen "komplexeren Fall" ist das "Sphären-Scrollen" - siehe das folgende Beispiel von Appy Geek. (Für den Moment bin ich nur daran interessiert in den horizontalen Scrollen)Wie kann ich eine 3D-kreisförmige Scroll-Ansicht für Text erstellen? (Wie in Appy Geek gesehen)

Beispiel von Appy Geek:

enter image description here

+0

Verwenden Animation auf der Anlage - die Position der Kinder animieren. –

Antwort

6

dieses Gut werden Sie den Einstieg, ich implementiert eine einfache Tag-Wolke beiden Ansätze (zB durch Verlängerung View und ViewGroup), die weiterdreht. Sie können diese Logik in Ihrem benutzerdefinierten ViewGroup verwenden, der seine Ansichten entsprechend positioniert. Danach fügen Sie anklickbare TextView s in diesem Layout hinzu und behandeln Touch-Ereignisse.

Endgültiges Ergebnis (natürlich seine Dreh, näher betrachten):

enter image description here

Viele Dinge können in den folgenden Code verbessert werden.

VON ViewGroup ERWEITERN:

Setzen Sie dieses in xml Layout:

<com.vj.tagcloud.TagCloudLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="TextView" /> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="TextView" /> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="TextView" /> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="TextView" /> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="TextView" /> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="TextView" /> 
</com.vj.tagcloud.TagCloudLayout> 

TagCloudLayout Klasse:

import java.util.Random; 

import android.content.Context; 
import android.os.Handler; 
import android.util.AttributeSet; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.TextView; 

public class TagCloudLayout extends ViewGroup { 
final Random mRandom = new Random(); 
private float mRotateAngle; 

private Handler mHandler = new Handler(); 
private float rotateAngleDegree; 

public TagCloudLayout(Context context) { 
    super(context); 
} 

public TagCloudLayout(Context context, AttributeSet attrs) { 
    super(context, attrs); 
} 

public TagCloudLayout(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    final float radius = Math.min(getMeasuredWidth(), getMeasuredHeight())/2F; 
    float halfWidth = getMeasuredWidth()/2F; 
    float halfHeight = getMeasuredHeight()/2F; 
    final int count = getChildCount(); 
    for (int i = 0; i < count; i++) { 
     View child = getChildAt(i); 
     LayoutParams lp = (LayoutParams) child.getLayoutParams(); 
     float sinTheta = (float) Math.sin(lp.theta); 
     float x = (int) (radius * Math.cos(lp.fi + mRotateAngle) 
       * sinTheta); 

     if (child instanceof TextView) { 
      ((TextView) child) 
        .setTextSize(15 * ((radius - x)/radius) + 10); 
     } 
     measureChild(child, widthMeasureSpec, heightMeasureSpec); 
     // http://en.wikipedia.org/wiki/Spherical_coordinates 
     lp.x = (int) ((halfWidth + radius * Math.sin(lp.fi + mRotateAngle) 
       * sinTheta) - /* for balancing on x-axis */(child 
       .getMeasuredWidth()/2F)); 
     lp.y = (int) (halfHeight + radius * Math.cos(lp.theta)-/* for balancing on y-axis */(child 
       .getMeasuredHeight()/2F)); 
    } 
} 

@Override 
protected void onAttachedToWindow() { 
    super.onAttachedToWindow(); 
    mHandler.postDelayed(new Runnable() { 

     @Override 
     public void run() { 
      rotateAngleDegree += 5; 
      mRotateAngle = (float) Math.toRadians(rotateAngleDegree); 
      requestLayout(); 
      mHandler.postDelayed(this, 40); 
     } 
    }, 40); 
} 

@Override 
protected void onDetachedFromWindow() { 
    super.onDetachedFromWindow(); 
    mHandler.removeCallbacksAndMessages(null); 
} 

@Override 
public void addView(View child, int index, 
     android.view.ViewGroup.LayoutParams params) { 
    super.addView(child, index, params); 

    LayoutParams lp = (LayoutParams) child.getLayoutParams(); 
    lp.fi = (float) Math.toRadians(mRandom.nextInt(360)); 
    lp.theta = (float) Math.toRadians(mRandom.nextInt(360)); 
} 

@Override 
protected void onLayout(boolean changed, int l, int t, int r, int b) { 
    final int count = getChildCount(); 
    for (int i = 0; i < count; i++) { 
     View child = getChildAt(i); 
     LayoutParams lp = (LayoutParams) child.getLayoutParams(); 
     child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y 
       + child.getMeasuredHeight()); 
    } 
} 

@Override 
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 
    return p instanceof LayoutParams; 
} 

@Override 
protected LayoutParams generateDefaultLayoutParams() { 
    return new LayoutParams(LayoutParams.WRAP_CONTENT, 
      LayoutParams.WRAP_CONTENT); 
} 

@Override 
public LayoutParams generateLayoutParams(AttributeSet attrs) { 
    return new LayoutParams(getContext(), attrs); 
} 

@Override 
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 
    return new LayoutParams(p.width, p.height); 
} 

public static class LayoutParams extends ViewGroup.LayoutParams { 
    int x; 
    int y; 
    float fi, theta; 

    public LayoutParams(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public LayoutParams(int w, int h) { 
     super(w, h); 
    } 
} 
} 

VONERWEITERN:

dieses Layout in xml Put:

<com.vj.wordtap.TagCloud 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" /> 

und dies in Java-Code:

import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 

import android.content.Context; 
import android.graphics.Camera; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.os.Handler; 
import android.text.TextPaint; 
import android.util.AttributeSet; 
import android.view.View; 

public class TagCloud extends View { 

private List<String> mItems = new ArrayList<String>(); 
private List<Angles> mAngles = new ArrayList<Angles>(); 
private Camera mCamera = new Camera(); 
private TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); 
private Handler mHandler = new Handler(); 
private float mRotateAngle; 
private float rotateAngleDegree; 

public static class Angles { 
    float fi, theta; 
} 

public TagCloud(Context context) { 
    super(context); 
    init(); 
} 

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

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

private void init() { 
    List<String> items = new ArrayList<String>(); 
    for (int i = 0; i < 10; i++) { 
     items.add("item:" + i); 
    } 
    setItems(items); 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    canvas.translate(canvas.getWidth()/2F, canvas.getHeight()/2F); 
    mTextPaint.setColor(Color.BLACK); 
    final float radius = 100; 
    mCamera.setLocation(0, 0, -100); 
    for (int i = 0; i < mItems.size(); i++) { 
     String item = mItems.get(i); 
     Angles xyz = mAngles.get(i); 
     mCamera.save(); 
     canvas.save(); 
     float sinTheta = (float) Math.sin(xyz.theta); 
     float x = (float) (radius * Math.cos(xyz.fi + mRotateAngle) * sinTheta); 
     float y = (float) (radius * Math.sin(xyz.fi + mRotateAngle) * sinTheta); 
     float z = (float) (radius * Math.cos(xyz.theta)); 
     // mapping coordinates with Android's coordinates 
     // http://en.wikipedia.org/wiki/Spherical_coordinates 
     mCamera.translate(y, z, x); 
     mCamera.applyToCanvas(canvas); 

     // http://en.wikipedia.org/wiki/Spherical_coordinates 
     // set size based on x-Axis that is coming towards us 
     mTextPaint.setTextSize(20 * ((100 - x)/100) + 10); 
     canvas.drawText(item, 0, 0, mTextPaint); 
     mCamera.restore(); 
     canvas.restore(); 
    } 
} 

@Override 
protected void onAttachedToWindow() { 
    super.onAttachedToWindow(); 
    mHandler.postDelayed(new Runnable() { 

     @Override 
     public void run() { 
      rotateAngleDegree += 5; 
      mRotateAngle = (float) Math.toRadians(rotateAngleDegree); 
      invalidate(); 
      mHandler.postDelayed(this, 40); 
     } 
    }, 40); 
} 

@Override 
protected void onDetachedFromWindow() { 
    super.onDetachedFromWindow(); 
    mHandler.removeCallbacksAndMessages(null); 
} 

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

public void setItems(List<String> items) { 
    mItems = items; 
    final Random ran = new Random(); 
    final List<Angles> xyzList = mAngles; 
    xyzList.clear(); 

    for (int i = 0; i < items.size(); i++) { 
     Angles xyz = new Angles(); 
     float fi = (float) Math.toRadians(ran.nextInt(360)); 
     xyz.fi = fi; 
     float theta = (float) Math.toRadians(ran.nextInt(360)); 
     xyz.theta = theta; 
     xyzList.add(xyz); 
    } 
} 
} 
+1

Dies funktionierte genau, indem der Code hier mit nur einer Layoutdatei kopiert wurde und dann das Layout nur von einer Aktivität aufgerufen wurde (nichts anderes wurde benötigt!). Sehr schöne Lösung - Danke für das Teilen – gnB

Verwandte Themen