距离上次发布(android高仿系列)今日头条 --新闻阅读器 (二)

相关的内容已经半个月了,最近利用空闲时间,把今日头条客户端完善了下。完善的功能一个一个全部实现后,就放整个源码。开发的进度就是按照一个一个功能的思路走的,所以开发一个小的功能,如果有用,就写一个专门的博客以便有人用到独立的功能可以方便使用。

这次实现的功能是很多新闻阅读器(网易,今日头条,360新闻等)以及腾讯视频等里面都会出现的频道管理功能。

下面先上这次实现功能的效果图:(注:这个效果图没有拖拽的时候移动动画,DEMO里面有,可以下载看看)

一、开发心里历程

刚开始接触这个的时候,不知道要如何实现,去网上翻了一大堆资料,懂了个大概,就是目前可以找到的都是拖拽的时候,不带移动动画的,和线上的客户端交互效果相差甚远,在反反复复的尝试查看相关东西,大致的做了出来,目前在模拟器上似乎有一点小BUG,真机测试没有问题,就先放上来,如果发现问题在修改优化。代码反面,没有好好的修改调整,可能会有点乱,请见谅哈。

二、开发前的准备

1.了解重写View的相关知识,并且知道GridView的一些内部方法,如:怎么通过触摸的坐标获取对应的position等(这里我采用的是继承GridView控件)

2.了解屏幕触摸动作传递原理    这里我以前转载的一篇或许会有帮助:Android事件分发机制完全解析,带你从源码的角度彻底理解(全)

3.了解位移动画Animation,本DEMO中主要用到:TranslateAnimation  平移动画

4.了解WindowManager的窗口机制,这里的item拖拽等都要设计到这个。

5.了解SQLiteDatabase 以及SQLiteOpenHelper等数据库操作相关的类,本DEMO中主要用到数据库进行存储频道信息,如果你要用文档进行存储读取也可以。

三、开发思路

1.  获取数据库中频道的列表,如果为空,赋予默认列表,并存入数据库,之后通过对应的适配器赋给对应的GridView

2.  2个GridView--(1.DragGrid   2. OtherGridView)

DragGrid 用于显示我的频道,带有长按拖拽效果

OtherGridView用于显示更多频道,不带推拽效果

注:由于屏幕大小不一定,外层使用ScrollView,所以2者都要重写计算高度

3.  点击2个GridView的时候,根据点击的Item对应的position,获取position对应的view,进行创建一层移动的动画层

起始位置:点击的positiongetLocationInWindow()获取。终点位置:另一个GridView的最后个ITEM 的position + 1的位置。

并赋予移动动画,等动画结束后对2者对应的频道列表进行数据的remove和add操作。

4.  设置点击和拖动的限制条件,如  推荐  这个ITEM是不允许用户操作的。

5.  拖动的DragGrid的操作:

(1)长按获取长按的ITEM的position  -- dragPosition 以及对应的view ,手指触摸屏幕的时候,调用onInterceptTouchEvent来获取MotionEvent.ACTION_DOWN事件,获取对应的数据。由于这里是继承了GridView,所以长按时间可以通过setOnItemLongClickListener监听来执行,或则你也可以通过计算点击时间来监听是否长按。

(2)通过onTouchEvent(MotionEvent ev)来监听手指的移动和抬起动作。当它移动到 其它的item下面,并且下方的item对应的position  不等于 dragPosition,进行数据交换,并且2者之间的所有item进行移动动画,动画结束后,数据更替刷新界面。

(3) 抬起手后,清除掉拖动时候创建的view,让GridView中的数据显示。

6.  退出时候,将改变后的频道列表存入数据库。

四、流程图

下面是大体的流程图:

五、核心代码

