How to draw a line in android? - android

I found some code for line drawing but it doesn't work. Can any one help me to draw a line in android?
here is my XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/layoutmain">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello"
/>
</LinearLayout>
here is my code for class:
public class DrawPoints extends Activity implements OnTouchListener {
static int i = 0;
static float static_x = 0;
static float static_y = 0;
static float static_x1 = 0;
static float static_y1 = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View topLayout = this.findViewById(R.id.layoutmain);
// register for events for the view, previously
topLayout.setOnTouchListener((OnTouchListener) this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
String tag = null;
if (i == 0) {
static_x = event.getX();
static_y = event.getY();
i = 1;
} else {
static_x1 = event.getX();
static_y1 = event.getY();
}
if (i == 1) {
Paint p = new Paint();
p.setColor(Color.WHITE);
p.setStyle(Paint.Style.STROKE);
Canvas canvas = new Canvas();
canvas.drawColor(Color.BLUE);
canvas.drawLine(static_x, static_y, static_x1, static_y1, p);
i = 0;
}
return false;
}
}

You can simply write this in your xml layout:
<View
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#cccccc"
android:paddingTop="20dp" />
This will create a horizontal line.

This is my solution with little trick, that improve Draw performance faster than 163 times when compare with penchoco solution:
<View
android:id="#+id/line"
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#drawable/ic_line"
</View>
The only difference thing with penchoco solution is used 9 patch drawable 1x1 pixel instead of color.
android:background="#drawable/ic_line"
Question:
Could anyone explain why using 9 patch image performance was improve more than 163 times, which implement behind scenario that make a magic result ?
Thanks

You can refer to this code provided in Android Samples.
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/FingerPaint.html

Related

How to make a view like this ? Actually I tried with drawable views but can't get it

I want to make the design like image and also display same in phone and 7 inch tab.
I am using Linear layout by dividing the view in 5 part of the screen with using Framlayout draw a line but not possible to achieve like this image.
What's the other option like using canvas or any other better option.
First Image is displing expected result.
and other two are getting result.
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<gradient
android:angle="360.0"
android:endColor="#A29AA4"
android:startColor="#A29AA4" />
</shape>
Below layout
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="5">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle1"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle2"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle3"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle4"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<View
android:id="#+id/mView_circle5"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="#drawable/circleshape" />
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="center_vertical"
android:background="#A29AA4">
</RelativeLayout>
</FrameLayout>
This is easier and cleaner in canvas. Here is how you would do the first one.. You can replicate this with slight modifications for the other two.
Create a Canvas View:
public class CanvasView extends View {
Paint bPaint;
RectF coordbounds;
public CanvasView(Context context) {
super(context);
}
private void init()
{
bPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bPaint.setStyle(Paint.Style.FILL_AND_STROKE);
bPaint.setColor(Color.BLACK);
}
#Override
public void onDraw(android.graphics.Canvas canvas)
{
super.onDraw(canvas);
canvas.drawLine(coordbounds.left,coordbounds.centerY(),
coordbounds.right,coordbounds.centerY(),bPaint);
int circledia=20;
//Divide the line into four segments and subtract 2 * half the radii
float actualspan = (coordbounds.right - coordbounds.left) - (2 * circledia/2);
//Segment the line into 3 parts
float interlinesegments = actualspan/(4-1);
for(int i=0; i<4;i++)
{
canvas.drawCircle(coordbounds.left + circledia/2 +
(i*interlinesegments),
coordbounds.centerY(),10,bPaint);
}
}
}
Create a layout to hold the view and call this view in your activity:
LinearLayout layout = (LinearLayout) findViewById(R.id.root);
CanvasView view = new CanvasView(this);
layout.addView(view);
oops, I forgot . :-) Please add this method in CanvasView class to declare the bounding box and set the layout:
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
float xpad = (float) (getPaddingLeft() + getPaddingRight());
float ypad = (float) (getPaddingTop() + getPaddingBottom());
float coww = 0.0f, cohh = 0.0f, coll = 0.0f;
init();
coww = (float) w - xpad;
cohh = (float) h - ypad;
// Create a bounding box
coordbounds = new RectF(0.0f,0.0f,
coww,cohh);
}
EDIT : Change the above methods for bitmap
private void init()
{
bPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bPaint.setStyle(Paint.Style.FILL_AND_STROKE);
bPaint.setColor(Color.BLACK);
bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.button);
}
Change onDraw as follows:
#Override
public void onDraw(android.graphics.Canvas canvas)
{
super.onDraw(canvas);
canvas.drawLine(coordbounds.left,coordbounds.centerY(),
coordbounds.right,coordbounds.centerY(),bPaint);
int rectwidth=bitmap.getWidth();
int rectheight=bitmap.getHeight();
//Divide the line into four segments and subtract 2 * half the radii
float actualspan = (coordbounds.right - coordbounds.left) - (2 * rectwidth/2);
//Segment the line into 3 parts
float interlinesegments = actualspan/(4-1);
for(int i=0; i<4;i++)
{
float left= coordbounds.left + (i * interlinesegments);
float top= coordbounds.centerY()-rectheight/2;
float right = coordbounds.left+(i * interlinesegments)+rectwidth;
float bottom= coordbounds.centerY()+ rectheight/2;
canvas.drawBitmap(bitmap,null,new RectF(left,top,right,bottom),null);
}
}
With the help of above code and previous code I made this Combination of circle shape and bitmap.
#Override
public void onDraw(android.graphics.Canvas canvas)
{
super.onDraw(canvas);
canvas.drawLine(coordbounds.left, coordbounds.centerY(),
coordbounds.right, coordbounds.centerY(), bPaint);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_myprofile);
int rectwidth=bitmap.getWidth();
int rectheight=bitmap.getHeight();
//Divide the line into four segments and subtract 2 * half the radii
float actualspan_image = (coordbounds.right - coordbounds.left) - (2 * rectwidth/2);
//Segment the line into 3 parts
float interlinesegments_bitmap = actualspan_image / (4 - 1);
int circledia = 20;
//Divide the line into four segments and subtract 2 * half the radii
float actualspan = (coordbounds.right - coordbounds.left) - (2 * circledia/2);
//Segment the line into 3 parts
float interlinesegments = actualspan/(4-1);
for(int i=0; i<4;i++)
{
float left= coordbounds.left + (i * interlinesegments_bitmap);
float top= coordbounds.centerY()-rectheight/2;
float right = coordbounds.left+(i * interlinesegments_bitmap)+rectwidth;
float bottom= coordbounds.centerY()+ rectheight/2;
if(i==1){
canvas.drawBitmap(bitmap,null,new RectF(left,top,right,bottom),null);
}else{
canvas.drawCircle(coordbounds.left + circledia / 2 +
(i * interlinesegments),
coordbounds.centerY(), 10, bPaint);
}
}
}

