您的位置:首页 > 移动开发 > Android开发

仿QQ消息导航栏RadioGroup里添加拖拽的TextView(未读消息)

2017-07-19 00:15 477 查看
效果图:



MainActivity:

主要是放置拖拽的TextView的位置setTextView(); 设置未读消息 textView.setText(“10”);

public class MainActivity extends AppCompatActivity {

private DragPointView textView;
private RadioGroup group;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//初始化
textView =(DragPointView)findViewById(R.id.dpv_message);
group = (RadioGroup)findViewById(R.id.group);

//放置拖拽的TexView
setTextView();

group.setOnCheckedChangeListener(listener);
}

private RadioGroup.OnCheckedChangeListener listener = new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
if (checkedId == R.id.tab_rb_news) {

} else if (checkedId == R.id.tab_rb_contacts) {

} else if (checkedId == R.id.tab_rb_discover) {

} else if (checkedId == R.id.tab_rb_service) {

} else if (checkedId == R.id.tab_rb_myself) {

}
}
};

private void setTextView() {
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = displayMetrics.widthPixels;
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) textView.getLayoutParams();
layoutParams.leftMargin = screenWidth * 8/ 25;
textView.setLayoutParams(layoutParams);
textView.setText("10");
textView.setBackgroundColor(Color.RED);
}

}


布局activity_main:

刚开始项目就已经使用RadioGroup了,本来准备在RadioButton里面动手脚的,后来发现不好测量,会与RadioButton的点击发生冲突,后来使用自定义的TipButton是可以实现未读消息是小圆点的,然后就是使用帧布局将RadioGroup和TextView包裹,然后进行测量TextView的宽就行了,效果还不错.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical"
tools:context="com.example.myapplication.MainActivity">

<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>

<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:minHeight="48dp"
>

<RadioGroup
android:id="@+id/group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:gravity="center"
android:minHeight="48dp"
android:orientation="horizontal"
>

<com.example.myapplication.TipButton
android:id="@+id/tab_rb_news"
style="@style/radioButton"
android:button="@null"
android:checked="true"
android:drawableTop="@drawable/tab_schoolmate_news_selector"
android:text="校友会" />

<com.example.myapplication.TipButton
android:id="@+id/tab_rb_contacts"
style="@style/radioButton"
android:button="@null"
android:drawableTop="@drawable/tab_schoolmate_contacts_selector"
android:text="消息" />

<com.example.myapplication.TipButton
android:id="@+id/tab_rb_discover"
android:button="@null"
style="@style/radioButton"
android:drawableTop="@drawable/tab_discover_selector"
android:text="发现" />

<com.example.myapplication.TipButton
android:id="@+id/tab_rb_service"
android:button="@null"
style="@style/radioButton"
android:drawableTop="@drawable/tab_schoolmate_service_selector"
android:text="服务" />

<com.example.myapplication.TipButton
android:id="@+id/tab_rb_myself"
style="@style/radioButton"
android:button="@null"
android:drawableTop="@drawable/tab_schoolmate_self_selector"
android:text="我的" />

</RadioGroup>

<com.example.myapplication.DragPointView
android:id="@+id/dpv_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|left|center"
android:layout_marginTop="3dp"
android:layout_marginLeft="120dp"
android:background="@drawable/shapecount"
android:backgroundTint="@color/red"
android:gravity="center"
android:paddingLeft="3dp"
android:paddingRight="3dp"
android:text="10"
android:textColor="#ffffffff"
android:textSize="11sp" />

11ea6
</FrameLayout>
</LinearLayout>


自定义的TipButton:

setTipOn(true)是可以设置小红点的

/**
* Create by xuke  2017/7/17
* desc:可以显示小圆点的RadioButton
* */

@SuppressLint("AppCompatCustomView")
public class TipButton extends RadioButton {

private boolean mTipOn = false;

private Dot mDot;

private class Dot {

int color;
int radius;
int marginTop;
int marginRight;

Dot() {
float density = getContext().getResources().getDisplayMetrics().density;
radius = (int) (5 * density);
marginTop = (int) (3 * density);
marginRight = (int) (3 * density);

color = getContext().getResources().getColor(R.color.red);
}

}

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

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

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

private void init() {
mDot = new Dot();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

if (mTipOn) {
float cx = getWidth() - mDot.marginRight - mDot.radius;
float cy = mDot.marginTop + mDot.radius;

Drawable drawableTop = getCompoundDrawables()[1];
if (drawableTop != null) {
int drawableTopWidth = drawableTop.getIntrinsicWidth();
if (drawableTopWidth > 0) {
int dotLeft = getWidth() / 2 + drawableTopWidth / 2;
cx = dotLeft + mDot.radius;
}
}

Paint paint = getPaint();
//save
int tempColor = paint.getColor();

paint.setColor(mDot.color);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(cx, cy, mDot.radius, paint);

//restore
paint.setColor(tempColor);
}
}

public void setTipOn(boolean tip) {
this.mTipOn = tip;

invalidate();
}

public boolean isTipOn() {
return mTipOn;
}
}


