仿QQ电话/消息切换的自定义布局结合Fragment解决你的需求!

转载请注明出处:王亟亟的大牛之路

先上模仿的对象:QQ的电话/消息 界面

用户点击消息或者电话会切换不同的界面

然后再上自己实现的界面

然后再附带了一些每一个Fragment内部的操作,来模拟切换后的效果

实现方法: 一个自定义控件+下面的Fragment.利用setOnSegmentControlViewClickListener方法来监听用户的点击来对界面进行操作。

项目目录结构

一个主Activity加一系列分页的Fragment(其实这里可以用Java代码来添加Fragment,但是考虑到大家的使用性,还是用麻烦的方法。毕竟 Copy走就直接可以改每一个单独的Fragment进行修改了)

主Activity

package com.wjj.wjjdemo;
import com.wjj.wjjdemo.customView.SegmentControlView;
import com.wjj.wjjdemo.customView.SegmentControlView.onSegmentControlViewClickListener;
import com.wjj.wjjdemo.fragment.fragmenta;
import com.wjj.wjjdemo.fragment.fragmentb;
import com.wjj.wjjdemo.fragment.fragmentc;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

public class MainActivity extends Activity {
    private SegmentControlView SegmentControlView = null;
    /*等会要用于切换的3个Fragment*/
    private fragmenta fragmenta;
    private fragmentb fragmentb;
    private fragmentc fragmentc;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FindById();
     // 设置默认的Fragment
        setDefaultFragment();
        Listener();
    }

    private void FindById(){
        SegmentControlView = (SegmentControlView) findViewById(R.id.SegmentControlView);
    }

    private void Listener(){
        SegmentControlView.setOnSegmentControlViewClickListener(new onSegmentControlViewClickListener() {

            @Override
            public void onSegmentControlViewClick(View view, int position) {
                FragmentManager fm = getFragmentManager();
                // 开启Fragment事务
                FragmentTransaction transaction = fm.beginTransaction(); 

                switch (position) {
                    case 0:
                        if (fragmenta == null)
                        {
                            fragmenta = new fragmenta();
                        }
                        // 使用当前Fragment的布局替代id_content的控件
                        transaction.replace(R.id.fragmentlayout, fragmenta);
                        // 事务提交
                        transaction.commit();
                        break;
                    case 1:
                     if (fragmentb == null)
                        {
                            fragmentb = new fragmentb();
                        }
                        // 使用当前Fragment的布局替代id_content的控件
                        transaction.replace(R.id.fragmentlayout, fragmentb);
                        // 事务提交
                        transaction.commit();
                        break;
                    case 2:
                     if (fragmentc == null)
                        {
                            fragmentc = new fragmentc();
                        }
                        // 使用当前Fragment的布局替代id_content的控件
                        transaction.replace(R.id.fragmentlayout, fragmentc);
                        // 事务提交
                        transaction.commit();
                        break;
                    default:
                        break;
                }
            }
        });
    }

    private void setDefaultFragment(){
        FragmentManager fm = getFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        fragmenta=new fragmenta();
        transaction.replace(R.id.fragmentlayout, fragmenta);
        transaction.commit();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

其实 当中监听时间的transaction.commit(); 些多余了,大家就自行修改吧,放到函数外面就行了,因为会break出去,并不需要每一个case里都要加

自定义View

@SuppressLint("NewApi")
public class SegmentControlView extends LinearLayout {

    private TextView textView1 = null;
    private TextView textView2 = null;
    private TextView textView3 = null;
    private View verTextView1 = null;//中间的竖线
    private View verTextView2 = null;//中间的竖线
    private onSegmentControlViewClickListener listener;

    public SegmentControlView(Context context) {
        super(context);
        initView();
    }

    public SegmentControlView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public SegmentControlView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {

        textView1 = new TextView(getContext());
        textView2 = new TextView(getContext());
        textView3 = new TextView(getContext());
        verTextView1 = new View(getContext());
        verTextView2 = new View(getContext());

        textView1.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1));
        verTextView1.setLayoutParams(new LayoutParams(1, LayoutParams.MATCH_PARENT));
        textView2.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1));
        verTextView2.setLayoutParams(new LayoutParams(1, LayoutParams.MATCH_PARENT));
        textView3.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1));

        setSegmentText(0, getContext().getString(R.string.noti_msg));
        setSegmentText(1, getContext().getString(R.string.friends_list));
        setSegmentText(2, getContext().getString(R.string.all_list));
        setSegmentTextSize(16);//设置文字大小

        XmlPullParser xrp = getResources().getXml(R.drawable.seg_text_color_selector);
        try {
            ColorStateList csl = ColorStateList.createFromXml(getResources(), xrp);
            textView1.setTextColor(csl);
            textView2.setTextColor(csl);
            textView3.setTextColor(csl);
          } catch (Exception e) {
        }
        textView1.setGravity(Gravity.CENTER);
        textView2.setGravity(Gravity.CENTER);
        textView3.setGravity(Gravity.CENTER);
        textView1.setPadding(3, 6, 3, 6);
        textView2.setPadding(3, 6, 3, 6);
        textView3.setPadding(3, 6, 3, 6);
        textView1.setBackgroundResource(R.drawable.seg_left);
        textView2.setBackgroundResource(R.drawable.seg_middle);
        textView3.setBackgroundResource(R.drawable.seg_right);
        verTextView1.setBackgroundColor(getResources().getColor(R.color.blue));
        verTextView2.setBackgroundColor(getResources().getColor(R.color.blue));

        this.removeAllViews();
        this.addView(textView1);
        this.addView(verTextView1);
        this.addView(textView2);
        this.addView(verTextView2);
        this.addView(textView3);
        this.invalidate();

        textView1.setSelected(true);

        textView1.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (textView1.isSelected()) {
                    return;
                }
                textView1.setSelected(true);
                textView2.setSelected(false);
                textView3.setSelected(false);
                if (listener != null) {
                    listener.onSegmentControlViewClick(textView1, 0);
                }
            }
        });
        textView2.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (textView2.isSelected()) {
                    return;
                }
                textView2.setSelected(true);
                textView1.setSelected(false);
                textView3.setSelected(false);
                if (listener != null) {
                    listener.onSegmentControlViewClick(textView2, 1);
                }
            }
        });

        textView3.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (textView3.isSelected()) {
                    return;
                }
                textView3.setSelected(true);
                textView1.setSelected(false);
                textView2.setSelected(false);
                if (listener != null) {
                    listener.onSegmentControlViewClick(textView2, 2);
                }
            }
        });
    }

    /**
     * 设置字体大小 单位dip
     * @param dp
     */
    public void setSegmentTextSize(int dp) {
        textView1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, dp);
        textView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, dp);
        textView3.setTextSize(TypedValue.COMPLEX_UNIT_DIP, dp);
    }

    /**
     * 设置文字
     * @param text
     * @param position
     */
    public void setSegmentText(int position, CharSequence text) {
        if (position == 0) {//左
            textView1.setText(text);
        }
        if (position == 1) {//中
            textView2.setText(text);
        }
        if (position == 2) {//右
            textView3.setText(text);
        }
    }

    public void setOnSegmentControlViewClickListener(onSegmentControlViewClickListener listener) {
        this.listener = listener;
    }

    public static interface onSegmentControlViewClickListener{

        /**
         * @param v
         * @param position 0-左边 1-中间 2-右边
         */
        public void onSegmentControlViewClick(View v,int position);
    }

    /**
     * dp与px转化函数
     * @param context
     * @param dp
     * @return
     */
    private static int dp2Px(Context context, float dp) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }
}