Drawing on top of an image to create an animation

I'm new on Android, and I am having trouble with the following:
I have an image of an empty test-tube (png or bmp).
And I need to draw lines on top of it to make the illusion that its being filled in with liquid.
I really don't know how to proceed. I have read google's documentation about animations, but that didn't help much.
I'd appreciate if you guys could give me some suggestions of how it can be done, and point to some tutorials/documentation that can help me.
Thanks in advance.
UPDATE:
The tube is not retangular, the bottom is oval.
I think I need to make the liquid fall into the test tube, then paint line by line, starting from the bottom. And I have to check for the borders of the tube (right and lef black pixels).
Any ideas of how this can be done?
UPDATE 2:
Here is the tube image: http://i61.tinypic.com/2nw0eb9.png
You can use a SurfaceView to draw what ever you want:
Basicly, you lock the surface's canvas by
Canvas canvas = mSurfaceView.getHolder().lockCanvas();
Then, use the canvas's methods to draw on it. canvas.drawBitmap, canvas.drawLine etc..
When you're finished lock the canvas with mSurfaceView.getHolder().unlockCanvasAndPost(canvas); and you're done.
here's an example from a quick google search:
http://android-coding.blogspot.co.il/2011/05/drawing-on-surfaceview.html
Best way to do this would be with a custom View. Make a new class, that extends View, then in its onDraw method first draw the picture, then draw your animations. If you want to do it by hand, you can do something like this:
private class TestTubeView extends View {
private int top = 0;
private Paint myPaint;
public MyView(Context context) {
super(context);
myPaint = new Paint();
myPaint.setColor(getResources().getColor(R.color.blue));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//First draw your bitmap
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.my_testtube), 0, 0, myPaint); //might need to use a different paint
//Then your "animation" as a static image, that has its position set from a variable, in this case "y" and "x"
canvas.drawRect(0, top, getWidth(), getHeight(), myPaint);
}
//In this method update your variables, that define the positions of your animated lines / bubbles
public boolean updateAnimation() {
top++;
invalidate();
//So it stops animationg
return top > getHeight();
}
}
Then in your layout you put it in like a normal view:
<com.example.TestTubeView
android:id="#+id/my_testtube"
android:layout_width="20dp"
android:layout_height="200dp" />
And then you animate it with a self-repeating Runnable:
final MyView testTube = findViewById(R.id.my_testtube);
final Handler myHandler = new Handler();
myHandler.post(new Runnable() {
#Override
public void run() {
if(testTube.updateAnimation()){
myHandler.postDelayed(this, 200);
}
}
});
You'll have to play around with sizes / heights and things like that though. Another way of doing this is with an ObjectAnimatior
Tube Drawable: (this is for test purposes. you will use your tube image)
tube.xml (drawable folder)
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke android:width="5dp" android:color="#ffccffff" />
<solid android:color="#00000000" />
</shape>
tube_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/orangeJuiceLinearLayout"
android:layout_width="140dp"
android:layout_height="0dp"
android:layout_gravity="bottom"
android:orientation="vertical"
android:background="#fff58225">
</LinearLayout>
<ImageView
android:id="#+id/tubeImageView"
android:layout_width="140dp"
android:layout_height="220dp"
android:layout_gravity="center"
android:background="#drawable/tube"
android:onClick="fillJuice"
android:clickable="true" />
</FrameLayout>
</LinearLayout>
TubeAcivity.java
public class TubeActivity extends Activity {
LinearLayout orangeLL;
ImageView tubeIV;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tube_activity);
orangeLL = (LinearLayout)findViewById(R.id.orangeJuiceLinearLayout);
tubeIV = (ImageView)findViewById(R.id.tubeImageView);
}
public void fillJuice(View view) {
ValueAnimator va = ValueAnimator.ofInt(0, tubeIV.getMeasuredHeight());
va.setDuration(1500);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
orangeLL.getLayoutParams().height = value.intValue();
orangeLL.requestLayout();
}
});
va.start();
}
}

