zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

android ListView加HeadView左右切换图片(类似各大新闻客户端)

Android客户端 图片 切换 新闻 listview 类似 左右
2023-09-14 08:59:39 时间
         我简单的介绍下实现方法:其实就是listview addHeaderView.只不过这个view是一个可以切换图片的view,至于这个view怎么做,就要根据自己的喜爱了,实现有多种方法,下面我简单介绍一下.

第一种:ViewFlipper+GestureDetector

主布局就是一个listview,这里就不介绍了,我介绍下切换图片布局

head_iamge.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:orientation="vertical" 

 FrameLayout

 android:id="@+id/fl_main"

 android:layout_width="match_parent"

 android:layout_height="wrap_content" 

 ViewFlipper

 android:id="@+id/ViewFlipper01"

 android:layout_width="fill_parent"

 android:layout_height="fill_parent" 

 /ViewFlipper 

 LinearLayout

 android:id="@+id/ll_point"

 android:layout_width="wrap_content"

 android:layout_height="wrap_content"

 android:layout_gravity="bottom|center_horizontal"

 android:layout_marginBottom="10dp"

 android:src="@drawable/indicator" / 

 /FrameLayout 

 /LinearLayout 

这里我就添加一系列切换点,至于显示新闻标题,透明效果等等,大家可以自己布局,方法同理,不难实现.
接下来我们看动画布局.

push_left_in.xml

 ?xml version="1.0" encoding="utf-8"? 

 set xmlns:android="http://schemas.android.com/apk/res/android"

 android:fillAfter="true" 

 translate

 android:duration="500"

 android:fromXDelta="-100%p"

 android:toXDelta="0" / 

 alpha

 android:duration="500"

 android:fromAlpha="0.1"

 android:toAlpha="1.0" / 

 /set 

push_left_out.xml

 ?xml version="1.0" encoding="utf-8"? 

 set xmlns:android="http://schemas.android.com/apk/res/android" 

 translate

 android:duration="500"

 android:fromXDelta="0"

 android:toXDelta="-100%p" / 

 alpha

 android:duration="500"

 android:fromAlpha="1.0"

 android:toAlpha="0.5" / 

 /set 

push_right_in.xml

 ?xml version="1.0" encoding="utf-8"? 

 set xmlns:android="http://schemas.android.com/apk/res/android"

 android:fillAfter="true" 

 translate

 android:duration="500"

 android:fromXDelta="100%p"

 android:toXDelta="0" / 

 alpha

 android:duration="500"

 android:fromAlpha="0.1"

 android:toAlpha="1.0" / 

 /set 

push_right_out.xml

 ?xml version="1.0" encoding="utf-8"? 

 set xmlns:android="http://schemas.android.com/apk/res/android" 

 translate

 android:duration="500"

 android:fromXDelta="0"

 android:toXDelta="100%p" / 

 alpha

 android:duration="500"

 android:fromAlpha="1.0"

 android:toAlpha="0.5" / 

 /set 

我简单介绍下这些布局:

push_left_in:左边进入,则要进入的view初始位置在-100%p位置,终止位置在0,而push_left_out:左边出来,则此时view的位置在0,而终止位置在-100%p.

右进右出同理,至于alpha渐变,很简单,动画就说道这里,相信了解动画的同学们不用看就ok了.


下面重点是如何实现.

代码:

MainActivity.java

import java.util.ArrayList;

import java.util.Timer;

import java.util.TimerTask;

import android.app.Activity;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Matrix;

import android.os.Bundle;

import android.util.Log;

import android.view.GestureDetector;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.View.OnTouchListener;

import android.view.animation.AnimationUtils;

import android.widget.AdapterView;

import android.widget.AdapterView.OnItemClickListener;

import android.widget.Button;

import android.widget.ImageView.ScaleType;

import android.widget.LinearLayout.LayoutParams;

import android.widget.ArrayAdapter;

import android.widget.FrameLayout;

import android.widget.ImageView;

import android.widget.LinearLayout;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.Toast;

import android.widget.ViewFlipper;

