DragActivity.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. package com.xunao.effectdemo.activity;
  2. import static com.blankj.utilcode.util.ScreenUtils.getScreenHeight;
  3. import static com.blankj.utilcode.util.ScreenUtils.getScreenWidth;
  4. import androidx.appcompat.app.AppCompatActivity;
  5. import androidx.core.content.res.ResourcesCompat;
  6. import android.animation.Animator;
  7. import android.animation.AnimatorSet;
  8. import android.animation.ObjectAnimator;
  9. import android.app.Activity;
  10. import android.content.ClipData;
  11. import android.content.Context;
  12. import android.content.Intent;
  13. import android.graphics.Color;
  14. import android.os.Bundle;
  15. import android.os.SystemClock;
  16. import android.util.Log;
  17. import android.util.TypedValue;
  18. import android.view.DragEvent;
  19. import android.view.Gravity;
  20. import android.view.HapticFeedbackConstants;
  21. import android.view.MotionEvent;
  22. import android.view.View;
  23. import android.view.ViewGroup;
  24. import android.view.ViewTreeObserver;
  25. import android.view.animation.Animation;
  26. import android.view.animation.AnimationUtils;
  27. import android.view.animation.TranslateAnimation;
  28. import android.widget.FrameLayout;
  29. import android.widget.ImageView;
  30. import android.widget.LinearLayout;
  31. import android.widget.RelativeLayout;
  32. import android.widget.TextView;
  33. import com.xunao.effectdemo.R;
  34. import java.util.ArrayList;
  35. import java.util.List;
  36. import java.util.Random;
  37. import java.util.Timer;
  38. import java.util.TimerTask;
  39. public class DragActivity extends Activity{
  40. private static final String RED = "RED";
  41. RelativeLayout select_rl;
  42. RelativeLayout rl_bg;
  43. TextView tv_content;
  44. //进行滑动的TextView
  45. private TextView moveTextView;
  46. List<String> selectList;
  47. private int answerSize = 0;
  48. private int halfAnswerSize = 0;
  49. private int selectRootWidth = 0;
  50. private int selectRootHeight = 0;
  51. //选项位置的集合。初始的显示位置。用于后续拖动松手后,选项做回归动画
  52. private List<String> selectInitialLocationList;
  53. //分隔符
  54. private String SeparateSymbol = "-";
  55. //认为的最小滑动值。超过这个值,就认为是滑动;如果没有超过,就是认为是点击
  56. private int reputeMixMoveValue = 10;
  57. //按下时候的x,y坐标
  58. private float downX = 0;
  59. private float downY = 0;
  60. //当前点击或者按住了哪个选项
  61. private int currentOptionPosition = -1;
  62. //移动、滑动时候,当前位置的x,y坐标
  63. private float moveCurrentX;
  64. private float moveCurrentY;
  65. private String selectedContent = "";
  66. private final String correctAnswer = "选项2";
  67. private int wrongNum = 0;
  68. Timer timer = new Timer();
  69. @Override
  70. protected void onCreate(Bundle savedInstanceState) {
  71. super.onCreate(savedInstanceState);
  72. setContentView(R.layout.activity_drag);
  73. tv_content = findViewById(R.id.tv_content);
  74. select_rl = findViewById(R.id.select_rl);
  75. rl_bg = findViewById(R.id.rl_bg);
  76. initData();
  77. }
  78. void initData(){
  79. selectInitialLocationList = new ArrayList<>();
  80. // 选项集合
  81. List<String> selectList = new ArrayList<>();
  82. selectList.add("选项1");
  83. selectList.add("选项2");
  84. selectList.add("选项3");
  85. this.selectList = selectList;
  86. answerSize = dp2px(50);
  87. halfAnswerSize = answerSize / 2;
  88. ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
  89. @Override
  90. public void onGlobalLayout() {
  91. View view = new View(DragActivity.this);
  92. RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  93. params.width = getScreenWidth()/2;
  94. params.height = getScreenHeight();
  95. view.setLayoutParams(params);
  96. view.setBackgroundColor(getResources().getColor(R.color.textGrayColor));
  97. rl_bg.addView(view);
  98. select_rl.getViewTreeObserver().removeOnGlobalLayoutListener(this);
  99. handleSelect();
  100. }
  101. };
  102. select_rl.getViewTreeObserver().addOnGlobalLayoutListener(listener);
  103. }
  104. @Override
  105. public boolean onTouchEvent(MotionEvent event) {
  106. switch (event.getAction()){
  107. case MotionEvent.ACTION_DOWN:
  108. if (moveTextView != null) {
  109. break;
  110. }
  111. currentOptionPosition = -1;
  112. downX = event.getX();
  113. downY = event.getY();
  114. //指定当前滑动的TextView
  115. for (int i = 0; i < selectInitialLocationList.size(); i++) {
  116. float x1 = Float.parseFloat(selectInitialLocationList.get(i).split(SeparateSymbol)[0]);
  117. float x2 = x1 + answerSize*4;
  118. float y1 = Float.parseFloat(selectInitialLocationList.get(i).split(SeparateSymbol)[1]);
  119. float y2 = y1 + answerSize;
  120. //x1、y1,是选项左上角的坐标。x2、y2,是选项右下角的坐标
  121. if (downX > x1 && downX < x2 && downY > y1 && downY < y2) {
  122. if(select_rl.getChildAt(i).getVisibility() == View.VISIBLE){
  123. //拿到当前选择的这个选项的view
  124. moveTextView = (TextView) select_rl.getChildAt(i);
  125. //记下现在选的,是第几个选项
  126. currentOptionPosition = i;
  127. Log.e("按下", currentOptionPosition + "");
  128. break;
  129. }
  130. }
  131. }
  132. break;
  133. case MotionEvent.ACTION_MOVE:
  134. if (moveTextView == null) {
  135. return false;
  136. }
  137. moveCurrentX = event.getX();
  138. moveCurrentY = event.getY();
  139. if (Math.abs(moveCurrentX - downX) > reputeMixMoveValue && Math.abs(moveCurrentY - downY) > reputeMixMoveValue) {
  140. //这里,按下的坐标,要减去选项的一半,让选项的中间,跟着手指动。否则,就是选项的左上角,跟着手指移动,不美观
  141. moveTextView.setX(moveCurrentX - halfAnswerSize);
  142. moveTextView.setY(moveCurrentY - halfAnswerSize);
  143. }
  144. break;
  145. case MotionEvent.ACTION_UP:
  146. case MotionEvent.ACTION_CANCEL:
  147. if (moveTextView == null) {
  148. return false;
  149. }
  150. // 当移动到答案框内时
  151. if(moveCurrentX > tv_content.getX() && moveCurrentX < tv_content.getX() + tv_content.getWidth() &&
  152. moveCurrentY >tv_content.getY() && moveCurrentY < tv_content.getY() + tv_content.getHeight()){
  153. // 正确答案
  154. if(selectList.get(currentOptionPosition).equals(correctAnswer)){
  155. tv_content.setText(selectList.get(currentOptionPosition));
  156. tv_content.setBackground(ResourcesCompat.getDrawable(getResources(),R.drawable.drag_success_bg, null));
  157. moveTextView = null;
  158. select_rl.getChildAt(currentOptionPosition).setVisibility(View.INVISIBLE);
  159. }else{ // 错误答案
  160. // 先抖一抖再回去
  161. wrongAnimator();
  162. }
  163. }else {
  164. //说明没有放到答案框,就做回归动画
  165. moveAnimator(0, 0, 0, 0, 0, -1);
  166. }
  167. break;
  168. default:
  169. break;
  170. }
  171. return true;
  172. }
  173. //处理选项。计算选项,摆放选项的位置
  174. private void handleSelect() {
  175. selectRootWidth = select_rl.getWidth();
  176. selectRootHeight = select_rl.getHeight();
  177. //移除之前的子控件(避免数据造成冲突)
  178. select_rl.removeAllViews();
  179. float x = 0;
  180. float y = 0;
  181. for (int i = 0; i < selectList.size(); i++) {
  182. String option = selectList.get(i);
  183. TextView tvAnswer = createSelectTv(option);
  184. x = getScreenWidth()*3/5;
  185. y = getScreenHeight()/4 + dp2px(80) * i;
  186. //这里的setX、setY,是指选项(正方形)左上角的坐标位置
  187. tvAnswer.setX(x);
  188. tvAnswer.setY(y);
  189. //保存这个选项的坐标位置
  190. selectInitialLocationList.add(x + SeparateSymbol + y);
  191. select_rl.addView(tvAnswer);
  192. }
  193. }
  194. /**
  195. * 创建选项TextView
  196. *
  197. * @param str textView上要展示的内容
  198. * @return
  199. */
  200. private TextView createSelectTv(String str) {
  201. TextView tv = new TextView(this);
  202. tv.setBackground(ResourcesCompat.getDrawable(getResources(),R.drawable.drag_default_bg,null));
  203. tv.setText(str);
  204. tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
  205. RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
  206. ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  207. params.width = answerSize*4;
  208. params.height = answerSize;
  209. tv.setLayoutParams(params);
  210. tv.setGravity(Gravity.CENTER);
  211. return tv;
  212. }
  213. // 抖一抖动画
  214. private void wrongAnimator(){
  215. wrongNum = wrongNum + 1;
  216. Animation anim = AnimationUtils.loadAnimation(DragActivity.this, R.anim.myanim);
  217. tv_content.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.drag_error_bg, null));
  218. tv_content.setText(selectList.get(currentOptionPosition));
  219. tv_content.startAnimation(anim);
  220. moveTextView.setVisibility(View.GONE);
  221. //抖完后回去
  222. timer.schedule(new TimerTask() {
  223. @Override
  224. public void run() {
  225. runOnUiThread(() -> {
  226. tv_content.setBackground(ResourcesCompat.getDrawable(getResources(), R.drawable.drag_default_bg, null));
  227. tv_content.setText("");
  228. moveAnimator(0, 0, 0, 0, 0, -1);
  229. });
  230. }
  231. }, 1200);
  232. }
  233. /**
  234. * 回归动画
  235. * type:
  236. * 0、没有拖动到空格处,松开手后控件回到初始位置
  237. * 1、拖动到空格处,松开手后,隐藏控件,静默回归
  238. * 2、点击选项,控件移动到空缺的位置
  239. * 3、点击选项,内容填充到空格处后,控件需要静默回归
  240. */
  241. private void moveAnimator(final int type, float sX, float sY, float eX, float eY, final int position) {
  242. Log.e("type is ", type + "");
  243. Log.e("currentOptionPosition ", currentOptionPosition + "");
  244. if (currentOptionPosition == -1 || moveTextView == null) {
  245. return;
  246. }
  247. moveTextView.setVisibility(View.VISIBLE);
  248. try {
  249. float startX = 0;
  250. float startY = 0;
  251. float endX = 0;
  252. float endY = 0;
  253. AnimatorSet animatorSet = new AnimatorSet();
  254. ObjectAnimator translationX;
  255. ObjectAnimator translationY;
  256. String location = selectInitialLocationList.get(currentOptionPosition);
  257. startX = moveTextView.getX();
  258. startY = moveTextView.getY();
  259. endX = Float.parseFloat(location.split(SeparateSymbol)[0]);
  260. endY = Float.parseFloat(location.split(SeparateSymbol)[1]);
  261. translationX = ObjectAnimator.ofFloat(
  262. moveTextView,
  263. "translationX",
  264. startX,
  265. endX
  266. );
  267. translationY = ObjectAnimator.ofFloat(
  268. moveTextView,
  269. "translationY",
  270. startY,
  271. endY
  272. );
  273. animatorSet.playTogether(translationX, translationY);
  274. long durationTime = 1000;
  275. animatorSet.setDuration(durationTime);
  276. animatorSet.addListener(new Animator.AnimatorListener() {
  277. @Override
  278. public void onAnimationStart(Animator animator) {
  279. }
  280. @Override
  281. public void onAnimationEnd(Animator animator) {
  282. //抬起手后,释放滑动的TextView
  283. moveTextView = null;
  284. currentOptionPosition = -1;
  285. if(wrongNum > 2){
  286. for(int i = 0; i < select_rl.getChildCount(); i ++){
  287. if(((TextView) select_rl.getChildAt(i)).getText().equals(correctAnswer)){
  288. ((TextView) select_rl.getChildAt(i)).setBackground(ResourcesCompat.getDrawable(getResources(),R.drawable.drag_hint_bg,null));
  289. }
  290. }
  291. }
  292. }
  293. @Override
  294. public void onAnimationCancel(Animator animator) {
  295. }
  296. @Override
  297. public void onAnimationRepeat(Animator animator) {
  298. }
  299. });
  300. animatorSet.start();
  301. } catch (Exception e) {
  302. e.printStackTrace();
  303. }
  304. }
  305. private int dp2px(float dpValue) {
  306. final float scale = getResources().getDisplayMetrics().density;
  307. return (int) (dpValue * scale + 0.5f);
  308. }
  309. }