Unable to draw line over gridview elements properly through textview cells in Android

I would like to implement Word Search app. As part of implementation i have come across canvas and drawing line over grid view cells( letters that form the word) to indicate that user is touching finger over letters to form the word.
I have succeeded partially as of now i can draw a line over letters of grid view but the line is not through center of views of grid View.
Please can anyone assist me with your valuable suggestions .
Have a glance on below screen shot to get a clear idea.
Edited: I'm posting code to get an idea of how I'm implementing it.
xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#fff" >
<RelativeLayout
android:id="#+id/topbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#A9E2F3" >
<LinearLayout
android:id="#+id/topbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#336699"
android:orientation="horizontal" >
<Button
android:id="#+id/btn_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pause" />
<Chronometer
android:id="#+id/chronometer1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Chronometer" />
<TextView
android:id="#+id/counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="20sp"
android:typeface="serif" />
</LinearLayout>
</RelativeLayout>
<FrameLayout
android:id="#+id/gridFrame"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/wTable"
android:layout_below="#+id/textdisplay" >
<GridView
android:id="#+id/grid"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#E7E8E9"
android:fitsSystemWindows="true"
android:gravity="center"
android:horizontalSpacing="10sp"
android:numColumns="10"
android:padding="1dp"
android:stretchMode="columnWidth"
android:verticalSpacing="10sp" >
</GridView>
</FrameLayout>
<GridView
android:id="#+id/wTable"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#fff"
android:numColumns="3"
android:orientation="vertical" />
</RelativeLayout>
The paint is drawing over frame layout which contains grid view. Grid view elements are printed through custom text view file.
To draw a line i have used LineView.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.View;
public class LineView extends View {
public static final float LINE_WIDTH = 30.0f;
public Paint paint = new Paint();
protected Context context;
public float startingX, startingY, endingX, endingY;
public LineView(Context context) {
super(context);
this.context = context;
paint.setColor(Color.parseColor("#2E9AFE"));
paint.setStrokeWidth(LINE_WIDTH);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setDither(true);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
paint.setAlpha(90);
}
public void setPoints(float startX, float startY, float endX, float endY) {
startingX = startX;
startingY = startY;
endingX = endX;
endingY = endY;
invalidate();
}
#Override
public void onDraw(Canvas canvas) {
Log.e("LINEVIEW", "startingX" + startingX + " startingY:" + startingY);
Log.e("LINEVIEW", "endingX" + endingX + " endingY:" + endingY);
// canvas.drawLine(startingX, startingY, endingX, endingY, paint);
canvas.drawLine(startingX, startingY, endingX, endingY, paint);
}
}
Main Activity where logic is implemented:
Written only the required logic here.
newGrid = (GridView) findViewById(R.id.grid);
newGrid.setAdapter(new FormTheGridLetters());
newGrid.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// if (mp.isPlaying()) {
// mp.stop();
// }
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
// data
PaintViewHolder newPaint = new PaintViewHolder();
newPaint.DrawLine = new LineView(WordSearchActivity.this);
gridFrame.addView(newPaint.DrawLine);
buildWord = new StringBuilder();
int x = (int) event.getX();
int y = (int) event.getY();
// test = new LineView(WordSearchActivity.this);
int position = newGrid.pointToPosition(x, y);
Point one,
two;
if (position != GridView.INVALID_POSITION) {
v.getParent().requestDisallowInterceptTouchEvent(true);
cellView = (TextView) newGrid.getChildAt(position);
String a = cellView.getText().toString();
// Log.v(">>>>><<<<<<<????????", a.toString());
switch (action) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
// Checking the list for formed word ;
//if found that is painted
for (int i1 = 0; i1 < Ans.size(); i1++)
{
if (formedWord.equals(Ans.get(i1)))
{
answerAdapter.notifyDataSetChanged();
newPaint.DrawLine.setPoints(startX, startY, x, y);
// Painted the letters by passing starting and ending points
}
}
break;
}
} else {
if (mSelecting) {
mSelecting = false;
}
}
break;
case MotionEvent.ACTION_CANCEL:
mSelecting = false;
break;
}
return true;
}
});
I don't know if you fix the issue but I will answer anyway for the people that may have these kind of problems. After you recieve the valid position, you can get the center of the view and you can set these values as beginning of the draw.
Like this:
if (position != GridView.INVALID_POSITION) {
MyList.add(position);
v.getParent().requestDisallowInterceptTouchEvent(true);
TextView cellView = (TextView) gridView.getChildAt(position);
centreX = cellView.getX() + cellView.getWidth() / 2;
centreY = cellView.getY() + cellView.getHeight() / 2;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
newPaint.DrawLine.touch_start(x, y,centreX,centreY);
I have tried this code and it is working. I don't think that you need anymore but I have joined this site recently so maybe it will help other people. I can post more code if you want but
newPaint.DrawLine.touch_start(x, y,centreX,centreY);
is the trick for that issue.
Hope this helps.

Blur background image like yahoo weather app in android

I'm trying to implement a similar kind of UI which yahoo weather app did. I am able to blur the background image with the listview based on this link. http://nicolaspomepuy.fr/?p=18. In the above URL the author is using Listview onScrollListerner. But I have to implement that effect using a scrollview.
Inside a scrollview I'll be having 3 pages with 3 views. On scrolling the first view I want the background image to be blurred. I wrote a custom scrollview which extends Scrollview to achieve the onScroll Changed functionality.
But couldn't able to change the alpha values of blured Image based on Scroll positions.
Here I'm attaching my sample code. Please help me to figure it out.
public class MainActivity extends Activity implements ScrollViewListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initUI();
mBlurredImage.setAlpha(alpha);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
screenWidth = displaymetrics.widthPixels;
empty.getLayoutParams().height = (int) (displaymetrics.heightPixels * 0.6);
// Try to find the blurred image
final File blurredImage = new File(getFilesDir() + BLURRED_IMG_PATH);
if (!blurredImage.exists()) {
new Thread(new Runnable() {
#Override
public void run() {
// No image found => let's generate it!
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.image, options);
Bitmap newImg = Blur.fastblur(MainActivity.this, image, 12);
ImageUtils.storeImage(newImg, blurredImage);
runOnUiThread(new Runnable() {
#Override
public void run() {
updateView(screenWidth);
}
});
}
}).start();
} else {
// The image has been found. Let's update the view
updateView(screenWidth);
}
}
private void updateView(final int screenWidth) {
Bitmap bmpBlurred = BitmapFactory.decodeFile(getFilesDir() + BLURRED_IMG_PATH);
bmpBlurred = Bitmap.createScaledBitmap(bmpBlurred, screenWidth, (int) (bmpBlurred.getHeight()
* ((float) screenWidth) / (float) bmpBlurred.getWidth()), false);
mBlurredImage.setImageBitmap(bmpBlurred);
}
private void initUI() {
textView = (TextView) findViewById(R.id.textview);
empty = (LinearLayout) findViewById(R.id.empty);
scrollView = (ObservableScrollView) findViewById(R.id.customScrollView);
mBlurredImage = (ImageView) findViewById(R.id.blurred_image);
normalImage = (ImageView) findViewById(R.id.normal_image);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onScrollChanged(ObservableScrollView scrollView, int x, int y,
int oldx, int oldy) {
// TODO Auto-generated method stub
Log.i("Scrolling", "X from ["+oldx+"] to ["+x+"]");
Toast.makeText(this,"HI welcome ", Toast.LENGTH_SHORT).show();
alpha = (float) -textView.getTop() / (float) TOP_HEIGHT;
// // Apply a ceil
if (alpha > 1) {
alpha = 1;
}
}
}
public class ObservableScrollView extends ScrollView{
private ScrollViewListener scrollViewListener = null;
public ObservableScrollView(Context context) {
super(context);
}
public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
#Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if(scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
public interface ScrollViewListener {
void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);
}
Here is the XML file
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.blureffect.TopCenterImageView
android:id="#+id/normal_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/image" />
<com.example.blureffect.TopCenterImageView
android:id="#+id/blurred_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0" />
<com.example.blureffect.ObservableScrollView
android:id="#+id/customScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
/>
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="It was a good track to bowl on. It had good bounce, the ball was turning sharply as well. We bowled in the right areas. When batsmen bat in partnerships the job is easy. That is the same case with bowlers. Ashwin and I have formed a good partnership. It has been a honour to play with Sachin paaji. I would like to dedicate my five-wicket haul to Sachin paaji. We were all motivated from yesterday and we want to enjoy this occasion." />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="It was a good track to bowl on. It had good bounce, the ball was turning sharply as well. We bowled in the right areas. When batsmen bat in partnerships the job is easy. That is the same case with bowlers. Ashwin and I have formed a good partnership. It has been a honour to play with Sachin paaji. I would like to dedicate my five-wicket haul to Sachin paaji. We were all motivated from yesterday and we want to enjoy this occasion." />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="It was a good track to bowl on. It had good bounce, the ball was turning sharply as well. We bowled in the right areas. When batsmen bat in partnerships the job is easy. That is the same case with bowlers. Ashwin and I have formed a good partnership. It has been a honour to play with Sachin paaji. I would like to dedicate my five-wicket haul to Sachin paaji. We were all motivated from yesterday and we want to enjoy this occasion." />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="It was a good track to bowl on. It had good bounce, the ball was turning sharply as well. We bowled in the right areas. When batsmen bat in partnerships the job is easy. That is the same case with bowlers. Ashwin and I have formed a good partnership. It has been a honour to play with Sachin paaji. I would like to dedicate my five-wicket haul to Sachin paaji. We were all motivated from yesterday and we want to enjoy this occasion." />
</LinearLayout>
</com.example.blureffect.ObservableScrollView>
</FrameLayout>
I had to implement something similar not a long time ago - in my case it was a vertical ScrollView that, when scrolled, would affect the blur of the background.
First of all, I implemented ObservableScrollView to expose the onScrollChanged() method and also to be able to set my own listener for it:
public void setScrollViewListener(ObservableScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
#Override
protected void onScrollChanged(int x, int y, int oldX, int oldY) {
super.onScrollChanged(x, y, oldX, oldY);
if(scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldX, oldY);
}
}
Now, to achieve the blurring effect I basically change the alpha of the blurred background ImageView - shown in this snippet from my class which is responsible for both the ObservableScrollView and the ImageViews:
#Override
public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldX, int oldY) {
//...
// Blurring
float blurredImageAlpha = (float) y / SCROLL_VIEW_INITIAL_OFFSET;
if (blurredImageAlpha > 1.0) {
blurredImageAlpha = (float) 1.0;
}
imageBackgroundBlurred.setAlpha(blurredImageAlpha);
}
As you can see, I divide the y by a certain value simply not to have the the blur start straight away - this depends on what you exactly need.
As for my XML layout, it looks something like this:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/aboutMainView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/black"
android:padding="0dp" >
<ImageView
android:id="#+id/aboutImageBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="#null"
android:scaleType="centerCrop"
android:src="#drawable/about_back_a" />
<ImageView
android:id="#+id/aboutImageBackgroundBlurred"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:alpha="0.0"
android:contentDescription="#null"
android:scaleType="centerCrop"
android:src="#drawable/about_back_b" />
<com.bronzelabs.maa.widgets.ObservableScrollView
android:id="#+id/aboutObservableScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:orientation="vertical" />
</RelativeLayout>
check out this sample project:
https://github.com/MoshDev/LikeYahooWeather