点击进行添加删除:
  1. /** GRIDVIEW对应的ITEM点击监听接口  */
  2. @Override
  3. public void onItemClick(AdapterView<?> parent, final View view, final int position,long id) {
  4. //如果点击的时候,之前动画还没结束,那么就让点击事件无效
  5. if(isMove){
  6. return;
  7. }
  8. switch (parent.getId()) {
  9. case R.id.userGridView:
  10. //position为 0,1 的不可以进行任何操作
  11. if (position != 0 && position != 1) {
  12. final ImageView moveImageView = getView(view);
  13. if (moveImageView != null) {
  14. TextView newTextView = (TextView) view.findViewById(R.id.text_item);
  15. final int[] startLocation = new int[2];
  16. newTextView.getLocationInWindow(startLocation);
  17. final ChannelItem channel = ((DragAdapter) parent.getAdapter()).getItem(position);//获取点击的频道内容
  18. otherAdapter.setVisible(false);
  19. //添加到最后一个
  20. otherAdapter.addItem(channel);
  21. new Handler().postDelayed(new Runnable() {
  22. public void run() {
  23. try {
  24. int[] endLocation = new int[2];
  25. //获取终点的坐标
  26. otherGridView.getChildAt(otherGridView.getLastVisiblePosition()).getLocationInWindow(endLocation);
  27. MoveAnim(moveImageView, startLocation , endLocation, channel,userGridView);
  28. userAdapter.setRemove(position);
  29. } catch (Exception localException) {
  30. }
  31. }
  32. }, 50L);
  33. }
  34. }
  35. break;
  36. case R.id.otherGridView:
  37. final ImageView moveImageView = getView(view);
  38. if (moveImageView != null){
  39. TextView newTextView = (TextView) view.findViewById(R.id.text_item);
  40. final int[] startLocation = new int[2];
  41. newTextView.getLocationInWindow(startLocation);
  42. final ChannelItem channel = ((OtherAdapter) parent.getAdapter()).getItem(position);
  43. userAdapter.setVisible(false);
  44. //添加到最后一个
  45. userAdapter.addItem(channel);
  46. new Handler().postDelayed(new Runnable() {
  47. public void run() {
  48. try {
  49. int[] endLocation = new int[2];
  50. //获取终点的坐标
  51. userGridView.getChildAt(userGridView.getLastVisiblePosition()).getLocationInWindow(endLocation);
  52. MoveAnim(moveImageView, startLocation , endLocation, channel,otherGridView);
  53. otherAdapter.setRemove(position);
  54. } catch (Exception localException) {
  55. }
  56. }
  57. }, 50L);
  58. }
  59. break;
  60. default:
  61. break;
  62. }
  63. }
 
 

移动动画:

  1. <span style="font-size:14px;">private void MoveAnim(View moveView, int[] startLocation,int[] endLocation, final ChannelItem moveChannel,
  2. final GridView clickGridView) {
  3. int[] initLocation = new int[2];
  4. //获取传递过来的VIEW的坐标
  5. moveView.getLocationInWindow(initLocation);
  6. //得到要移动的VIEW,并放入对应的容器中
  7. final ViewGroup moveViewGroup = getMoveViewGroup();
  8. final View mMoveView = getMoveView(moveViewGroup, moveView, initLocation);
  9. //创建移动动画
  10. TranslateAnimation moveAnimation = new TranslateAnimation(
  11. startLocation[0], endLocation[0], startLocation[1],
  12. endLocation[1]);
  13. moveAnimation.setDuration(300L);//动画时间
  14. //动画配置
  15. AnimationSet moveAnimationSet = new AnimationSet(true);
  16. moveAnimationSet.setFillAfter(false);//动画效果执行完毕后,View对象不保留在终止的位置
  17. moveAnimationSet.addAnimation(moveAnimation);
  18. mMoveView.startAnimation(moveAnimationSet);
  19. moveAnimationSet.setAnimationListener(new AnimationListener() {
  20. @Override
  21. public void onAnimationStart(Animation animation) {
  22. isMove = true;
  23. }
  24. @Override
  25. public void onAnimationRepeat(Animation animation) {
  26. }
  27. @Override
  28. public void onAnimationEnd(Animation animation) {
  29. moveViewGroup.removeView(mMoveView);
  30. // instanceof 方法判断2边实例是不是一样,判断点击的是DragGrid还是OtherGridView
  31. if (clickGridView instanceof DragGrid) {
  32. otherAdapter.setVisible(true);
  33. otherAdapter.notifyDataSetChanged();
  34. userAdapter.remove();
  35. }else{
  36. userAdapter.setVisible(true);
  37. userAdapter.notifyDataSetChanged();
  38. otherAdapter.remove();
  39. }
  40. isMove = false;
  41. }
  42. });
  43. }</span>