整体封装的还不错,需要修改UI的观众老爷可自行进行修改,大体功能已经实现了

3个Fragment中的一个

public class fragmenta extends Fragment{
    Button fragmentaButton;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        View view= inflater.inflate(R.layout.fragemnta, container, false);
        fragmentaButton=(Button)view.findViewById(R.id.fragmentaButtona);
        fragmentaButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Toast.makeText(getActivity(), "fragmenta", 1).show();
            }
        });
        return view;
    }

}

主布局文件

<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.wjj.wjjdemo.MainActivity"
    android:background="@color/white">

    <com.wjj.wjjdemo.customView.SegmentControlView
        android:id="@+id/SegmentControlView"
        android:layout_width="240dp"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/seg_linear"
        android:padding="0.5dp" >
    </com.wjj.wjjdemo.customView.SegmentControlView>

    <FrameLayout
        android:id="@+id/fragmentlayout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_alignParentBottom="true"
        android:layout_below="@+id/SegmentControlView" >
    </FrameLayout>

</RelativeLayout>

这里要补充下,楼主在FrameLayout节点这一部分犯了一个错误,之前用Fragment来填充这一部分,导致出现了2个View重叠的问题,所以用FrameLayout之类的布局来填充就好了。

大体主要的代码就这些了,源码在下面会补上,布局文件资源文件什么的都在里面了,大家拿来就可以用。

http://yunpan.cn/cdcyxcXkLZnye 访问密码 0d8e

有疑问欢迎QQ联系452270579

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

时间: 2024-10-03 13:36:05

仿QQ电话/消息切换的自定义布局结合Fragment解决你的需求!的相关文章

【WP8】仿QQ提示消息

WP版的QQ提示消息的时候从顶部滑入,3秒后从顶部滑出,本文模仿该效果实现一个MessageToastManager类用于显示提示消息 思路很简单,就是动画而已,支持配置颜色和回掉 // ************************************************* // // 作者:bomo // 小组:WP开发组 // 创建日期:2014/7/7 15:18:12 // 版本号:V1.00 // 说明: // // ****************************

制作高仿QQ的聊天系统(一)—— 布局文件 &amp; 减少过度绘制