然后自定义的DragPointView:

/**
* Create by xuke  2017/7/17
* desc:可以拖拽的TextView
* */

@SuppressLint("AppCompatCustomView")
public class DragPointView extends TextView {
private boolean initBgFlag;
private OnDragListencer dragListencer;
private int backgroundColor = Color.parseColor("#0F88EB");
private PointView pointView;
private int x, y, r;
private ViewGroup scrollParent;
private int[] p = new int[2];

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

public OnDragListencer getDragListencer() {
return dragListencer;
}

public void setDragListencer(OnDragListencer dragListencer) {
this.dragListencer = dragListencer;
}

public int getBackgroundColor() {
return backgroundColor;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int w = getMeasuredWidth();
int h = getMeasuredHeight();
if (w != h) { // 简单的将宽高搞成一样的,如果有更好的方法欢迎在我博客下方留言!
int x = Math.max(w, h);
setMeasuredDimension(x, x);
}
}

@SuppressWarnings("deprecation")
public void setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
DragPointView.this.setBackgroundDrawable(createStateListDrawable((getHeight() > getWidth() ? getHeight()
: getWidth()) / 2, backgroundColor));
}

private void initbg() {
setGravity(Gravity.CENTER);
getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {

@SuppressWarnings("deprecation")
@Override
public boolean onPreDraw() {
if (!initBgFlag) {
DragPointView.this.setBackgroundDrawable(createStateListDrawable(
(getHeight() > getWidth() ? getHeight() : getWidth()) / 2, backgroundColor));
initBgFlag = true;
return false;
}
return true;
}
});
}

@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
View root = getRootView();
if (root == null || !(root instanceof ViewGroup)) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
root.getLocationOnScreen(p);
scrollParent = getScrollParent();
if (scrollParent != null) {
scrollParent.requestDisallowInterceptTouchEvent(true);
}
int location[] = new int[2];
getLocationOnScreen(location);
x = location[0] + (getWidth() / 2) - p[0];
y = location[1] + (getHeight() / 2) - p[1];
r = (getWidth() + getHeight()) / 4;
pointView = new PointView(getContext());
pointView.setLayoutParams(new ViewGroup.LayoutParams(root.getWidth(), root.getHeight()));
setDrawingCacheEnabled(true);
pointView.catchBitmap = getDrawingCache();
pointView.setLocation(x, y, r, event.getRawX() - p[0], event.getRawY() - p[1]);
((ViewGroup) root).addView(pointView);
setVisibility(View.INVISIBLE);
break;
case MotionEvent.ACTION_MOVE:
pointView.refrashXY(event.getRawX() - p[0], event.getRawY() - p[1]);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (scrollParent != null) {
scrollParent.requestDisallowInterceptTouchEvent(false);
}
if (!pointView.broken) { // 没有拉断
pointView.cancel();
} else if (pointView.nearby) {// 拉断了,但是又回去了
pointView.cancel();
} else { // 彻底拉断了
pointView.broken();
}
break;
default:
break;
}
return true;
}

private ViewGroup getScrollParent() {
View p = this;
while (true) {
View v;
try {
v = (View) p.getParent();
} catch (ClassCastException e) {
return null;
}
if (v == null)
return null;
if (v instanceof AbsListView || v instanceof ScrollView || v instanceof ViewPager) {
return (ViewGroup) v;
}
p = v;
}
}

public interface OnDragListencer {
public void onDragOut();
}

