Android之自定义索引

       自定义view在我看来,一直都是一个难点,它的逻辑思维很强,有时候你会完全想不到。我自己也是对自定义view很抵触,可奈何,再抵触还是要学,要会的一个知识点。今天我们就在写一回,但其实我觉得好像也不完全算是自定义view。好了,不扯了,入正题。

       微信主页面的好友列表大家应该都熟悉,我要说的是列表最右边的那一竖排字母的索引,就是它让我们在寻找好友得时候可以方便一点,并且你的好友都是在按照字母的顺序排列着,我们就写一写那个,但是汉字的话还是有点难度的。我们就实现一个简单的。

一、先写布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:textColor="#000"
        android:textSize="16sp"
        android:text="分组索引listview列表" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff" >

        <ListView
            android:id="@+id/listView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
        </ListView>

        <TextView
            android:id="@+id/tv"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_gravity="center"
            android:background="#f0606060"
            android:gravity="center"
            android:text="A"
            android:textColor="#ffffff"
            android:textSize="30sp" />

        <LinearLayout
            android:id="@+id/layout"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_gravity="right"
            android:background="#d7d7d7"
            android:gravity="center"
            android:orientation="vertical" >
        </LinearLayout>
    </FrameLayout>

</LinearLayout>


二、这个listview我们需要两个item

第一个item
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="#ffffff"
    android:orientation="vertical"
    android:paddingBottom="5dp"
    android:paddingLeft="20dp"
    android:paddingTop="5dp" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textColor="#000000"
        android:textSize="20sp" />
</LinearLayout>

第二个index

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="#9c9c9c"
    android:orientation="vertical"
    android:paddingBottom="2dp"
    android:paddingLeft="10dp"
    android:paddingTop="2dp" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textColor="#ffffff" />
</LinearLayout>

好了,我们下面来看看MainActivity的操作


public class MainActivity extends Activity {