public class MainActivity extends Activity implements

 GestureDetector.OnGestureListener {

 private GestureDetector detector;

 private ViewFlipper flipper;

 private int image_id[] = { R.drawable.a, R.drawable.b, R.drawable.c };

 private ListView lv_main;

 private LayoutInflater layoutInflater;

 private LinearLayout ll_point;

 private FrameLayout frameLayout;

 private final String msg[] = { "one", "two", "three", "four", "five",

 "six", "seven" };

 private int frameheight;// 图片的高度

 private int window_width;// 屏幕宽度

 private ArrayList ImageView imageViews;// ponit 集合

 private ArrayList View views;// flipper的孩子

 private Timer timer;

 /***

 * 初始化 point

 void initPoint() {

 imageViews = new ArrayList ImageView 

 ImageView imageView;

 for (int i = 0; i image_id.length; i++) {

 imageView = new ImageView(this);

 imageView.setBackgroundResource(R.drawable.indicator);

 LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(

 new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,

 LayoutParams.WRAP_CONTENT));

 layoutParams.leftMargin = 10;

 layoutParams.rightMargin = 10;

 ll_point.addView(imageView, layoutParams);

 imageViews.add(imageView);

 /***

 * ChildView

 void initChildView(ViewFlipper flipper) {

 views = new ArrayList View 

 LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT,

 LayoutParams.FILL_PARENT);

 for (int i = 0; i image_id.length; i++) {

 ImageView imageView = new ImageView(this);

 imageView.setScaleType(ScaleType.FIT_XY);

 Bitmap bitmap = BitmapFactory.decodeResource(getResources(),

 image_id[i]);

 Bitmap bitmap2 = getBitmap(bitmap, window_width);

 frameheight = bitmap2.getHeight();// 获取要显示的高度

 imageView.setImageResource(image_id[i]);

 flipper.addView(imageView, layoutParams);

 views.add(imageView);

 initPoint();

 /***

 * 初始化 HeadImage

 void initHeadImage() {

 layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

 View headview = layoutInflater.inflate(R.layout.head_image, null);

 flipper = (ViewFlipper) headview.findViewById(R.id.ViewFlipper01);

 ll_point = (LinearLayout) headview.findViewById(R.id.ll_point);

 frameLayout = (FrameLayout) headview.findViewById(R.id.fl_main);

 initChildView(flipper);

 LayoutParams layoutParams = (LayoutParams) frameLayout

 .getLayoutParams();

 layoutParams.height = frameheight;

 frameLayout.setLayoutParams(layoutParams);

 draw_Point(0);// 默认首次进入

 lv_main.addHeaderView(headview);// 要卸载setAdapter前面

 lv_main.setAdapter(new ArrayAdapter String (this,

 android.R.layout.simple_list_item_1, msg));

 /***

 * init view

 void initView() {

 setTitle("jjhappyforever...");

 setContentView(R.layout.main);

 lv_main = (ListView) findViewById(R.id.lv_main);

 lv_main.setOnItemClickListener(new OnItemClickListener() {

 @Override

 public void onItemClick(AdapterView ? parent, View view,

 int position, long id) {

 if (position != 0)

 Toast.makeText(MainActivity.this, msg[position - 1], 1)

 .show();

 else {

 int index = getPageIndex(flipper.getCurrentView());

 Toast.makeText(MainActivity.this, "图" + index, 1).show();

 initHeadImage();

 /***

 * 更新选中点

 * @param index

 private void draw_Point(int index) {

 for (int i = 0; i imageViews.size(); i++) {

 imageViews.get(i).setImageResource(R.drawable.indicator);

 imageViews.get(index).setImageResource(R.drawable.indicator_focused);

 @Override

 public void onCreate(Bundle savedInstanceState) {

 super.onCreate(savedInstanceState);

 setContentView(R.layout.main);

 // 获取屏幕的宽度

 window_width = (int) getResources().getDimension(R.dimen.window_width);

 detector = new GestureDetector(this);

 initView();

 timer = new Timer(true);

 timer.schedule(new TimerTask() {

 @Override

 public void run() {

 runOnUiThread(new Runnable() {

 @Override

 public void run() {

 int pageIndex = getPageIndex(flipper.getCurrentView());

 if (pageIndex == flipper.getChildCount() - 1)

 pageIndex = 0;

 else

 pageIndex++;

 flipper.setInAnimation(AnimationUtils.loadAnimation(

 MainActivity.this, R.anim.push_right_in));

 flipper.setOutAnimation(AnimationUtils.loadAnimation(

 MainActivity.this, R.anim.push_left_out));

 flipper.showNext();

 draw_Point(pageIndex);

 }, 5000, 5000);

 /***

 * 对图片处理

 * @author zhangjia

 Bitmap getBitmap(Bitmap bitmap, int width) {

 int w = bitmap.getWidth();

 int h = bitmap.getHeight();

 Matrix matrix = new Matrix();

 float scale = (float) width / w;

 // 保证图片不变形.

 matrix.postScale(scale, scale);

 // w,h是原图的属性.

 return Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);

 @Override

 public boolean dispatchTouchEvent(MotionEvent ev) {

 this.detector.onTouchEvent(ev);

 return super.dispatchTouchEvent(ev);

 @Override

 public boolean onDown(MotionEvent e) {

 return true;

 /***

 * 返回当前第几屏

 int getPageIndex(View view) {

 for (int i = 0; i views.size(); i++) {

 if (view == views.get(i))

 return i;

 return 0;

 * 监听滑动

 @Override

 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,

 float velocityY) {

 int pageIndex = getPageIndex(flipper.getCurrentView());

 // 左划

 if (e1.getX() - e2.getX() 120) {

 this.flipper.setInAnimation(AnimationUtils.loadAnimation(this,

 R.anim.push_right_in));

 this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this,

 R.anim.push_left_out));

 this.flipper.showNext();

 if (pageIndex == flipper.getChildCount() - 1)

 draw_Point(0);

 else

 draw_Point(++pageIndex);

 return true;

 // 右划

 } else if (e1.getX() - e2.getX() -120) {

 this.flipper.setInAnimation(AnimationUtils.loadAnimation(this,

 R.anim.push_left_in));

 this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this,

 R.anim.push_right_out));

 this.flipper.showPrevious();

 if (pageIndex == 0)

 draw_Point(flipper.getChildCount() - 1);

 else

 draw_Point(--pageIndex);

 return true;

 return true;

 @Override

 public void onLongPress(MotionEvent e) {

 @Override

 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,

 float distanceY) {

 return false;

 @Override

 public void onShowPress(MotionEvent e) {

 @Override

 public boolean onSingleTapUp(MotionEvent e) {

 return false;

}





你可以手势左右滑动图片切换,由于我们加入了动画,则在切换图片效果会比较人性,这一点比较不错.另外一点,我开启了timer,让它自己切换,感觉这点比较不错,可惜好多应用都没有这么搞,总之实现就行了,我们开发人员嘛,就是开发别人想出来的东西,感慨程序员苦逼...

如果你按照上诉操作的话会有几个问题:1,我移动图片下面的item图片也会切换,2,我在滑动切换图片的时候偶尔也会执行onclick事件,这两点bug严重不允许,为之我也煞费神经细胞啊,没办法因为基础不好,对触摸种种事件还是搞不明白,有时间了还得在看看研究研究,扯远了,下面我说下解决方法:

第一:我只让listview的第一项监听手势操作,其他的不执行.

方法很简单,自定义一个listview.重写其onTouchEvent事件.


@Override

 public boolean onTouchEvent(MotionEvent ev) {

 Log.e("jj", "onTouchEvent...");

 int x = (int) ev.getX();

 int y = (int) ev.getY();

 int position = pointToPosition(x, y);

 // 只有headview才进行手势操作.

 if (position == 0) {

 // 注入手势

 gestureDetector.onTouchEvent(ev);

 return super.onTouchEvent(ev);

 }

大家一看就明白了,我们只对position==0进行手势监听,也许有人问了,其实也可以直接在MainActivity中的dispatchTouchEvent分发事件中获取点击listview的position,可是这样不准确,我点击第0项获取的有的是0,有的是1,原因目前不明,不过但可以肯定,这样是能获取listview的position的,所以就干脆自定义吧,这样不会出错.这样解决了不会滑动下面item图片跟着切换.

再有就是我们要把listview item的第一项 onclick事件禁止了,我们直接把这个点击事件搬到onSingleTapUp中,这样就不会因为手势操作而影响item的onclick事件了,这样问题基本都解决了,其实我想有简单的方法,只要把Touch事件弄懂,可惜啊...不给力啊...

效果和上面一样.

经过多次测试,目前没有发现问题,如有不妥我会给出提示.


第二种方法:ViewPager.

viewpager效果相比大家都熟知,因此我就省略显示的那部分,方法和上面一样,只是显示用的是viewpager而已.

但是这里面存在一个严重的问题:ViewPager和listview共存的问题,二者都有自身的滑动事件,必然要产生冲突。viewpager操作起来相当的不灵敏.

这里我重点说一下解决办法:我们需要自定义Listview,对其拦截事件进行处理.另外我们要用手势,判断上下左右滑动.


MyListView.java

import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.view.GestureDetector;

import android.view.GestureDetector.SimpleOnGestureListener;

import android.view.MotionEvent;

import android.view.View;

import android.widget.ListView;

public class MyListView extends ListView {

 private GestureDetector mGestureDetector;

 View.OnTouchListener mGestureListener;

 public MyListView(Context context) {

 super(context);

 public MyListView(Context context, AttributeSet attrs) {

 super(context, attrs);

 mGestureDetector = new GestureDetector(new YScrollDetector());

 setFadingEdgeLength(0);

 public MyListView(Context context, AttributeSet attrs, int defStyle) {

 super(context, attrs, defStyle);

 @Override

 public boolean onInterceptTouchEvent(MotionEvent ev) {

 super.onInterceptTouchEvent(ev);

 return mGestureDetector.onTouchEvent(ev);

 class YScrollDetector extends SimpleOnGestureListener {

 @Override

 public boolean onScroll(MotionEvent e1, MotionEvent e2,

 float distanceX, float distanceY) {

 if (Math.abs(distanceY) = Math.abs(distanceX)) {

 Log.e("jj", "上下....");

 return true;

 Log.e("jj", "左右....");

 return false;

}

这样viewpager滑动就不会受listview干扰了,listview上下也可以滑动.

由于自己对事件分发不是很了解,所以不过多介绍,想知道的话,自己慢慢研究吧,我这里只是提供一个解决方法,我也在学习中... 其他部分不难,这里就不讲解了.

感觉还是第二种方法好,这也是为什么那么多客户端都是这么搞,不过各有千秋,因人而异.

对第二种方法实现简单讲解:

我们的目的是:我们左右滑动ViewPager的时候ListView不影响,而当ViewPager上下滑动的时候可以随意滑动.

我们可以这样做:我们把onInterceptTouchEvent返回值更改为fase,那么意味着,如果孩子存在onInterceptTouchEvent那么会继续传递给孩子的onInterceptTouchEvent...后面我们不管(此时ListView失去touch事件),这个时候ViewPager获取Touch事件. 这个时候ViewPager就可以左右滑动(不可以上下滑动)。 如果孩子不存在onInterceptTouchEvent,ListView执行本身ontouch.  

那么把onInterceptTouchEvent返回值更改为true.意思就是:我对touch事件进行拦截,不进行向下传递,直接执行自身的Ontouch事件,这个时候ViewPager就可以上下滑了(不可以左右滑动切换).

根据实情,那么我们如何动态控制这个onInterceptTouchEvent的返回值,这个时候我们可以借助:GestureDetector手势来实现.


/***

 * @author zhangjia

 class YScrollDetector extends SimpleOnGestureListener {

 @Override

 public boolean onScroll(MotionEvent e1, MotionEvent e2,

 float distanceX, float distanceY) {

 if (Math.abs(distanceY) = Math.abs(distanceX)) {

 Log.e("jj", "上下....");

 return true;

 Log.e("jj", "左右....");

 return false;

 }

上面这个方法可以根据手势来判断我们手的滑动方向.而:boolean b = mGestureDetector.onTouchEvent(ev);

这个值就是onScroll返回的值.这个值是代表我们手势mGestureDetector消费了没,为什么这么说呢,因为这个和我们外界的touch分开了,就算我们在这里消费了那么外面该怎么执行就怎么执行。经过测试觉得mGestureDetector.onTouchEvent(ev)这个方法就是执行手势相应方法,然后返回的是onScroll的返回值.

而当我们上下滑动的时候mGestureDetector.onTouchEvent(ev)返回true,而ViewPager需要上下滑动的时候只需要将onInterceptTouchEvent的返回值更改为true,左右滑动同理.

那么这样我们就实现了ViewPager与ListView滑动的冲突.


好了,就写到这里了,下面给一个Demo,大家可以拿去看看!

http://download.csdn.net/detail/gulaer/4965682


Android 组件化(一)项目模式管理、模式切换 在进行安装开发的时候我们经常会对项目进行不同业务逻辑处理分包,例如专门处理网络、数据库、业务逻辑代码的,如果我们不分包则所有东西写在一起,势必在开发过程中会浪费很多时间在寻找文件上,而分包的思想源于模块化,例如一些utils类,专门放到一个包下面,这样在使用的时候就能很快找到。节省开发时间,降低后期维护成本,那么组件化是什么?
Android TabLayout 加 ViewPager实现选项卡切换功能 今天讲一个很简单的功能,就是可以切换的选项卡功能,很多app都有类似这种效果,实现的方法也有很多,这里我采用TabLayout加上ViewPager来实现,这里我做了一个封装,相当于一个工具类来着,哪个地方需要用到都可以使用,使用上我的那个封装类就可以了。