可拖拽的DragGrid代码:

  1. public class DragGrid extends GridView {
  2. /** 点击时候的X位置 */
  3. public int downX;
  4. /** 点击时候的Y位置 */
  5. public int downY;
  6. /** 点击时候对应整个界面的X位置 */
  7. public int windowX;
  8. /** 点击时候对应整个界面的Y位置 */
  9. public int windowY;
  10. /** 屏幕上的X */
  11. private int win_view_x;
  12. /** 屏幕上的Y */
  13. private int win_view_y;
  14. /** 拖动的里x的距离 */
  15. int dragOffsetX;
  16. /** 拖动的里Y的距离 */
  17. int dragOffsetY;
  18. /** 长按时候对应postion */
  19. public int dragPosition;
  20. /** Up后对应的ITEM的Position */
  21. private int dropPosition;
  22. /** 开始拖动的ITEM的Position */
  23. private int startPosition;
  24. /** item高 */
  25. private int itemHeight;
  26. /** item宽 */
  27. private int itemWidth;
  28. /** 拖动的时候对应ITEM的VIEW */
  29. private View dragImageView = null;
  30. /** 长按的时候ITEM的VIEW */
  31. private ViewGroup dragItemView = null;
  32. /** WindowManager管理器 */
  33. private WindowManager windowManager = null;
  34. /** */
  35. private WindowManager.LayoutParams windowParams = null;
  36. /** item总量 */
  37. private int itemTotalCount;
  38. /** 一行的ITEM数量 */
  39. private int nColumns = 4;
  40. /** 行数 */
  41. private int nRows;
  42. /** 剩余部分 */
  43. private int Remainder;
  44. /** 是否在移动 */
  45. private boolean isMoving = false;
  46. /** */
  47. private int holdPosition;
  48. /** 拖动的时候放大的倍数 */
  49. private double dragScale = 1.2D;
  50. /** 震动器 */
  51. private Vibrator mVibrator;
  52. /** 每个ITEM之间的水平间距 */
  53. private int mHorizontalSpacing = 15;
  54. /** 每个ITEM之间的竖直间距 */
  55. private int mVerticalSpacing = 15;
  56. /* 移动时候最后个动画的ID */
  57. private String LastAnimationID;
  58. public DragGrid(Context context) {
  59. super(context);
  60. init(context);
  61. }
  62. public DragGrid(Context context, AttributeSet attrs, int defStyle) {
  63. super(context, attrs, defStyle);
  64. init(context);
  65. }
  66. public DragGrid(Context context, AttributeSet attrs) {
  67. super(context, attrs);
  68. init(context);
  69. }
  70. public void init(Context context) {
  71. mVibrator = (Vibrator) context
  72. .getSystemService(Context.VIBRATOR_SERVICE);
  73. // 将布局文件中设置的间距dip转为px
  74. mHorizontalSpacing = DataTools.dip2px(context, mHorizontalSpacing);
  75. }
  76. @Override
  77. public boolean onInterceptTouchEvent(MotionEvent ev) {
  78. // TODO Auto-generated method stub
  79. if (ev.getAction() == MotionEvent.ACTION_DOWN) {
  80. downX = (int) ev.getX();
  81. downY = (int) ev.getY();
  82. windowX = (int) ev.getX();
  83. windowY = (int) ev.getY();
  84. setOnItemClickListener(ev);
  85. }
  86. return super.onInterceptTouchEvent(ev);
  87. }
  88. @Override
  89. public boolean onTouchEvent(MotionEvent ev) {
  90. // TODO Auto-generated method stub
  91. boolean bool = true;
  92. if (dragImageView != null
  93. && dragPosition != AdapterView.INVALID_POSITION) {
  94. // 移动时候的对应x,y位置
  95. bool = super.onTouchEvent(ev);
  96. int x = (int) ev.getX();
  97. int y = (int) ev.getY();
  98. switch (ev.getAction()) {
  99. case MotionEvent.ACTION_DOWN:
  100. downX = (int) ev.getX();
  101. windowX = (int) ev.getX();
  102. downY = (int) ev.getY();
  103. windowY = (int) ev.getY();
  104. break;
  105. case MotionEvent.ACTION_MOVE:
  106. onDrag(x, y, (int) ev.getRawX(), (int) ev.getRawY());
  107. if (!isMoving) {
  108. OnMove(x, y);
  109. }
  110. if (pointToPosition(x, y) != AdapterView.INVALID_POSITION) {
  111. break;
  112. }
  113. break;
  114. case MotionEvent.ACTION_UP:
  115. stopDrag();
  116. onDrop(x, y);
  117. requestDisallowInterceptTouchEvent(false);
  118. break;
  119. default:
  120. break;
  121. }
  122. }
  123. return super.onTouchEvent(ev);
  124. }
  125. /** 在拖动的情况 */
  126. private void onDrag(int x, int y, int rawx, int rawy) {
  127. if (dragImageView != null) {
  128. windowParams.alpha = 0.6f;
  129. windowParams.x = rawx - win_view_x;
  130. windowParams.y = rawy - win_view_y;
  131. windowManager.updateViewLayout(dragImageView, windowParams);
  132. }
  133. }
  134. /** 在松手下放的情况 */
  135. private void onDrop(int x, int y) {
  136. // 根据拖动到的x,y坐标获取拖动位置下方的ITEM对应的POSTION
  137. int tempPostion = pointToPosition(x, y);
  138. dropPosition = tempPostion;
  139. DragAdapter mDragAdapter = (DragAdapter) getAdapter();
  140. // 显示刚拖动的ITEM
  141. mDragAdapter.setShowDropItem(true);
  142. // 刷新适配器,让对应的ITEM显示
  143. mDragAdapter.notifyDataSetChanged();
  144. }
  145. /**
  146. * 长按点击监听
  147. * @param ev
  148. */
  149. public void setOnItemClickListener(final MotionEvent ev) {
  150. setOnItemLongClickListener(new OnItemLongClickListener() {
  151. @Override
  152. public boolean onItemLongClick(AdapterView<?> parent, View view,
  153. int position, long id) {
  154. int x = (int) ev.getX();// 长安事件的X位置
  155. int y = (int) ev.getY();// 长安事件的y位置
  156. startPosition = position;// 第一次点击的postion
  157. dragPosition = position;
  158. if (startPosition <= 1) {
  159. return false;
  160. }
  161. ViewGroup dragViewGroup = (ViewGroup) getChildAt(dragPosition
  162. - getFirstVisiblePosition());
  163. TextView dragTextView = (TextView) dragViewGroup
  164. .findViewById(R.id.text_item);
  165. dragTextView.setSelected(true);
  166. dragTextView.setEnabled(false);
  167. itemHeight = dragViewGroup.getHeight();
  168. itemWidth = dragViewGroup.getWidth();
  169. itemTotalCount = DragGrid.this.getCount();
  170. int row = itemTotalCount / nColumns;// 算出行数
  171. Remainder = (itemTotalCount % nColumns);// 算出最后一行多余的数量
  172. if (Remainder != 0) {
  173. nRows = row + 1;
  174. } else {
  175. nRows = row;
  176. }
  177. // 如果特殊的这个不等于拖动的那个,并且不等于-1
  178. if (dragPosition != AdapterView.INVALID_POSITION) {
  179. // 释放的资源使用的绘图缓存。如果你调用buildDrawingCache()手动没有调用setDrawingCacheEnabled(真正的),你应该清理缓存使用这种方法。
  180. win_view_x = windowX - dragViewGroup.getLeft();// VIEW相对自己的X,半斤
  181. win_view_y = windowY - dragViewGroup.getTop();// VIEW相对自己的y,半斤
  182. dragOffsetX = (int) (ev.getRawX() - x);// 手指在屏幕的上X位置-手指在控件中的位置就是距离最左边的距离
  183. dragOffsetY = (int) (ev.getRawY() - y);// 手指在屏幕的上y位置-手指在控件中的位置就是距离最上边的距离
  184. dragItemView = dragViewGroup;
  185. dragViewGroup.destroyDrawingCache();
  186. dragViewGroup.setDrawingCacheEnabled(true);
  187. Bitmap dragBitmap = Bitmap.createBitmap(dragViewGroup
  188. .getDrawingCache());
  189. mVibrator.vibrate(50);// 设置震动时间
  190. startDrag(dragBitmap, (int) ev.getRawX(),
  191. (int) ev.getRawY());
  192. hideDropItem();
  193. dragViewGroup.setVisibility(View.INVISIBLE);
  194. isMoving = false;
  195. requestDisallowInterceptTouchEvent(true);
  196. return true;
  197. }
  198. return false;
  199. }
  200. });
  201. }
  202. public void startDrag(Bitmap dragBitmap, int x, int y) {
  203. stopDrag();
  204. windowParams = new WindowManager.LayoutParams();// 获取WINDOW界面的
  205. // Gravity.TOP|Gravity.LEFT;这个必须加
  206. windowParams.gravity = Gravity.TOP | Gravity.LEFT;
  207. // 得到preview左上角相对于屏幕的坐标
  208. windowParams.x = x - win_view_x;
  209. windowParams.y = y - win_view_y;
  210. // 设置拖拽item的宽和高
  211. windowParams.width = (int) (dragScale * dragBitmap.getWidth());// 放大dragScale倍,可以设置拖动后的倍数
  212. windowParams.height = (int) (dragScale * dragBitmap.getHeight());// 放大dragScale倍,可以设置拖动后的倍数
  213. this.windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
  214. | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
  215. | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
  216. | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
  217. this.windowParams.format = PixelFormat.TRANSLUCENT;
  218. this.windowParams.windowAnimations = 0;
  219. ImageView iv = new ImageView(getContext());
  220. iv.setImageBitmap(dragBitmap);
  221. windowManager = (WindowManager) getContext().getSystemService(
  222. Context.WINDOW_SERVICE);// "window"
  223. windowManager.addView(iv, windowParams);
  224. dragImageView = iv;
  225. }
  226. /** 停止拖动 ,释放并初始化 */
  227. private void stopDrag() {
  228. if (dragImageView != null) {
  229. windowManager.removeView(dragImageView);
  230. dragImageView = null;
  231. }
  232. }
  233. /** 在ScrollView内,所以要进行计算高度 */
  234. @Override
  235. public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  236. int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
  237. MeasureSpec.AT_MOST);
  238. super.onMeasure(widthMeasureSpec, expandSpec);
  239. }
  240. /** 隐藏 放下 的ITEM */
  241. private void hideDropItem() {
  242. ((DragAdapter) getAdapter()).setShowDropItem(false);
  243. }
  244. /** 获取移动动画 */
  245. public Animation getMoveAnimation(float toXValue, float toYValue) {
  246. TranslateAnimation mTranslateAnimation = new TranslateAnimation(
  247. Animation.RELATIVE_TO_SELF, 0.0F, Animation.RELATIVE_TO_SELF,
  248. toXValue, Animation.RELATIVE_TO_SELF, 0.0F,
  249. Animation.RELATIVE_TO_SELF, toYValue);// 当前位置移动到指定位置
  250. mTranslateAnimation.setFillAfter(true);// 设置一个动画效果执行完毕后,View对象保留在终止的位置。
  251. mTranslateAnimation.setDuration(300L);
  252. return mTranslateAnimation;
  253. }
  254. /** 移动的时候触发 */
  255. public void OnMove(int x, int y) {
  256. // 拖动的VIEW下方的POSTION
  257. int dPosition = pointToPosition(x, y);
  258. // 判断下方的POSTION是否是最开始2个不能拖动的
  259. if (dPosition > 1) {
  260. if ((dPosition == -1) || (dPosition == dragPosition)) {
  261. return;
  262. }
  263. dropPosition = dPosition;
  264. if (dragPosition != startPosition) {
  265. dragPosition = startPosition;
  266. }
  267. int movecount;
  268. // 拖动的=开始拖的,并且 拖动的 不等于放下的
  269. if ((dragPosition == startPosition)
  270. || (dragPosition != dropPosition)) {
  271. // 移需要移动的动ITEM数量
  272. movecount = dropPosition - dragPosition;
  273. } else {
  274. // 移需要移动的动ITEM数量为0
  275. movecount = 0;
  276. }
  277. if (movecount == 0) {
  278. return;
  279. }
  280. int movecount_abs = Math.abs(movecount);
  281. if (dPosition != dragPosition) {
  282. // dragGroup设置为不可见
  283. ViewGroup dragGroup = (ViewGroup) getChildAt(dragPosition);
  284. dragGroup.setVisibility(View.INVISIBLE);
  285. float to_x = 1;// 当前下方positon
  286. float to_y;// 当前下方右边positon
  287. // x_vlaue移动的距离百分比(相对于自己长度的百分比)
  288. float x_vlaue = ((float) mHorizontalSpacing / (float) itemWidth) + 1.0f;
  289. // y_vlaue移动的距离百分比(相对于自己宽度的百分比)
  290. float y_vlaue = ((float) mVerticalSpacing / (float) itemHeight) + 1.0f;
  291. Log.d("x_vlaue", "x_vlaue = " + x_vlaue);
  292. for (int i = 0; i < movecount_abs; i++) {
  293. to_x = x_vlaue;
  294. to_y = y_vlaue;
  295. // 像左
  296. if (movecount > 0) {
  297. // 判断是不是同一行的
  298. holdPosition = dragPosition + i + 1;
  299. if (dragPosition / nColumns == holdPosition / nColumns) {
  300. to_x = -x_vlaue;
  301. to_y = 0;
  302. } else if (holdPosition % 4 == 0) {
  303. to_x = 3 * x_vlaue;
  304. to_y = -y_vlaue;
  305. } else {
  306. to_x = -x_vlaue;
  307. to_y = 0;
  308. }
  309. } else {
  310. // 向右,下移到上,右移到左
  311. holdPosition = dragPosition - i - 1;
  312. if (dragPosition / nColumns == holdPosition / nColumns) {
  313. to_x = x_vlaue;
  314. to_y = 0;
  315. } else if ((holdPosition + 1) % 4 == 0) {
  316. to_x = -3 * x_vlaue;
  317. to_y = y_vlaue;
  318. } else {
  319. to_x = x_vlaue;
  320. to_y = 0;
  321. }
  322. }
  323. ViewGroup moveViewGroup = (ViewGroup) getChildAt(holdPosition);
  324. Animation moveAnimation = getMoveAnimation(to_x, to_y);
  325. moveViewGroup.startAnimation(moveAnimation);
  326. // 如果是最后一个移动的,那么设置他的最后个动画ID为LastAnimationID
  327. if (holdPosition == dropPosition) {
  328. LastAnimationID = moveAnimation.toString();
  329. }
  330. moveAnimation.setAnimationListener(new AnimationListener() {
  331. @Override
  332. public void onAnimationStart(Animation animation) {
  333. // TODO Auto-generated method stub
  334. isMoving = true;
  335. }
  336. @Override
  337. public void onAnimationRepeat(Animation animation) {
  338. // TODO Auto-generated method stub
  339. }
  340. @Override
  341. public void onAnimationEnd(Animation animation) {
  342. // TODO Auto-generated method stub
  343. // 如果为最后个动画结束,那执行下面的方法
  344. if (animation.toString().equalsIgnoreCase(
  345. LastAnimationID)) {
  346. DragAdapter mDragAdapter = (DragAdapter) getAdapter();
  347. mDragAdapter.exchange(startPosition,
  348. dropPosition);
  349. startPosition = dropPosition;
  350. dragPosition = dropPosition;
  351. isMoving = false;
  352. }
  353. }
  354. });
  355. }
  356. }
  357. }
  358. }
  359. }
 