class PointView extends View {
private Bitmap catchBitmap;
private Circle c1;
private Circle c2;
private Paint paint;
private Path path = new Path();
private int maxDistance = 10; // 10倍半径距离视为拉断
private boolean broken; // 是否拉断过
private boolean out; // 放手的时候是否拉断
private boolean nearby;
private int brokenProgress;

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

public void init() {
paint = new Paint();
paint.setColor(backgroundColor);
paint.setAntiAlias(true);
}

public void setLocation(float c1X, float c1Y, float r, float endX, float endY) {
broken = false;
c1 = new Circle(c1X, c1Y, r);
c2 = new Circle(endX, endY, r);
}

public void refrashXY(float x, float y) {
c2.x = x;
c2.y = y;
// 以前的半径应该根据距离缩小点了
// 计算出距离
double distance = c1.getDistance(c2);
int rate = 10;
c1.r = (float) ((c2.r * c2.r * rate) / (distance + (c2.r * rate)));
invalidate();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.TRANSPARENT);
if (out) {
float dr = c2.r / 2 + c2.r * 4 * (brokenProgress / 100f);
canvas.drawCircle(c2.x, c2.y, c2.r / (brokenProgress + 1), paint);
canvas.drawCircle(c2.x - dr, c2.y - dr, c2.r / (brokenProgress + 2), paint);
canvas.drawCircle(c2.x + dr, c2.y - dr, c2.r / (brokenProgress + 2), paint);
canvas.drawCircle(c2.x - dr, c2.y + dr, c2.r / (brokenProgress + 2), paint);
canvas.drawCircle(c2.x + dr, c2.y + dr, c2.r / (brokenProgress + 2), paint);
} else {
// 绘制手指跟踪的圆形
canvas.drawBitmap(catchBitmap, c2.x - c2.r, c2.y - c2.r, paint);
path.reset();
float deltaX = c2.x - c1.x;
float deltaY = -(c2.y - c1.y);
double distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
double sin = deltaY / distance;
double cos = deltaX / distance;
nearby = distance < c2.r * maxDistance;
if (nearby && !broken) {
canvas.drawCircle(c1.x, c1.y, c1.r, paint);
path.moveTo((float) (c1.x - c1.r * sin), (float) (c1.y - c1.r * cos));
path.lineTo((float) (c1.x + c1.r * sin), (float) (c1.y + c1.r * cos));
path.quadTo((c1.x + c2.x) / 2, (c1.y + c2.y) / 2, (float) (c2.x + c2.r * sin), (float) (c2.y + c2.r
* cos));
path.lineTo((float) (c2.x - c2.r * sin), (float) (c2.y - c2.r * cos));
path.quadTo((c1.x + c2.x) / 2, (c1.y + c2.y) / 2, (float) (c1.x - c1.r * sin), (float) (c1.y - c1.r
* cos));
canvas.drawPath(path, paint);
} else {
broken = true; // 已经拉断了
}
}

}

public void cancel() {
int duration = 150;
AnimatorSet set = new AnimatorSet();
ValueAnimator animx = ValueAnimator.ofFloat(c2.x, c1.x);
animx.setDuration(duration);
animx.setInterpolator(new OvershootInterpolator(2));
animx.addUpdateListener(new AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
c2.x = (float) animation.getAnimatedValue();
invalidate();
}
});
ValueAnimator animy = ValueAnimator.ofFloat(c2.y, c1.y);
animy.setDuration(duration);
animy.setInterpolator(new OvershootInterpolator(2));
animy.addUpdateListener(new AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
c2.y = (float) animation.getAnimatedValue();
invalidate();
}
});
set.playTogether(animx, animy);
set.addListener(new AnimatorListenerAdapter() {

@Override
public void onAnimationEnd(Animator animation) {
ViewGroup vg = (ViewGroup) PointView.this.getParent();
vg.removeView(PointView.this);
DragPointView.this.setVisibility(View.VISIBLE);
}
});
set.start();

}

public void broken() {
out = true;
int duration = 500;
ValueAnimator a = ValueAnimator.ofInt(0, 100);
a.setDuration(duration);
a.setInterpolator(new LinearInterpolator());
a.addUpdateListener(new AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
brokenProgress = (int) animation.getAnimatedValue();
invalidate();
}
});
a.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
ViewGroup vg = (ViewGroup) PointView.this.getParent();
vg.removeView(PointView.this);
}
});
a.start();
if (dragListencer != null) {
dragListencer.onDragOut();
}
}

class Circle {
float x;
float y;
float r;

public Circle(float x, float y, float r) {
this.x = x;
this.y = y;
this.r = r;
}

public double getDistance(Circle c) {
float deltaX = x - c.x;
float deltaY = y - c.y;
double distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
return distance;
}
}

}

/**
* @param radius 圆角角度
* @param color  填充颜色
* @return StateListDrawable 对象
* @author zy
*/
public static StateListDrawable createStateListDrawable(int radius, int color) {
StateListDrawable bg = new StateListDrawable();
GradientDrawable gradientStateNormal = new GradientDrawable();
gradientStateNormal.setColor(color);
gradientStateNormal.setShape(GradientDrawable.RECTANGLE);
gradientStateNormal.setCornerRadius(radius);
gradientStateNormal.setStroke(0, 0);
bg.addState(View.EMPTY_STATE_SET, gradientStateNormal);
return bg;
}

// 分别记录上次滑动的坐标(onInterceptTouchEvent)
private int mLastXIntercept = 0;
private int mLastYIntercept = 0;

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
getParent().requestDisallowInterceptTouchEvent(true);
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastXIntercept;
int deltaY = y - mLastYIntercept;
//如果是左右滑动
if (Math.abs(deltaX) > Math.abs(deltaY)) {
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
}
case MotionEvent.ACTION_UP: {
getParent().requestDisallowInterceptTouchEvent(false);
break;
}
}
mLastXIntercept = x;
mLastYIntercept = y;
return super.dispatchTouchEvent(ev);
}
}


源码demo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息