We have Android 3D Carousel here: http://www.codeproject.com/KB/android/androcarousel.aspx
There my problem is that: i want to make text label between the image and the reflection ?
how can i do it?
Help me please
I found the anwser: Use CarouselFrame
public class CarouselFrame extends FrameLayout implements Comparable<CarouselFrame> {
private int index;
private float currentAngle;
private float x;
private float y;
private float z;
private boolean drawn;
private ImageView image;
private TextView txt;
public CarouselFrame(Context context) {
this(context, null, 0);
}
public CarouselFrame(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CarouselFrame(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
image = new ImageView(context);
this.addView(image, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
txt = new TextView(context);
this.addView(txt, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
}
public void setImageBitmap(Bitmap img){
image.setImageBitmap(img);
}
public void setText(String text){
txt.setText(text);
}
public void setIndex(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public void setCurrentAngle(float currentAngle) {
this.currentAngle = currentAngle;
}
public float getCurrentAngle() {
return currentAngle;
}
public int compareTo(CarouselFrame another) {
return (int)(another.z - this.z);
}
public void setX(float x) {
this.x = x;
}
public float getX() {
return x;
}
public void setY(float y) {
this.y = y;
}
public float getY() {
return y;
}
public void setZ(float z) {
this.z = z;
}
public float getZ() {
return z;
}
public void setDrawn(boolean drawn) {
this.drawn = drawn;
}
public boolean isDrawn() {
return drawn;
}
}
Related
I've followed some forums and I'm lost with this problem:
I have a Custom View that draws 9 circles for me as shown below:
This circles must be an icon to the main one and 8 images for the others and it must be a drawable resource (I have png pictures in on my drawable folder).
How may I proceed to set this drawable images instead of the colors?
This is my actual code:
public class CircleView extends View {
public static interface IMenuListener{
public void onMenuClick(MenuCircle item);
}
public static class MenuCircle{
private int x,y,radius;
public int id;
public String text;
}
private Paint mainPaint;
private Paint secondPaint;
private Paint textPaint;
private int radius_main =130;
private int menuInnerPadding = 40;
private int radialCircleRadius = 60;
private int textPadding = 25;
private double startAngle = - Math.PI/2f;
private ArrayList<MenuCircle> elements;
private IMenuListener listener;
public void setListener(IMenuListener listener){
this.listener = listener;
}
public void clear(){
elements.clear();
listener=null;
}
public CircleView(Context context) {
super(context);
init();
}
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
elements = new ArrayList<>();
}
public void addMenuItem(String text,int id){
MenuCircle item = new MenuCircle();
item.id = id;
item.text=text;
elements.add(item);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
mainPaint = new Paint();
mainPaint.setColor(Color.DKGRAY); //color of main circle
secondPaint = new Paint();
secondPaint.setColor(Color.DKGRAY); // color of 8 circles
textPaint = new Paint();
textPaint.setColor(Color.BLACK); // text under 8 circles
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centerX = canvas.getWidth()/2 ;
int centerY= canvas.getHeight()/2;
canvas.drawCircle(centerX,centerY,radius_main,mainPaint);
for(int i=0;i<elements.size();i++){
double angle =0;
if(i==0){
angle = startAngle;
}else{
angle = startAngle+(i * ((2 * Math.PI) / elements.size()));
}
elements.get(i).x = (int) (centerX + Math.cos(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
elements.get(i).y = (int) (centerY + Math.sin(angle)*(radius_main+menuInnerPadding+radialCircleRadius));
canvas.drawCircle( elements.get(i).x,elements.get(i).y,radialCircleRadius,secondPaint);
float tW = textPaint.measureText(elements.get(i).text);
canvas.drawText(elements.get(i).text,elements.get(i).x-tW/2,elements.get(i).y+radialCircleRadius+textPadding,textPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
for(MenuCircle mc : elements){
double distance = Math.hypot(event.getX()-mc.x,event.getY()-mc.y);
if(distance<= radialCircleRadius){
//touched
if(listener!=null)
listener.onMenuClick(mc);
return true;
}
}
}
return super.onTouchEvent(event);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}
I have following TextView
public class Cube extends TextView {
Context mContext;
Drawable background;//Hintergrund des Blocks
char mLetter;//Buchstabe des Blocks
int x, y;//Koordinaten des Blocks
#SuppressWarnings("deprecation")
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public Cube(Context context, char letter, int _x, int _y) {
super(context);
mContext = context;
mLetter = letter;
background = ContextCompat.getDrawable(getContext(), R.drawable.cube);
x = _x;
y = _y;
this.setText("" + letter);
if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN)
this.setBackgroundDrawable(background);
else
this.setBackground(background);
}
public void drawCube(Canvas canvas){//how to draw now!? This is called from a separate thread in SurfaceView
}
}
If I call following in drawCube():
background.setBounds(x, y, x + 20, y + 20);
background.draw(canvas);
it just draws the backgroundDrawable. But how can I draw it with the text/the letter inside? That it looks like this: (The background ist the canvas, the orange and white one is the Background and the "A" is the letter/text)
EDIT: Code at 21.09
This is my (shortened) thread:
public class CanvasThread extends Thread {
private SurfaceHolder mSh;
private ArrayList<Cube> mCubes;
private Canvas mCanvas;
private Context mContext;
private boolean mRun = false;
private boolean mDown = false;
private boolean newCube = false;
public CanvasThread(SurfaceHolder sh, Context context){
mSh = sh;
mCubes = new ArrayList<>();
mContext = context;
}
public void run(){
while(mRun){
mCanvas = null;
try{
mCanvas = mSh.lockCanvas(null);
synchronized (mSh){
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
newCube = true;
for(int i = 0; i < mCubes.size(); i++){
if(mCubes.get(i).getSpeed() > 0)
newCube = false;
if(mDown) {
if (mCubes.get(i).moveDown(feld)) {
mDown = false;
}
}
//mCubes.get(i).invalidate();
//mCubes.get(i).requestLayout();
mCubes.get(i).draw(mCanvas);
}
if(newCube)
addCube();
}
} finally {
if(mCanvas != null){
mSh.unlockCanvasAndPost(mCanvas);
}
}
}
}
public void addCube(){
Random r = new Random();
Cube cube = new Cube(mContext, mBuchstaben[r.nextInt(29)], r.nextInt(10), 0, mCanvas);
mCubes.add(cube);
}
}
This is my (shortened) fragment which uses the canvas/surface view:
public class KlassischFragment extends Fragment implements SurfaceHolder.Callback {
SurfaceHolder sh;
SurfaceView sv;
private CanvasThread thread;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_klassisch, container, false);
sv = (SurfaceView) view.findViewById(R.id.surfaceView);
sh = sv.getHolder();
sh.addCallback(this);
sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
return view;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new CanvasThread(sh, getContext());
thread.setRunnable(true);
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
//thread.setRunnable(false);
while(retry){
try{
thread.join();
retry = false;
} catch(InterruptedException ie){
//Immer wieder versuchen
}
break;
}
thread = null;
}
}
Here is an example on how to draw a text on top of a square. Some of the values hardcoded but you should be able to make them dynamic.
public class Cube extends View {
private final static String TEST_STRING = "ABC";
private Paint mBackgroundPaint;
private Paint mTextPaint;
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public Cube(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public Cube(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public Cube(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public Cube(Context context) {
this(context, null, -1);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Just for demo purposes this should be calculated properly
int desiredWidth = 100;
int desiredHeight = 100;
setMeasuredDimension(desiredWidth, desiredHeight);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int savedCount = canvas.save();
drawRectangle(canvas);
drawText(canvas);
canvas.restoreToCount(savedCount);
}
private void init() {
mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBackgroundPaint.setColor(Color.BLUE);
mBackgroundPaint.setStyle(Paint.Style.FILL);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
// This need to be adjusted based on the requirements that you have
mTextPaint.setTextSize(20.0f);
}
private void drawRectangle(Canvas canvas) {
canvas.drawRect(0, 0, getWidth(), getHeight(), mBackgroundPaint);
}
private void drawText(Canvas canvas) {
Rect rect = new Rect();
// For simplicity I am using a hardcoded string
mTextPaint.getTextBounds(TEST_STRING, 0, 1, rect);
int w = getWidth(), h = getHeight();
float x = (w - rect.width()) / 2, y = ((h - rect.height()) / 2) + rect.height();
canvas.drawText(TEST_STRING, 0, 1, x, y, mTextPaint);
}
}
I have a customview , inside it , i have one view slide up and down , when slide i draw fade background like this :
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.drawARGB(alpha, 0, 0, 0);
super.dispatchDraw(canvas);
}
It work with my device android 4.2.2 but with android 4.4.2 or google nexus one android 2.3.7 ,it so bad.
2 images below show in my device 4.2.2(slide in and slide out):
http://imgur.com/p6i9gw8
http://imgur.com/9Sdzy7v
and 2 images below show in google nexus one android 2.3.7(slide in and slide out):
http://imgur.com/ZGKiRJi
http://imgur.com/Uf3vRdb
As you can see, in 2 image first, fade draw correct , and in other, it look bad.
Complete code for this view is :
public class SlideView extends ViewGroup {
private static final int MAXDURATIONSLIDE = 500;
protected View content;
private int childHeight;
private int childOffset;
private int childWidth;
private int alpha;
private Fillinger fillinger;
public ISlide getSlideChangeListener() {
return slideListener;
}
public void setSlideChangeListener(ISlide slideChangeListener) {
this.slideListener = slideChangeListener;
}
private ISlide slideListener;
public SlideView(Context context) {
super(context);
init(context, null);
}
private void init(Context context, AttributeSet attrs) {
if(attrs!=null){
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlideView);
try {
int contentLayoutId = a.getResourceId(R.styleable.SlideView_slideView, 0);
DebugLog.d(contentLayoutId);
setContent(contentLayoutId);
} finally {
a.recycle();
}
}
fillinger = new Fillinger(context);
}
public SlideView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = r - l;
final int height = b - t;
DebugLog.d("width "+width+" height "+height);
childOffset = height;
content.layout(0, childOffset, childWidth, childOffset + childHeight);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(0, widthMeasureSpec);
int height = getDefaultSize(0, heightMeasureSpec);
measureChild(content, widthMeasureSpec, height);
childHeight = content.getMeasuredHeight();
childWidth = content.getMeasuredWidth();
DebugLog.d("childWidth "+childWidth+" childHeight "+childHeight);
setMeasuredDimension(width, height);
}
public void setContent(int resId) {
View view = LayoutInflater.from(getContext()).inflate(resId, this,false);
setContent(view);
}
public void setContent(View v) {
if (content != null)
removeView(content);
content = v;
addView(content);
}
private void moveViewByY(int diffY) {
childOffset += diffY;
alpha = (int) (Math.abs((getHeight()-childOffset)*255/(childHeight))*0.5f);
content.layout(0, childOffset, childWidth, childOffset + childHeight);
if(slideListener!=null){
slideListener.onSlide(childOffset,childHeight);
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.drawARGB(alpha, 0, 0, 0);
super.dispatchDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(isIn()&&touchOutSide(event)){
toogle();
return true;
}
return false;
}
private boolean touchOutSide(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
if(x<content.getLeft()||x>content.getRight()||y<content.getTop()||y>content.getBottom()){
return true;
}
return false;
}
public void hide(){
if(isIn()){
fillinger.startScroll(content.getTop(),getHeight(),childHeight,MAXDURATIONSLIDE);
}
}
public void show(){
if(!isIn()){
fillinger.startScroll(content.getTop(),getHeight()-childHeight,childHeight,MAXDURATIONSLIDE);
}
}
public void toogle(){
fillinger.cancleAnimation();
if(isIn()){
hide();
}else{
show();
}
}
public boolean isIn(){
return content.getTop()<getHeight();
}
public class Fillinger implements Runnable {
private static final String tag = "Fillinger";
private Scroller mScroller;
private int lastY;
private boolean more;
private int currentY;
private int diffY;
public Fillinger(Context context) {
mScroller = new Scroller(context);
}
public void startScroll(float startY, float endY, float maxDistance, int maxDurationForFling) {
int duration = (int) Math.min(Math.abs((endY - startY)) / maxDistance * maxDurationForFling, maxDurationForFling);
lastY = (int) startY;
if(slideListener!=null){
slideListener.onStartSlide();
}
mScroller.startScroll(0, (int) startY, 0, -(int) (endY - startY), duration);
setDrawingCacheEnabled(true);
post(this);
}
public void cancleAnimation(){
removeCallbacks(this);
}
#Override
public void run() {
more = mScroller.computeScrollOffset();
currentY = mScroller.getCurrY();
diffY = lastY - currentY;
moveViewByY(diffY);
lastY = currentY;
if (more) {
post(this);
}else{
setDrawingCacheEnabled(false);
if(slideListener!=null){
slideListener.onSlideFinish(isIn());
}
}
}
}
}
What i missing?
Sorry for my bad english.
Thanks all.
Edit: finally , i must call invalidate in moveViewByY method like this
private void moveViewByY(int diffY) {
childOffset += diffY;
alpha = (int) (Math.abs((getHeight()-childOffset)*255/(childHeight))*0.5f);
content.layout(0, childOffset, childWidth, childOffset + childHeight);
invalidate();
if(slideListener!=null){
slideListener.onSlide(childOffset,childHeight);
}
}
I dont know why , may be invalidate , view tree redraw and old canvas cleared.
Expect best solution, thanks .
In the main activity I have a handler to exchange messages with the bluetooth service. This works fine.
Now, I want launch second activity (SurfaceViewAnimation). I do this with:
startActivity (new Intent (this, SurfaceViewAnimation.class));
but I want change some attributes of SufaceViewAnimation class from main activity when it receives a command for bluetooth.
How I can do this?
The code of SufaceViewAnimation class is:
class BouncingBallView extends SurfaceView implements SurfaceHolder.Callback {
private BouncingBallAnimationThread bbThread = null;
private int xPosition = getWidth()/2;
private int yPosition = getHeight()/2;
private int xDirection = 20;
private int yDirection = 40;
private static int radius = 20;
private static int ballColor = Color.RED;
public BouncingBallView(Context ctx, AttributeSet attrs, int defStyle) {
super(ctx, attrs, defStyle);
getHolder().addCallback(this);
}
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawRect(0,0,getWidth(),getHeight(), paint);
paint.setColor(ballColor);
canvas.drawCircle(xPosition, yPosition, radius, paint);
}
public void surfaceCreated(SurfaceHolder holder) {
if (bbThread!=null) return;
bbThread = new BouncingBallAnimationThread(getHolder());
bbThread.start();
}
public void surfaceChanged(SurfaceHolder holder,int format, int width, int height) { }
public void surfaceDestroyed(SurfaceHolder holder) {
bbThread.stop = true;
}
private class BouncingBallAnimationThread extends Thread {
public boolean stop = false;
private SurfaceHolder surfaceHolder;
public BouncingBallAnimationThread(SurfaceHolder surfaceHolder) {
this.surfaceHolder = surfaceHolder;
}
public void run() {
while (!stop) {
xPosition += xDirection;
yPosition += yDirection;
if (xPosition<0) {
xDirection = -xDirection;
xPosition = radius; }
if (xPosition>getWidth()-radius) {
xDirection = -xDirection;
xPosition = getWidth()-radius; }
if (yPosition<0) {
yDirection = -yDirection;
yPosition = radius; }
if (yPosition>getHeight()-radius) {
yDirection = -yDirection;
yPosition = getHeight()-radius-1; }
Canvas c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
onDraw(c);
}
} finally {
if (c != null) surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN) return false;
if (xDirection!=0 || yDirection!=0)
xDirection = yDirection = 0;
else {
xDirection = (int) event.getX() - xPosition;
yDirection = (int) event.getY() - yPosition;
}
if(ballColor==Color.RED)
ballColor=Color.GREEN;
else
ballColor=Color.RED;
return true;
}
public void setxDirection(int xDirection) {
this.xDirection = xDirection;
}
public void setyDirection(int yDirection) {
this.yDirection = yDirection;
}
public void setballColor(int ballColor) {
this.ballColor = ballColor;
}
public void setradius(int radius) {
this.radius = radius;
}
}
public class SurfaceViewAnimation extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new BouncingBallView(this,null,0));
}
}
If you want to change the data in SurfaceViewAnimation while SurfaceViewAnimation is running, you're best off with creating an own handler.
Besides that you can fall back to basic Inter(Process/Activity)Communication using Handlers, static variables or the Observer pattern.
I've a View class that creates circles:
public class PieItem extends View{
private final float x;
private final float y;
private final int r;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public PieItem(Context context, float x, float y, int r) {
super(context);
mPaint.setColor(0xFFFF0000);
this.x = x;
this.y = y;
this.r = r;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, r, mPaint);
}
}
Edit:
I want to fit it into a framelayout programtically and then recreate it in activities:
This is me extending a Framelayout:
public class PieMenu extends FrameLayout{
private Context _context;
public PieMenu(Context context) {
super(context);
_context = context;
// TODO Auto-generated constructor stub
}
public void addPieMenu(int x, int y){
Toast.makeText(_context, "text",Toast.LENGTH_LONG).show();
PieItem pieView = new PieItem(_context,x,y,1);
FrameLayout.LayoutParams lyp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
pieView.setLayoutParams(lyp);
addView(pieView);
invalidate();
}
}
Activity:
public class MainActivity extends Activity {
PieMenu pieMenu;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pieMenu = new PieMenu(getApplicationContext());
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
{
pieMenu.addPieMenu(x,y);
}
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
}
return false;
}
}
Try it this way In your PieMenu
public class PieMenu extends FrameLayout{
public PieMenu(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
private void init(){
PieItem pieView = new PieItem(context,x,y,r);
addView(pieView);
}
I had a similar issue of the view not being displayed, but figured out the cause: you need to add the view (call addView()) not in the constructor, but after the view has finished inflating (onFinishInflate()). Here's a sample:
public class CustomFrameLayout extends FrameLayout {
public CustomFrameLayout(Context context) {
super(context);
}
public CustomFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
View blackOverlay = new View(getContext());
blackOverlay.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
blackOverlay.setBackgroundResource(android.R.color.black);
blackOverlay.setAlpha(0.2f);
addView(blackOverlay);
}
}
You can do it like this:
public class PieMenu extends FrameLayout {
public PieMenu(Context context) {
super(context);
PieItem pieView = new PieItem(context, x, y);
FrameLayout.LayoutParams lyp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
pieView.setLayoutParams(lyp);
addView(pieView);
}
}
You may need FrameLayout.LayoutParams to located the PieItem, then you can add PieMenu in Activity by call addContentView(view, params).