数据库SQLHelper文件

  1. public class SQLHelper extends SQLiteOpenHelper {
  2. public static final String DB_NAME = "database.db";// 数据库名称
  3. public static final int VERSION = 1;
  4. public static final String TABLE_CHANNEL = "channel";//数据表
  5. public static final String ID = "id";//
  6. public static final String NAME = "name";
  7. public static final String ORDERID = "orderId";
  8. public static final String SELECTED = "selected";
  9. private Context context;
  10. public SQLHelper(Context context) {
  11. super(context, DB_NAME, null, VERSION);
  12. this.context = context;
  13. }
  14. public Context getContext(){
  15. return context;
  16. }
  17. @Override
  18. public void onCreate(SQLiteDatabase db) {
  19. // TODO 创建数据库后,对数据库的操作
  20. String sql = "create table if not exists "+TABLE_CHANNEL +
  21. "(_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
  22. ID + " INTEGER , " +
  23. NAME + " TEXT , " +
  24. ORDERID + " INTEGER , " +
  25. SELECTED + " SELECTED)";
  26. db.execSQL(sql);
  27. }
  28. @Override
  29. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  30. // TODO 更改数据库版本的操作
  31. onCreate(db);
  32. }
  33. }
 

注:本DEMO中,加入了长按震动,所以在权限里面记得加上“

  1. <!-- 在SDCard中创建与删除文件权限 -->
  2. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
  3. <!-- 往SDCard写入数据权限 -->
  4. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  5. <!-- 震动权限 -->
  6. <uses-permission android:name="android.permission.VIBRATE"/>