    LinearLayout layoutIndex;
    private String[] str = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
            "K", "L", "M", "N", "O", "P", "Q", "U", "V", "W", "X", "Y", "Z" };

    int height;// 字体高度
    private String data[] = { "android", "java", "news", "baidu", "oberser",
            "mary", "next", "ruby", "money", "lucy", "very", "thunder",
            "object", "lily", "jay", "answer", "layout", "demos", "com",
            "collect", "custom", "blog", "round", "redirect", "ground", "gray",
            "blue", "zone", "james", "zhang", "location" };
    String nData[];// 数据源,整合了索引字母
    private ListView listView;
    MyAdapter adapter;
    private TextView tv_show;// 中间显示标题的文本

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        layoutIndex = (LinearLayout) this.findViewById(R.id.layout);
        layoutIndex.setBackgroundColor(Color.parseColor("#00ffffff"));
        // height =
        // this.getWindowManager().getDefaultDisplay().getHeight()//获取屏幕的高度然后除以索引字母的长度
        // / str.length;
        sortIndex();
        listView = (ListView) findViewById(R.id.listView1);
        adapter = new MyAdapter(this);
        listView.setAdapter(adapter);

        tv_show = (TextView) findViewById(R.id.tv);
        tv_show.setVisibility(View.INVISIBLE);

    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        // 在oncreate里面执行下面的代码没反应,因为oncreate里面得到的getHeight=0
        System.out.println("layoutIndex.getHeight()=" + layoutIndex.getHeight());
        height = layoutIndex.getHeight() / str.length;
        getIndexView();
    }

    /** 获取排序后的新数据 */
    public void sortIndex() {
        TreeSet<String> set = new TreeSet<String>();
        // 获取初始化数据源中的首字母,添加到set中
        for (String string : data) {
            set.add(String.valueOf(string.charAt(0)));
        }
        // 新数组的长度为原数据加上set的大小
        nData = new String[data.length + set.size()];
        int i = 0;
        for (String string : set) {
            nData[i] = string;
            i++;
        }
        // 将原数据拷贝到新数据中
        System.arraycopy(data, 0, nData, set.size(), data.length);
        Arrays.sort(nData, String.CASE_INSENSITIVE_ORDER);// 自动按照首字母排序
    }

    /** 绘制索引列表 */
    public void getIndexView() {
        LinearLayout.LayoutParams params = new LayoutParams(
                LayoutParams.WRAP_CONTENT, height);
        // params.setMargins(10, 5, 10, 0);
        for (int i = 0; i < str.length; i++) {
            final TextView tv = new TextView(this);
            tv.setLayoutParams(params);
            tv.setText(str[i]);
            // tv.setTextColor(Color.parseColor("#606060"));
            // tv.setTextSize(16);
            tv.setPadding(10, 0, 10, 0);
            layoutIndex.addView(tv);
            layoutIndex.setOnTouchListener(new OnTouchListener() {

                @Override
                public boolean onTouch(View v, MotionEvent event)

                {
                    float y = event.getY();
                    int index = (int) (y / height);
                    if (index > -1 && index < str.length) {// 防止越界
                        String key = str[index];
                        if (selector.containsKey(key)) {
                            int pos = selector.get(key);
                            if (listView.getHeaderViewsCount() > 0) {// 防止ListView有标题栏,本例中没有。
                                listView.setSelectionFromTop(
                                        pos + listView.getHeaderViewsCount(), 0);
                            } else {
                                listView.setSelectionFromTop(pos, 0);// 滑动到第一项
                            }
                            tv_show.setVisibility(View.VISIBLE);
                            tv_show.setText(str[index]);
                        }
                    }
                    switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        layoutIndex.setBackgroundColor(Color
                                .parseColor("#606060"));
                        break;

                    case MotionEvent.ACTION_MOVE:

                        break;
                    case MotionEvent.ACTION_UP:
                        layoutIndex.setBackgroundColor(Color
                                .parseColor("#00ffffff"));
                        tv_show.setVisibility(View.INVISIBLE);
                        break;
                    }
                    return true;
                }
            });
        }
    }

    private HashMap<String, Integer> selector;// 存放含有索引字母的位置

    /** 适配器 */
    private class MyAdapter extends BaseAdapter {

        Holder holder;
        Context context;

        public MyAdapter(Context context) {
            this.context = context;
            selector = new HashMap<String, Integer>();
            for (int j = 0; j < str.length; j++) {// 循环字母表,找出nData中对应字母的位置
                for (int i = 0; i < nData.length; i++) {
                    if (nData[i].equals(str[j].toLowerCase())) {
                        selector.put(str[j], i);
                    }
                }
            }
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return nData.length;
        }

        @Override
        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return nData[position];
        }

        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return 0;
        }

        @Override
        public boolean isEnabled(int position) {
            // TODO Auto-generated method stub
            if (nData[position].length() == 1)// 如果是字母索引
                return false;// 表示不能点击
            return super.isEnabled(position);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            String item = nData[position];
            // TODO Auto-generated method stub

            if (item.length() == 1)
                convertView = getLayoutInflater().inflate(R.layout.index, null);
            else
                convertView = getLayoutInflater().inflate(R.layout.item, null);
            TextView tv = (TextView) convertView.findViewById(R.id.textView1);

            tv.setText(item);
            return convertView;
        }

        class Holder {
            TextView tv;
        }
    }

}
代码到这里就完成了,有兴趣的可以把代码拿过去试试。其实这个我也是看别人的一个比较完整的一个demo摘出来的一部分,感觉还不错。就这样了,拜拜。^-^   ^-^   ^-^





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现自定义画廊效果,可以通过继承ViewPager类,重写其onInterceptTouchEvent()和onTouchEvent()方法,并在onDraw()方法中绘制自定义效果。 以下是一个简单的实现步骤: 1. 继承ViewPager类,重写onInterceptTouchEvent()和onTouchEvent()方法,用于捕捉和处理触摸事件。 ```java public class GalleryViewPager extends ViewPager { private float mLastMotionX; private int mTouchSlop; public GalleryViewPager(Context context) { super(context); init(); } public GalleryViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { ViewConfiguration config = ViewConfiguration.get(getContext()); mTouchSlop = config.getScaledTouchSlop(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) && (Math.abs(mLastMotionX - ev.getX()) > mTouchSlop)) { return true; } mLastMotionX = ev.getX(); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { return super.onTouchEvent(ev); } } ``` 2. 在onDraw()方法中绘制自定义效果。例如,可以绘制一个圆形的选中框,并将当前选中的页面放大。 ```java public class GalleryViewPager extends ViewPager { // ... private Paint mPaint; private RectF mRectF; private float mRadius; // 当前选中的页面索引 private int mCurrentPageIndex = 0; public GalleryViewPager(Context context) { super(context); init(); } public GalleryViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { // ... mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(4); mPaint.setColor(Color.WHITE); mRadius = 100; mRectF = new RectF(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (getChildCount() <= 0) { return; } // 绘制圆形选中框 float cx = getWidth() / 2f; float cy = getHeight() / 2f; float x = cx - mRadius; float y = cy - mRadius; mRectF.set(x, y, x + 2 * mRadius, y + 2 * mRadius); canvas.drawOval(mRectF, mPaint); // 放大当前选中的页面 View currentPage = getChildAt(mCurrentPageIndex); float currentScale = 1.2f; float scale = (currentPage.getWidth() * currentScale) / currentPage.getWidth(); currentPage.setScaleX(scale); currentPage.setScaleY(scale); } // ... } ``` 3. 在onPageSelected()方法中更新当前选中的页面索引,并调用invalidate()方法强制重绘。 ```java public class GalleryViewPager extends ViewPager { // ... @Override public void onPageSelected(int position) { mCurrentPageIndex = position; invalidate(); super.onPageSelected(position); } // ... } ``` 最后,使用自定义的GalleryViewPager代替原来的ViewPager即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值