由于没有自己的服务器,我就找了个能实现双方通信的SDK,这个SDK是友盟的用户反馈SDK.本系列的博文关注的不是网络通信,而是如何在网络通信机制已经做好的情况下,做出一个可用的聊天系统.其实,刚开始做的时候觉得适配器挺难的,但后来发现实现和QQ相同的布局文件也需要技术,所以本篇就来详细的说下布局文件该怎么写. 一.主界面 主界面的元素分为三块,一个是标题栏,还有是中间的listview,最后是下方的输入区域.整体分析后发现顶部的 1.1 ActionBar 标题栏我们没办法用系统自带的actio

Android UI设计: 分享一个仿QQ聊天消息提示可以拖拉气泡

首先上效果图 功能有: 1. 可以随时拖拉 2. 拖拉超过一定距离会监听 3. 拖拉返回的时候,有来回反弹效果 此效果先是参照了网上github两个版本的效果.不过都不是自己想要那么理想. 1.其中有一个是两层,一层是textview控件和一层surfaceview.经测试效果不错,但是效率不高,在刚点击的有闪动现象.会跳帧.于是放弃这种方法.不过它能够全屏拖拉. 2另一个的实现方法很赞,全程一个view就完事,全部自绘,没有用控件.而且贝塞尔曲线就是中间那个瘦瘦的,随着距离越来越瘦的,是两条贝

mina的编码和解码以及断包的处理,发送自定义协议,仿qq聊天,发送xml或json和

最近一段时间以来,mina很火,和移动开发一样,异常的火爆.前面写了几篇移动开发的文章,都还不错,你们的鼓励就是我最大的动力.好了,废话少说.我们来看下tcp通讯吧. tcp通讯对于java来说是很简单的.就是socket,也就是大家常说的套接字.大家不要把它看的很难.说白了tcp通讯其实就是数据流的读写.一条输入流,一条输出流.分别复杂发消息和接收消息. 明白了这些,ok,我们来看看我写的例子吧.先看服务器端的测试类的源码: package com.minaqq.test; import co

仿QQ聊天布局--iOS

虽然注册博客园这么久了,但很少在这上面写些东西,一来也是觉得自己能力不够,二来怕误人子弟,所以一直秉着“多看,多做,少说”的原则混迹在各论坛之中.但日子久了,觉着这其实是一种逃避的方法.思来想去,那些牛逼的人其实是那些能把自己心中所想完全表达出来,让人看之舒服,听之认同的人.所以,除了“多看,多做,少说”外,怕要加一条“多总结”,否则恐要淹死在这信息化的浪潮中了. 最近对QQ.微信聊天布局产生兴趣,便搜索资料试着搞搞,趁着空隙,先上效果图,得空再补充说明. 大致思路就是 自定义tableView

android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变

首先要知道  自定义scrollview 仿QQ效果 下拉伸缩放大顶部图片 的原理是监听ontouch事件,在MotionEvent.ACTION_MOVE事件时候,使用不同倍数的系数,重置布局位置[注此处是伸缩隐藏,不是同比例放大] inner.layout(normal.left, (int) (normal.top + inner_move_H), normal.right, (int) (normal.bottom + inner_move_H)); 关于“自定义scrollview 仿

Android高仿QQ消息滑动删除(附源码)

大家都应该使用过QQ吧,他的消息中可以滑动删除功能,我觉得比较有意思,所以模仿写了一个,并且修改了其滑动算法.我先贴几个简单示范图吧 其实主要用的是算法以及对ListView的把控. 一下是适配器的类 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

Android中仿淘宝首页顶部滚动自定义HorizontalScrollView定时水平自动切换图片

Android中仿淘宝首页顶部滚动自定义HorizontalScrollView定时水平自动切换图片 自定义ADPager 自定义水平滚动的ScrollView效仿ViewPager 当遇到要在ViewPager中添加多张网络请求图片的情况下,不能进行复用,导致每次都要重新去求情已经请求过的数据致使流量数据过大 自定义的数据结构解决了这个问题,固定传递的图片数据之后进行统一请求,完成后进行页面切换数据复用 代码中涉及网络请求是用的Volley网络请求框架 PicCarousel是网络数据请求的U

Android UI之自定义——最简单的仿QQ音乐歌词颜色渐变

Android UI之自定义--最简单的仿QQ音乐歌词颜色渐变 记得刚开始做android的时候,就发现QQ音乐歌词颜色渐变的效果,就在网上搜索过,但是就是没有找到满意的.今天突然用QQ音乐听歌的时候,看到歌词颜色渐变,决定来分析看看,没想到实现原来如此简单.这篇只是将最简单的歌词颜色渐变功能,不包括歌词滚动等效果. 首先来看下QQ音乐歌词界面 实现步骤 从界面上可以看出,是通过不同颜色的文本叠加所形成的视觉效果.那么android文本一般使用TextView实现,那就来试试用TextView在