六、源码下载

源码DEMO下载地址如下:下载地址

版权声明:本文为博主原创文章,未经博主允许不得转载。

Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO的更多相关文章

  1. Android 高仿 频道管理----网易、今日头条、腾讯视频 (能够拖动的GridView)附源代码DEMO

    距离上次公布(android高仿系列)今日头条 --新闻阅读器 (二) 相关的内容已经半个月了.近期利用空暇时间,把今日头条client完好了下.完好的功能一个一个所有实现后.就放整个源代码.开发的进 ...

  2. Android 仿 新闻阅读器 菜单弹出效果(附源码DEMO)

    这一系列博文都是:(android高仿系列)今日头条 --新闻阅读器 (一) 开发中碰到问题之后实现的,觉得可能有的开发者用的到或则希望独立成一个小功能DEMO,所以就放出来这么一个DEMO. 原本觉 ...

  3. 【Android初级】如何实现一个比相册更高大上的左右滑动特效(附源码)

    在Android里面,想要实现一个类似相册的左右滑动效果,我们除了可以用Gallery.HorizontalScrollView.ViewPager等控件,还可以用一个叫做 ViewFlipper 的 ...

  4. 仿酷狗音乐播放器开发日志二十七 用ole为窗体增加文件拖动功能(附源码)

    转载请说明原出处,谢谢~~ 中秋到了,出去玩了几天.今天把仿酷狗程序做了收尾,已经开发完成了,下一篇博客把完结的情况说一下.在这篇博客里说一下使用OLE为窗体增加文件拖拽的功能.使用播放器,我更喜欢直 ...

  5. Android 音视频深入 九 FFmpeg解码视频生成yuv文件(附源码下载)

    项目地址,求star https://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg(MP4%E8 ...

  6. Android 音视频深入 十八 FFmpeg播放视频,有声音(附源码下载)

    项目地址https://github.com/979451341/AudioVideoStudyCodeTwo/tree/master/FFmpegv%E6%92%AD%E6%94%BE%E8%A7% ...

  7. (android高仿系列)今日头条 --新闻阅读器 (三) 完结 、总结 篇

    从写第一篇今日头条高仿系列开始,到现在已经过去了1个多月了,其实大体都做好了,就是迟迟没有放出来,因为我觉得,做这个东西也是有个过程的,我想把这个模仿中一步一步学习的过程,按照自己的思路写下来,在根据 ...

  8. (android高仿系列)今日头条 --新闻阅读器 (二)

    高仿今日头条 --- 第一篇:(android高仿系列)今日头条 --新闻阅读器 (一)    上次,已经完毕了头部新闻分类栏目的拖动效果. 这篇文章是继续去完好APP 今日头条  这个新闻阅读器的其 ...

  9. android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码

    Android精选源码 android模仿支付宝app"记账本"模块源码 android一个超轻量级剪贴板历史记录管理软件源码 android模仿QQ拖动红点消失动画效果源码 展示 ...