Clickable items inside an EditText

The problem:
To make a long story short, I would like to insert a custom clickable Drawable (or something that looks like a little button and acts like a single character) inside an EditText.
Research:
I've read some documentation as well as related questions and I almost achieved the result I want (see "Code" section). It's a little bit tricky, but I wasn't able to find another way out. I'm using Html.fromHtml(source, imageGetter, tagHandler) to insert the drawable I need with a link and then implementing a custom LinkMovementMethod to handle clicks on it.
But there are some things I would like to avoid:
If there are no text after my drawable, it gets clicked even if I click anywhere right to it. So I'm not able to place a cursor next to it without moving it manually.
On some devices the cursor appears at the very beginning of EditText every time I perform a click, except cases when I click drawable.
Code:
Inserting drawable with a link and setting the custom LinkMovementMethod:
Html.ImageGetter imgGetter = new Html.ImageGetter() {
#Override
public Drawable getDrawable(String source) {
Drawable drawable = getResources().getDrawable(R.drawable.blip_icon_read);
//Making it as small as a character
drawable.setBounds(0, 0, (int)getTextSize(), (int)getTextSize());
return drawable;
}
};
String buttonSrc = "<a href='button://" + "somedata" + "'><img src=/></a>";
myEditText.append(Html.fromHtml(buttonSrc, imgGetter, null));
myEditText.setMovementMethod(MyLinkMovementMethod.getInstance(context));
Custom LinkMovementMethod:
public class MyLinkMovementMethod extends LinkMovementMethod {
private static Context movementContext;
private static MyLinkMovementMethod linkMovementMethod = new MyLinkMovementMethod();
public boolean onTouchEvent(android.widget.TextView widget, android.text.Spannable buffer, android.view.MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
URLSpan[] link = buffer.getSpans(off, off, URLSpan.class);
if (link.length != 0) {
URI uri;
try {
uri = new URI(link[0].getURL());
} catch (URISyntaxException e) {
e.printStackTrace();
return true;
}
if (uri.getScheme().equals("button")) {
//Doing stuff here
}
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
public static android.text.method.MovementMethod getInstance(Context c) {
movementContext = c;
return linkMovementMethod;
}
}
Layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/my_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:textColor="#android:color/black"
android:scrollbars="vertical"
android:textCursorDrawable="#null"
android:gravity="top" >
</EditText>
</LinearLayout>
Questions:
Is there any way to avoid things I described in the end of "Research" section using this approach?
Is there another approach I should use?
Will be glad to read advices or any ideas. Thank you.
this seems to work (unless i dont really understand your idea)
public class MyMovementMethod extends ArrowKeyMovementMethod {
#Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
MyClickableSpan[] link = buffer.getSpans(off, off, MyClickableSpan.class);
if (link.length != 0 && off != buffer.length()) {
link[0].doSomething();
return true;
}
}
return super.onTouchEvent(widget, buffer, event);
}
}
class MyClickableSpan extends ImageSpan {
public MyClickableSpan(Bitmap b) {
super(b);
}
public void doSomething() {
Log.d(TAG, "doSomething ***********************************************");
}
}
to test it add the following in Activity.onCreate:
LinearLayout ll = new LinearLayout(this);
EditText et = new EditText(this);
SpannableStringBuilder b = new SpannableStringBuilder();
b.append("Attach the specified markup object to the ");
int start = b.length();
b.append("x");
int end = b.length();
b.append(" range start end of the text, or move the object to that range if it was...");
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
b.setSpan(new MyClickableSpan(bitmap), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
et.setText(b);
et.setMovementMethod(new MyMovementMethod());
ll.addView(et);
setContentView(ll);
just use a ScrollView as parentView will help you.
Like this
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="45dp"
android:layout_below="#id/header_container"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/title"
android:hint="输入标题"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginEnd="15dp"
android:inputType="text"
android:textSize="22sp"
android:singleLine="true"
android:textCursorDrawable="#color/cursor_white"
android:background="#drawable/bg_edittext_title_white"
android:padding="5dp"
>
</EditText>
<EditText
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#null"
android:gravity="start|top"
android:layout_marginLeft="15dp"
android:layout_marginStart="15dp"
android:layout_marginRight="15dp"
android:layout_marginEnd="15dp"
android:layout_marginTop="10dp"
android:inputType="textMultiLine"
android:minHeight="220dp"
android:singleLine="false"
android:textCursorDrawable="#color/cursor_white"
android:hint="输入内容"
android:padding="5dp"
/>
</LinearLayout>
</ScrollView>

Categories

Resources