随机推荐

  1. 【SVN】is out of date

    右击项目(team->update 或者 team->freash/cleanup),再操作,提交就可以了.

  2. ios8.1上运行程序,程序界面只显示一部分

    在ios 9.1上运行程序没问题 但是在8.1上运行发现模拟器上只显示了程序的一小部分界面,没有显示完全. 结果发现由以下代码设置问题引起的 - (BOOL)application:(UIApplic ...

  3. linux 修改IP, DNS 命令

    linux 修改IP, DNS 命令 http://www.cnblogs.com/fighter/archive/2010/03/04/1678007.html 修改DNS [root@localh ...

  4. Sprintf()的思考和引出的相关问题

    Sprintf()为什么不安全? 功能 把格式化的数据写入某个 字符串 缓冲区. 头文件 stdio.h 原型 int sprintf( char *buffer, const char *forma ...

  5. ThinkPHP文件上传类

    TP框架自带文件上传类使用: 类文件在ThinkPHP/Library/Think/默认在目录下 public function upload(){ $upload = new \Think\Uplo ...

  6. struts2总结【转载】

    1,struts2的form表单里面和url里面的传值以及Action所继承的父类都可以自动set属性注入action中,及继承的action中. 2,凡是url和form表单传值,在action方法 ...

  7. Page的生命周期及相关事件苛

    (1)请求页面:页请求发生在页生命周期开始之前. (2)开始:在开始阶段,将设置页属性,如Request和Response.在此阶段,页还将确定请求是回发请求还是新请求,并设置IsPostBack属性 ...

  8. Use Node.js DDP Client on Arduino Yun to Access Meteor Server

    Use Node.js DDP Client on Arduino Yun to Access Meteor Server 概述 在Arduino Yun上安装 Node.js, 并測试与 Meteo ...

  9. XML(三)

     使用 XSLT 显示 XML -------------------------------------------------------------------------------- 通 ...

  10. activity入门2

    1.如何获取其他应用的包名和类名? 点击和查看logcat第一条信息2.第二步Intent intent = new Intent();intent.setClassName("com.an ...